From d4a3b6c520785ea6f967f2157ab6e65e21a1f59b Mon Sep 17 00:00:00 2001 From: Kongqun Yang Date: Tue, 18 Feb 2014 15:32:48 -0800 Subject: [PATCH] Remove base and build directories in packager. chromium/src/base and chromium/src/build will be pulled using repo manifest @ https://widevine-internal-review.googlesource.com/#/c/9071 Also ignore base and build in .gitignore. Bug: 12588544 Change-Id: Iec9ad12d61c7b7719e066b30a6672c558ef15851 --- .gitignore | 2 + base/DEPS | 15 - base/OWNERS | 29 - base/PRESUBMIT.py | 56 - base/allocator/README | 59 - base/allocator/allocator.gyp | 676 --- base/allocator/allocator_extension.cc | 56 - base/allocator/allocator_extension.h | 59 - base/allocator/allocator_extension_thunks.cc | 52 - base/allocator/allocator_extension_thunks.h | 36 - base/allocator/allocator_shim.cc | 446 -- base/allocator/allocator_shim.h | 27 - base/allocator/allocator_unittests.cc | 521 -- base/allocator/debugallocation_shim.cc | 9 - base/allocator/generic_allocators.cc | 168 - base/allocator/prep_libc.py | 67 - base/allocator/tcmalloc_unittest.cc | 81 - base/allocator/type_profiler.cc | 63 - base/allocator/type_profiler.h | 40 - base/allocator/type_profiler_control.cc | 38 - base/allocator/type_profiler_control.h | 31 - base/allocator/type_profiler_map_unittests.cc | 99 - base/allocator/type_profiler_tcmalloc.cc | 37 - base/allocator/type_profiler_tcmalloc.h | 29 - base/allocator/type_profiler_unittests.cc | 189 - base/allocator/unittest_utils.cc | 18 - base/allocator/win_allocator.cc | 73 - base/android/OWNERS | 3 - base/android/activity_state_list.h | 16 - base/android/activity_status.cc | 66 - base/android/activity_status.h | 98 - base/android/activity_status_unittest.cc | 128 - base/android/base_jni_registrar.cc | 58 - base/android/base_jni_registrar.h | 21 - base/android/build_info.cc | 78 - base/android/build_info.h | 115 - base/android/context_types.cc | 26 - base/android/context_types.h | 22 - base/android/cpu_features.cc | 26 - base/android/cpu_features.h | 18 - base/android/fifo_utils.cc | 25 - base/android/fifo_utils.h | 32 - base/android/important_file_writer_android.cc | 42 - base/android/important_file_writer_android.h | 18 - .../org/chromium/base/AccessedByNative.java | 20 - .../org/chromium/base/ActivityState.template | 14 - .../src/org/chromium/base/ActivityStatus.java | 136 - .../chromium/base/ApiCompatibilityUtils.java | 140 - .../java/src/org/chromium/base/BuildInfo.java | 117 - .../src/org/chromium/base/CalledByNative.java | 23 - .../base/CalledByNativeUnchecked.java | 27 - .../org/chromium/base/ChromiumActivity.java | 49 - .../src/org/chromium/base/ContextTypes.java | 96 - .../src/org/chromium/base/CpuFeatures.java | 40 - .../base/ImportantFileWriterAndroid.java | 29 - .../src/org/chromium/base/JNINamespace.java | 20 - .../org/chromium/base/JavaHandlerThread.java | 41 - .../base/MemoryPressureLevelList.template | 12 - .../chromium/base/MemoryPressureListener.java | 55 - .../base/NativeClassQualifiedName.java | 25 - .../src/org/chromium/base/ObserverList.java | 177 - .../src/org/chromium/base/PathService.java | 24 - .../java/src/org/chromium/base/PathUtils.java | 108 - .../src/org/chromium/base/PowerMonitor.java | 92 - .../chromium/base/PowerStatusReceiver.java | 23 - .../java/src/org/chromium/base/SysUtils.java | 30 - .../chromium/base/SystemMessageHandler.java | 55 - .../src/org/chromium/base/ThreadUtils.java | 172 - .../src/org/chromium/base/WeakContext.java | 45 - base/android/java_handler_thread.cc | 62 - base/android/java_handler_thread.h | 48 - .../org/chromium/base/ContextTypesTest.java | 43 - .../org/chromium/base/ObserverListTest.java | 180 - base/android/jni_android.cc | 323 -- base/android/jni_android.h | 132 - base/android/jni_android_unittest.cc | 141 - base/android/jni_array.cc | 186 - base/android/jni_array.h | 86 - base/android/jni_array_unittest.cc | 148 - .../golden_sample_for_tests_jni.h | 373 -- .../example/jni_generator/SampleForTests.java | 288 - base/android/jni_generator/jni_generator.gyp | 67 - base/android/jni_generator/jni_generator.py | 1065 ---- .../jni_generator/jni_generator_tests.py | 2084 ------- .../android/jni_generator/sample_for_tests.cc | 106 - base/android/jni_generator/sample_for_tests.h | 46 - base/android/jni_helper.cc | 67 - base/android/jni_helper.h | 41 - base/android/jni_registrar.cc | 30 - base/android/jni_registrar.h | 27 - base/android/jni_string.cc | 99 - base/android/jni_string.h | 45 - base/android/jni_string_unittest.cc | 32 - .../memory_pressure_listener_android.cc | 31 - .../memory_pressure_listener_android.h | 30 - base/android/path_service_android.cc | 26 - base/android/path_service_android.h | 18 - base/android/path_utils.cc | 67 - base/android/path_utils.h | 48 - base/android/path_utils_unittest.cc | 46 - base/android/scoped_java_ref.cc | 73 - base/android/scoped_java_ref.h | 198 - base/android/scoped_java_ref_unittest.cc | 122 - base/android/sys_utils.cc | 31 - base/android/sys_utils.h | 26 - base/android/thread_utils.h | 16 - base/at_exit.cc | 82 - base/at_exit.h | 76 - base/at_exit_unittest.cc | 87 - base/atomic_ref_count.h | 80 - base/atomic_sequence_num.h | 60 - base/atomicops.h | 164 - base/atomicops_internals_arm_gcc.h | 285 - base/atomicops_internals_atomicword_compat.h | 100 - base/atomicops_internals_gcc.h | 106 - base/atomicops_internals_mac.h | 197 - base/atomicops_internals_mips_gcc.h | 154 - base/atomicops_internals_tsan.h | 378 -- base/atomicops_internals_x86_gcc.cc | 104 - base/atomicops_internals_x86_gcc.h | 269 - base/atomicops_internals_x86_msvc.h | 194 - base/atomicops_unittest.cc | 241 - base/auto_reset.h | 41 - base/base.gyp | 1315 ----- base/base.gypi | 894 --- base/base64.cc | 43 - base/base64.h | 25 - base/base64_unittest.cc | 28 - base/base_export.h | 34 - base/base_paths.cc | 47 - base/base_paths.h | 51 - base/base_paths_android.cc | 63 - base/base_paths_android.h | 25 - base/base_paths_mac.h | 24 - base/base_paths_mac.mm | 117 - base/base_paths_posix.cc | 119 - base/base_paths_posix.h | 29 - base/base_paths_win.cc | 208 - base/base_paths_win.h | 51 - base/base_switches.cc | 60 - base/base_switches.h | 31 - base/base_unittests.isolate | 55 - base/base_untrusted.gyp | 41 - base/basictypes.h | 369 -- base/bind.h | 517 -- base/bind.h.pump | 153 - base/bind_helpers.cc | 29 - base/bind_helpers.h | 563 -- base/bind_helpers_unittest.cc | 39 - base/bind_internal.h | 2789 ---------- base/bind_internal.h.pump | 500 -- base/bind_internal_win.h | 368 -- base/bind_internal_win.h.pump | 81 - base/bind_unittest.cc | 833 --- base/bind_unittest.nc | 203 - base/bits.h | 47 - base/bits_unittest.cc | 48 - base/build_time.cc | 25 - base/build_time.h | 25 - base/build_time_unittest.cc | 30 - base/callback.h | 765 --- base/callback.h.pump | 436 -- base/callback_forward.h | 17 - base/callback_helpers.h | 30 - base/callback_internal.cc | 38 - base/callback_internal.h | 184 - base/callback_unittest.cc | 181 - base/callback_unittest.nc | 50 - base/cancelable_callback.h | 272 - base/cancelable_callback_unittest.cc | 184 - base/check_example.cc | 25 - base/chromeos/chromeos_version.cc | 24 - base/chromeos/chromeos_version.h | 20 - base/command_line.cc | 424 -- base/command_line.h | 178 - base/command_line_unittest.cc | 360 -- base/compiler_specific.h | 184 - base/containers/hash_tables.h | 264 - base/containers/hash_tables_unittest.cc | 53 - base/containers/linked_list.h | 164 - base/containers/linked_list_unittest.cc | 261 - base/containers/mru_cache.h | 305 -- base/containers/mru_cache_unittest.cc | 271 - base/containers/small_map.h | 652 --- base/containers/small_map_unittest.cc | 492 -- base/containers/stack_container.h | 258 - base/containers/stack_container_unittest.cc | 143 - base/cpu.cc | 162 - base/cpu.h | 81 - base/cpu_unittest.cc | 93 - base/critical_closure.h | 37 - base/critical_closure_ios.mm | 49 - .../FileVersionInfoTest1.dll | Bin 13824 -> 0 bytes .../FileVersionInfoTest2.dll | Bin 13824 -> 0 bytes base/debug/OWNERS | 3 - base/debug/alias.cc | 23 - base/debug/alias.h | 21 - base/debug/crash_logging.cc | 201 - base/debug/crash_logging.h | 104 - base/debug/crash_logging_unittest.cc | 182 - base/debug/debug_on_start_win.cc | 74 - base/debug/debug_on_start_win.h | 83 - base/debug/debugger.cc | 41 - base/debug/debugger.h | 48 - base/debug/debugger_posix.cc | 261 - base/debug/debugger_win.cc | 114 - base/debug/leak_annotations.h | 65 - base/debug/leak_tracker.h | 136 - base/debug/leak_tracker_unittest.cc | 113 - base/debug/proc_maps_linux.cc | 101 - base/debug/proc_maps_linux.h | 56 - base/debug/proc_maps_linux_unittest.cc | 281 - base/debug/profiler.cc | 217 - base/debug/profiler.h | 90 - base/debug/stack_trace.cc | 41 - base/debug/stack_trace.h | 101 - base/debug/stack_trace_android.cc | 132 - base/debug/stack_trace_ios.mm | 53 - base/debug/stack_trace_posix.cc | 556 -- base/debug/stack_trace_unittest.cc | 229 - base/debug/stack_trace_win.cc | 271 - base/debug/trace_event.h | 1542 ------ base/debug/trace_event_android.cc | 158 - base/debug/trace_event_impl.cc | 1692 ------ base/debug/trace_event_impl.h | 595 -- base/debug/trace_event_impl_constants.cc | 14 - base/debug/trace_event_memory.cc | 414 -- base/debug/trace_event_memory.h | 152 - base/debug/trace_event_memory_unittest.cc | 211 - base/debug/trace_event_unittest.cc | 2024 ------- base/debug/trace_event_unittest.h | 14 - base/debug/trace_event_win.cc | 120 - base/debug/trace_event_win.h | 123 - base/debug/trace_event_win_unittest.cc | 319 -- base/debug_message.cc | 17 - base/deferred_sequenced_task_runner.cc | 99 - base/deferred_sequenced_task_runner.h | 79 - ...deferred_sequenced_task_runner_unittest.cc | 184 - base/environment.cc | 127 - base/environment.h | 48 - base/environment_unittest.cc | 85 - base/event_recorder.h | 109 - base/event_recorder_stubs.cc | 28 - base/event_recorder_win.cc | 258 - base/event_types.h | 37 - base/file_descriptor_posix.h | 45 - base/file_util.cc | 264 - base/file_util.h | 464 -- base/file_util_android.cc | 16 - base/file_util_linux.cc | 62 - base/file_util_mac.mm | 42 - base/file_util_posix.cc | 958 ---- base/file_util_unittest.cc | 2426 --------- base/file_util_win.cc | 759 --- base/file_version_info.h | 87 - base/file_version_info_mac.h | 53 - base/file_version_info_mac.mm | 120 - base/file_version_info_unittest.cc | 140 - base/file_version_info_win.cc | 189 - base/file_version_info_win.h | 62 - base/files/OWNERS | 2 - base/files/dir_reader_fallback.h | 35 - base/files/dir_reader_linux.h | 98 - base/files/dir_reader_posix.h | 36 - base/files/dir_reader_posix_unittest.cc | 92 - base/files/file_enumerator.cc | 21 - base/files/file_enumerator.h | 156 - base/files/file_enumerator_posix.cc | 160 - base/files/file_enumerator_win.cc | 151 - base/files/file_path.cc | 1300 ----- base/files/file_path.h | 458 -- base/files/file_path_constants.cc | 22 - base/files/file_path_unittest.cc | 1231 ----- base/files/file_path_watcher.cc | 39 - base/files/file_path_watcher.h | 108 - base/files/file_path_watcher_browsertest.cc | 909 ---- base/files/file_path_watcher_kqueue.cc | 518 -- base/files/file_path_watcher_linux.cc | 487 -- base/files/file_path_watcher_stub.cc | 36 - base/files/file_path_watcher_win.cc | 292 - base/files/file_util_proxy.cc | 414 -- base/files/file_util_proxy.h | 195 - base/files/file_util_proxy_unittest.cc | 411 -- base/files/important_file_writer.cc | 167 - base/files/important_file_writer.h | 121 - base/files/important_file_writer_unittest.cc | 122 - base/files/memory_mapped_file.cc | 58 - base/files/memory_mapped_file.h | 76 - base/files/memory_mapped_file_posix.cc | 54 - base/files/memory_mapped_file_win.cc | 87 - base/files/scoped_platform_file_closer.cc | 16 - base/files/scoped_platform_file_closer.h | 26 - base/files/scoped_temp_dir.cc | 85 - base/files/scoped_temp_dir.h | 62 - base/files/scoped_temp_dir_unittest.cc | 117 - base/float_util.h | 36 - base/format_macros.h | 73 - ...c-x86-32.base_untrusted.source_list.gypcmd | 353 -- ...c-x86-64.base_untrusted.source_list.gypcmd | 353 -- base/gmock_unittest.cc | 137 - base/gtest_prod_util.h | 66 - base/guid.cc | 32 - base/guid.h | 32 - base/guid_posix.cc | 28 - base/guid_unittest.cc | 42 - base/guid_win.cc | 38 - base/hash.cc | 73 - base/hash.h | 31 - base/i18n/OWNERS | 1 - base/i18n/base_i18n_export.h | 29 - base/i18n/bidi_line_iterator.cc | 60 - base/i18n/bidi_line_iterator.h | 46 - base/i18n/break_iterator.cc | 126 - base/i18n/break_iterator.h | 131 - base/i18n/break_iterator_unittest.cc | 338 -- base/i18n/case_conversion.cc | 26 - base/i18n/case_conversion.h | 24 - base/i18n/case_conversion_unittest.cc | 26 - base/i18n/char_iterator.cc | 82 - base/i18n/char_iterator.h | 130 - base/i18n/char_iterator_unittest.cc | 101 - base/i18n/file_util_icu.cc | 170 - base/i18n/file_util_icu.h | 43 - base/i18n/file_util_icu_unittest.cc | 107 - base/i18n/i18n_constants.cc | 15 - base/i18n/i18n_constants.h | 20 - base/i18n/icu_encoding_detection.cc | 104 - base/i18n/icu_encoding_detection.h | 30 - base/i18n/icu_string_conversions.cc | 292 - base/i18n/icu_string_conversions.h | 70 - base/i18n/icu_string_conversions_unittest.cc | 386 -- base/i18n/icu_util.cc | 135 - base/i18n/icu_util.h | 18 - base/i18n/icu_util_nacl_win64.cc | 13 - base/i18n/number_formatting.cc | 87 - base/i18n/number_formatting.h | 34 - base/i18n/number_formatting_unittest.cc | 88 - base/i18n/rtl.cc | 383 -- base/i18n/rtl.h | 147 - base/i18n/rtl_unittest.cc | 385 -- base/i18n/string_compare.cc | 29 - base/i18n/string_compare.h | 28 - base/i18n/string_search.cc | 80 - base/i18n/string_search.h | 53 - base/i18n/string_search_unittest.cc | 226 - base/i18n/time_formatting.cc | 164 - base/i18n/time_formatting.h | 66 - base/i18n/time_formatting_unittest.cc | 175 - base/id_map.h | 257 - base/id_map_unittest.cc | 335 -- base/ini_parser.cc | 66 - base/ini_parser.h | 69 - base/ini_parser_unittest.cc | 131 - base/ios/OWNERS | 3 - base/ios/device_util.h | 65 - base/ios/device_util.mm | 165 - base/ios/device_util_unittest.mm | 122 - base/ios/ios_util.h | 26 - base/ios/ios_util.mm | 42 - base/ios/scoped_critical_action.h | 48 - base/ios/scoped_critical_action.mm | 54 - ...t-x86-32.base_untrusted.source_list.gypcmd | 353 -- ...t-x86-64.base_untrusted.source_list.gypcmd | 353 -- base/json/json_file_value_serializer.cc | 99 - base/json/json_file_value_serializer.h | 88 - base/json/json_parser.cc | 965 ---- base/json/json_parser.h | 271 - base/json/json_parser_unittest.cc | 319 -- base/json/json_reader.cc | 110 - base/json/json_reader.h | 135 - base/json/json_reader_unittest.cc | 656 --- base/json/json_string_value_serializer.cc | 48 - base/json/json_string_value_serializer.h | 77 - base/json/json_value_converter.h | 527 -- base/json/json_value_converter_unittest.cc | 256 - base/json/json_value_serializer_unittest.cc | 471 -- base/json/json_writer.cc | 233 - base/json/json_writer.h | 83 - base/json/json_writer_unittest.cc | 131 - base/json/string_escape.cc | 105 - base/json/string_escape.h | 38 - base/json/string_escape_unittest.cc | 100 - base/lazy_instance.cc | 59 - base/lazy_instance.h | 212 - base/lazy_instance_unittest.cc | 172 - base/linux_util.cc | 304 -- base/linux_util.h | 47 - base/location.cc | 102 - base/location.h | 94 - base/logging.cc | 866 --- base/logging.h | 1022 ---- base/logging_unittest.cc | 261 - base/logging_win.cc | 139 - base/logging_win.h | 80 - base/mac/OWNERS | 2 - base/mac/authorization_util.h | 73 - base/mac/authorization_util.mm | 187 - base/mac/bind_objc_block.h | 54 - base/mac/bind_objc_block_unittest.mm | 54 - base/mac/bundle_locations.h | 67 - base/mac/bundle_locations.mm | 83 - base/mac/cocoa_protocols.h | 42 - base/mac/foundation_util.h | 369 -- base/mac/foundation_util.mm | 400 -- base/mac/foundation_util_unittest.mm | 319 -- base/mac/launch_services_util.cc | 65 - base/mac/launch_services_util.h | 33 - base/mac/launchd.cc | 75 - base/mac/launchd.h | 34 - base/mac/libdispatch_task_runner.cc | 80 - base/mac/libdispatch_task_runner.h | 81 - base/mac/libdispatch_task_runner_unittest.cc | 224 - base/mac/mac_logging.cc | 37 - base/mac/mac_logging.h | 87 - base/mac/mac_util.h | 204 - base/mac/mac_util.mm | 703 --- base/mac/mac_util_unittest.mm | 256 - base/mac/objc_property_releaser.h | 127 - base/mac/objc_property_releaser.mm | 131 - base/mac/objc_property_releaser_unittest.mm | 350 -- base/mac/os_crash_dumps.cc | 57 - base/mac/os_crash_dumps.h | 22 - base/mac/scoped_aedesc.h | 52 - base/mac/scoped_authorizationref.h | 85 - base/mac/scoped_block.h | 92 - base/mac/scoped_cffiledescriptorref.h | 75 - base/mac/scoped_cftyperef.h | 106 - base/mac/scoped_ioobject.h | 74 - base/mac/scoped_ioplugininterface.h | 76 - base/mac/scoped_launch_data.h | 75 - base/mac/scoped_mach_port.cc | 25 - base/mac/scoped_mach_port.h | 44 - base/mac/scoped_nsautorelease_pool.h | 45 - base/mac/scoped_nsautorelease_pool.mm | 32 - base/mac/scoped_nsexception_enabler.h | 54 - base/mac/scoped_nsexception_enabler.mm | 63 - base/mac/scoped_nsobject.h | 156 - base/mac/scoped_nsobject_unittest.mm | 86 - base/mac/scoped_sending_event.h | 48 - base/mac/scoped_sending_event.mm | 24 - base/mac/scoped_sending_event_unittest.mm | 38 - base/mac/sdk_forward_declarations.h | 67 - base/md5.cc | 292 - base/md5.h | 69 - base/md5_unittest.cc | 207 - base/memory/aligned_memory.cc | 47 - base/memory/aligned_memory.h | 114 - base/memory/aligned_memory_unittest.cc | 95 - base/memory/discardable_memory.cc | 66 - base/memory/discardable_memory.h | 118 - base/memory/discardable_memory_android.cc | 164 - base/memory/discardable_memory_mac.cc | 102 - base/memory/discardable_memory_unittest.cc | 61 - base/memory/linked_ptr.h | 181 - base/memory/linked_ptr_unittest.cc | 110 - base/memory/manual_constructor.h | 125 - base/memory/memory_pressure_level_list.h | 19 - base/memory/memory_pressure_listener.cc | 57 - base/memory/memory_pressure_listener.h | 80 - .../raw_scoped_refptr_mismatch_checker.h | 129 - base/memory/ref_counted.cc | 95 - base/memory/ref_counted.h | 301 -- .../ref_counted_delete_on_message_loop.h | 70 - base/memory/ref_counted_memory.cc | 77 - base/memory/ref_counted_memory.h | 118 - base/memory/ref_counted_memory_unittest.cc | 71 - base/memory/ref_counted_unittest.cc | 62 - base/memory/scoped_handle.h | 50 - base/memory/scoped_open_process.h | 48 - base/memory/scoped_policy.h | 25 - base/memory/scoped_ptr.h | 709 --- base/memory/scoped_ptr_unittest.cc | 606 --- base/memory/scoped_ptr_unittest.nc | 113 - base/memory/scoped_vector.h | 130 - base/memory/scoped_vector_unittest.cc | 299 - base/memory/shared_memory.h | 281 - base/memory/shared_memory_android.cc | 57 - base/memory/shared_memory_nacl.cc | 158 - base/memory/shared_memory_posix.cc | 423 -- base/memory/shared_memory_unittest.cc | 561 -- base/memory/shared_memory_win.cc | 260 - base/memory/singleton.cc | 31 - base/memory/singleton.h | 285 - base/memory/singleton_objc.h | 60 - base/memory/singleton_unittest.cc | 288 - base/memory/weak_ptr.cc | 77 - base/memory/weak_ptr.h | 338 -- base/memory/weak_ptr_unittest.cc | 606 --- base/memory/weak_ptr_unittest.nc | 138 - base/message_loop/incoming_task_queue.cc | 169 - base/message_loop/incoming_task_queue.h | 104 - base/message_loop/message_loop.cc | 754 --- base/message_loop/message_loop.h | 719 --- base/message_loop/message_loop_proxy.cc | 17 - base/message_loop/message_loop_proxy.h | 38 - base/message_loop/message_loop_proxy_impl.cc | 54 - base/message_loop/message_loop_proxy_impl.h | 53 - .../message_loop_proxy_impl_unittest.cc | 129 - .../message_loop_proxy_unittest.cc | 266 - base/message_loop/message_loop_unittest.cc | 2104 -------- base/message_loop/message_pump.cc | 15 - base/message_loop/message_pump.h | 126 - base/message_loop/message_pump_android.cc | 133 - base/message_loop/message_pump_android.h | 45 - base/message_loop/message_pump_aurax11.cc | 307 -- base/message_loop/message_pump_aurax11.h | 120 - base/message_loop/message_pump_default.cc | 88 - base/message_loop/message_pump_default.h | 40 - base/message_loop/message_pump_dispatcher.h | 32 - base/message_loop/message_pump_glib.cc | 334 -- base/message_loop/message_pump_glib.h | 109 - .../message_pump_glib_unittest.cc | 580 -- base/message_loop/message_pump_gtk.cc | 114 - base/message_loop/message_pump_gtk.h | 74 - base/message_loop/message_pump_io_ios.cc | 209 - base/message_loop/message_pump_io_ios.h | 144 - .../message_pump_io_ios_unittest.cc | 188 - base/message_loop/message_pump_libevent.cc | 375 -- base/message_loop/message_pump_libevent.h | 177 - .../message_pump_libevent_unittest.cc | 162 - base/message_loop/message_pump_mac.h | 329 -- base/message_loop/message_pump_mac.mm | 704 --- base/message_loop/message_pump_observer.h | 47 - base/message_loop/message_pump_ozone.cc | 61 - base/message_loop/message_pump_ozone.h | 52 - base/message_loop/message_pump_win.cc | 686 --- base/message_loop/message_pump_win.h | 396 -- base/metrics/OWNERS | 8 - base/metrics/bucket_ranges.cc | 139 - base/metrics/bucket_ranges.h | 79 - base/metrics/bucket_ranges_unittest.cc | 92 - base/metrics/field_trial.cc | 505 -- base/metrics/field_trial.h | 486 -- base/metrics/field_trial_unittest.cc | 859 --- base/metrics/histogram.cc | 834 --- base/metrics/histogram.h | 675 --- base/metrics/histogram_base.cc | 161 - base/metrics/histogram_base.h | 171 - base/metrics/histogram_base_unittest.cc | 191 - base/metrics/histogram_flattener.h | 51 - base/metrics/histogram_samples.cc | 126 - base/metrics/histogram_samples.h | 87 - base/metrics/histogram_snapshot_manager.cc | 117 - base/metrics/histogram_snapshot_manager.h | 61 - base/metrics/histogram_unittest.cc | 493 -- base/metrics/sample_map.cc | 86 - base/metrics/sample_map.h | 65 - base/metrics/sample_map_unittest.cc | 123 - base/metrics/sample_vector.cc | 161 - base/metrics/sample_vector.h | 84 - base/metrics/sample_vector_unittest.cc | 265 - base/metrics/sparse_histogram.cc | 179 - base/metrics/sparse_histogram.h | 117 - base/metrics/sparse_histogram_unittest.cc | 144 - base/metrics/statistics_recorder.cc | 292 - base/metrics/statistics_recorder.h | 108 - base/metrics/statistics_recorder_unittest.cc | 266 - base/metrics/stats_counters.cc | 125 - base/metrics/stats_counters.h | 197 - base/metrics/stats_table.cc | 568 -- base/metrics/stats_table.h | 193 - base/metrics/stats_table_unittest.cc | 424 -- base/move.h | 207 - base/native_library.h | 91 - base/native_library_mac.mm | 125 - base/native_library_posix.cc | 53 - base/native_library_win.cc | 73 - ...b-x86-32.base_untrusted.source_list.gypcmd | 353 -- ...b-x86-64.base_untrusted.source_list.gypcmd | 353 -- base/nix/mime_util_xdg.cc | 655 --- base/nix/mime_util_xdg.h | 42 - base/nix/xdg_util.cc | 115 - base/nix/xdg_util.h | 74 - base/nix/xdg_util_unittest.cc | 76 - base/observer_list.h | 216 - base/observer_list_threadsafe.h | 295 - base/observer_list_unittest.cc | 549 -- base/os_compat_android.cc | 170 - base/os_compat_android.h | 28 - base/os_compat_android_unittest.cc | 41 - base/os_compat_nacl.cc | 30 - base/os_compat_nacl.h | 16 - base/path_service.cc | 336 -- base/path_service.h | 82 - base/path_service_unittest.cc | 216 - base/pending_task.cc | 60 - base/pending_task.h | 60 - base/perftimer.cc | 45 - base/perftimer.h | 85 - base/pickle.cc | 361 -- base/pickle.h | 347 -- base/pickle_unittest.cc | 342 -- base/platform_file.cc | 31 - base/platform_file.h | 254 - base/platform_file_posix.cc | 461 -- base/platform_file_unittest.cc | 400 -- base/platform_file_win.cc | 301 -- base/port.h | 54 - base/posix/eintr_wrapper.h | 51 - base/posix/file_descriptor_shuffle.cc | 96 - base/posix/file_descriptor_shuffle.h | 87 - .../posix/file_descriptor_shuffle_unittest.cc | 287 - base/posix/global_descriptors.cc | 60 - base/posix/global_descriptors.h | 70 - base/posix/unix_domain_socket_linux.cc | 173 - base/posix/unix_domain_socket_linux.h | 76 - .../unix_domain_socket_linux_unittest.cc | 81 - base/power_monitor/power_monitor.cc | 61 - base/power_monitor/power_monitor.h | 55 - .../power_monitor_device_source.cc | 39 - .../power_monitor_device_source.h | 110 - .../power_monitor_device_source_android.cc | 45 - .../power_monitor_device_source_android.h | 17 - .../power_monitor_device_source_ios.mm | 40 - .../power_monitor_device_source_mac.mm | 107 - .../power_monitor_device_source_posix.cc | 14 - .../power_monitor_device_source_win.cc | 130 - base/power_monitor/power_monitor_source.cc | 66 - base/power_monitor/power_monitor_source.h | 65 - base/power_monitor/power_monitor_unittest.cc | 80 - base/power_monitor/power_observer.h | 31 - base/prefs/OWNERS | 7 - base/prefs/README | 6 - base/prefs/base_prefs_export.h | 29 - base/prefs/default_pref_store.cc | 53 - base/prefs/default_pref_store.h | 52 - base/prefs/default_pref_store_unittest.cc | 69 - base/prefs/json_pref_store.cc | 358 -- base/prefs/json_pref_store.h | 103 - base/prefs/json_pref_store_unittest.cc | 287 - base/prefs/mock_pref_change_callback.cc | 24 - base/prefs/mock_pref_change_callback.h | 52 - base/prefs/overlay_user_pref_store.cc | 182 - base/prefs/overlay_user_pref_store.h | 85 - .../prefs/overlay_user_pref_store_unittest.cc | 278 - base/prefs/persistent_pref_store.h | 95 - base/prefs/pref_change_registrar.cc | 95 - base/prefs/pref_change_registrar.h | 81 - base/prefs/pref_change_registrar_unittest.cc | 200 - base/prefs/pref_member.cc | 225 - base/prefs/pref_member.h | 352 -- base/prefs/pref_member_unittest.cc | 321 -- base/prefs/pref_notifier.h | 26 - base/prefs/pref_notifier_impl.cc | 117 - base/prefs/pref_notifier_impl.h | 73 - base/prefs/pref_notifier_impl_unittest.cc | 227 - base/prefs/pref_observer.h | 21 - base/prefs/pref_registry.cc | 63 - base/prefs/pref_registry.h | 72 - base/prefs/pref_registry_simple.cc | 67 - base/prefs/pref_registry_simple.h | 44 - base/prefs/pref_service.cc | 591 -- base/prefs/pref_service.h | 354 -- base/prefs/pref_service_builder.cc | 102 - base/prefs/pref_service_builder.h | 72 - base/prefs/pref_service_unittest.cc | 318 -- base/prefs/pref_store.cc | 13 - base/prefs/pref_store.h | 63 - base/prefs/pref_store_observer_mock.cc | 9 - base/prefs/pref_store_observer_mock.h | 25 - base/prefs/pref_value_map.cc | 152 - base/prefs/pref_value_map.h | 88 - base/prefs/pref_value_map_unittest.cc | 115 - base/prefs/pref_value_store.cc | 277 - base/prefs/pref_value_store.h | 260 - base/prefs/pref_value_store_unittest.cc | 592 -- base/prefs/testing_pref_service.cc | 54 - base/prefs/testing_pref_service.h | 198 - base/prefs/testing_pref_store.cc | 136 - base/prefs/testing_pref_store.h | 84 - base/prefs/value_map_pref_store.cc | 45 - base/prefs/value_map_pref_store.h | 52 - base/process/internal_linux.cc | 190 - base/process/internal_linux.h | 89 - base/process/kill.cc | 26 - base/process/kill.h | 144 - base/process/kill_mac.cc | 173 - base/process/kill_posix.cc | 492 -- base/process/kill_win.cc | 255 - base/process/launch.h | 258 - base/process/launch_ios.cc | 13 - base/process/launch_mac.cc | 28 - base/process/launch_posix.cc | 760 --- base/process/launch_win.cc | 283 - base/process/memory.h | 69 - base/process/memory_linux.cc | 183 - base/process/memory_mac.mm | 704 --- base/process/memory_stubs.cc | 19 - base/process/memory_unittest.cc | 379 -- base/process/memory_unittest_mac.h | 32 - base/process/memory_unittest_mac.mm | 59 - base/process/memory_win.cc | 85 - base/process/process.h | 70 - base/process/process_handle.h | 96 - base/process/process_handle_freebsd.cc | 39 - base/process/process_handle_linux.cc | 30 - base/process/process_handle_mac.cc | 27 - base/process/process_handle_openbsd.cc | 49 - base/process/process_handle_posix.cc | 49 - base/process/process_handle_win.cc | 126 - base/process/process_info.h | 25 - base/process/process_info_linux.cc | 27 - base/process/process_info_mac.cc | 31 - base/process/process_info_win.cc | 25 - base/process/process_iterator.cc | 65 - base/process/process_iterator.h | 183 - base/process/process_iterator_freebsd.cc | 124 - base/process/process_iterator_linux.cc | 137 - base/process/process_iterator_mac.cc | 134 - base/process/process_iterator_openbsd.cc | 128 - base/process/process_iterator_win.cc | 41 - base/process/process_linux.cc | 137 - base/process/process_metrics.h | 269 - base/process/process_metrics_freebsd.cc | 122 - base/process/process_metrics_ios.cc | 64 - base/process/process_metrics_linux.cc | 516 -- base/process/process_metrics_mac.cc | 325 -- base/process/process_metrics_openbsd.cc | 168 - base/process/process_metrics_posix.cc | 55 - base/process/process_metrics_win.cc | 315 -- base/process/process_posix.cc | 73 - base/process/process_util_unittest.cc | 961 ---- base/process/process_util_unittest_ios.cc | 15 - base/process/process_win.cc | 92 - base/profiler/alternate_timer.cc | 37 - base/profiler/alternate_timer.h | 44 - base/profiler/scoped_profile.cc | 31 - base/profiler/scoped_profile.h | 67 - base/profiler/tracked_time.cc | 76 - base/profiler/tracked_time.h | 71 - base/profiler/tracked_time_unittest.cc | 110 - base/rand_util.cc | 80 - base/rand_util.h | 58 - base/rand_util_nacl.cc | 53 - base/rand_util_posix.cc | 61 - base/rand_util_unittest.cc | 122 - base/rand_util_win.cc | 31 - base/run_loop.cc | 94 - base/run_loop.h | 121 - base/safe_numerics.h | 135 - base/safe_numerics_unittest.cc | 151 - base/safe_numerics_unittest.nc | 29 - base/safe_strerror_posix.cc | 111 - base/safe_strerror_posix.h | 38 - base/scoped_clear_errno.h | 34 - base/scoped_clear_errno_unittest.cc | 30 - base/scoped_native_library.cc | 44 - base/scoped_native_library.h | 52 - base/scoped_native_library_unittest.cc | 37 - base/scoped_observer.h | 54 - base/security_unittest.cc | 306 -- base/sequence_checker.h | 68 - base/sequence_checker_impl.cc | 46 - base/sequence_checker_impl.h | 52 - base/sequence_checker_unittest.cc | 339 -- base/sequenced_task_runner.cc | 31 - base/sequenced_task_runner.h | 159 - base/sequenced_task_runner_helpers.h | 112 - base/sha1.h | 29 - base/sha1_portable.cc | 215 - base/sha1_unittest.cc | 108 - base/sha1_win.cc | 67 - base/single_thread_task_runner.h | 37 - base/stl_util.h | 222 - base/stl_util_unittest.cc | 82 - base/strings/latin1_string_conversions.cc | 19 - base/strings/latin1_string_conversions.h | 32 - base/strings/nullable_string16.cc | 17 - base/strings/nullable_string16.h | 46 - base/strings/nullable_string16_unittest.cc | 35 - base/strings/string16.cc | 82 - base/strings/string16.h | 189 - base/strings/string16_unittest.cc | 54 - base/strings/string_number_conversions.cc | 516 -- base/strings/string_number_conversions.h | 122 - .../string_number_conversions_unittest.cc | 713 --- base/strings/string_piece.cc | 255 - base/strings/string_piece.h | 451 -- base/strings/string_piece_unittest.cc | 677 --- base/strings/string_split.cc | 219 - base/strings/string_split.h | 83 - base/strings/string_split_unittest.cc | 318 -- base/strings/string_tokenizer.h | 260 - base/strings/string_tokenizer_unittest.cc | 234 - base/strings/string_util.cc | 1011 ---- base/strings/string_util.h | 576 -- base/strings/string_util_constants.cc | 55 - base/strings/string_util_posix.h | 53 - base/strings/string_util_unittest.cc | 1191 ---- base/strings/string_util_win.h | 61 - base/strings/stringize_macros.h | 31 - base/strings/stringize_macros_unittest.cc | 29 - base/strings/stringprintf.cc | 186 - base/strings/stringprintf.h | 62 - base/strings/stringprintf_unittest.cc | 188 - base/strings/sys_string_conversions.h | 83 - base/strings/sys_string_conversions_mac.mm | 186 - .../sys_string_conversions_mac_unittest.mm | 21 - base/strings/sys_string_conversions_posix.cc | 161 - .../sys_string_conversions_unittest.cc | 187 - base/strings/sys_string_conversions_win.cc | 70 - base/strings/utf_offset_string_conversions.cc | 166 - base/strings/utf_offset_string_conversions.h | 93 - .../utf_offset_string_conversions_unittest.cc | 154 - base/strings/utf_string_conversion_utils.cc | 148 - base/strings/utf_string_conversion_utils.h | 97 - base/strings/utf_string_conversions.cc | 185 - base/strings/utf_string_conversions.h | 72 - .../utf_string_conversions_unittest.cc | 211 - base/supports_user_data.cc | 40 - base/supports_user_data.h | 81 - base/sync_socket.h | 130 - base/sync_socket_nacl.cc | 73 - base/sync_socket_posix.cc | 154 - base/sync_socket_win.cc | 273 - base/synchronization/cancellation_flag.cc | 22 - base/synchronization/cancellation_flag.h | 43 - .../cancellation_flag_unittest.cc | 64 - base/synchronization/condition_variable.h | 118 - .../condition_variable_posix.cc | 80 - .../condition_variable_unittest.cc | 715 --- .../synchronization/condition_variable_win.cc | 669 --- base/synchronization/lock.cc | 48 - base/synchronization/lock.h | 140 - base/synchronization/lock_impl.h | 61 - base/synchronization/lock_impl_posix.cc | 55 - base/synchronization/lock_impl_win.cc | 36 - base/synchronization/lock_unittest.cc | 216 - base/synchronization/spin_wait.h | 50 - base/synchronization/waitable_event.h | 182 - base/synchronization/waitable_event_posix.cc | 407 -- .../waitable_event_unittest.cc | 108 - base/synchronization/waitable_event_watcher.h | 114 - .../waitable_event_watcher_posix.cc | 271 - .../waitable_event_watcher_unittest.cc | 176 - .../waitable_event_watcher_win.cc | 48 - base/synchronization/waitable_event_win.cc | 102 - base/sys_byteorder.h | 147 - base/sys_info.cc | 20 - base/sys_info.h | 113 - base/sys_info_android.cc | 167 - base/sys_info_chromeos.cc | 119 - base/sys_info_freebsd.cc | 36 - base/sys_info_ios.mm | 90 - base/sys_info_linux.cc | 85 - base/sys_info_mac.cc | 88 - base/sys_info_openbsd.cc | 75 - base/sys_info_posix.cc | 97 - base/sys_info_unittest.cc | 111 - base/sys_info_win.cc | 125 - base/system_monitor/system_monitor.cc | 52 - base/system_monitor/system_monitor.h | 75 - .../system_monitor/system_monitor_unittest.cc | 54 - base/task_runner.cc | 68 - base/task_runner.h | 153 - base/task_runner_util.h | 71 - base/task_runner_util_unittest.cc | 128 - base/template_util.h | 108 - base/template_util_unittest.cc | 80 - base/test/OWNERS | 1 - base/test/android/OWNERS | 3 - .../base/test/util/AdvancedMockContext.java | 103 - .../chromium/base/test/util/DisabledTest.java | 21 - .../chromium/base/test/util/EnormousTest.java | 24 - .../org/chromium/base/test/util/Feature.java | 29 - .../test/util/InMemorySharedPreferences.java | 238 - .../base/test/util/InstrumentationUtils.java | 32 - .../chromium/base/test/util/PhoneOnly.java | 19 - .../base/test/util/ScalableTimeout.java | 28 - .../chromium/base/test/util/TabletOnly.java | 19 - .../chromium/base/test/util/TestFileUtil.java | 77 - .../chromium/base/test/util/TestThread.java | 143 - .../chromium/base/test/util/TimeoutScale.java | 22 - .../org/chromium/base/test/util/UrlUtils.java | 45 - base/test/data/file_util/binary_file.bin | Bin 538 -> 0 bytes base/test/data/file_util/binary_file_diff.bin | Bin 538 -> 0 bytes base/test/data/file_util/binary_file_same.bin | Bin 538 -> 0 bytes base/test/data/file_util/blank_line.txt | 3 - base/test/data/file_util/blank_line_crlf.txt | 3 - base/test/data/file_util/crlf.txt | 1 - base/test/data/file_util/different.txt | 1 - base/test/data/file_util/different_first.txt | 1 - base/test/data/file_util/different_last.txt | 1 - base/test/data/file_util/empty1.txt | 0 base/test/data/file_util/empty2.txt | 0 base/test/data/file_util/first1.txt | 2 - base/test/data/file_util/first2.txt | 2 - base/test/data/file_util/original.txt | 1 - base/test/data/file_util/same.txt | 1 - base/test/data/file_util/same_length.txt | 1 - base/test/data/file_util/shortened.txt | 1 - base/test/data/json/bom_feff.json | 10 - base/test/data/prefs/invalid.json | 1 - base/test/data/prefs/read.json | 8 - .../data/prefs/read.need_empty_value.json | 10 - base/test/data/prefs/write.golden.json | 11 - .../prefs/write.golden.need_empty_value.json | 6 - base/test/data/serializer_nested_test.json | 17 - base/test/data/serializer_test.json | 8 - .../data/serializer_test_nowhitespace.json | 1 - base/test/expectations/OWNERS | 1 - base/test/expectations/expectation.cc | 157 - base/test/expectations/expectation.h | 94 - .../test/expectations/expectation_unittest.cc | 120 - base/test/expectations/parser.cc | 201 - base/test/expectations/parser.h | 143 - base/test/expectations/parser_unittest.cc | 209 - base/test/mock_chrome_application_mac.h | 33 - base/test/mock_chrome_application_mac.mm | 44 - base/test/mock_devices_changed_observer.cc | 15 - base/test/mock_devices_changed_observer.h | 29 - base/test/mock_time_provider.cc | 31 - base/test/mock_time_provider.h | 69 - base/test/multiprocess_test.cc | 56 - base/test/multiprocess_test.h | 85 - base/test/multiprocess_test_android.cc | 61 - base/test/null_task_runner.cc | 31 - base/test/null_task_runner.h | 34 - base/test/perf_test_suite.cc | 46 - base/test/perf_test_suite.h | 22 - base/test/power_monitor_test_base.cc | 64 - base/test/power_monitor_test_base.h | 55 - base/test/run_all_perftests.cc | 9 - base/test/run_all_unittests.cc | 9 - base/test/scoped_locale.cc | 23 - base/test/scoped_locale.h | 29 - base/test/scoped_path_override.cc | 30 - base/test/scoped_path_override.h | 36 - .../sequenced_task_runner_test_template.cc | 270 - .../sequenced_task_runner_test_template.h | 376 -- base/test/sequenced_worker_pool_owner.cc | 55 - base/test/sequenced_worker_pool_owner.h | 61 - base/test/simple_test_clock.cc | 28 - base/test/simple_test_clock.h | 41 - base/test/simple_test_tick_clock.cc | 26 - base/test/simple_test_tick_clock.h | 38 - base/test/task_runner_test_template.cc | 48 - base/test/task_runner_test_template.h | 225 - base/test/test_file_util.cc | 23 - base/test/test_file_util.h | 77 - base/test/test_file_util_linux.cc | 28 - base/test/test_file_util_mac.cc | 51 - base/test/test_file_util_posix.cc | 118 - base/test/test_file_util_win.cc | 291 - base/test/test_launcher.cc | 451 -- base/test/test_launcher.h | 92 - base/test/test_listener_ios.h | 17 - base/test/test_listener_ios.mm | 45 - base/test/test_pending_task.cc | 35 - base/test/test_pending_task.h | 58 - base/test/test_process_killer_win.cc | 167 - base/test/test_process_killer_win.h | 19 - base/test/test_reg_util_win.cc | 65 - base/test/test_reg_util_win.h | 63 - base/test/test_shortcut_win.cc | 161 - base/test/test_shortcut_win.h | 25 - base/test/test_simple_task_runner.cc | 82 - base/test/test_simple_task_runner.h | 86 - base/test/test_suite.cc | 258 - base/test/test_suite.h | 81 - base/test/test_support_android.cc | 192 - base/test/test_support_android.h | 26 - base/test/test_support_ios.h | 24 - base/test/test_support_ios.mm | 188 - base/test/test_switches.cc | 12 - base/test/test_switches.h | 19 - base/test/test_timeouts.cc | 98 - base/test/test_timeouts.h | 58 - base/test/thread_test_helper.cc | 38 - base/test/thread_test_helper.h | 48 - base/test/trace_event_analyzer.cc | 963 ---- base/test/trace_event_analyzer.h | 684 --- base/test/trace_event_analyzer_unittest.cc | 835 --- base/test/values_test_util.cc | 78 - base/test/values_test_util.h | 56 - base/third_party/dmg_fp/LICENSE | 18 - base/third_party/dmg_fp/README.chromium | 22 - base/third_party/dmg_fp/dmg_fp.h | 30 - base/third_party/dmg_fp/dtoa.cc | 4209 --------------- base/third_party/dmg_fp/dtoa_wrapper.cc | 46 - .../dmg_fp/float_precision_crash.patch | 13 - base/third_party/dmg_fp/g_fmt.cc | 102 - base/third_party/dmg_fp/gcc_64_bit.patch | 25 - base/third_party/dmg_fp/gcc_warnings.patch | 126 - base/third_party/dmg_fp/mac_wextra.patch | 53 - base/third_party/dmg_fp/win_vs2012.patch | 13 - base/third_party/dynamic_annotations/LICENSE | 28 - .../dynamic_annotations/README.chromium | 13 - .../dynamic_annotations/dynamic_annotations.c | 269 - .../dynamic_annotations.gyp | 47 - .../dynamic_annotations/dynamic_annotations.h | 595 -- base/third_party/icu/LICENSE | 32 - base/third_party/icu/README.chromium | 16 - base/third_party/icu/icu_utf.cc | 228 - base/third_party/icu/icu_utf.h | 388 -- base/third_party/nspr/LICENSE | 35 - base/third_party/nspr/OWNERS | 2 - base/third_party/nspr/README.chromium | 3 - base/third_party/nspr/nspr.gyp | 41 - base/third_party/nspr/prcpucfg.h | 51 - base/third_party/nspr/prcpucfg_freebsd.h | 337 -- base/third_party/nspr/prcpucfg_linux.h | 756 --- base/third_party/nspr/prcpucfg_mac.h | 197 - base/third_party/nspr/prcpucfg_nacl.h | 246 - base/third_party/nspr/prcpucfg_openbsd.h | 337 -- base/third_party/nspr/prcpucfg_solaris.h | 203 - base/third_party/nspr/prcpucfg_win.h | 256 - base/third_party/nspr/prtime.cc | 1210 ----- base/third_party/nspr/prtime.h | 238 - base/third_party/nspr/prtypes.h | 558 -- base/third_party/symbolize/DEPS | 3 - base/third_party/symbolize/LICENSE | 28 - base/third_party/symbolize/README.chromium | 21 - base/third_party/symbolize/config.h | 7 - base/third_party/symbolize/demangle.cc | 1231 ----- base/third_party/symbolize/demangle.h | 84 - base/third_party/symbolize/glog/logging.h | 5 - base/third_party/symbolize/glog/raw_logging.h | 6 - base/third_party/symbolize/symbolize.cc | 683 --- base/third_party/symbolize/symbolize.h | 133 - base/third_party/symbolize/utilities.h | 11 - base/third_party/valgrind/LICENSE | 39 - base/third_party/valgrind/README.chromium | 11 - base/third_party/valgrind/memcheck.h | 279 - base/third_party/valgrind/valgrind.h | 4792 ----------------- base/third_party/xdg_mime/LICENSE | 168 - base/third_party/xdg_mime/README | 8 - base/third_party/xdg_mime/README.chromium | 11 - base/third_party/xdg_mime/compile.patch | 17 - base/third_party/xdg_mime/xdgmime.c | 934 ---- base/third_party/xdg_mime/xdgmime.h | 133 - base/third_party/xdg_mime/xdgmimealias.c | 184 - base/third_party/xdg_mime/xdgmimealias.h | 51 - base/third_party/xdg_mime/xdgmimecache.c | 1069 ---- base/third_party/xdg_mime/xdgmimecache.h | 81 - base/third_party/xdg_mime/xdgmimeglob.c | 691 --- base/third_party/xdg_mime/xdgmimeglob.h | 70 - base/third_party/xdg_mime/xdgmimeicon.c | 183 - base/third_party/xdg_mime/xdgmimeicon.h | 50 - base/third_party/xdg_mime/xdgmimeint.c | 206 - base/third_party/xdg_mime/xdgmimeint.h | 78 - base/third_party/xdg_mime/xdgmimemagic.c | 813 --- base/third_party/xdg_mime/xdgmimemagic.h | 57 - base/third_party/xdg_mime/xdgmimeparent.c | 219 - base/third_party/xdg_mime/xdgmimeparent.h | 51 - base/third_party/xdg_user_dirs/LICENSE | 21 - .../third_party/xdg_user_dirs/README.chromium | 7 - .../xdg_user_dirs/xdg_user_dir_lookup.cc | 232 - .../xdg_user_dirs/xdg_user_dir_lookup.h | 33 - base/thread_task_runner_handle.cc | 46 - base/thread_task_runner_handle.h | 40 - base/threading/OWNERS | 2 - base/threading/non_thread_safe.h | 73 - base/threading/non_thread_safe_impl.cc | 23 - base/threading/non_thread_safe_impl.h | 39 - base/threading/non_thread_safe_unittest.cc | 167 - base/threading/platform_thread.h | 160 - base/threading/platform_thread_android.cc | 105 - base/threading/platform_thread_linux.cc | 116 - base/threading/platform_thread_mac.mm | 224 - base/threading/platform_thread_posix.cc | 231 - base/threading/platform_thread_unittest.cc | 121 - base/threading/platform_thread_win.cc | 234 - base/threading/post_task_and_reply_impl.cc | 90 - base/threading/post_task_and_reply_impl.h | 42 - base/threading/sequenced_worker_pool.cc | 1287 ----- base/threading/sequenced_worker_pool.h | 358 -- .../sequenced_worker_pool_unittest.cc | 936 ---- base/threading/simple_thread.cc | 159 - base/threading/simple_thread.h | 190 - base/threading/simple_thread_unittest.cc | 170 - base/threading/thread.cc | 221 - base/threading/thread.h | 216 - base/threading/thread_checker.h | 85 - base/threading/thread_checker_impl.cc | 34 - base/threading/thread_checker_impl.h | 43 - base/threading/thread_checker_unittest.cc | 183 - base/threading/thread_collision_warner.cc | 64 - base/threading/thread_collision_warner.h | 244 - .../thread_collision_warner_unittest.cc | 385 -- base/threading/thread_id_name_manager.cc | 112 - base/threading/thread_id_name_manager.h | 67 - .../thread_id_name_manager_unittest.cc | 93 - base/threading/thread_local.h | 128 - base/threading/thread_local_posix.cc | 40 - base/threading/thread_local_storage.h | 93 - base/threading/thread_local_storage_posix.cc | 49 - .../thread_local_storage_unittest.cc | 124 - base/threading/thread_local_storage_win.cc | 277 - base/threading/thread_local_unittest.cc | 169 - base/threading/thread_local_win.cc | 42 - base/threading/thread_restrictions.cc | 85 - base/threading/thread_restrictions.h | 247 - base/threading/thread_unittest.cc | 239 - base/threading/watchdog.cc | 178 - base/threading/watchdog.h | 94 - base/threading/watchdog_unittest.cc | 142 - base/threading/worker_pool.cc | 117 - base/threading/worker_pool.h | 60 - base/threading/worker_pool_posix.cc | 202 - base/threading/worker_pool_posix.h | 98 - base/threading/worker_pool_posix_unittest.cc | 254 - base/threading/worker_pool_unittest.cc | 112 - base/threading/worker_pool_win.cc | 73 - base/time/clock.cc | 11 - base/time/clock.h | 40 - base/time/default_clock.cc | 15 - base/time/default_clock.h | 25 - base/time/default_tick_clock.cc | 15 - base/time/default_tick_clock.h | 25 - base/time/pr_time_unittest.cc | 165 - base/time/tick_clock.cc | 11 - base/time/tick_clock.h | 40 - base/time/time.cc | 195 - base/time/time.h | 667 --- base/time/time_mac.cc | 205 - base/time/time_posix.cc | 344 -- base/time/time_unittest.cc | 691 --- base/time/time_win.cc | 492 -- base/time/time_win_unittest.cc | 239 - base/timer/hi_res_timer_manager.h | 38 - base/timer/hi_res_timer_manager_posix.cc | 24 - base/timer/hi_res_timer_manager_unittest.cc | 61 - base/timer/hi_res_timer_manager_win.cc | 36 - base/timer/timer.cc | 186 - base/timer/timer.h | 246 - base/timer/timer_unittest.cc | 489 -- base/tools_sanity_unittest.cc | 273 - base/tracked_objects.cc | 870 --- base/tracked_objects.h | 717 --- base/tracked_objects_unittest.cc | 581 -- base/tracking_info.cc | 28 - base/tracking_info.h | 54 - base/tuple.h | 1291 ----- base/tuple_unittest.cc | 128 - base/value_conversions.cc | 46 - base/value_conversions.h | 29 - base/values.cc | 1119 ---- base/values.h | 529 -- base/values_unittest.cc | 776 --- base/version.cc | 176 - base/version.h | 72 - base/version_unittest.cc | 141 - base/vlog.cc | 177 - base/vlog.h | 78 - base/vlog_unittest.cc | 126 - base/win/OWNERS | 1 - base/win/dllmain.cc | 123 - base/win/enum_variant.cc | 83 - base/win/enum_variant.h | 52 - base/win/enum_variant_unittest.cc | 118 - base/win/event_trace_consumer.h | 148 - base/win/event_trace_consumer_unittest.cc | 383 -- base/win/event_trace_controller.cc | 173 - base/win/event_trace_controller.h | 151 - base/win/event_trace_controller_unittest.cc | 239 - base/win/event_trace_provider.cc | 134 - base/win/event_trace_provider.h | 180 - base/win/event_trace_provider_unittest.cc | 110 - base/win/i18n.cc | 169 - base/win/i18n.h | 34 - base/win/i18n_unittest.cc | 42 - base/win/iat_patch_function.cc | 278 - base/win/iat_patch_function.h | 72 - base/win/iunknown_impl.cc | 42 - base/win/iunknown_impl.h | 38 - base/win/iunknown_impl_unittest.cc | 51 - base/win/message_window.cc | 165 - base/win/message_window.h | 75 - base/win/message_window_unittest.cc | 61 - base/win/metro.cc | 187 - base/win/metro.h | 142 - base/win/object_watcher.cc | 111 - base/win/object_watcher.h | 103 - base/win/object_watcher_unittest.cc | 174 - base/win/pe_image.cc | 571 -- base/win/pe_image.h | 268 - base/win/pe_image_unittest.cc | 271 - base/win/registry.cc | 483 -- base/win/registry.h | 219 - base/win/registry_unittest.cc | 164 - base/win/resource_util.cc | 51 - base/win/resource_util.h | 39 - base/win/sampling_profiler.cc | 238 - base/win/sampling_profiler.h | 73 - base/win/sampling_profiler_unittest.cc | 120 - base/win/scoped_bstr.cc | 71 - base/win/scoped_bstr.h | 97 - base/win/scoped_bstr_unittest.cc | 77 - base/win/scoped_co_mem.h | 64 - base/win/scoped_com_initializer.h | 74 - base/win/scoped_comptr.h | 168 - base/win/scoped_comptr_unittest.cc | 111 - base/win/scoped_gdi_object.h | 77 - base/win/scoped_handle.cc | 68 - base/win/scoped_handle.h | 205 - base/win/scoped_handle_unittest.cc | 31 - base/win/scoped_hdc.h | 76 - base/win/scoped_hglobal.h | 52 - base/win/scoped_process_information.cc | 110 - base/win/scoped_process_information.h | 106 - .../scoped_process_information_unittest.cc | 160 - base/win/scoped_propvariant.h | 59 - base/win/scoped_select_object.h | 43 - base/win/scoped_variant.cc | 276 - base/win/scoped_variant.h | 166 - base/win/scoped_variant_unittest.cc | 261 - base/win/shortcut.cc | 249 - base/win/shortcut.h | 143 - base/win/shortcut_unittest.cc | 273 - base/win/startup_information.cc | 109 - base/win/startup_information.h | 49 - base/win/startup_information_unittest.cc | 76 - base/win/text_services_message_filter.cc | 82 - base/win/text_services_message_filter.h | 48 - base/win/win_util.cc | 350 -- base/win/win_util.h | 127 - base/win/win_util_unittest.cc | 58 - base/win/windows_version.cc | 111 - base/win/windows_version.h | 110 - base/win/wrapped_window_proc.cc | 63 - base/win/wrapped_window_proc.h | 85 - base/win/wrapped_window_proc_unittest.cc | 79 - build/OWNERS | 1 - build/README.chromium | 15 - build/all.gyp | 908 ---- build/all_android.gyp | 136 - build/android/AndroidManifest.xml | 13 - build/android/CheckInstallApk-debug.apk | Bin 37106 -> 0 bytes build/android/PRESUBMIT.py | 57 - .../android/adb_android_webview_command_line | 37 - .../adb_chromium_testshell_command_line | 37 - build/android/adb_content_shell_command_line | 37 - build/android/adb_device_functions.sh | 139 - build/android/adb_gdb | 963 ---- build/android/adb_gdb_android_webview_shell | 16 - build/android/adb_gdb_chromium_testshell | 16 - build/android/adb_gdb_content_shell | 16 - build/android/adb_gdb_drt | 16 - build/android/adb_install_apk.py | 77 - build/android/adb_kill_content_shell | 24 - build/android/adb_logcat_monitor.py | 156 - build/android/adb_logcat_printer.py | 202 - build/android/adb_profile_chrome | 139 - build/android/adb_reverse_forwarder.py | 63 - build/android/adb_run_android_webview_shell | 15 - build/android/adb_run_chromium_testshell | 14 - build/android/adb_run_content_shell | 14 - build/android/ant/apk-codegen.xml | 114 - build/android/ant/apk-compile.xml | 247 - build/android/ant/apk-obfuscate.xml | 156 - build/android/ant/apk-package-resources.xml | 132 - build/android/ant/apk-package.xml | 74 - build/android/ant/chromium-debug.keystore | Bin 2223 -> 0 bytes build/android/ant/create-test-jar.js | 65 - build/android/ant/empty/res/.keep | 2 - .../arm-linux-androideabi-ld | 1 - build/android/arm-linux-androideabi-gold/ld | 1 - build/android/asan_symbolize.py | 103 - build/android/avd.py | 63 - .../config.ini | 30 - .../config.ini | 29 - build/android/bb_run_sharded_steps.py | 42 - build/android/buildbot/OWNERS | 6 - build/android/buildbot/bb_annotations.py | 46 - .../buildbot/bb_device_status_check.py | 260 - build/android/buildbot/bb_device_steps.py | 387 -- build/android/buildbot/bb_host_steps.py | 141 - build/android/buildbot/bb_run_bot.py | 273 - build/android/buildbot/bb_utils.py | 92 - build/android/buildbot/env_to_json.py | 11 - .../android/buildbot/tests/bb_run_bot_test.py | 35 - build/android/chrome_with_libs.gyp | 82 - build/android/cpufeatures.gypi | 31 - .../android/create_standalone_apk_action.gypi | 41 - .../android/developer_recommended_flags.gypi | 61 - build/android/device_stats_monitor.py | 43 - build/android/dex_action.gypi | 61 - build/android/empty/src/.keep | 6 - build/android/empty_proguard.flags | 1 - build/android/enable_asserts.py | 31 - build/android/envsetup.sh | 163 - build/android/envsetup_functions.sh | 326 -- build/android/finalize_apk_action.gypi | 46 - build/android/findbugs_diff.py | 50 - .../findbugs_filter/findbugs_exclude.xml | 44 - .../findbugs_filter/findbugs_known_bugs.txt | 47 - build/android/gyp/ant.py | 30 - build/android/gyp/apk_install.py | 99 - .../gyp/create_device_library_links.py | 110 - .../gyp/create_native_libraries_header.py | 50 - build/android/gyp/create_standalone_apk.py | 61 - build/android/gyp/dex.py | 63 - build/android/gyp/finalize_apk.py | 69 - build/android/gyp/gcc_preprocess.py | 50 - .../gyp/generate_v14_compatible_resources.py | 336 -- build/android/gyp/get_device_configuration.py | 75 - build/android/gyp/jar.py | 62 - build/android/gyp/jar_toc.py | 110 - build/android/gyp/javac.py | 100 - build/android/gyp/process_resources.py | 97 - build/android/gyp/push_libraries.py | 72 - build/android/gyp/strip_library_for_device.py | 59 - build/android/gyp/util/__init__.py | 4 - build/android/gyp/util/build_device.py | 98 - build/android/gyp/util/build_utils.py | 146 - build/android/gyp/util/md5_check.py | 76 - build/android/gyp/util/md5_check_test.py | 69 - build/android/gyp/write_ordered_libraries.py | 125 - build/android/host_heartbeat.py | 33 - build/android/install_emulator_deps.py | 151 - build/android/java_cpp_template.gypi | 78 - build/android/lighttpd_server.py | 253 - build/android/native_app_dependencies.gypi | 62 - build/android/provision_devices.py | 98 - build/android/push_libraries.gypi | 45 - build/android/pylib/OWNERS | 3 - build/android/pylib/__init__.py | 3 - build/android/pylib/android_commands.py | 1528 ------ build/android/pylib/base/__init__.py | 4 - build/android/pylib/base/base_test_result.py | 176 - .../pylib/base/base_test_result_unittest.py | 80 - build/android/pylib/base/base_test_runner.py | 213 - build/android/pylib/base/test_dispatcher.py | 393 -- .../pylib/base/test_dispatcher_unittest.py | 217 - .../pylib/chrome_test_server_spawner.py | 439 -- build/android/pylib/cmd_helper.py | 110 - build/android/pylib/constants.py | 104 - build/android/pylib/device_stats_monitor.html | 143 - build/android/pylib/device_stats_monitor.py | 116 - build/android/pylib/fake_dns.py | 64 - build/android/pylib/flag_changer.py | 145 - build/android/pylib/forwarder.py | 322 -- build/android/pylib/gtest/__init__.py | 4 - build/android/pylib/gtest/filter/OWNERS | 1 - .../gtest/filter/base_unittests_disabled | 25 - ...ase_unittests_emulator_additional_disabled | 10 - .../gtest/filter/breakpad_unittests_disabled | 3 - .../filter/content_browsertests_disabled | 103 - .../gtest/filter/content_unittests_disabled | 16 - .../pylib/gtest/filter/ipc_tests_disabled | 15 - .../gtest/filter/media_unittests_disabled | 11 - .../pylib/gtest/filter/net_unittests_disabled | 42 - .../gtest/filter/sync_unit_tests_disabled | 4 - .../pylib/gtest/filter/ui_unittests_disabled | 45 - .../pylib/gtest/filter/unit_tests_disabled | 124 - .../gtest/filter/webkit_unit_tests_disabled | 21 - build/android/pylib/gtest/gtest_config.py | 48 - build/android/pylib/gtest/setup.py | 303 -- build/android/pylib/gtest/test_options.py | 17 - build/android/pylib/gtest/test_package.py | 101 - build/android/pylib/gtest/test_package_apk.py | 135 - build/android/pylib/gtest/test_package_exe.py | 148 - build/android/pylib/gtest/test_runner.py | 193 - build/android/pylib/host_driven/__init__.py | 4 - build/android/pylib/host_driven/setup.py | 203 - build/android/pylib/host_driven/test_case.py | 151 - .../pylib/host_driven/test_info_collection.py | 144 - .../android/pylib/host_driven/test_runner.py | 135 - .../pylib/host_driven/tests_annotations.py | 93 - .../android/pylib/instrumentation/__init__.py | 4 - build/android/pylib/instrumentation/setup.py | 35 - .../android/pylib/instrumentation/test_jar.py | 220 - .../pylib/instrumentation/test_options.py | 23 - .../pylib/instrumentation/test_package.py | 38 - .../pylib/instrumentation/test_result.py | 34 - .../pylib/instrumentation/test_runner.py | 345 -- build/android/pylib/io_stats_parser.py | 32 - build/android/pylib/json_perf_parser.py | 160 - build/android/pylib/monkey/__init__.py | 0 build/android/pylib/monkey/setup.py | 27 - build/android/pylib/monkey/test_options.py | 18 - build/android/pylib/monkey/test_runner.py | 77 - build/android/pylib/perf/__init__.py | 3 - build/android/pylib/perf/setup.py | 74 - build/android/pylib/perf/test_options.py | 13 - build/android/pylib/perf/test_runner.py | 154 - build/android/pylib/perf_tests_helper.py | 202 - build/android/pylib/pexpect.py | 21 - build/android/pylib/ports.py | 176 - .../android/pylib/surface_stats_collector.py | 298 - build/android/pylib/thermal_throttle.py | 72 - build/android/pylib/uiautomator/__init__.py | 4 - build/android/pylib/uiautomator/setup.py | 35 - .../android/pylib/uiautomator/test_options.py | 22 - .../android/pylib/uiautomator/test_package.py | 27 - .../android/pylib/uiautomator/test_runner.py | 63 - build/android/pylib/utils/__init__.py | 0 build/android/pylib/utils/apk_helper.py | 21 - build/android/pylib/utils/emulator.py | 371 -- build/android/pylib/utils/findbugs.py | 233 - .../flakiness_dashboard_results_uploader.py | 206 - build/android/pylib/utils/repo_utils.py | 16 - build/android/pylib/utils/report_results.py | 111 - build/android/pylib/utils/reraiser_thread.py | 125 - .../pylib/utils/reraiser_thread_unittest.py | 96 - build/android/pylib/utils/run_tests_helper.py | 44 - .../pylib/utils/test_options_parser.py | 68 - build/android/pylib/utils/time_profile.py | 26 - build/android/pylib/utils/watchdog_timer.py | 37 - build/android/pylib/utils/xvfb.py | 56 - build/android/pylib/valgrind_tools.py | 264 - build/android/screenshot.py | 49 - build/android/setup.gyp | 82 - build/android/strip_native_libraries.gypi | 54 - build/android/surface_stats.py | 132 - build/android/symbolize.py | 88 - build/android/symbolize_test.py | 131 - build/android/test_runner.py | 758 --- .../multiple_proguards/AndroidManifest.xml | 30 - .../multiple_proguards/multiple_proguards.gyp | 35 - .../tests/multiple_proguards/proguard1.flags | 2 - .../tests/multiple_proguards/proguard2.flags | 3 - .../src/dummy/DummyActivity.java | 14 - build/android/tests/symbolize/Makefile | 11 - build/android/tests/symbolize/a.cc | 14 - build/android/tests/symbolize/b.cc | 14 - build/android/tests/symbolize/liba.so | Bin 6908 -> 0 bytes build/android/tests/symbolize/libb.so | Bin 6896 -> 0 bytes build/android/tombstones.py | 195 - build/android/write_ordered_libraries.gypi | 42 - build/apk_fake_jar.gypi | 25 - build/apk_test.gypi | 42 - build/apply_locales.py | 45 - build/asan.saves | 23 - build/branding_value.sh | 51 - build/build_config.h | 154 - build/common.croc | 127 - build/common.gypi | 4718 ---------------- build/common_untrusted.gypi | 29 - build/compiler_version.py | 55 - build/copy_test_data_ios.gypi | 48 - build/copy_test_data_ios.py | 105 - build/cp.py | 23 - build/dir_exists.py | 15 - build/download_nacl_toolchains.py | 63 - build/escape_unicode.py | 56 - build/extract_from_cab.py | 63 - build/filename_rules.gypi | 105 - build/gdb-add-index | 47 - build/git-hooks/OWNERS | 3 - build/git-hooks/pre-commit | 34 - build/grit_action.gypi | 41 - build/grit_target.gypi | 30 - build/gyp_chromium | 157 - build/gyp_chromium.py | 18 - build/gyp_helper.py | 53 - build/install-build-deps-android.sh | 104 - build/install-build-deps.sh | 510 -- build/install-chroot.sh | 852 --- build/internal/README.chromium | 24 - build/internal/release_defaults.gypi | 18 - build/internal/release_impl.gypi | 17 - build/internal/release_impl_official.gypi | 43 - build/intsafe_workaround.h | 27 - build/ios/PRESUBMIT.py | 39 - build/ios/chrome_ios.croc | 71 - build/ios/clean_env.py | 77 - build/ios/grit_whitelist.txt | 1113 ---- build/ios/mac_build.gypi | 85 - build/isolate.gypi | 109 - build/jar_file_jni_generator.gypi | 59 - build/java.gypi | 308 -- build/java_aidl.gypi | 78 - build/java_apk.gypi | 645 --- build/java_prebuilt.gypi | 59 - build/jni_generator.gypi | 70 - build/json_schema_bundle_compile.gypi | 63 - build/json_schema_compile.gypi | 108 - build/json_to_struct.gypi | 49 - build/landmines.py | 244 - build/linux/chrome_linux.croc | 29 - build/linux/dump_app_syms | 36 - build/linux/install-arm-sysroot.py | 67 - build/linux/install-chromeos-fonts.py | 79 - build/linux/pkg-config-wrapper | 57 - build/linux/python_arch.sh | 43 - build/linux/rewrite_dirs.py | 71 - build/linux/sysroot_ld_path.sh | 96 - build/linux/system.gyp | 842 --- build/linux/unbundle/README | 28 - build/linux/unbundle/expat.gyp | 17 - build/linux/unbundle/ffmpeg.gyp | 54 - build/linux/unbundle/flac.gyp | 37 - build/linux/unbundle/harfbuzz.gyp | 38 - build/linux/unbundle/icu.gyp | 221 - build/linux/unbundle/jsoncpp.gyp | 39 - build/linux/unbundle/libevent.gyp | 27 - build/linux/unbundle/libjpeg.gyp | 29 - build/linux/unbundle/libpng.gyp | 38 - build/linux/unbundle/libusb.gyp | 34 - build/linux/unbundle/libvpx.gyp | 42 - build/linux/unbundle/libwebp.gyp | 28 - build/linux/unbundle/libxml.gyp | 38 - build/linux/unbundle/libxslt.gyp | 25 - build/linux/unbundle/openssl.gyp | 25 - build/linux/unbundle/opus.gyp | 38 - build/linux/unbundle/re2.gyp | 37 - build/linux/unbundle/replace_gyp_files.py | 81 - build/linux/unbundle/snappy.gyp | 29 - build/linux/unbundle/speex.gyp | 45 - build/linux/unbundle/sqlite.gyp | 28 - build/linux/unbundle/v8.gyp | 64 - build/linux/unbundle/zlib.gyp | 67 - build/mac/OWNERS | 2 - build/mac/asan.gyp | 32 - build/mac/change_mach_o_flags.py | 273 - build/mac/change_mach_o_flags_from_xcode.sh | 15 - build/mac/chrome_mac.croc | 36 - build/mac/copy_asan_runtime_dylib.sh | 63 - build/mac/copy_framework_unversioned.sh | 118 - build/mac/edit_xibs.sh | 17 - build/mac/find_sdk.py | 82 - build/mac/make_more_helpers.sh | 91 - build/mac/strip_from_xcode | 62 - build/mac/strip_save_dsym | 341 -- build/mac/tweak_info_plist.py | 305 -- build/mac/verify_no_objc.sh | 43 - build/nocompile.gypi | 96 - build/output_dll_copy.rules | 17 - build/precompile.cc | 7 - build/precompile.h | 110 - build/protoc.gypi | 124 - build/protoc_java.gypi | 82 - build/protoc_java.py | 56 - build/release.gypi | 17 - build/sanitize-mac-build-log.sed | 35 - build/sanitize-mac-build-log.sh | 6 - build/sanitize-png-files.sh | 445 -- build/sanitize-win-build-log.sed | 18 - build/sanitize-win-build-log.sh | 6 - build/shim_headers.gypi | 53 - build/some.gyp | 24 - build/symlink.py | 44 - build/temp_gyp/README.chromium | 3 - build/temp_gyp/pdfsqueeze.gyp | 40 - build/uiautomator_test.gypi | 47 - build/update-linux-sandbox.sh | 75 - build/util/LASTCHANGE | 1 - build/util/LASTCHANGE.blink | 1 - build/util/lastchange.py | 236 - build/util/lib/common/__init__.py | 0 build/util/lib/common/unittest_util.py | 151 - build/util/lib/common/util.py | 151 - build/whitespace_file.txt | 73 - build/win/chrome_win.croc | 26 - build/win/compatibility.manifest | 15 - build/win/importlibs/create_import_lib.gypi | 54 - build/win/importlibs/create_importlib_win.py | 217 - build/win/importlibs/filter_export_list.py | 85 - build/win/importlibs/x86/user32.winxp.imports | 670 --- build/win/importlibs/x86/user32.winxp.lib | Bin 141662 -> 0 bytes build/win/install-build-deps.py | 47 - build/win/setup_cygwin_mount.py | 20 - build/win_precompile.gypi | 20 - 1555 files changed, 2 insertions(+), 252780 deletions(-) delete mode 100644 base/DEPS delete mode 100644 base/OWNERS delete mode 100644 base/PRESUBMIT.py delete mode 100644 base/allocator/README delete mode 100644 base/allocator/allocator.gyp delete mode 100644 base/allocator/allocator_extension.cc delete mode 100644 base/allocator/allocator_extension.h delete mode 100644 base/allocator/allocator_extension_thunks.cc delete mode 100644 base/allocator/allocator_extension_thunks.h delete mode 100644 base/allocator/allocator_shim.cc delete mode 100644 base/allocator/allocator_shim.h delete mode 100644 base/allocator/allocator_unittests.cc delete mode 100644 base/allocator/debugallocation_shim.cc delete mode 100644 base/allocator/generic_allocators.cc delete mode 100755 base/allocator/prep_libc.py delete mode 100644 base/allocator/tcmalloc_unittest.cc delete mode 100644 base/allocator/type_profiler.cc delete mode 100644 base/allocator/type_profiler.h delete mode 100644 base/allocator/type_profiler_control.cc delete mode 100644 base/allocator/type_profiler_control.h delete mode 100644 base/allocator/type_profiler_map_unittests.cc delete mode 100644 base/allocator/type_profiler_tcmalloc.cc delete mode 100644 base/allocator/type_profiler_tcmalloc.h delete mode 100644 base/allocator/type_profiler_unittests.cc delete mode 100644 base/allocator/unittest_utils.cc delete mode 100644 base/allocator/win_allocator.cc delete mode 100644 base/android/OWNERS delete mode 100644 base/android/activity_state_list.h delete mode 100644 base/android/activity_status.cc delete mode 100644 base/android/activity_status.h delete mode 100644 base/android/activity_status_unittest.cc delete mode 100644 base/android/base_jni_registrar.cc delete mode 100644 base/android/base_jni_registrar.h delete mode 100644 base/android/build_info.cc delete mode 100644 base/android/build_info.h delete mode 100644 base/android/context_types.cc delete mode 100644 base/android/context_types.h delete mode 100644 base/android/cpu_features.cc delete mode 100644 base/android/cpu_features.h delete mode 100644 base/android/fifo_utils.cc delete mode 100644 base/android/fifo_utils.h delete mode 100644 base/android/important_file_writer_android.cc delete mode 100644 base/android/important_file_writer_android.h delete mode 100644 base/android/java/src/org/chromium/base/AccessedByNative.java delete mode 100644 base/android/java/src/org/chromium/base/ActivityState.template delete mode 100644 base/android/java/src/org/chromium/base/ActivityStatus.java delete mode 100644 base/android/java/src/org/chromium/base/ApiCompatibilityUtils.java delete mode 100644 base/android/java/src/org/chromium/base/BuildInfo.java delete mode 100644 base/android/java/src/org/chromium/base/CalledByNative.java delete mode 100644 base/android/java/src/org/chromium/base/CalledByNativeUnchecked.java delete mode 100644 base/android/java/src/org/chromium/base/ChromiumActivity.java delete mode 100644 base/android/java/src/org/chromium/base/ContextTypes.java delete mode 100644 base/android/java/src/org/chromium/base/CpuFeatures.java delete mode 100644 base/android/java/src/org/chromium/base/ImportantFileWriterAndroid.java delete mode 100644 base/android/java/src/org/chromium/base/JNINamespace.java delete mode 100644 base/android/java/src/org/chromium/base/JavaHandlerThread.java delete mode 100644 base/android/java/src/org/chromium/base/MemoryPressureLevelList.template delete mode 100644 base/android/java/src/org/chromium/base/MemoryPressureListener.java delete mode 100644 base/android/java/src/org/chromium/base/NativeClassQualifiedName.java delete mode 100644 base/android/java/src/org/chromium/base/ObserverList.java delete mode 100644 base/android/java/src/org/chromium/base/PathService.java delete mode 100644 base/android/java/src/org/chromium/base/PathUtils.java delete mode 100644 base/android/java/src/org/chromium/base/PowerMonitor.java delete mode 100644 base/android/java/src/org/chromium/base/PowerStatusReceiver.java delete mode 100644 base/android/java/src/org/chromium/base/SysUtils.java delete mode 100644 base/android/java/src/org/chromium/base/SystemMessageHandler.java delete mode 100644 base/android/java/src/org/chromium/base/ThreadUtils.java delete mode 100644 base/android/java/src/org/chromium/base/WeakContext.java delete mode 100644 base/android/java_handler_thread.cc delete mode 100644 base/android/java_handler_thread.h delete mode 100644 base/android/javatests/src/org/chromium/base/ContextTypesTest.java delete mode 100644 base/android/javatests/src/org/chromium/base/ObserverListTest.java delete mode 100644 base/android/jni_android.cc delete mode 100644 base/android/jni_android.h delete mode 100644 base/android/jni_android_unittest.cc delete mode 100644 base/android/jni_array.cc delete mode 100644 base/android/jni_array.h delete mode 100644 base/android/jni_array_unittest.cc delete mode 100644 base/android/jni_generator/golden_sample_for_tests_jni.h delete mode 100644 base/android/jni_generator/java/src/org/chromium/example/jni_generator/SampleForTests.java delete mode 100644 base/android/jni_generator/jni_generator.gyp delete mode 100755 base/android/jni_generator/jni_generator.py delete mode 100755 base/android/jni_generator/jni_generator_tests.py delete mode 100644 base/android/jni_generator/sample_for_tests.cc delete mode 100644 base/android/jni_generator/sample_for_tests.h delete mode 100644 base/android/jni_helper.cc delete mode 100644 base/android/jni_helper.h delete mode 100644 base/android/jni_registrar.cc delete mode 100644 base/android/jni_registrar.h delete mode 100644 base/android/jni_string.cc delete mode 100644 base/android/jni_string.h delete mode 100644 base/android/jni_string_unittest.cc delete mode 100644 base/android/memory_pressure_listener_android.cc delete mode 100644 base/android/memory_pressure_listener_android.h delete mode 100644 base/android/path_service_android.cc delete mode 100644 base/android/path_service_android.h delete mode 100644 base/android/path_utils.cc delete mode 100644 base/android/path_utils.h delete mode 100644 base/android/path_utils_unittest.cc delete mode 100644 base/android/scoped_java_ref.cc delete mode 100644 base/android/scoped_java_ref.h delete mode 100644 base/android/scoped_java_ref_unittest.cc delete mode 100644 base/android/sys_utils.cc delete mode 100644 base/android/sys_utils.h delete mode 100644 base/android/thread_utils.h delete mode 100644 base/at_exit.cc delete mode 100644 base/at_exit.h delete mode 100644 base/at_exit_unittest.cc delete mode 100644 base/atomic_ref_count.h delete mode 100644 base/atomic_sequence_num.h delete mode 100644 base/atomicops.h delete mode 100644 base/atomicops_internals_arm_gcc.h delete mode 100644 base/atomicops_internals_atomicword_compat.h delete mode 100644 base/atomicops_internals_gcc.h delete mode 100644 base/atomicops_internals_mac.h delete mode 100644 base/atomicops_internals_mips_gcc.h delete mode 100644 base/atomicops_internals_tsan.h delete mode 100644 base/atomicops_internals_x86_gcc.cc delete mode 100644 base/atomicops_internals_x86_gcc.h delete mode 100644 base/atomicops_internals_x86_msvc.h delete mode 100644 base/atomicops_unittest.cc delete mode 100644 base/auto_reset.h delete mode 100644 base/base.gyp delete mode 100644 base/base.gypi delete mode 100644 base/base64.cc delete mode 100644 base/base64.h delete mode 100644 base/base64_unittest.cc delete mode 100644 base/base_export.h delete mode 100644 base/base_paths.cc delete mode 100644 base/base_paths.h delete mode 100644 base/base_paths_android.cc delete mode 100644 base/base_paths_android.h delete mode 100644 base/base_paths_mac.h delete mode 100644 base/base_paths_mac.mm delete mode 100644 base/base_paths_posix.cc delete mode 100644 base/base_paths_posix.h delete mode 100644 base/base_paths_win.cc delete mode 100644 base/base_paths_win.h delete mode 100644 base/base_switches.cc delete mode 100644 base/base_switches.h delete mode 100644 base/base_unittests.isolate delete mode 100644 base/base_untrusted.gyp delete mode 100644 base/basictypes.h delete mode 100644 base/bind.h delete mode 100644 base/bind.h.pump delete mode 100644 base/bind_helpers.cc delete mode 100644 base/bind_helpers.h delete mode 100644 base/bind_helpers_unittest.cc delete mode 100644 base/bind_internal.h delete mode 100644 base/bind_internal.h.pump delete mode 100644 base/bind_internal_win.h delete mode 100644 base/bind_internal_win.h.pump delete mode 100644 base/bind_unittest.cc delete mode 100644 base/bind_unittest.nc delete mode 100644 base/bits.h delete mode 100644 base/bits_unittest.cc delete mode 100644 base/build_time.cc delete mode 100644 base/build_time.h delete mode 100644 base/build_time_unittest.cc delete mode 100644 base/callback.h delete mode 100644 base/callback.h.pump delete mode 100644 base/callback_forward.h delete mode 100644 base/callback_helpers.h delete mode 100644 base/callback_internal.cc delete mode 100644 base/callback_internal.h delete mode 100644 base/callback_unittest.cc delete mode 100644 base/callback_unittest.nc delete mode 100644 base/cancelable_callback.h delete mode 100644 base/cancelable_callback_unittest.cc delete mode 100644 base/check_example.cc delete mode 100644 base/chromeos/chromeos_version.cc delete mode 100644 base/chromeos/chromeos_version.h delete mode 100644 base/command_line.cc delete mode 100644 base/command_line.h delete mode 100644 base/command_line_unittest.cc delete mode 100644 base/compiler_specific.h delete mode 100644 base/containers/hash_tables.h delete mode 100644 base/containers/hash_tables_unittest.cc delete mode 100644 base/containers/linked_list.h delete mode 100644 base/containers/linked_list_unittest.cc delete mode 100644 base/containers/mru_cache.h delete mode 100644 base/containers/mru_cache_unittest.cc delete mode 100644 base/containers/small_map.h delete mode 100644 base/containers/small_map_unittest.cc delete mode 100644 base/containers/stack_container.h delete mode 100644 base/containers/stack_container_unittest.cc delete mode 100644 base/cpu.cc delete mode 100644 base/cpu.h delete mode 100644 base/cpu_unittest.cc delete mode 100644 base/critical_closure.h delete mode 100644 base/critical_closure_ios.mm delete mode 100755 base/data/file_version_info_unittest/FileVersionInfoTest1.dll delete mode 100755 base/data/file_version_info_unittest/FileVersionInfoTest2.dll delete mode 100644 base/debug/OWNERS delete mode 100644 base/debug/alias.cc delete mode 100644 base/debug/alias.h delete mode 100644 base/debug/crash_logging.cc delete mode 100644 base/debug/crash_logging.h delete mode 100644 base/debug/crash_logging_unittest.cc delete mode 100644 base/debug/debug_on_start_win.cc delete mode 100644 base/debug/debug_on_start_win.h delete mode 100644 base/debug/debugger.cc delete mode 100644 base/debug/debugger.h delete mode 100644 base/debug/debugger_posix.cc delete mode 100644 base/debug/debugger_win.cc delete mode 100644 base/debug/leak_annotations.h delete mode 100644 base/debug/leak_tracker.h delete mode 100644 base/debug/leak_tracker_unittest.cc delete mode 100644 base/debug/proc_maps_linux.cc delete mode 100644 base/debug/proc_maps_linux.h delete mode 100644 base/debug/proc_maps_linux_unittest.cc delete mode 100644 base/debug/profiler.cc delete mode 100644 base/debug/profiler.h delete mode 100644 base/debug/stack_trace.cc delete mode 100644 base/debug/stack_trace.h delete mode 100644 base/debug/stack_trace_android.cc delete mode 100644 base/debug/stack_trace_ios.mm delete mode 100644 base/debug/stack_trace_posix.cc delete mode 100644 base/debug/stack_trace_unittest.cc delete mode 100644 base/debug/stack_trace_win.cc delete mode 100644 base/debug/trace_event.h delete mode 100644 base/debug/trace_event_android.cc delete mode 100644 base/debug/trace_event_impl.cc delete mode 100644 base/debug/trace_event_impl.h delete mode 100644 base/debug/trace_event_impl_constants.cc delete mode 100644 base/debug/trace_event_memory.cc delete mode 100644 base/debug/trace_event_memory.h delete mode 100644 base/debug/trace_event_memory_unittest.cc delete mode 100644 base/debug/trace_event_unittest.cc delete mode 100644 base/debug/trace_event_unittest.h delete mode 100644 base/debug/trace_event_win.cc delete mode 100644 base/debug/trace_event_win.h delete mode 100644 base/debug/trace_event_win_unittest.cc delete mode 100644 base/debug_message.cc delete mode 100644 base/deferred_sequenced_task_runner.cc delete mode 100644 base/deferred_sequenced_task_runner.h delete mode 100644 base/deferred_sequenced_task_runner_unittest.cc delete mode 100644 base/environment.cc delete mode 100644 base/environment.h delete mode 100644 base/environment_unittest.cc delete mode 100644 base/event_recorder.h delete mode 100644 base/event_recorder_stubs.cc delete mode 100644 base/event_recorder_win.cc delete mode 100644 base/event_types.h delete mode 100644 base/file_descriptor_posix.h delete mode 100644 base/file_util.cc delete mode 100644 base/file_util.h delete mode 100644 base/file_util_android.cc delete mode 100644 base/file_util_linux.cc delete mode 100644 base/file_util_mac.mm delete mode 100644 base/file_util_posix.cc delete mode 100644 base/file_util_unittest.cc delete mode 100644 base/file_util_win.cc delete mode 100644 base/file_version_info.h delete mode 100644 base/file_version_info_mac.h delete mode 100644 base/file_version_info_mac.mm delete mode 100644 base/file_version_info_unittest.cc delete mode 100644 base/file_version_info_win.cc delete mode 100644 base/file_version_info_win.h delete mode 100644 base/files/OWNERS delete mode 100644 base/files/dir_reader_fallback.h delete mode 100644 base/files/dir_reader_linux.h delete mode 100644 base/files/dir_reader_posix.h delete mode 100644 base/files/dir_reader_posix_unittest.cc delete mode 100644 base/files/file_enumerator.cc delete mode 100644 base/files/file_enumerator.h delete mode 100644 base/files/file_enumerator_posix.cc delete mode 100644 base/files/file_enumerator_win.cc delete mode 100644 base/files/file_path.cc delete mode 100644 base/files/file_path.h delete mode 100644 base/files/file_path_constants.cc delete mode 100644 base/files/file_path_unittest.cc delete mode 100644 base/files/file_path_watcher.cc delete mode 100644 base/files/file_path_watcher.h delete mode 100644 base/files/file_path_watcher_browsertest.cc delete mode 100644 base/files/file_path_watcher_kqueue.cc delete mode 100644 base/files/file_path_watcher_linux.cc delete mode 100644 base/files/file_path_watcher_stub.cc delete mode 100644 base/files/file_path_watcher_win.cc delete mode 100644 base/files/file_util_proxy.cc delete mode 100644 base/files/file_util_proxy.h delete mode 100644 base/files/file_util_proxy_unittest.cc delete mode 100644 base/files/important_file_writer.cc delete mode 100644 base/files/important_file_writer.h delete mode 100644 base/files/important_file_writer_unittest.cc delete mode 100644 base/files/memory_mapped_file.cc delete mode 100644 base/files/memory_mapped_file.h delete mode 100644 base/files/memory_mapped_file_posix.cc delete mode 100644 base/files/memory_mapped_file_win.cc delete mode 100644 base/files/scoped_platform_file_closer.cc delete mode 100644 base/files/scoped_platform_file_closer.h delete mode 100644 base/files/scoped_temp_dir.cc delete mode 100644 base/files/scoped_temp_dir.h delete mode 100644 base/files/scoped_temp_dir_unittest.cc delete mode 100644 base/float_util.h delete mode 100644 base/format_macros.h delete mode 100644 base/glibc-x86-32.base_untrusted.source_list.gypcmd delete mode 100644 base/glibc-x86-64.base_untrusted.source_list.gypcmd delete mode 100644 base/gmock_unittest.cc delete mode 100644 base/gtest_prod_util.h delete mode 100644 base/guid.cc delete mode 100644 base/guid.h delete mode 100644 base/guid_posix.cc delete mode 100644 base/guid_unittest.cc delete mode 100644 base/guid_win.cc delete mode 100644 base/hash.cc delete mode 100644 base/hash.h delete mode 100644 base/i18n/OWNERS delete mode 100644 base/i18n/base_i18n_export.h delete mode 100644 base/i18n/bidi_line_iterator.cc delete mode 100644 base/i18n/bidi_line_iterator.h delete mode 100644 base/i18n/break_iterator.cc delete mode 100644 base/i18n/break_iterator.h delete mode 100644 base/i18n/break_iterator_unittest.cc delete mode 100644 base/i18n/case_conversion.cc delete mode 100644 base/i18n/case_conversion.h delete mode 100644 base/i18n/case_conversion_unittest.cc delete mode 100644 base/i18n/char_iterator.cc delete mode 100644 base/i18n/char_iterator.h delete mode 100644 base/i18n/char_iterator_unittest.cc delete mode 100644 base/i18n/file_util_icu.cc delete mode 100644 base/i18n/file_util_icu.h delete mode 100644 base/i18n/file_util_icu_unittest.cc delete mode 100644 base/i18n/i18n_constants.cc delete mode 100644 base/i18n/i18n_constants.h delete mode 100644 base/i18n/icu_encoding_detection.cc delete mode 100644 base/i18n/icu_encoding_detection.h delete mode 100644 base/i18n/icu_string_conversions.cc delete mode 100644 base/i18n/icu_string_conversions.h delete mode 100644 base/i18n/icu_string_conversions_unittest.cc delete mode 100644 base/i18n/icu_util.cc delete mode 100644 base/i18n/icu_util.h delete mode 100644 base/i18n/icu_util_nacl_win64.cc delete mode 100644 base/i18n/number_formatting.cc delete mode 100644 base/i18n/number_formatting.h delete mode 100644 base/i18n/number_formatting_unittest.cc delete mode 100644 base/i18n/rtl.cc delete mode 100644 base/i18n/rtl.h delete mode 100644 base/i18n/rtl_unittest.cc delete mode 100644 base/i18n/string_compare.cc delete mode 100644 base/i18n/string_compare.h delete mode 100644 base/i18n/string_search.cc delete mode 100644 base/i18n/string_search.h delete mode 100644 base/i18n/string_search_unittest.cc delete mode 100644 base/i18n/time_formatting.cc delete mode 100644 base/i18n/time_formatting.h delete mode 100644 base/i18n/time_formatting_unittest.cc delete mode 100644 base/id_map.h delete mode 100644 base/id_map_unittest.cc delete mode 100644 base/ini_parser.cc delete mode 100644 base/ini_parser.h delete mode 100644 base/ini_parser_unittest.cc delete mode 100644 base/ios/OWNERS delete mode 100644 base/ios/device_util.h delete mode 100644 base/ios/device_util.mm delete mode 100644 base/ios/device_util_unittest.mm delete mode 100644 base/ios/ios_util.h delete mode 100644 base/ios/ios_util.mm delete mode 100644 base/ios/scoped_critical_action.h delete mode 100644 base/ios/scoped_critical_action.mm delete mode 100644 base/irt-x86-32.base_untrusted.source_list.gypcmd delete mode 100644 base/irt-x86-64.base_untrusted.source_list.gypcmd delete mode 100644 base/json/json_file_value_serializer.cc delete mode 100644 base/json/json_file_value_serializer.h delete mode 100644 base/json/json_parser.cc delete mode 100644 base/json/json_parser.h delete mode 100644 base/json/json_parser_unittest.cc delete mode 100644 base/json/json_reader.cc delete mode 100644 base/json/json_reader.h delete mode 100644 base/json/json_reader_unittest.cc delete mode 100644 base/json/json_string_value_serializer.cc delete mode 100644 base/json/json_string_value_serializer.h delete mode 100644 base/json/json_value_converter.h delete mode 100644 base/json/json_value_converter_unittest.cc delete mode 100644 base/json/json_value_serializer_unittest.cc delete mode 100644 base/json/json_writer.cc delete mode 100644 base/json/json_writer.h delete mode 100644 base/json/json_writer_unittest.cc delete mode 100644 base/json/string_escape.cc delete mode 100644 base/json/string_escape.h delete mode 100644 base/json/string_escape_unittest.cc delete mode 100644 base/lazy_instance.cc delete mode 100644 base/lazy_instance.h delete mode 100644 base/lazy_instance_unittest.cc delete mode 100644 base/linux_util.cc delete mode 100644 base/linux_util.h delete mode 100644 base/location.cc delete mode 100644 base/location.h delete mode 100644 base/logging.cc delete mode 100644 base/logging.h delete mode 100644 base/logging_unittest.cc delete mode 100644 base/logging_win.cc delete mode 100644 base/logging_win.h delete mode 100644 base/mac/OWNERS delete mode 100644 base/mac/authorization_util.h delete mode 100644 base/mac/authorization_util.mm delete mode 100644 base/mac/bind_objc_block.h delete mode 100644 base/mac/bind_objc_block_unittest.mm delete mode 100644 base/mac/bundle_locations.h delete mode 100644 base/mac/bundle_locations.mm delete mode 100644 base/mac/cocoa_protocols.h delete mode 100644 base/mac/foundation_util.h delete mode 100644 base/mac/foundation_util.mm delete mode 100644 base/mac/foundation_util_unittest.mm delete mode 100644 base/mac/launch_services_util.cc delete mode 100644 base/mac/launch_services_util.h delete mode 100644 base/mac/launchd.cc delete mode 100644 base/mac/launchd.h delete mode 100644 base/mac/libdispatch_task_runner.cc delete mode 100644 base/mac/libdispatch_task_runner.h delete mode 100644 base/mac/libdispatch_task_runner_unittest.cc delete mode 100644 base/mac/mac_logging.cc delete mode 100644 base/mac/mac_logging.h delete mode 100644 base/mac/mac_util.h delete mode 100644 base/mac/mac_util.mm delete mode 100644 base/mac/mac_util_unittest.mm delete mode 100644 base/mac/objc_property_releaser.h delete mode 100644 base/mac/objc_property_releaser.mm delete mode 100644 base/mac/objc_property_releaser_unittest.mm delete mode 100644 base/mac/os_crash_dumps.cc delete mode 100644 base/mac/os_crash_dumps.h delete mode 100644 base/mac/scoped_aedesc.h delete mode 100644 base/mac/scoped_authorizationref.h delete mode 100644 base/mac/scoped_block.h delete mode 100644 base/mac/scoped_cffiledescriptorref.h delete mode 100644 base/mac/scoped_cftyperef.h delete mode 100644 base/mac/scoped_ioobject.h delete mode 100644 base/mac/scoped_ioplugininterface.h delete mode 100644 base/mac/scoped_launch_data.h delete mode 100644 base/mac/scoped_mach_port.cc delete mode 100644 base/mac/scoped_mach_port.h delete mode 100644 base/mac/scoped_nsautorelease_pool.h delete mode 100644 base/mac/scoped_nsautorelease_pool.mm delete mode 100644 base/mac/scoped_nsexception_enabler.h delete mode 100644 base/mac/scoped_nsexception_enabler.mm delete mode 100644 base/mac/scoped_nsobject.h delete mode 100644 base/mac/scoped_nsobject_unittest.mm delete mode 100644 base/mac/scoped_sending_event.h delete mode 100644 base/mac/scoped_sending_event.mm delete mode 100644 base/mac/scoped_sending_event_unittest.mm delete mode 100644 base/mac/sdk_forward_declarations.h delete mode 100644 base/md5.cc delete mode 100644 base/md5.h delete mode 100644 base/md5_unittest.cc delete mode 100644 base/memory/aligned_memory.cc delete mode 100644 base/memory/aligned_memory.h delete mode 100644 base/memory/aligned_memory_unittest.cc delete mode 100644 base/memory/discardable_memory.cc delete mode 100644 base/memory/discardable_memory.h delete mode 100644 base/memory/discardable_memory_android.cc delete mode 100644 base/memory/discardable_memory_mac.cc delete mode 100644 base/memory/discardable_memory_unittest.cc delete mode 100644 base/memory/linked_ptr.h delete mode 100644 base/memory/linked_ptr_unittest.cc delete mode 100644 base/memory/manual_constructor.h delete mode 100644 base/memory/memory_pressure_level_list.h delete mode 100644 base/memory/memory_pressure_listener.cc delete mode 100644 base/memory/memory_pressure_listener.h delete mode 100644 base/memory/raw_scoped_refptr_mismatch_checker.h delete mode 100644 base/memory/ref_counted.cc delete mode 100644 base/memory/ref_counted.h delete mode 100644 base/memory/ref_counted_delete_on_message_loop.h delete mode 100644 base/memory/ref_counted_memory.cc delete mode 100644 base/memory/ref_counted_memory.h delete mode 100644 base/memory/ref_counted_memory_unittest.cc delete mode 100644 base/memory/ref_counted_unittest.cc delete mode 100644 base/memory/scoped_handle.h delete mode 100644 base/memory/scoped_open_process.h delete mode 100644 base/memory/scoped_policy.h delete mode 100644 base/memory/scoped_ptr.h delete mode 100644 base/memory/scoped_ptr_unittest.cc delete mode 100644 base/memory/scoped_ptr_unittest.nc delete mode 100644 base/memory/scoped_vector.h delete mode 100644 base/memory/scoped_vector_unittest.cc delete mode 100644 base/memory/shared_memory.h delete mode 100644 base/memory/shared_memory_android.cc delete mode 100644 base/memory/shared_memory_nacl.cc delete mode 100644 base/memory/shared_memory_posix.cc delete mode 100644 base/memory/shared_memory_unittest.cc delete mode 100644 base/memory/shared_memory_win.cc delete mode 100644 base/memory/singleton.cc delete mode 100644 base/memory/singleton.h delete mode 100644 base/memory/singleton_objc.h delete mode 100644 base/memory/singleton_unittest.cc delete mode 100644 base/memory/weak_ptr.cc delete mode 100644 base/memory/weak_ptr.h delete mode 100644 base/memory/weak_ptr_unittest.cc delete mode 100644 base/memory/weak_ptr_unittest.nc delete mode 100644 base/message_loop/incoming_task_queue.cc delete mode 100644 base/message_loop/incoming_task_queue.h delete mode 100644 base/message_loop/message_loop.cc delete mode 100644 base/message_loop/message_loop.h delete mode 100644 base/message_loop/message_loop_proxy.cc delete mode 100644 base/message_loop/message_loop_proxy.h delete mode 100644 base/message_loop/message_loop_proxy_impl.cc delete mode 100644 base/message_loop/message_loop_proxy_impl.h delete mode 100644 base/message_loop/message_loop_proxy_impl_unittest.cc delete mode 100644 base/message_loop/message_loop_proxy_unittest.cc delete mode 100644 base/message_loop/message_loop_unittest.cc delete mode 100644 base/message_loop/message_pump.cc delete mode 100644 base/message_loop/message_pump.h delete mode 100644 base/message_loop/message_pump_android.cc delete mode 100644 base/message_loop/message_pump_android.h delete mode 100644 base/message_loop/message_pump_aurax11.cc delete mode 100644 base/message_loop/message_pump_aurax11.h delete mode 100644 base/message_loop/message_pump_default.cc delete mode 100644 base/message_loop/message_pump_default.h delete mode 100644 base/message_loop/message_pump_dispatcher.h delete mode 100644 base/message_loop/message_pump_glib.cc delete mode 100644 base/message_loop/message_pump_glib.h delete mode 100644 base/message_loop/message_pump_glib_unittest.cc delete mode 100644 base/message_loop/message_pump_gtk.cc delete mode 100644 base/message_loop/message_pump_gtk.h delete mode 100644 base/message_loop/message_pump_io_ios.cc delete mode 100644 base/message_loop/message_pump_io_ios.h delete mode 100644 base/message_loop/message_pump_io_ios_unittest.cc delete mode 100644 base/message_loop/message_pump_libevent.cc delete mode 100644 base/message_loop/message_pump_libevent.h delete mode 100644 base/message_loop/message_pump_libevent_unittest.cc delete mode 100644 base/message_loop/message_pump_mac.h delete mode 100644 base/message_loop/message_pump_mac.mm delete mode 100644 base/message_loop/message_pump_observer.h delete mode 100644 base/message_loop/message_pump_ozone.cc delete mode 100644 base/message_loop/message_pump_ozone.h delete mode 100644 base/message_loop/message_pump_win.cc delete mode 100644 base/message_loop/message_pump_win.h delete mode 100644 base/metrics/OWNERS delete mode 100644 base/metrics/bucket_ranges.cc delete mode 100644 base/metrics/bucket_ranges.h delete mode 100644 base/metrics/bucket_ranges_unittest.cc delete mode 100644 base/metrics/field_trial.cc delete mode 100644 base/metrics/field_trial.h delete mode 100644 base/metrics/field_trial_unittest.cc delete mode 100644 base/metrics/histogram.cc delete mode 100644 base/metrics/histogram.h delete mode 100644 base/metrics/histogram_base.cc delete mode 100644 base/metrics/histogram_base.h delete mode 100644 base/metrics/histogram_base_unittest.cc delete mode 100644 base/metrics/histogram_flattener.h delete mode 100644 base/metrics/histogram_samples.cc delete mode 100644 base/metrics/histogram_samples.h delete mode 100644 base/metrics/histogram_snapshot_manager.cc delete mode 100644 base/metrics/histogram_snapshot_manager.h delete mode 100644 base/metrics/histogram_unittest.cc delete mode 100644 base/metrics/sample_map.cc delete mode 100644 base/metrics/sample_map.h delete mode 100644 base/metrics/sample_map_unittest.cc delete mode 100644 base/metrics/sample_vector.cc delete mode 100644 base/metrics/sample_vector.h delete mode 100644 base/metrics/sample_vector_unittest.cc delete mode 100644 base/metrics/sparse_histogram.cc delete mode 100644 base/metrics/sparse_histogram.h delete mode 100644 base/metrics/sparse_histogram_unittest.cc delete mode 100644 base/metrics/statistics_recorder.cc delete mode 100644 base/metrics/statistics_recorder.h delete mode 100644 base/metrics/statistics_recorder_unittest.cc delete mode 100644 base/metrics/stats_counters.cc delete mode 100644 base/metrics/stats_counters.h delete mode 100644 base/metrics/stats_table.cc delete mode 100644 base/metrics/stats_table.h delete mode 100644 base/metrics/stats_table_unittest.cc delete mode 100644 base/move.h delete mode 100644 base/native_library.h delete mode 100644 base/native_library_mac.mm delete mode 100644 base/native_library_posix.cc delete mode 100644 base/native_library_win.cc delete mode 100644 base/newlib-x86-32.base_untrusted.source_list.gypcmd delete mode 100644 base/newlib-x86-64.base_untrusted.source_list.gypcmd delete mode 100644 base/nix/mime_util_xdg.cc delete mode 100644 base/nix/mime_util_xdg.h delete mode 100644 base/nix/xdg_util.cc delete mode 100644 base/nix/xdg_util.h delete mode 100644 base/nix/xdg_util_unittest.cc delete mode 100644 base/observer_list.h delete mode 100644 base/observer_list_threadsafe.h delete mode 100644 base/observer_list_unittest.cc delete mode 100644 base/os_compat_android.cc delete mode 100644 base/os_compat_android.h delete mode 100644 base/os_compat_android_unittest.cc delete mode 100644 base/os_compat_nacl.cc delete mode 100644 base/os_compat_nacl.h delete mode 100644 base/path_service.cc delete mode 100644 base/path_service.h delete mode 100644 base/path_service_unittest.cc delete mode 100644 base/pending_task.cc delete mode 100644 base/pending_task.h delete mode 100644 base/perftimer.cc delete mode 100644 base/perftimer.h delete mode 100644 base/pickle.cc delete mode 100644 base/pickle.h delete mode 100644 base/pickle_unittest.cc delete mode 100644 base/platform_file.cc delete mode 100644 base/platform_file.h delete mode 100644 base/platform_file_posix.cc delete mode 100644 base/platform_file_unittest.cc delete mode 100644 base/platform_file_win.cc delete mode 100644 base/port.h delete mode 100644 base/posix/eintr_wrapper.h delete mode 100644 base/posix/file_descriptor_shuffle.cc delete mode 100644 base/posix/file_descriptor_shuffle.h delete mode 100644 base/posix/file_descriptor_shuffle_unittest.cc delete mode 100644 base/posix/global_descriptors.cc delete mode 100644 base/posix/global_descriptors.h delete mode 100644 base/posix/unix_domain_socket_linux.cc delete mode 100644 base/posix/unix_domain_socket_linux.h delete mode 100644 base/posix/unix_domain_socket_linux_unittest.cc delete mode 100644 base/power_monitor/power_monitor.cc delete mode 100644 base/power_monitor/power_monitor.h delete mode 100644 base/power_monitor/power_monitor_device_source.cc delete mode 100644 base/power_monitor/power_monitor_device_source.h delete mode 100644 base/power_monitor/power_monitor_device_source_android.cc delete mode 100644 base/power_monitor/power_monitor_device_source_android.h delete mode 100644 base/power_monitor/power_monitor_device_source_ios.mm delete mode 100644 base/power_monitor/power_monitor_device_source_mac.mm delete mode 100644 base/power_monitor/power_monitor_device_source_posix.cc delete mode 100644 base/power_monitor/power_monitor_device_source_win.cc delete mode 100644 base/power_monitor/power_monitor_source.cc delete mode 100644 base/power_monitor/power_monitor_source.h delete mode 100644 base/power_monitor/power_monitor_unittest.cc delete mode 100644 base/power_monitor/power_observer.h delete mode 100644 base/prefs/OWNERS delete mode 100644 base/prefs/README delete mode 100644 base/prefs/base_prefs_export.h delete mode 100644 base/prefs/default_pref_store.cc delete mode 100644 base/prefs/default_pref_store.h delete mode 100644 base/prefs/default_pref_store_unittest.cc delete mode 100644 base/prefs/json_pref_store.cc delete mode 100644 base/prefs/json_pref_store.h delete mode 100644 base/prefs/json_pref_store_unittest.cc delete mode 100644 base/prefs/mock_pref_change_callback.cc delete mode 100644 base/prefs/mock_pref_change_callback.h delete mode 100644 base/prefs/overlay_user_pref_store.cc delete mode 100644 base/prefs/overlay_user_pref_store.h delete mode 100644 base/prefs/overlay_user_pref_store_unittest.cc delete mode 100644 base/prefs/persistent_pref_store.h delete mode 100644 base/prefs/pref_change_registrar.cc delete mode 100644 base/prefs/pref_change_registrar.h delete mode 100644 base/prefs/pref_change_registrar_unittest.cc delete mode 100644 base/prefs/pref_member.cc delete mode 100644 base/prefs/pref_member.h delete mode 100644 base/prefs/pref_member_unittest.cc delete mode 100644 base/prefs/pref_notifier.h delete mode 100644 base/prefs/pref_notifier_impl.cc delete mode 100644 base/prefs/pref_notifier_impl.h delete mode 100644 base/prefs/pref_notifier_impl_unittest.cc delete mode 100644 base/prefs/pref_observer.h delete mode 100644 base/prefs/pref_registry.cc delete mode 100644 base/prefs/pref_registry.h delete mode 100644 base/prefs/pref_registry_simple.cc delete mode 100644 base/prefs/pref_registry_simple.h delete mode 100644 base/prefs/pref_service.cc delete mode 100644 base/prefs/pref_service.h delete mode 100644 base/prefs/pref_service_builder.cc delete mode 100644 base/prefs/pref_service_builder.h delete mode 100644 base/prefs/pref_service_unittest.cc delete mode 100644 base/prefs/pref_store.cc delete mode 100644 base/prefs/pref_store.h delete mode 100644 base/prefs/pref_store_observer_mock.cc delete mode 100644 base/prefs/pref_store_observer_mock.h delete mode 100644 base/prefs/pref_value_map.cc delete mode 100644 base/prefs/pref_value_map.h delete mode 100644 base/prefs/pref_value_map_unittest.cc delete mode 100644 base/prefs/pref_value_store.cc delete mode 100644 base/prefs/pref_value_store.h delete mode 100644 base/prefs/pref_value_store_unittest.cc delete mode 100644 base/prefs/testing_pref_service.cc delete mode 100644 base/prefs/testing_pref_service.h delete mode 100644 base/prefs/testing_pref_store.cc delete mode 100644 base/prefs/testing_pref_store.h delete mode 100644 base/prefs/value_map_pref_store.cc delete mode 100644 base/prefs/value_map_pref_store.h delete mode 100644 base/process/internal_linux.cc delete mode 100644 base/process/internal_linux.h delete mode 100644 base/process/kill.cc delete mode 100644 base/process/kill.h delete mode 100644 base/process/kill_mac.cc delete mode 100644 base/process/kill_posix.cc delete mode 100644 base/process/kill_win.cc delete mode 100644 base/process/launch.h delete mode 100644 base/process/launch_ios.cc delete mode 100644 base/process/launch_mac.cc delete mode 100644 base/process/launch_posix.cc delete mode 100644 base/process/launch_win.cc delete mode 100644 base/process/memory.h delete mode 100644 base/process/memory_linux.cc delete mode 100644 base/process/memory_mac.mm delete mode 100644 base/process/memory_stubs.cc delete mode 100644 base/process/memory_unittest.cc delete mode 100644 base/process/memory_unittest_mac.h delete mode 100644 base/process/memory_unittest_mac.mm delete mode 100644 base/process/memory_win.cc delete mode 100644 base/process/process.h delete mode 100644 base/process/process_handle.h delete mode 100644 base/process/process_handle_freebsd.cc delete mode 100644 base/process/process_handle_linux.cc delete mode 100644 base/process/process_handle_mac.cc delete mode 100644 base/process/process_handle_openbsd.cc delete mode 100644 base/process/process_handle_posix.cc delete mode 100644 base/process/process_handle_win.cc delete mode 100644 base/process/process_info.h delete mode 100644 base/process/process_info_linux.cc delete mode 100644 base/process/process_info_mac.cc delete mode 100644 base/process/process_info_win.cc delete mode 100644 base/process/process_iterator.cc delete mode 100644 base/process/process_iterator.h delete mode 100644 base/process/process_iterator_freebsd.cc delete mode 100644 base/process/process_iterator_linux.cc delete mode 100644 base/process/process_iterator_mac.cc delete mode 100644 base/process/process_iterator_openbsd.cc delete mode 100644 base/process/process_iterator_win.cc delete mode 100644 base/process/process_linux.cc delete mode 100644 base/process/process_metrics.h delete mode 100644 base/process/process_metrics_freebsd.cc delete mode 100644 base/process/process_metrics_ios.cc delete mode 100644 base/process/process_metrics_linux.cc delete mode 100644 base/process/process_metrics_mac.cc delete mode 100644 base/process/process_metrics_openbsd.cc delete mode 100644 base/process/process_metrics_posix.cc delete mode 100644 base/process/process_metrics_win.cc delete mode 100644 base/process/process_posix.cc delete mode 100644 base/process/process_util_unittest.cc delete mode 100644 base/process/process_util_unittest_ios.cc delete mode 100644 base/process/process_win.cc delete mode 100644 base/profiler/alternate_timer.cc delete mode 100644 base/profiler/alternate_timer.h delete mode 100644 base/profiler/scoped_profile.cc delete mode 100644 base/profiler/scoped_profile.h delete mode 100644 base/profiler/tracked_time.cc delete mode 100644 base/profiler/tracked_time.h delete mode 100644 base/profiler/tracked_time_unittest.cc delete mode 100644 base/rand_util.cc delete mode 100644 base/rand_util.h delete mode 100644 base/rand_util_nacl.cc delete mode 100644 base/rand_util_posix.cc delete mode 100644 base/rand_util_unittest.cc delete mode 100644 base/rand_util_win.cc delete mode 100644 base/run_loop.cc delete mode 100644 base/run_loop.h delete mode 100644 base/safe_numerics.h delete mode 100644 base/safe_numerics_unittest.cc delete mode 100644 base/safe_numerics_unittest.nc delete mode 100644 base/safe_strerror_posix.cc delete mode 100644 base/safe_strerror_posix.h delete mode 100644 base/scoped_clear_errno.h delete mode 100644 base/scoped_clear_errno_unittest.cc delete mode 100644 base/scoped_native_library.cc delete mode 100644 base/scoped_native_library.h delete mode 100644 base/scoped_native_library_unittest.cc delete mode 100644 base/scoped_observer.h delete mode 100644 base/security_unittest.cc delete mode 100644 base/sequence_checker.h delete mode 100644 base/sequence_checker_impl.cc delete mode 100644 base/sequence_checker_impl.h delete mode 100644 base/sequence_checker_unittest.cc delete mode 100644 base/sequenced_task_runner.cc delete mode 100644 base/sequenced_task_runner.h delete mode 100644 base/sequenced_task_runner_helpers.h delete mode 100644 base/sha1.h delete mode 100644 base/sha1_portable.cc delete mode 100644 base/sha1_unittest.cc delete mode 100644 base/sha1_win.cc delete mode 100644 base/single_thread_task_runner.h delete mode 100644 base/stl_util.h delete mode 100644 base/stl_util_unittest.cc delete mode 100644 base/strings/latin1_string_conversions.cc delete mode 100644 base/strings/latin1_string_conversions.h delete mode 100644 base/strings/nullable_string16.cc delete mode 100644 base/strings/nullable_string16.h delete mode 100644 base/strings/nullable_string16_unittest.cc delete mode 100644 base/strings/string16.cc delete mode 100644 base/strings/string16.h delete mode 100644 base/strings/string16_unittest.cc delete mode 100644 base/strings/string_number_conversions.cc delete mode 100644 base/strings/string_number_conversions.h delete mode 100644 base/strings/string_number_conversions_unittest.cc delete mode 100644 base/strings/string_piece.cc delete mode 100644 base/strings/string_piece.h delete mode 100644 base/strings/string_piece_unittest.cc delete mode 100644 base/strings/string_split.cc delete mode 100644 base/strings/string_split.h delete mode 100644 base/strings/string_split_unittest.cc delete mode 100644 base/strings/string_tokenizer.h delete mode 100644 base/strings/string_tokenizer_unittest.cc delete mode 100644 base/strings/string_util.cc delete mode 100644 base/strings/string_util.h delete mode 100644 base/strings/string_util_constants.cc delete mode 100644 base/strings/string_util_posix.h delete mode 100644 base/strings/string_util_unittest.cc delete mode 100644 base/strings/string_util_win.h delete mode 100644 base/strings/stringize_macros.h delete mode 100644 base/strings/stringize_macros_unittest.cc delete mode 100644 base/strings/stringprintf.cc delete mode 100644 base/strings/stringprintf.h delete mode 100644 base/strings/stringprintf_unittest.cc delete mode 100644 base/strings/sys_string_conversions.h delete mode 100644 base/strings/sys_string_conversions_mac.mm delete mode 100644 base/strings/sys_string_conversions_mac_unittest.mm delete mode 100644 base/strings/sys_string_conversions_posix.cc delete mode 100644 base/strings/sys_string_conversions_unittest.cc delete mode 100644 base/strings/sys_string_conversions_win.cc delete mode 100644 base/strings/utf_offset_string_conversions.cc delete mode 100644 base/strings/utf_offset_string_conversions.h delete mode 100644 base/strings/utf_offset_string_conversions_unittest.cc delete mode 100644 base/strings/utf_string_conversion_utils.cc delete mode 100644 base/strings/utf_string_conversion_utils.h delete mode 100644 base/strings/utf_string_conversions.cc delete mode 100644 base/strings/utf_string_conversions.h delete mode 100644 base/strings/utf_string_conversions_unittest.cc delete mode 100644 base/supports_user_data.cc delete mode 100644 base/supports_user_data.h delete mode 100644 base/sync_socket.h delete mode 100644 base/sync_socket_nacl.cc delete mode 100644 base/sync_socket_posix.cc delete mode 100644 base/sync_socket_win.cc delete mode 100644 base/synchronization/cancellation_flag.cc delete mode 100644 base/synchronization/cancellation_flag.h delete mode 100644 base/synchronization/cancellation_flag_unittest.cc delete mode 100644 base/synchronization/condition_variable.h delete mode 100644 base/synchronization/condition_variable_posix.cc delete mode 100644 base/synchronization/condition_variable_unittest.cc delete mode 100644 base/synchronization/condition_variable_win.cc delete mode 100644 base/synchronization/lock.cc delete mode 100644 base/synchronization/lock.h delete mode 100644 base/synchronization/lock_impl.h delete mode 100644 base/synchronization/lock_impl_posix.cc delete mode 100644 base/synchronization/lock_impl_win.cc delete mode 100644 base/synchronization/lock_unittest.cc delete mode 100644 base/synchronization/spin_wait.h delete mode 100644 base/synchronization/waitable_event.h delete mode 100644 base/synchronization/waitable_event_posix.cc delete mode 100644 base/synchronization/waitable_event_unittest.cc delete mode 100644 base/synchronization/waitable_event_watcher.h delete mode 100644 base/synchronization/waitable_event_watcher_posix.cc delete mode 100644 base/synchronization/waitable_event_watcher_unittest.cc delete mode 100644 base/synchronization/waitable_event_watcher_win.cc delete mode 100644 base/synchronization/waitable_event_win.cc delete mode 100644 base/sys_byteorder.h delete mode 100644 base/sys_info.cc delete mode 100644 base/sys_info.h delete mode 100644 base/sys_info_android.cc delete mode 100644 base/sys_info_chromeos.cc delete mode 100644 base/sys_info_freebsd.cc delete mode 100644 base/sys_info_ios.mm delete mode 100644 base/sys_info_linux.cc delete mode 100644 base/sys_info_mac.cc delete mode 100644 base/sys_info_openbsd.cc delete mode 100644 base/sys_info_posix.cc delete mode 100644 base/sys_info_unittest.cc delete mode 100644 base/sys_info_win.cc delete mode 100644 base/system_monitor/system_monitor.cc delete mode 100644 base/system_monitor/system_monitor.h delete mode 100644 base/system_monitor/system_monitor_unittest.cc delete mode 100644 base/task_runner.cc delete mode 100644 base/task_runner.h delete mode 100644 base/task_runner_util.h delete mode 100644 base/task_runner_util_unittest.cc delete mode 100644 base/template_util.h delete mode 100644 base/template_util_unittest.cc delete mode 100644 base/test/OWNERS delete mode 100644 base/test/android/OWNERS delete mode 100644 base/test/android/javatests/src/org/chromium/base/test/util/AdvancedMockContext.java delete mode 100644 base/test/android/javatests/src/org/chromium/base/test/util/DisabledTest.java delete mode 100644 base/test/android/javatests/src/org/chromium/base/test/util/EnormousTest.java delete mode 100644 base/test/android/javatests/src/org/chromium/base/test/util/Feature.java delete mode 100644 base/test/android/javatests/src/org/chromium/base/test/util/InMemorySharedPreferences.java delete mode 100644 base/test/android/javatests/src/org/chromium/base/test/util/InstrumentationUtils.java delete mode 100644 base/test/android/javatests/src/org/chromium/base/test/util/PhoneOnly.java delete mode 100644 base/test/android/javatests/src/org/chromium/base/test/util/ScalableTimeout.java delete mode 100644 base/test/android/javatests/src/org/chromium/base/test/util/TabletOnly.java delete mode 100644 base/test/android/javatests/src/org/chromium/base/test/util/TestFileUtil.java delete mode 100644 base/test/android/javatests/src/org/chromium/base/test/util/TestThread.java delete mode 100644 base/test/android/javatests/src/org/chromium/base/test/util/TimeoutScale.java delete mode 100644 base/test/android/javatests/src/org/chromium/base/test/util/UrlUtils.java delete mode 100644 base/test/data/file_util/binary_file.bin delete mode 100644 base/test/data/file_util/binary_file_diff.bin delete mode 100644 base/test/data/file_util/binary_file_same.bin delete mode 100644 base/test/data/file_util/blank_line.txt delete mode 100644 base/test/data/file_util/blank_line_crlf.txt delete mode 100644 base/test/data/file_util/crlf.txt delete mode 100644 base/test/data/file_util/different.txt delete mode 100644 base/test/data/file_util/different_first.txt delete mode 100644 base/test/data/file_util/different_last.txt delete mode 100644 base/test/data/file_util/empty1.txt delete mode 100644 base/test/data/file_util/empty2.txt delete mode 100644 base/test/data/file_util/first1.txt delete mode 100644 base/test/data/file_util/first2.txt delete mode 100644 base/test/data/file_util/original.txt delete mode 100644 base/test/data/file_util/same.txt delete mode 100644 base/test/data/file_util/same_length.txt delete mode 100644 base/test/data/file_util/shortened.txt delete mode 100644 base/test/data/json/bom_feff.json delete mode 100644 base/test/data/prefs/invalid.json delete mode 100644 base/test/data/prefs/read.json delete mode 100644 base/test/data/prefs/read.need_empty_value.json delete mode 100644 base/test/data/prefs/write.golden.json delete mode 100644 base/test/data/prefs/write.golden.need_empty_value.json delete mode 100644 base/test/data/serializer_nested_test.json delete mode 100644 base/test/data/serializer_test.json delete mode 100644 base/test/data/serializer_test_nowhitespace.json delete mode 100644 base/test/expectations/OWNERS delete mode 100644 base/test/expectations/expectation.cc delete mode 100644 base/test/expectations/expectation.h delete mode 100644 base/test/expectations/expectation_unittest.cc delete mode 100644 base/test/expectations/parser.cc delete mode 100644 base/test/expectations/parser.h delete mode 100644 base/test/expectations/parser_unittest.cc delete mode 100644 base/test/mock_chrome_application_mac.h delete mode 100644 base/test/mock_chrome_application_mac.mm delete mode 100644 base/test/mock_devices_changed_observer.cc delete mode 100644 base/test/mock_devices_changed_observer.h delete mode 100644 base/test/mock_time_provider.cc delete mode 100644 base/test/mock_time_provider.h delete mode 100644 base/test/multiprocess_test.cc delete mode 100644 base/test/multiprocess_test.h delete mode 100644 base/test/multiprocess_test_android.cc delete mode 100644 base/test/null_task_runner.cc delete mode 100644 base/test/null_task_runner.h delete mode 100644 base/test/perf_test_suite.cc delete mode 100644 base/test/perf_test_suite.h delete mode 100644 base/test/power_monitor_test_base.cc delete mode 100644 base/test/power_monitor_test_base.h delete mode 100644 base/test/run_all_perftests.cc delete mode 100644 base/test/run_all_unittests.cc delete mode 100644 base/test/scoped_locale.cc delete mode 100644 base/test/scoped_locale.h delete mode 100644 base/test/scoped_path_override.cc delete mode 100644 base/test/scoped_path_override.h delete mode 100644 base/test/sequenced_task_runner_test_template.cc delete mode 100644 base/test/sequenced_task_runner_test_template.h delete mode 100644 base/test/sequenced_worker_pool_owner.cc delete mode 100644 base/test/sequenced_worker_pool_owner.h delete mode 100644 base/test/simple_test_clock.cc delete mode 100644 base/test/simple_test_clock.h delete mode 100644 base/test/simple_test_tick_clock.cc delete mode 100644 base/test/simple_test_tick_clock.h delete mode 100644 base/test/task_runner_test_template.cc delete mode 100644 base/test/task_runner_test_template.h delete mode 100644 base/test/test_file_util.cc delete mode 100644 base/test/test_file_util.h delete mode 100644 base/test/test_file_util_linux.cc delete mode 100644 base/test/test_file_util_mac.cc delete mode 100644 base/test/test_file_util_posix.cc delete mode 100644 base/test/test_file_util_win.cc delete mode 100644 base/test/test_launcher.cc delete mode 100644 base/test/test_launcher.h delete mode 100644 base/test/test_listener_ios.h delete mode 100644 base/test/test_listener_ios.mm delete mode 100644 base/test/test_pending_task.cc delete mode 100644 base/test/test_pending_task.h delete mode 100644 base/test/test_process_killer_win.cc delete mode 100644 base/test/test_process_killer_win.h delete mode 100644 base/test/test_reg_util_win.cc delete mode 100644 base/test/test_reg_util_win.h delete mode 100644 base/test/test_shortcut_win.cc delete mode 100644 base/test/test_shortcut_win.h delete mode 100644 base/test/test_simple_task_runner.cc delete mode 100644 base/test/test_simple_task_runner.h delete mode 100644 base/test/test_suite.cc delete mode 100644 base/test/test_suite.h delete mode 100644 base/test/test_support_android.cc delete mode 100644 base/test/test_support_android.h delete mode 100644 base/test/test_support_ios.h delete mode 100644 base/test/test_support_ios.mm delete mode 100644 base/test/test_switches.cc delete mode 100644 base/test/test_switches.h delete mode 100644 base/test/test_timeouts.cc delete mode 100644 base/test/test_timeouts.h delete mode 100644 base/test/thread_test_helper.cc delete mode 100644 base/test/thread_test_helper.h delete mode 100644 base/test/trace_event_analyzer.cc delete mode 100644 base/test/trace_event_analyzer.h delete mode 100644 base/test/trace_event_analyzer_unittest.cc delete mode 100644 base/test/values_test_util.cc delete mode 100644 base/test/values_test_util.h delete mode 100644 base/third_party/dmg_fp/LICENSE delete mode 100644 base/third_party/dmg_fp/README.chromium delete mode 100644 base/third_party/dmg_fp/dmg_fp.h delete mode 100644 base/third_party/dmg_fp/dtoa.cc delete mode 100644 base/third_party/dmg_fp/dtoa_wrapper.cc delete mode 100644 base/third_party/dmg_fp/float_precision_crash.patch delete mode 100644 base/third_party/dmg_fp/g_fmt.cc delete mode 100644 base/third_party/dmg_fp/gcc_64_bit.patch delete mode 100644 base/third_party/dmg_fp/gcc_warnings.patch delete mode 100644 base/third_party/dmg_fp/mac_wextra.patch delete mode 100644 base/third_party/dmg_fp/win_vs2012.patch delete mode 100644 base/third_party/dynamic_annotations/LICENSE delete mode 100644 base/third_party/dynamic_annotations/README.chromium delete mode 100644 base/third_party/dynamic_annotations/dynamic_annotations.c delete mode 100644 base/third_party/dynamic_annotations/dynamic_annotations.gyp delete mode 100644 base/third_party/dynamic_annotations/dynamic_annotations.h delete mode 100644 base/third_party/icu/LICENSE delete mode 100644 base/third_party/icu/README.chromium delete mode 100644 base/third_party/icu/icu_utf.cc delete mode 100644 base/third_party/icu/icu_utf.h delete mode 100644 base/third_party/nspr/LICENSE delete mode 100644 base/third_party/nspr/OWNERS delete mode 100644 base/third_party/nspr/README.chromium delete mode 100644 base/third_party/nspr/nspr.gyp delete mode 100644 base/third_party/nspr/prcpucfg.h delete mode 100644 base/third_party/nspr/prcpucfg_freebsd.h delete mode 100644 base/third_party/nspr/prcpucfg_linux.h delete mode 100644 base/third_party/nspr/prcpucfg_mac.h delete mode 100644 base/third_party/nspr/prcpucfg_nacl.h delete mode 100644 base/third_party/nspr/prcpucfg_openbsd.h delete mode 100644 base/third_party/nspr/prcpucfg_solaris.h delete mode 100644 base/third_party/nspr/prcpucfg_win.h delete mode 100644 base/third_party/nspr/prtime.cc delete mode 100644 base/third_party/nspr/prtime.h delete mode 100644 base/third_party/nspr/prtypes.h delete mode 100644 base/third_party/symbolize/DEPS delete mode 100644 base/third_party/symbolize/LICENSE delete mode 100644 base/third_party/symbolize/README.chromium delete mode 100644 base/third_party/symbolize/config.h delete mode 100644 base/third_party/symbolize/demangle.cc delete mode 100644 base/third_party/symbolize/demangle.h delete mode 100644 base/third_party/symbolize/glog/logging.h delete mode 100644 base/third_party/symbolize/glog/raw_logging.h delete mode 100644 base/third_party/symbolize/symbolize.cc delete mode 100644 base/third_party/symbolize/symbolize.h delete mode 100644 base/third_party/symbolize/utilities.h delete mode 100644 base/third_party/valgrind/LICENSE delete mode 100644 base/third_party/valgrind/README.chromium delete mode 100644 base/third_party/valgrind/memcheck.h delete mode 100644 base/third_party/valgrind/valgrind.h delete mode 100644 base/third_party/xdg_mime/LICENSE delete mode 100644 base/third_party/xdg_mime/README delete mode 100644 base/third_party/xdg_mime/README.chromium delete mode 100644 base/third_party/xdg_mime/compile.patch delete mode 100644 base/third_party/xdg_mime/xdgmime.c delete mode 100644 base/third_party/xdg_mime/xdgmime.h delete mode 100644 base/third_party/xdg_mime/xdgmimealias.c delete mode 100644 base/third_party/xdg_mime/xdgmimealias.h delete mode 100644 base/third_party/xdg_mime/xdgmimecache.c delete mode 100644 base/third_party/xdg_mime/xdgmimecache.h delete mode 100644 base/third_party/xdg_mime/xdgmimeglob.c delete mode 100644 base/third_party/xdg_mime/xdgmimeglob.h delete mode 100644 base/third_party/xdg_mime/xdgmimeicon.c delete mode 100644 base/third_party/xdg_mime/xdgmimeicon.h delete mode 100644 base/third_party/xdg_mime/xdgmimeint.c delete mode 100644 base/third_party/xdg_mime/xdgmimeint.h delete mode 100644 base/third_party/xdg_mime/xdgmimemagic.c delete mode 100644 base/third_party/xdg_mime/xdgmimemagic.h delete mode 100644 base/third_party/xdg_mime/xdgmimeparent.c delete mode 100644 base/third_party/xdg_mime/xdgmimeparent.h delete mode 100644 base/third_party/xdg_user_dirs/LICENSE delete mode 100644 base/third_party/xdg_user_dirs/README.chromium delete mode 100644 base/third_party/xdg_user_dirs/xdg_user_dir_lookup.cc delete mode 100644 base/third_party/xdg_user_dirs/xdg_user_dir_lookup.h delete mode 100644 base/thread_task_runner_handle.cc delete mode 100644 base/thread_task_runner_handle.h delete mode 100644 base/threading/OWNERS delete mode 100644 base/threading/non_thread_safe.h delete mode 100644 base/threading/non_thread_safe_impl.cc delete mode 100644 base/threading/non_thread_safe_impl.h delete mode 100644 base/threading/non_thread_safe_unittest.cc delete mode 100644 base/threading/platform_thread.h delete mode 100644 base/threading/platform_thread_android.cc delete mode 100644 base/threading/platform_thread_linux.cc delete mode 100644 base/threading/platform_thread_mac.mm delete mode 100644 base/threading/platform_thread_posix.cc delete mode 100644 base/threading/platform_thread_unittest.cc delete mode 100644 base/threading/platform_thread_win.cc delete mode 100644 base/threading/post_task_and_reply_impl.cc delete mode 100644 base/threading/post_task_and_reply_impl.h delete mode 100644 base/threading/sequenced_worker_pool.cc delete mode 100644 base/threading/sequenced_worker_pool.h delete mode 100644 base/threading/sequenced_worker_pool_unittest.cc delete mode 100644 base/threading/simple_thread.cc delete mode 100644 base/threading/simple_thread.h delete mode 100644 base/threading/simple_thread_unittest.cc delete mode 100644 base/threading/thread.cc delete mode 100644 base/threading/thread.h delete mode 100644 base/threading/thread_checker.h delete mode 100644 base/threading/thread_checker_impl.cc delete mode 100644 base/threading/thread_checker_impl.h delete mode 100644 base/threading/thread_checker_unittest.cc delete mode 100644 base/threading/thread_collision_warner.cc delete mode 100644 base/threading/thread_collision_warner.h delete mode 100644 base/threading/thread_collision_warner_unittest.cc delete mode 100644 base/threading/thread_id_name_manager.cc delete mode 100644 base/threading/thread_id_name_manager.h delete mode 100644 base/threading/thread_id_name_manager_unittest.cc delete mode 100644 base/threading/thread_local.h delete mode 100644 base/threading/thread_local_posix.cc delete mode 100644 base/threading/thread_local_storage.h delete mode 100644 base/threading/thread_local_storage_posix.cc delete mode 100644 base/threading/thread_local_storage_unittest.cc delete mode 100644 base/threading/thread_local_storage_win.cc delete mode 100644 base/threading/thread_local_unittest.cc delete mode 100644 base/threading/thread_local_win.cc delete mode 100644 base/threading/thread_restrictions.cc delete mode 100644 base/threading/thread_restrictions.h delete mode 100644 base/threading/thread_unittest.cc delete mode 100644 base/threading/watchdog.cc delete mode 100644 base/threading/watchdog.h delete mode 100644 base/threading/watchdog_unittest.cc delete mode 100644 base/threading/worker_pool.cc delete mode 100644 base/threading/worker_pool.h delete mode 100644 base/threading/worker_pool_posix.cc delete mode 100644 base/threading/worker_pool_posix.h delete mode 100644 base/threading/worker_pool_posix_unittest.cc delete mode 100644 base/threading/worker_pool_unittest.cc delete mode 100644 base/threading/worker_pool_win.cc delete mode 100644 base/time/clock.cc delete mode 100644 base/time/clock.h delete mode 100644 base/time/default_clock.cc delete mode 100644 base/time/default_clock.h delete mode 100644 base/time/default_tick_clock.cc delete mode 100644 base/time/default_tick_clock.h delete mode 100644 base/time/pr_time_unittest.cc delete mode 100644 base/time/tick_clock.cc delete mode 100644 base/time/tick_clock.h delete mode 100644 base/time/time.cc delete mode 100644 base/time/time.h delete mode 100644 base/time/time_mac.cc delete mode 100644 base/time/time_posix.cc delete mode 100644 base/time/time_unittest.cc delete mode 100644 base/time/time_win.cc delete mode 100644 base/time/time_win_unittest.cc delete mode 100644 base/timer/hi_res_timer_manager.h delete mode 100644 base/timer/hi_res_timer_manager_posix.cc delete mode 100644 base/timer/hi_res_timer_manager_unittest.cc delete mode 100644 base/timer/hi_res_timer_manager_win.cc delete mode 100644 base/timer/timer.cc delete mode 100644 base/timer/timer.h delete mode 100644 base/timer/timer_unittest.cc delete mode 100644 base/tools_sanity_unittest.cc delete mode 100644 base/tracked_objects.cc delete mode 100644 base/tracked_objects.h delete mode 100644 base/tracked_objects_unittest.cc delete mode 100644 base/tracking_info.cc delete mode 100644 base/tracking_info.h delete mode 100644 base/tuple.h delete mode 100644 base/tuple_unittest.cc delete mode 100644 base/value_conversions.cc delete mode 100644 base/value_conversions.h delete mode 100644 base/values.cc delete mode 100644 base/values.h delete mode 100644 base/values_unittest.cc delete mode 100644 base/version.cc delete mode 100644 base/version.h delete mode 100644 base/version_unittest.cc delete mode 100644 base/vlog.cc delete mode 100644 base/vlog.h delete mode 100644 base/vlog_unittest.cc delete mode 100644 base/win/OWNERS delete mode 100644 base/win/dllmain.cc delete mode 100644 base/win/enum_variant.cc delete mode 100644 base/win/enum_variant.h delete mode 100644 base/win/enum_variant_unittest.cc delete mode 100644 base/win/event_trace_consumer.h delete mode 100644 base/win/event_trace_consumer_unittest.cc delete mode 100644 base/win/event_trace_controller.cc delete mode 100644 base/win/event_trace_controller.h delete mode 100644 base/win/event_trace_controller_unittest.cc delete mode 100644 base/win/event_trace_provider.cc delete mode 100644 base/win/event_trace_provider.h delete mode 100644 base/win/event_trace_provider_unittest.cc delete mode 100644 base/win/i18n.cc delete mode 100644 base/win/i18n.h delete mode 100644 base/win/i18n_unittest.cc delete mode 100644 base/win/iat_patch_function.cc delete mode 100644 base/win/iat_patch_function.h delete mode 100644 base/win/iunknown_impl.cc delete mode 100644 base/win/iunknown_impl.h delete mode 100644 base/win/iunknown_impl_unittest.cc delete mode 100644 base/win/message_window.cc delete mode 100644 base/win/message_window.h delete mode 100644 base/win/message_window_unittest.cc delete mode 100644 base/win/metro.cc delete mode 100644 base/win/metro.h delete mode 100644 base/win/object_watcher.cc delete mode 100644 base/win/object_watcher.h delete mode 100644 base/win/object_watcher_unittest.cc delete mode 100644 base/win/pe_image.cc delete mode 100644 base/win/pe_image.h delete mode 100644 base/win/pe_image_unittest.cc delete mode 100644 base/win/registry.cc delete mode 100644 base/win/registry.h delete mode 100644 base/win/registry_unittest.cc delete mode 100644 base/win/resource_util.cc delete mode 100644 base/win/resource_util.h delete mode 100644 base/win/sampling_profiler.cc delete mode 100644 base/win/sampling_profiler.h delete mode 100644 base/win/sampling_profiler_unittest.cc delete mode 100644 base/win/scoped_bstr.cc delete mode 100644 base/win/scoped_bstr.h delete mode 100644 base/win/scoped_bstr_unittest.cc delete mode 100644 base/win/scoped_co_mem.h delete mode 100644 base/win/scoped_com_initializer.h delete mode 100644 base/win/scoped_comptr.h delete mode 100644 base/win/scoped_comptr_unittest.cc delete mode 100644 base/win/scoped_gdi_object.h delete mode 100644 base/win/scoped_handle.cc delete mode 100644 base/win/scoped_handle.h delete mode 100644 base/win/scoped_handle_unittest.cc delete mode 100644 base/win/scoped_hdc.h delete mode 100644 base/win/scoped_hglobal.h delete mode 100644 base/win/scoped_process_information.cc delete mode 100644 base/win/scoped_process_information.h delete mode 100644 base/win/scoped_process_information_unittest.cc delete mode 100644 base/win/scoped_propvariant.h delete mode 100644 base/win/scoped_select_object.h delete mode 100644 base/win/scoped_variant.cc delete mode 100644 base/win/scoped_variant.h delete mode 100644 base/win/scoped_variant_unittest.cc delete mode 100644 base/win/shortcut.cc delete mode 100644 base/win/shortcut.h delete mode 100644 base/win/shortcut_unittest.cc delete mode 100644 base/win/startup_information.cc delete mode 100644 base/win/startup_information.h delete mode 100644 base/win/startup_information_unittest.cc delete mode 100644 base/win/text_services_message_filter.cc delete mode 100644 base/win/text_services_message_filter.h delete mode 100644 base/win/win_util.cc delete mode 100644 base/win/win_util.h delete mode 100644 base/win/win_util_unittest.cc delete mode 100644 base/win/windows_version.cc delete mode 100644 base/win/windows_version.h delete mode 100644 base/win/wrapped_window_proc.cc delete mode 100644 base/win/wrapped_window_proc.h delete mode 100644 base/win/wrapped_window_proc_unittest.cc delete mode 100644 build/OWNERS delete mode 100644 build/README.chromium delete mode 100644 build/all.gyp delete mode 100644 build/all_android.gyp delete mode 100644 build/android/AndroidManifest.xml delete mode 100644 build/android/CheckInstallApk-debug.apk delete mode 100644 build/android/PRESUBMIT.py delete mode 100755 build/android/adb_android_webview_command_line delete mode 100755 build/android/adb_chromium_testshell_command_line delete mode 100755 build/android/adb_content_shell_command_line delete mode 100755 build/android/adb_device_functions.sh delete mode 100755 build/android/adb_gdb delete mode 100755 build/android/adb_gdb_android_webview_shell delete mode 100755 build/android/adb_gdb_chromium_testshell delete mode 100755 build/android/adb_gdb_content_shell delete mode 100755 build/android/adb_gdb_drt delete mode 100755 build/android/adb_install_apk.py delete mode 100755 build/android/adb_kill_content_shell delete mode 100755 build/android/adb_logcat_monitor.py delete mode 100755 build/android/adb_logcat_printer.py delete mode 100755 build/android/adb_profile_chrome delete mode 100755 build/android/adb_reverse_forwarder.py delete mode 100755 build/android/adb_run_android_webview_shell delete mode 100755 build/android/adb_run_chromium_testshell delete mode 100755 build/android/adb_run_content_shell delete mode 100644 build/android/ant/apk-codegen.xml delete mode 100644 build/android/ant/apk-compile.xml delete mode 100644 build/android/ant/apk-obfuscate.xml delete mode 100644 build/android/ant/apk-package-resources.xml delete mode 100644 build/android/ant/apk-package.xml delete mode 100644 build/android/ant/chromium-debug.keystore delete mode 100644 build/android/ant/create-test-jar.js delete mode 100644 build/android/ant/empty/res/.keep delete mode 120000 build/android/arm-linux-androideabi-gold/arm-linux-androideabi-ld delete mode 120000 build/android/arm-linux-androideabi-gold/ld delete mode 100755 build/android/asan_symbolize.py delete mode 100755 build/android/avd.py delete mode 100644 build/android/avd_configs/AVD_for_Galaxy_Nexus_by_Google_arm.avd/config.ini delete mode 100644 build/android/avd_configs/AVD_for_Galaxy_Nexus_by_Google_x86.avd/config.ini delete mode 100755 build/android/bb_run_sharded_steps.py delete mode 100644 build/android/buildbot/OWNERS delete mode 100644 build/android/buildbot/bb_annotations.py delete mode 100755 build/android/buildbot/bb_device_status_check.py delete mode 100755 build/android/buildbot/bb_device_steps.py delete mode 100755 build/android/buildbot/bb_host_steps.py delete mode 100755 build/android/buildbot/bb_run_bot.py delete mode 100644 build/android/buildbot/bb_utils.py delete mode 100755 build/android/buildbot/env_to_json.py delete mode 100755 build/android/buildbot/tests/bb_run_bot_test.py delete mode 100644 build/android/chrome_with_libs.gyp delete mode 100644 build/android/cpufeatures.gypi delete mode 100644 build/android/create_standalone_apk_action.gypi delete mode 100644 build/android/developer_recommended_flags.gypi delete mode 100755 build/android/device_stats_monitor.py delete mode 100644 build/android/dex_action.gypi delete mode 100644 build/android/empty/src/.keep delete mode 100644 build/android/empty_proguard.flags delete mode 100755 build/android/enable_asserts.py delete mode 100755 build/android/envsetup.sh delete mode 100755 build/android/envsetup_functions.sh delete mode 100644 build/android/finalize_apk_action.gypi delete mode 100755 build/android/findbugs_diff.py delete mode 100644 build/android/findbugs_filter/findbugs_exclude.xml delete mode 100644 build/android/findbugs_filter/findbugs_known_bugs.txt delete mode 100755 build/android/gyp/ant.py delete mode 100755 build/android/gyp/apk_install.py delete mode 100755 build/android/gyp/create_device_library_links.py delete mode 100755 build/android/gyp/create_native_libraries_header.py delete mode 100755 build/android/gyp/create_standalone_apk.py delete mode 100755 build/android/gyp/dex.py delete mode 100755 build/android/gyp/finalize_apk.py delete mode 100755 build/android/gyp/gcc_preprocess.py delete mode 100755 build/android/gyp/generate_v14_compatible_resources.py delete mode 100755 build/android/gyp/get_device_configuration.py delete mode 100755 build/android/gyp/jar.py delete mode 100755 build/android/gyp/jar_toc.py delete mode 100755 build/android/gyp/javac.py delete mode 100755 build/android/gyp/process_resources.py delete mode 100755 build/android/gyp/push_libraries.py delete mode 100755 build/android/gyp/strip_library_for_device.py delete mode 100644 build/android/gyp/util/__init__.py delete mode 100644 build/android/gyp/util/build_device.py delete mode 100644 build/android/gyp/util/build_utils.py delete mode 100644 build/android/gyp/util/md5_check.py delete mode 100644 build/android/gyp/util/md5_check_test.py delete mode 100755 build/android/gyp/write_ordered_libraries.py delete mode 100755 build/android/host_heartbeat.py delete mode 100755 build/android/install_emulator_deps.py delete mode 100644 build/android/java_cpp_template.gypi delete mode 100755 build/android/lighttpd_server.py delete mode 100644 build/android/native_app_dependencies.gypi delete mode 100755 build/android/provision_devices.py delete mode 100644 build/android/push_libraries.gypi delete mode 100644 build/android/pylib/OWNERS delete mode 100644 build/android/pylib/__init__.py delete mode 100644 build/android/pylib/android_commands.py delete mode 100644 build/android/pylib/base/__init__.py delete mode 100644 build/android/pylib/base/base_test_result.py delete mode 100644 build/android/pylib/base/base_test_result_unittest.py delete mode 100644 build/android/pylib/base/base_test_runner.py delete mode 100644 build/android/pylib/base/test_dispatcher.py delete mode 100644 build/android/pylib/base/test_dispatcher_unittest.py delete mode 100644 build/android/pylib/chrome_test_server_spawner.py delete mode 100644 build/android/pylib/cmd_helper.py delete mode 100644 build/android/pylib/constants.py delete mode 100644 build/android/pylib/device_stats_monitor.html delete mode 100644 build/android/pylib/device_stats_monitor.py delete mode 100644 build/android/pylib/fake_dns.py delete mode 100644 build/android/pylib/flag_changer.py delete mode 100644 build/android/pylib/forwarder.py delete mode 100644 build/android/pylib/gtest/__init__.py delete mode 100644 build/android/pylib/gtest/filter/OWNERS delete mode 100644 build/android/pylib/gtest/filter/base_unittests_disabled delete mode 100644 build/android/pylib/gtest/filter/base_unittests_emulator_additional_disabled delete mode 100644 build/android/pylib/gtest/filter/breakpad_unittests_disabled delete mode 100644 build/android/pylib/gtest/filter/content_browsertests_disabled delete mode 100644 build/android/pylib/gtest/filter/content_unittests_disabled delete mode 100644 build/android/pylib/gtest/filter/ipc_tests_disabled delete mode 100644 build/android/pylib/gtest/filter/media_unittests_disabled delete mode 100644 build/android/pylib/gtest/filter/net_unittests_disabled delete mode 100644 build/android/pylib/gtest/filter/sync_unit_tests_disabled delete mode 100644 build/android/pylib/gtest/filter/ui_unittests_disabled delete mode 100644 build/android/pylib/gtest/filter/unit_tests_disabled delete mode 100644 build/android/pylib/gtest/filter/webkit_unit_tests_disabled delete mode 100644 build/android/pylib/gtest/gtest_config.py delete mode 100644 build/android/pylib/gtest/setup.py delete mode 100644 build/android/pylib/gtest/test_options.py delete mode 100644 build/android/pylib/gtest/test_package.py delete mode 100644 build/android/pylib/gtest/test_package_apk.py delete mode 100644 build/android/pylib/gtest/test_package_exe.py delete mode 100644 build/android/pylib/gtest/test_runner.py delete mode 100644 build/android/pylib/host_driven/__init__.py delete mode 100644 build/android/pylib/host_driven/setup.py delete mode 100644 build/android/pylib/host_driven/test_case.py delete mode 100644 build/android/pylib/host_driven/test_info_collection.py delete mode 100644 build/android/pylib/host_driven/test_runner.py delete mode 100644 build/android/pylib/host_driven/tests_annotations.py delete mode 100644 build/android/pylib/instrumentation/__init__.py delete mode 100644 build/android/pylib/instrumentation/setup.py delete mode 100644 build/android/pylib/instrumentation/test_jar.py delete mode 100644 build/android/pylib/instrumentation/test_options.py delete mode 100644 build/android/pylib/instrumentation/test_package.py delete mode 100644 build/android/pylib/instrumentation/test_result.py delete mode 100644 build/android/pylib/instrumentation/test_runner.py delete mode 100644 build/android/pylib/io_stats_parser.py delete mode 100644 build/android/pylib/json_perf_parser.py delete mode 100644 build/android/pylib/monkey/__init__.py delete mode 100644 build/android/pylib/monkey/setup.py delete mode 100644 build/android/pylib/monkey/test_options.py delete mode 100644 build/android/pylib/monkey/test_runner.py delete mode 100644 build/android/pylib/perf/__init__.py delete mode 100644 build/android/pylib/perf/setup.py delete mode 100644 build/android/pylib/perf/test_options.py delete mode 100644 build/android/pylib/perf/test_runner.py delete mode 100644 build/android/pylib/perf_tests_helper.py delete mode 100644 build/android/pylib/pexpect.py delete mode 100644 build/android/pylib/ports.py delete mode 100644 build/android/pylib/surface_stats_collector.py delete mode 100644 build/android/pylib/thermal_throttle.py delete mode 100644 build/android/pylib/uiautomator/__init__.py delete mode 100644 build/android/pylib/uiautomator/setup.py delete mode 100644 build/android/pylib/uiautomator/test_options.py delete mode 100644 build/android/pylib/uiautomator/test_package.py delete mode 100644 build/android/pylib/uiautomator/test_runner.py delete mode 100644 build/android/pylib/utils/__init__.py delete mode 100644 build/android/pylib/utils/apk_helper.py delete mode 100755 build/android/pylib/utils/emulator.py delete mode 100755 build/android/pylib/utils/findbugs.py delete mode 100644 build/android/pylib/utils/flakiness_dashboard_results_uploader.py delete mode 100644 build/android/pylib/utils/repo_utils.py delete mode 100644 build/android/pylib/utils/report_results.py delete mode 100644 build/android/pylib/utils/reraiser_thread.py delete mode 100644 build/android/pylib/utils/reraiser_thread_unittest.py delete mode 100644 build/android/pylib/utils/run_tests_helper.py delete mode 100644 build/android/pylib/utils/test_options_parser.py delete mode 100644 build/android/pylib/utils/time_profile.py delete mode 100644 build/android/pylib/utils/watchdog_timer.py delete mode 100644 build/android/pylib/utils/xvfb.py delete mode 100644 build/android/pylib/valgrind_tools.py delete mode 100755 build/android/screenshot.py delete mode 100644 build/android/setup.gyp delete mode 100644 build/android/strip_native_libraries.gypi delete mode 100755 build/android/surface_stats.py delete mode 100755 build/android/symbolize.py delete mode 100755 build/android/symbolize_test.py delete mode 100755 build/android/test_runner.py delete mode 100644 build/android/tests/multiple_proguards/AndroidManifest.xml delete mode 100644 build/android/tests/multiple_proguards/multiple_proguards.gyp delete mode 100644 build/android/tests/multiple_proguards/proguard1.flags delete mode 100644 build/android/tests/multiple_proguards/proguard2.flags delete mode 100644 build/android/tests/multiple_proguards/src/dummy/DummyActivity.java delete mode 100644 build/android/tests/symbolize/Makefile delete mode 100644 build/android/tests/symbolize/a.cc delete mode 100644 build/android/tests/symbolize/b.cc delete mode 100644 build/android/tests/symbolize/liba.so delete mode 100644 build/android/tests/symbolize/libb.so delete mode 100755 build/android/tombstones.py delete mode 100644 build/android/write_ordered_libraries.gypi delete mode 100644 build/apk_fake_jar.gypi delete mode 100644 build/apk_test.gypi delete mode 100755 build/apply_locales.py delete mode 100644 build/asan.saves delete mode 100755 build/branding_value.sh delete mode 100644 build/build_config.h delete mode 100644 build/common.croc delete mode 100644 build/common.gypi delete mode 100644 build/common_untrusted.gypi delete mode 100755 build/compiler_version.py delete mode 100644 build/copy_test_data_ios.gypi delete mode 100755 build/copy_test_data_ios.py delete mode 100755 build/cp.py delete mode 100755 build/dir_exists.py delete mode 100755 build/download_nacl_toolchains.py delete mode 100755 build/escape_unicode.py delete mode 100755 build/extract_from_cab.py delete mode 100644 build/filename_rules.gypi delete mode 100755 build/gdb-add-index delete mode 100644 build/git-hooks/OWNERS delete mode 100755 build/git-hooks/pre-commit delete mode 100644 build/grit_action.gypi delete mode 100644 build/grit_target.gypi delete mode 100755 build/gyp_chromium delete mode 100644 build/gyp_chromium.py delete mode 100644 build/gyp_helper.py delete mode 100755 build/install-build-deps-android.sh delete mode 100755 build/install-build-deps.sh delete mode 100755 build/install-chroot.sh delete mode 100644 build/internal/README.chromium delete mode 100644 build/internal/release_defaults.gypi delete mode 100644 build/internal/release_impl.gypi delete mode 100644 build/internal/release_impl_official.gypi delete mode 100644 build/intsafe_workaround.h delete mode 100644 build/ios/PRESUBMIT.py delete mode 100644 build/ios/chrome_ios.croc delete mode 100755 build/ios/clean_env.py delete mode 100644 build/ios/grit_whitelist.txt delete mode 100644 build/ios/mac_build.gypi delete mode 100644 build/isolate.gypi delete mode 100644 build/jar_file_jni_generator.gypi delete mode 100644 build/java.gypi delete mode 100644 build/java_aidl.gypi delete mode 100644 build/java_apk.gypi delete mode 100644 build/java_prebuilt.gypi delete mode 100644 build/jni_generator.gypi delete mode 100644 build/json_schema_bundle_compile.gypi delete mode 100644 build/json_schema_compile.gypi delete mode 100644 build/json_to_struct.gypi delete mode 100755 build/landmines.py delete mode 100644 build/linux/chrome_linux.croc delete mode 100755 build/linux/dump_app_syms delete mode 100755 build/linux/install-arm-sysroot.py delete mode 100755 build/linux/install-chromeos-fonts.py delete mode 100755 build/linux/pkg-config-wrapper delete mode 100755 build/linux/python_arch.sh delete mode 100755 build/linux/rewrite_dirs.py delete mode 100755 build/linux/sysroot_ld_path.sh delete mode 100644 build/linux/system.gyp delete mode 100644 build/linux/unbundle/README delete mode 100644 build/linux/unbundle/expat.gyp delete mode 100644 build/linux/unbundle/ffmpeg.gyp delete mode 100644 build/linux/unbundle/flac.gyp delete mode 100644 build/linux/unbundle/harfbuzz.gyp delete mode 100644 build/linux/unbundle/icu.gyp delete mode 100644 build/linux/unbundle/jsoncpp.gyp delete mode 100644 build/linux/unbundle/libevent.gyp delete mode 100644 build/linux/unbundle/libjpeg.gyp delete mode 100644 build/linux/unbundle/libpng.gyp delete mode 100644 build/linux/unbundle/libusb.gyp delete mode 100644 build/linux/unbundle/libvpx.gyp delete mode 100644 build/linux/unbundle/libwebp.gyp delete mode 100644 build/linux/unbundle/libxml.gyp delete mode 100644 build/linux/unbundle/libxslt.gyp delete mode 100644 build/linux/unbundle/openssl.gyp delete mode 100644 build/linux/unbundle/opus.gyp delete mode 100644 build/linux/unbundle/re2.gyp delete mode 100755 build/linux/unbundle/replace_gyp_files.py delete mode 100644 build/linux/unbundle/snappy.gyp delete mode 100644 build/linux/unbundle/speex.gyp delete mode 100644 build/linux/unbundle/sqlite.gyp delete mode 100644 build/linux/unbundle/v8.gyp delete mode 100644 build/linux/unbundle/zlib.gyp delete mode 100644 build/mac/OWNERS delete mode 100644 build/mac/asan.gyp delete mode 100755 build/mac/change_mach_o_flags.py delete mode 100755 build/mac/change_mach_o_flags_from_xcode.sh delete mode 100644 build/mac/chrome_mac.croc delete mode 100755 build/mac/copy_asan_runtime_dylib.sh delete mode 100755 build/mac/copy_framework_unversioned.sh delete mode 100755 build/mac/edit_xibs.sh delete mode 100755 build/mac/find_sdk.py delete mode 100755 build/mac/make_more_helpers.sh delete mode 100755 build/mac/strip_from_xcode delete mode 100755 build/mac/strip_save_dsym delete mode 100755 build/mac/tweak_info_plist.py delete mode 100755 build/mac/verify_no_objc.sh delete mode 100644 build/nocompile.gypi delete mode 100644 build/output_dll_copy.rules delete mode 100644 build/precompile.cc delete mode 100644 build/precompile.h delete mode 100644 build/protoc.gypi delete mode 100644 build/protoc_java.gypi delete mode 100755 build/protoc_java.py delete mode 100644 build/release.gypi delete mode 100755 build/sanitize-mac-build-log.sed delete mode 100755 build/sanitize-mac-build-log.sh delete mode 100755 build/sanitize-png-files.sh delete mode 100755 build/sanitize-win-build-log.sed delete mode 100755 build/sanitize-win-build-log.sh delete mode 100644 build/shim_headers.gypi delete mode 100644 build/some.gyp delete mode 100755 build/symlink.py delete mode 100644 build/temp_gyp/README.chromium delete mode 100644 build/temp_gyp/pdfsqueeze.gyp delete mode 100644 build/uiautomator_test.gypi delete mode 100755 build/update-linux-sandbox.sh delete mode 100644 build/util/LASTCHANGE delete mode 100644 build/util/LASTCHANGE.blink delete mode 100755 build/util/lastchange.py delete mode 100644 build/util/lib/common/__init__.py delete mode 100644 build/util/lib/common/unittest_util.py delete mode 100644 build/util/lib/common/util.py delete mode 100644 build/whitespace_file.txt delete mode 100644 build/win/chrome_win.croc delete mode 100644 build/win/compatibility.manifest delete mode 100644 build/win/importlibs/create_import_lib.gypi delete mode 100755 build/win/importlibs/create_importlib_win.py delete mode 100755 build/win/importlibs/filter_export_list.py delete mode 100644 build/win/importlibs/x86/user32.winxp.imports delete mode 100644 build/win/importlibs/x86/user32.winxp.lib delete mode 100755 build/win/install-build-deps.py delete mode 100644 build/win/setup_cygwin_mount.py delete mode 100644 build/win_precompile.gypi diff --git a/.gitignore b/.gitignore index 3921ecf41a..91c8211464 100644 --- a/.gitignore +++ b/.gitignore @@ -4,6 +4,8 @@ .pydevproject .repo .settings +base/ +build/ docs/ out/ third_party/gold/ diff --git a/base/DEPS b/base/DEPS deleted file mode 100644 index e1545aee51..0000000000 --- a/base/DEPS +++ /dev/null @@ -1,15 +0,0 @@ -include_rules = [ - "+jni", - "+native_client/src/untrusted/irt/irt.h", - "+third_party/ashmem", - "+third_party/apple_apsl", - "+third_party/libevent", - "+third_party/dmg_fp", - "+third_party/GTM", - "+third_party/mach_override", - "+third_party/modp_b64", - "+third_party/tcmalloc", - - # ICU dependendencies must be separate from the rest of base. - "-i18n", -] diff --git a/base/OWNERS b/base/OWNERS deleted file mode 100644 index 7e0e67fb6c..0000000000 --- a/base/OWNERS +++ /dev/null @@ -1,29 +0,0 @@ -mark@chromium.org -darin@chromium.org -brettw@chromium.org -willchan@chromium.org -jar@chromium.org - -per-file *.isolate=csharp@chromium.org -per-file *.isolate=maruel@chromium.org -per-file bind.h=ajwong@chromium.org -per-file bind_helpers.cc=ajwong@chromium.org -per-file bind_helpers.h=ajwong@chromium.org -per-file bind_helpers_unittest.cc=ajwong@chromium.org -per-file bind.h.pump=ajwong@chromium.org -per-file bind_internal.h=ajwong@chromium.org -per-file bind_internal.h.pump=ajwong@chromium.org -per-file bind_internal_win.h=ajwong@chromium.org -per-file bind_internal_win.h.pump=ajwong@chromium.org -per-file bind_unittest.cc=ajwong@chromium.org -per-file bind_unittest.nc=ajwong@chromium.org -per-file callback_forward.h=ajwong@chromium.org -per-file callback.h=ajwong@chromium.org -per-file callback_helpers.h=ajwong@chromium.org -per-file callback.h.pump=ajwong@chromium.org -per-file callback_internal.cc=ajwong@chromium.org -per-file callback_internal.h=ajwong@chromium.org -per-file callback_unittest.cc=ajwong@chromium.org -per-file callback_unittest.h=ajwong@chromium.org -per-file callback_unittest.nc=ajwong@chromium.org -per-file security_unittest.cc=jln@chromium.org diff --git a/base/PRESUBMIT.py b/base/PRESUBMIT.py deleted file mode 100644 index 7137c5a010..0000000000 --- a/base/PRESUBMIT.py +++ /dev/null @@ -1,56 +0,0 @@ -# Copyright (c) 2012 The Chromium Authors. All rights reserved. -# Use of this source code is governed by a BSD-style license that can be -# found in the LICENSE file. - -"""Chromium presubmit script for src/base. - -See http://dev.chromium.org/developers/how-tos/depottools/presubmit-scripts -for more details on the presubmit API built into gcl. -""" - -def _CheckNoInterfacesInBase(input_api, output_api): - """Checks to make sure no files in libbase.a have |@interface|.""" - pattern = input_api.re.compile(r'^\s*@interface', input_api.re.MULTILINE) - files = [] - for f in input_api.AffectedSourceFiles(input_api.FilterSourceFile): - if (f.LocalPath().startswith('base/') and - not "/test/" in f.LocalPath() and - not f.LocalPath().endswith('_unittest.mm') and - not f.LocalPath().endswith('mac/sdk_forward_declarations.h')): - contents = input_api.ReadFile(f) - if pattern.search(contents): - files.append(f) - - if len(files): - return [ output_api.PresubmitError( - 'Objective-C interfaces or categories are forbidden in libbase. ' + - 'See http://groups.google.com/a/chromium.org/group/chromium-dev/' + - 'browse_thread/thread/efb28c10435987fd', - files) ] - return [] - - -def _CommonChecks(input_api, output_api): - """Checks common to both upload and commit.""" - results = [] - results.extend(_CheckNoInterfacesInBase(input_api, output_api)) - return results - -def CheckChangeOnUpload(input_api, output_api): - results = [] - results.extend(_CommonChecks(input_api, output_api)) - return results - - -def CheckChangeOnCommit(input_api, output_api): - results = [] - results.extend(_CommonChecks(input_api, output_api)) - return results - - -def GetPreferredTrySlaves(): - return [ - 'linux_rel:sync_integration_tests', - 'mac_rel:sync_integration_tests', - 'win_rel:sync_integration_tests', - ] diff --git a/base/allocator/README b/base/allocator/README deleted file mode 100644 index ec8a707f41..0000000000 --- a/base/allocator/README +++ /dev/null @@ -1,59 +0,0 @@ -Notes about the Chrome memory allocator. - -Background ----------- -We use this library as a generic way to fork into any of several allocators. -Currently we can, at runtime, switch between: - the default windows allocator - the windows low-fragmentation-heap - tcmalloc - jemalloc (the heap used most notably within Mozilla Firefox) - -The mechanism for hooking LIBCMT in windows is rather tricky. The core -problem is that by default, the windows library does not declare malloc and -free as weak symbols. Because of this, they cannot be overriden. To work -around this, we start with the LIBCMT.LIB, and manually remove all allocator -related functions from it using the visual studio library tool. Once removed, -we can now link against the library and provide custom versions of the -allocator related functionality. - - -Source code ------------ -This directory contains just the allocator (i.e. shim) layer that switches -between the different underlying memory allocation implementations. - -The tcmalloc and jemalloc libraries originate outside of Chromium -and exist in ../../third_party/tcmalloc and ../../third_party/jemalloc -(currently, the actual locations are defined in the allocator.gyp file). -The third party sources use a vendor-branch SCM pattern to track -Chromium-specific changes independently from upstream changes. - -The general intent is to push local changes upstream so that over -time we no longer need any forked files. - - -Adding a new allocator ----------------------- -Adding a new allocator requires definition of the following five functions: - - extern "C" { - bool init(); - void* malloc(size_t s); - void* realloc(void* p, size_t s); - void free(void* s); - size_t msize(void* p); - } - -All other allocation related functions (new/delete/calloc/etc) have been -implemented generically to work across all allocators. - - -Usage ------ -You can use the different allocators by setting the environment variable -CHROME_ALLOCATOR to: - "tcmalloc" - TC Malloc (default) - "jemalloc" - JE Malloc - "winheap" - Windows default heap - "winlfh" - Windows Low-Fragmentation heap diff --git a/base/allocator/allocator.gyp b/base/allocator/allocator.gyp deleted file mode 100644 index ef98d09482..0000000000 --- a/base/allocator/allocator.gyp +++ /dev/null @@ -1,676 +0,0 @@ -# Copyright (c) 2012 The Chromium Authors. All rights reserved. -# Use of this source code is governed by a BSD-style license that can be -# found in the LICENSE file. - -{ - 'variables': { - 'jemalloc_dir': '../../third_party/jemalloc/chromium', - 'tcmalloc_dir': '../../third_party/tcmalloc/chromium', - 'use_vtable_verify%': 0, - }, - 'targets': [ - # Only executables and not libraries should depend on the - # allocator target; only the application (the final executable) - # knows what allocator makes sense. - { - 'target_name': 'allocator', - 'type': 'static_library', - # Make sure the allocation library is optimized to - # the hilt in official builds. - 'variables': { - 'optimize': 'max', - }, - 'include_dirs': [ - '.', - '<(tcmalloc_dir)/src/base', - '<(tcmalloc_dir)/src', - '../..', - ], - 'direct_dependent_settings': { - 'configurations': { - 'Common_Base': { - 'msvs_settings': { - 'VCLinkerTool': { - 'IgnoreDefaultLibraryNames': ['libcmtd.lib', 'libcmt.lib'], - 'AdditionalDependencies': [ - '<(SHARED_INTERMEDIATE_DIR)/allocator/libcmt.lib' - ], - }, - }, - }, - }, - 'conditions': [ - ['OS=="win"', { - 'defines': [ - 'PERFTOOLS_DLL_DECL=', - ], - }], - ], - }, - 'sources': [ - # Generated for our configuration from tcmalloc's build - # and checked in. - '<(tcmalloc_dir)/src/config.h', - '<(tcmalloc_dir)/src/config_android.h', - '<(tcmalloc_dir)/src/config_linux.h', - '<(tcmalloc_dir)/src/config_win.h', - - # all tcmalloc native and forked files - '<(tcmalloc_dir)/src/addressmap-inl.h', - '<(tcmalloc_dir)/src/base/abort.cc', - '<(tcmalloc_dir)/src/base/abort.h', - '<(tcmalloc_dir)/src/base/arm_instruction_set_select.h', - '<(tcmalloc_dir)/src/base/atomicops-internals-linuxppc.h', - '<(tcmalloc_dir)/src/base/atomicops-internals-arm-generic.h', - '<(tcmalloc_dir)/src/base/atomicops-internals-arm-v6plus.h', - '<(tcmalloc_dir)/src/base/atomicops-internals-macosx.h', - '<(tcmalloc_dir)/src/base/atomicops-internals-windows.h', - '<(tcmalloc_dir)/src/base/atomicops-internals-x86.cc', - '<(tcmalloc_dir)/src/base/atomicops-internals-x86.h', - '<(tcmalloc_dir)/src/base/atomicops.h', - '<(tcmalloc_dir)/src/base/basictypes.h', - '<(tcmalloc_dir)/src/base/commandlineflags.h', - '<(tcmalloc_dir)/src/base/cycleclock.h', - # We don't list dynamic_annotations.c since its copy is already - # present in the dynamic_annotations target. - '<(tcmalloc_dir)/src/base/dynamic_annotations.h', - '<(tcmalloc_dir)/src/base/elf_mem_image.cc', - '<(tcmalloc_dir)/src/base/elf_mem_image.h', - '<(tcmalloc_dir)/src/base/elfcore.h', - '<(tcmalloc_dir)/src/base/googleinit.h', - '<(tcmalloc_dir)/src/base/linux_syscall_support.h', - '<(tcmalloc_dir)/src/base/linuxthreads.cc', - '<(tcmalloc_dir)/src/base/linuxthreads.h', - '<(tcmalloc_dir)/src/base/logging.cc', - '<(tcmalloc_dir)/src/base/logging.h', - '<(tcmalloc_dir)/src/base/low_level_alloc.cc', - '<(tcmalloc_dir)/src/base/low_level_alloc.h', - '<(tcmalloc_dir)/src/base/simple_mutex.h', - '<(tcmalloc_dir)/src/base/spinlock.cc', - '<(tcmalloc_dir)/src/base/spinlock.h', - '<(tcmalloc_dir)/src/base/spinlock_internal.cc', - '<(tcmalloc_dir)/src/base/spinlock_internal.h', - '<(tcmalloc_dir)/src/base/spinlock_linux-inl.h', - '<(tcmalloc_dir)/src/base/spinlock_posix-inl.h', - '<(tcmalloc_dir)/src/base/spinlock_win32-inl.h', - '<(tcmalloc_dir)/src/base/stl_allocator.h', - '<(tcmalloc_dir)/src/base/synchronization_profiling.h', - '<(tcmalloc_dir)/src/base/sysinfo.cc', - '<(tcmalloc_dir)/src/base/sysinfo.h', - '<(tcmalloc_dir)/src/base/thread_annotations.h', - '<(tcmalloc_dir)/src/base/thread_lister.c', - '<(tcmalloc_dir)/src/base/thread_lister.h', - '<(tcmalloc_dir)/src/base/vdso_support.cc', - '<(tcmalloc_dir)/src/base/vdso_support.h', - '<(tcmalloc_dir)/src/central_freelist.cc', - '<(tcmalloc_dir)/src/central_freelist.h', - '<(tcmalloc_dir)/src/common.cc', - '<(tcmalloc_dir)/src/common.h', - '<(tcmalloc_dir)/src/debugallocation.cc', - '<(tcmalloc_dir)/src/deep-heap-profile.cc', - '<(tcmalloc_dir)/src/deep-heap-profile.h', - '<(tcmalloc_dir)/src/free_list.cc', - '<(tcmalloc_dir)/src/free_list.h', - '<(tcmalloc_dir)/src/getpc.h', - '<(tcmalloc_dir)/src/gperftools/heap-checker.h', - '<(tcmalloc_dir)/src/gperftools/heap-profiler.h', - '<(tcmalloc_dir)/src/gperftools/malloc_extension.h', - '<(tcmalloc_dir)/src/gperftools/malloc_extension_c.h', - '<(tcmalloc_dir)/src/gperftools/malloc_hook.h', - '<(tcmalloc_dir)/src/gperftools/malloc_hook_c.h', - '<(tcmalloc_dir)/src/gperftools/profiler.h', - '<(tcmalloc_dir)/src/gperftools/stacktrace.h', - '<(tcmalloc_dir)/src/gperftools/tcmalloc.h', - '<(tcmalloc_dir)/src/heap-checker-bcad.cc', - '<(tcmalloc_dir)/src/heap-checker.cc', - '<(tcmalloc_dir)/src/heap-profile-table.cc', - '<(tcmalloc_dir)/src/heap-profile-table.h', - '<(tcmalloc_dir)/src/heap-profiler.cc', - '<(tcmalloc_dir)/src/internal_logging.cc', - '<(tcmalloc_dir)/src/internal_logging.h', - '<(tcmalloc_dir)/src/libc_override.h', - '<(tcmalloc_dir)/src/libc_override_gcc_and_weak.h', - '<(tcmalloc_dir)/src/libc_override_glibc.h', - '<(tcmalloc_dir)/src/libc_override_osx.h', - '<(tcmalloc_dir)/src/libc_override_redefine.h', - '<(tcmalloc_dir)/src/linked_list.h', - '<(tcmalloc_dir)/src/malloc_extension.cc', - '<(tcmalloc_dir)/src/malloc_hook-inl.h', - '<(tcmalloc_dir)/src/malloc_hook.cc', - '<(tcmalloc_dir)/src/malloc_hook_mmap_freebsd.h', - '<(tcmalloc_dir)/src/malloc_hook_mmap_linux.h', - '<(tcmalloc_dir)/src/maybe_threads.cc', - '<(tcmalloc_dir)/src/maybe_threads.h', - '<(tcmalloc_dir)/src/memfs_malloc.cc', - '<(tcmalloc_dir)/src/memory_region_map.cc', - '<(tcmalloc_dir)/src/memory_region_map.h', - '<(tcmalloc_dir)/src/packed-cache-inl.h', - '<(tcmalloc_dir)/src/page_heap.cc', - '<(tcmalloc_dir)/src/page_heap.h', - '<(tcmalloc_dir)/src/page_heap_allocator.h', - '<(tcmalloc_dir)/src/pagemap.h', - '<(tcmalloc_dir)/src/profile-handler.cc', - '<(tcmalloc_dir)/src/profile-handler.h', - '<(tcmalloc_dir)/src/profiledata.cc', - '<(tcmalloc_dir)/src/profiledata.h', - '<(tcmalloc_dir)/src/profiler.cc', - '<(tcmalloc_dir)/src/raw_printer.cc', - '<(tcmalloc_dir)/src/raw_printer.h', - '<(tcmalloc_dir)/src/sampler.cc', - '<(tcmalloc_dir)/src/sampler.h', - '<(tcmalloc_dir)/src/span.cc', - '<(tcmalloc_dir)/src/span.h', - '<(tcmalloc_dir)/src/stack_trace_table.cc', - '<(tcmalloc_dir)/src/stack_trace_table.h', - '<(tcmalloc_dir)/src/stacktrace.cc', - '<(tcmalloc_dir)/src/stacktrace_arm-inl.h', - '<(tcmalloc_dir)/src/stacktrace_config.h', - '<(tcmalloc_dir)/src/stacktrace_generic-inl.h', - '<(tcmalloc_dir)/src/stacktrace_libunwind-inl.h', - '<(tcmalloc_dir)/src/stacktrace_powerpc-inl.h', - '<(tcmalloc_dir)/src/stacktrace_win32-inl.h', - '<(tcmalloc_dir)/src/stacktrace_with_context.cc', - '<(tcmalloc_dir)/src/stacktrace_x86-inl.h', - '<(tcmalloc_dir)/src/static_vars.cc', - '<(tcmalloc_dir)/src/static_vars.h', - '<(tcmalloc_dir)/src/symbolize.cc', - '<(tcmalloc_dir)/src/symbolize.h', - '<(tcmalloc_dir)/src/system-alloc.cc', - '<(tcmalloc_dir)/src/system-alloc.h', - '<(tcmalloc_dir)/src/tcmalloc.cc', - '<(tcmalloc_dir)/src/tcmalloc_guard.h', - '<(tcmalloc_dir)/src/thread_cache.cc', - '<(tcmalloc_dir)/src/thread_cache.h', - '<(tcmalloc_dir)/src/windows/config.h', - '<(tcmalloc_dir)/src/windows/get_mangled_names.cc', - '<(tcmalloc_dir)/src/windows/gperftools/tcmalloc.h', - '<(tcmalloc_dir)/src/windows/ia32_modrm_map.cc', - '<(tcmalloc_dir)/src/windows/ia32_opcode_map.cc', - '<(tcmalloc_dir)/src/windows/mingw.h', - '<(tcmalloc_dir)/src/windows/mini_disassembler.cc', - '<(tcmalloc_dir)/src/windows/mini_disassembler.h', - '<(tcmalloc_dir)/src/windows/mini_disassembler_types.h', - '<(tcmalloc_dir)/src/windows/override_functions.cc', - '<(tcmalloc_dir)/src/windows/patch_functions.cc', - '<(tcmalloc_dir)/src/windows/port.cc', - '<(tcmalloc_dir)/src/windows/port.h', - '<(tcmalloc_dir)/src/windows/preamble_patcher.cc', - '<(tcmalloc_dir)/src/windows/preamble_patcher.h', - '<(tcmalloc_dir)/src/windows/preamble_patcher_with_stub.cc', - - # jemalloc files - '<(jemalloc_dir)/jemalloc.c', - '<(jemalloc_dir)/jemalloc.h', - '<(jemalloc_dir)/ql.h', - '<(jemalloc_dir)/qr.h', - '<(jemalloc_dir)/rb.h', - - 'allocator_shim.cc', - 'allocator_shim.h', - 'debugallocation_shim.cc', - 'generic_allocators.cc', - 'win_allocator.cc', - ], - # sources! means that these are not compiled directly. - 'sources!': [ - # Included by allocator_shim.cc for maximal inlining. - 'generic_allocators.cc', - 'win_allocator.cc', - - # Included by debugallocation_shim.cc. - '<(tcmalloc_dir)/src/debugallocation.cc', - '<(tcmalloc_dir)/src/tcmalloc.cc', - - # We simply don't use these, but list them above so that IDE - # users can view the full available source for reference, etc. - '<(tcmalloc_dir)/src/addressmap-inl.h', - '<(tcmalloc_dir)/src/base/atomicops-internals-linuxppc.h', - '<(tcmalloc_dir)/src/base/atomicops-internals-macosx.h', - '<(tcmalloc_dir)/src/base/atomicops-internals-x86-msvc.h', - '<(tcmalloc_dir)/src/base/atomicops-internals-x86.cc', - '<(tcmalloc_dir)/src/base/atomicops-internals-x86.h', - '<(tcmalloc_dir)/src/base/atomicops.h', - '<(tcmalloc_dir)/src/base/basictypes.h', - '<(tcmalloc_dir)/src/base/commandlineflags.h', - '<(tcmalloc_dir)/src/base/cycleclock.h', - '<(tcmalloc_dir)/src/base/elf_mem_image.h', - '<(tcmalloc_dir)/src/base/elfcore.h', - '<(tcmalloc_dir)/src/base/googleinit.h', - '<(tcmalloc_dir)/src/base/linux_syscall_support.h', - '<(tcmalloc_dir)/src/base/simple_mutex.h', - '<(tcmalloc_dir)/src/base/spinlock_linux-inl.h', - '<(tcmalloc_dir)/src/base/spinlock_posix-inl.h', - '<(tcmalloc_dir)/src/base/spinlock_win32-inl.h', - '<(tcmalloc_dir)/src/base/stl_allocator.h', - '<(tcmalloc_dir)/src/base/thread_annotations.h', - '<(tcmalloc_dir)/src/getpc.h', - '<(tcmalloc_dir)/src/gperftools/heap-checker.h', - '<(tcmalloc_dir)/src/gperftools/heap-profiler.h', - '<(tcmalloc_dir)/src/gperftools/malloc_extension.h', - '<(tcmalloc_dir)/src/gperftools/malloc_extension_c.h', - '<(tcmalloc_dir)/src/gperftools/malloc_hook.h', - '<(tcmalloc_dir)/src/gperftools/malloc_hook_c.h', - '<(tcmalloc_dir)/src/gperftools/profiler.h', - '<(tcmalloc_dir)/src/gperftools/stacktrace.h', - '<(tcmalloc_dir)/src/gperftools/tcmalloc.h', - '<(tcmalloc_dir)/src/libc_override.h', - '<(tcmalloc_dir)/src/libc_override_gcc_and_weak.h', - '<(tcmalloc_dir)/src/libc_override_glibc.h', - '<(tcmalloc_dir)/src/libc_override_osx.h', - '<(tcmalloc_dir)/src/libc_override_redefine.h', - '<(tcmalloc_dir)/src/malloc_hook_mmap_freebsd.h', - '<(tcmalloc_dir)/src/malloc_hook_mmap_linux.h', - '<(tcmalloc_dir)/src/memfs_malloc.cc', - '<(tcmalloc_dir)/src/packed-cache-inl.h', - '<(tcmalloc_dir)/src/page_heap_allocator.h', - '<(tcmalloc_dir)/src/pagemap.h', - '<(tcmalloc_dir)/src/stacktrace_arm-inl.h', - '<(tcmalloc_dir)/src/stacktrace_config.h', - '<(tcmalloc_dir)/src/stacktrace_generic-inl.h', - '<(tcmalloc_dir)/src/stacktrace_libunwind-inl.h', - '<(tcmalloc_dir)/src/stacktrace_powerpc-inl.h', - '<(tcmalloc_dir)/src/stacktrace_win32-inl.h', - '<(tcmalloc_dir)/src/stacktrace_with_context.cc', - '<(tcmalloc_dir)/src/stacktrace_x86-inl.h', - '<(tcmalloc_dir)/src/tcmalloc_guard.h', - '<(tcmalloc_dir)/src/windows/config.h', - '<(tcmalloc_dir)/src/windows/gperftools/tcmalloc.h', - '<(tcmalloc_dir)/src/windows/get_mangled_names.cc', - '<(tcmalloc_dir)/src/windows/ia32_modrm_map.cc', - '<(tcmalloc_dir)/src/windows/ia32_opcode_map.cc', - '<(tcmalloc_dir)/src/windows/mingw.h', - '<(tcmalloc_dir)/src/windows/mini_disassembler.cc', - '<(tcmalloc_dir)/src/windows/mini_disassembler.h', - '<(tcmalloc_dir)/src/windows/mini_disassembler_types.h', - '<(tcmalloc_dir)/src/windows/override_functions.cc', - '<(tcmalloc_dir)/src/windows/patch_functions.cc', - '<(tcmalloc_dir)/src/windows/preamble_patcher.cc', - '<(tcmalloc_dir)/src/windows/preamble_patcher.h', - '<(tcmalloc_dir)/src/windows/preamble_patcher_with_stub.cc', - ], - 'dependencies': [ - '../third_party/dynamic_annotations/dynamic_annotations.gyp:dynamic_annotations', - ], - 'msvs_settings': { - # TODO(sgk): merge this with build/common.gypi settings - 'VCLibrarianTool': { - 'AdditionalOptions': ['/ignore:4006,4221'], - }, - 'VCLinkerTool': { - 'AdditionalOptions': ['/ignore:4006'], - }, - }, - 'configurations': { - 'Debug_Base': { - 'msvs_settings': { - 'VCCLCompilerTool': { - 'RuntimeLibrary': '0', - }, - }, - 'variables': { - # Provide a way to force disable debugallocation in Debug builds, - # e.g. for profiling (it's more rare to profile Debug builds, - # but people sometimes need to do that). - 'disable_debugallocation%': 0, - }, - 'conditions': [ - # TODO(phajdan.jr): Also enable on Windows. - ['disable_debugallocation==0 and OS!="win"', { - 'defines': [ - # Use debugallocation for Debug builds to catch problems early - # and cleanly, http://crbug.com/30715 . - 'TCMALLOC_FOR_DEBUGALLOCATION', - ], - }], - ], - }, - }, - 'conditions': [ - ['OS=="linux" and clang_type_profiler==1', { - 'dependencies': [ - 'type_profiler_tcmalloc', - ], - # It is undoing dependencies and cflags_cc for type_profiler which - # build/common.gypi injects into all targets. - 'dependencies!': [ - 'type_profiler', - ], - 'cflags_cc!': [ - '-fintercept-allocation-functions', - ], - }], - ['OS=="win"', { - 'defines': [ - 'PERFTOOLS_DLL_DECL=', - ], - 'defines!': [ - # tcmalloc source files unconditionally define this, remove it from - # the list of defines that common.gypi defines globally. - 'NOMINMAX', - ], - 'dependencies': [ - 'libcmt', - ], - 'include_dirs': [ - '<(jemalloc_dir)', - '<(tcmalloc_dir)/src/windows', - ], - 'sources!': [ - '<(tcmalloc_dir)/src/base/elf_mem_image.cc', - '<(tcmalloc_dir)/src/base/elf_mem_image.h', - '<(tcmalloc_dir)/src/base/linuxthreads.cc', - '<(tcmalloc_dir)/src/base/linuxthreads.h', - '<(tcmalloc_dir)/src/base/vdso_support.cc', - '<(tcmalloc_dir)/src/base/vdso_support.h', - '<(tcmalloc_dir)/src/maybe_threads.cc', - '<(tcmalloc_dir)/src/maybe_threads.h', - '<(tcmalloc_dir)/src/symbolize.h', - '<(tcmalloc_dir)/src/system-alloc.cc', - '<(tcmalloc_dir)/src/system-alloc.h', - - # included by allocator_shim.cc - 'debugallocation_shim.cc', - - # heap-profiler/checker/cpuprofiler - '<(tcmalloc_dir)/src/base/thread_lister.c', - '<(tcmalloc_dir)/src/base/thread_lister.h', - '<(tcmalloc_dir)/src/deep-heap-profile.cc', - '<(tcmalloc_dir)/src/deep-heap-profile.h', - '<(tcmalloc_dir)/src/heap-checker-bcad.cc', - '<(tcmalloc_dir)/src/heap-checker.cc', - '<(tcmalloc_dir)/src/heap-profiler.cc', - '<(tcmalloc_dir)/src/heap-profile-table.cc', - '<(tcmalloc_dir)/src/heap-profile-table.h', - '<(tcmalloc_dir)/src/memory_region_map.cc', - '<(tcmalloc_dir)/src/memory_region_map.h', - '<(tcmalloc_dir)/src/profiledata.cc', - '<(tcmalloc_dir)/src/profiledata.h', - '<(tcmalloc_dir)/src/profile-handler.cc', - '<(tcmalloc_dir)/src/profile-handler.h', - '<(tcmalloc_dir)/src/profiler.cc', - ], - }], - ['OS=="linux" or OS=="freebsd" or OS=="solaris" or OS=="android"', { - 'sources!': [ - '<(tcmalloc_dir)/src/system-alloc.h', - '<(tcmalloc_dir)/src/windows/port.cc', - '<(tcmalloc_dir)/src/windows/port.h', - - # TODO(willchan): Support allocator shim later on. - 'allocator_shim.cc', - - # TODO(willchan): support jemalloc on other platforms - # jemalloc files - '<(jemalloc_dir)/jemalloc.c', - '<(jemalloc_dir)/jemalloc.h', - '<(jemalloc_dir)/ql.h', - '<(jemalloc_dir)/qr.h', - '<(jemalloc_dir)/rb.h', - - ], - # We enable all warnings by default, but upstream disables a few. - # Keep "-Wno-*" flags in sync with upstream by comparing against: - # http://code.google.com/p/google-perftools/source/browse/trunk/Makefile.am - 'cflags': [ - '-Wno-sign-compare', - '-Wno-unused-result', - ], - 'cflags!': [ - '-fvisibility=hidden', - ], - 'link_settings': { - 'ldflags': [ - # Don't let linker rip this symbol out, otherwise the heap&cpu - # profilers will not initialize properly on startup. - '-Wl,-uIsHeapProfilerRunning,-uProfilerStart', - # Do the same for heap leak checker. - '-Wl,-u_Z21InitialMallocHook_NewPKvj,-u_Z22InitialMallocHook_MMapPKvS0_jiiix,-u_Z22InitialMallocHook_SbrkPKvi', - '-Wl,-u_Z21InitialMallocHook_NewPKvm,-u_Z22InitialMallocHook_MMapPKvS0_miiil,-u_Z22InitialMallocHook_SbrkPKvl', - '-Wl,-u_ZN15HeapLeakChecker12IgnoreObjectEPKv,-u_ZN15HeapLeakChecker14UnIgnoreObjectEPKv', - ]}, - }], - # Need to distinguish a non-SDK build for Android WebView - # due to differences in C include files. - ['OS=="android" and android_webview_build==1', { - 'defines': ['ANDROID_NON_SDK_BUILD'], - }], - [ 'use_vtable_verify==1', { - 'cflags': [ - '-fvtable-verify=preinit', - ], - }], - [ 'linux_keep_shadow_stacks==1', { - 'sources': [ - '<(tcmalloc_dir)/src/linux_shadow_stacks.cc', - '<(tcmalloc_dir)/src/linux_shadow_stacks.h', - '<(tcmalloc_dir)/src/stacktrace_shadow-inl.h', - ], - 'cflags': [ - '-finstrument-functions', - ], - 'defines': [ - 'KEEP_SHADOW_STACKS', - ], - }], - [ 'linux_use_heapchecker==0', { - # Do not compile and link the heapchecker source. - 'sources!': [ - '<(tcmalloc_dir)/src/heap-checker-bcad.cc', - '<(tcmalloc_dir)/src/heap-checker.cc', - ], - # Disable the heap checker in tcmalloc. - 'defines': [ - 'NO_HEAP_CHECK', - ], - }], - ['order_profiling != 0', { - 'target_conditions' : [ - ['_toolset=="target"', { - 'cflags!': [ '-finstrument-functions' ], - }], - ], - }], - ], - }, - { - # This library is linked in to src/base.gypi:base and allocator_unittests - # It can't depend on either and nothing else should depend on it - all - # other code should use the interfaced provided by base. - 'target_name': 'allocator_extension_thunks', - 'type': 'static_library', - 'sources': [ - 'allocator_extension_thunks.cc', - 'allocator_extension_thunks.h', - ], - 'toolsets': ['host', 'target'], - 'include_dirs': [ - '../../' - ], - 'conditions': [ - ['OS=="linux" and clang_type_profiler==1', { - # It is undoing dependencies and cflags_cc for type_profiler which - # build/common.gypi injects into all targets. - 'dependencies!': [ - 'type_profiler', - ], - 'cflags_cc!': [ - '-fintercept-allocation-functions', - ], - }], - ], - }, - ], - 'conditions': [ - ['OS=="win"', { - 'targets': [ - { - 'target_name': 'libcmt', - 'type': 'none', - 'actions': [ - { - 'action_name': 'libcmt', - 'inputs': [ - 'prep_libc.py', - ], - 'outputs': [ - '<(SHARED_INTERMEDIATE_DIR)/allocator/libcmt.lib', - ], - 'action': [ - 'python', - 'prep_libc.py', - '$(VCInstallDir)lib', - '<(SHARED_INTERMEDIATE_DIR)/allocator', - '<(target_arch)', - ], - }, - ], - }, - { - 'target_name': 'allocator_unittests', - 'type': 'executable', - 'dependencies': [ - 'allocator', - 'allocator_extension_thunks', - '../../testing/gtest.gyp:gtest', - ], - 'include_dirs': [ - '.', - '<(tcmalloc_dir)/src/base', - '<(tcmalloc_dir)/src', - '../..', - ], - 'sources': [ - 'allocator_unittests.cc', - '../profiler/alternate_timer.cc', - '../profiler/alternate_timer.h', - ], - }, - { - 'target_name': 'tcmalloc_unittest', - 'type': 'executable', - 'sources': [ - 'tcmalloc_unittest.cc', - ], - 'include_dirs': [ - '../..', - # For constants of TCMalloc. - '<(tcmalloc_dir)/src', - ], - 'dependencies': [ - '../../testing/gtest.gyp:gtest', - '../base.gyp:base', - 'allocator', - ], - }, - ], - }], - ['OS=="win" and target_arch=="ia32"', { - 'targets': [ - { - 'target_name': 'allocator_extension_thunks_win64', - 'type': 'static_library', - 'sources': [ - 'allocator_extension_thunks.cc', - 'allocator_extension_thunks.h', - ], - 'toolsets': ['host', 'target'], - 'include_dirs': [ - '../../' - ], - 'configurations': { - 'Common_Base': { - 'msvs_target_platform': 'x64', - }, - }, - }, - ], - }], - ['OS=="linux" and clang_type_profiler==1', { - # Some targets in this section undo dependencies and cflags_cc for - # type_profiler which build/common.gypi injects into all targets. - 'targets': [ - { - 'target_name': 'type_profiler', - 'type': 'static_library', - 'dependencies!': [ - 'type_profiler', - ], - 'cflags_cc!': [ - '-fintercept-allocation-functions', - ], - 'include_dirs': [ - '../..', - ], - 'sources': [ - 'type_profiler.cc', - 'type_profiler.h', - 'type_profiler_control.h', - ], - 'toolsets': ['host', 'target'], - }, - { - 'target_name': 'type_profiler_tcmalloc', - 'type': 'static_library', - 'dependencies!': [ - 'type_profiler', - ], - 'cflags_cc!': [ - '-fintercept-allocation-functions', - ], - 'include_dirs': [ - '<(tcmalloc_dir)/src', - '../..', - ], - 'sources': [ - 'type_profiler_tcmalloc.cc', - 'type_profiler_tcmalloc.h', - '<(tcmalloc_dir)/src/gperftools/type_profiler_map.h', - '<(tcmalloc_dir)/src/type_profiler_map.cc', - ], - }, - { - 'target_name': 'type_profiler_unittests', - 'type': 'executable', - 'dependencies': [ - '../../testing/gtest.gyp:gtest', - '../base.gyp:base', - 'allocator', - 'type_profiler_tcmalloc', - ], - 'include_dirs': [ - '../..', - ], - 'sources': [ - 'type_profiler_control.cc', - 'type_profiler_control.h', - 'type_profiler_unittests.cc', - ], - }, - { - 'target_name': 'type_profiler_map_unittests', - 'type': 'executable', - 'dependencies': [ - '../../testing/gtest.gyp:gtest', - '../base.gyp:base', - 'allocator', - ], - 'dependencies!': [ - 'type_profiler', - ], - 'cflags_cc!': [ - '-fintercept-allocation-functions', - ], - 'include_dirs': [ - '<(tcmalloc_dir)/src', - '../..', - ], - 'sources': [ - 'type_profiler_map_unittests.cc', - '<(tcmalloc_dir)/src/gperftools/type_profiler_map.h', - '<(tcmalloc_dir)/src/type_profiler_map.cc', - ], - }, - ], - }], - ], -} diff --git a/base/allocator/allocator_extension.cc b/base/allocator/allocator_extension.cc deleted file mode 100644 index 83e460ac82..0000000000 --- a/base/allocator/allocator_extension.cc +++ /dev/null @@ -1,56 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "base/allocator/allocator_extension.h" - -#include "base/logging.h" - -namespace base { -namespace allocator { - -bool GetAllocatorWasteSize(size_t* size) { - thunks::GetAllocatorWasteSizeFunction get_allocator_waste_size_function = - thunks::GetGetAllocatorWasteSizeFunction(); - return get_allocator_waste_size_function != NULL && - get_allocator_waste_size_function(size); -} - -void GetStats(char* buffer, int buffer_length) { - DCHECK_GT(buffer_length, 0); - thunks::GetStatsFunction get_stats_function = thunks::GetGetStatsFunction(); - if (get_stats_function) - get_stats_function(buffer, buffer_length); - else - buffer[0] = '\0'; -} - -void ReleaseFreeMemory() { - thunks::ReleaseFreeMemoryFunction release_free_memory_function = - thunks::GetReleaseFreeMemoryFunction(); - if (release_free_memory_function) - release_free_memory_function(); -} - -void SetGetAllocatorWasteSizeFunction( - thunks::GetAllocatorWasteSizeFunction get_allocator_waste_size_function) { - DCHECK_EQ(thunks::GetGetAllocatorWasteSizeFunction(), - reinterpret_cast(NULL)); - thunks::SetGetAllocatorWasteSizeFunction(get_allocator_waste_size_function); -} - -void SetGetStatsFunction(thunks::GetStatsFunction get_stats_function) { - DCHECK_EQ(thunks::GetGetStatsFunction(), - reinterpret_cast(NULL)); - thunks::SetGetStatsFunction(get_stats_function); -} - -void SetReleaseFreeMemoryFunction( - thunks::ReleaseFreeMemoryFunction release_free_memory_function) { - DCHECK_EQ(thunks::GetReleaseFreeMemoryFunction(), - reinterpret_cast(NULL)); - thunks::SetReleaseFreeMemoryFunction(release_free_memory_function); -} - -} // namespace allocator -} // namespace base diff --git a/base/allocator/allocator_extension.h b/base/allocator/allocator_extension.h deleted file mode 100644 index de3119f85e..0000000000 --- a/base/allocator/allocator_extension.h +++ /dev/null @@ -1,59 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef BASE_ALLOCATOR_ALLOCATOR_EXTENSION_H -#define BASE_ALLOCATOR_ALLOCATOR_EXTENSION_H - -#include // for size_t - -#include "base/allocator/allocator_extension_thunks.h" -#include "base/base_export.h" -#include "build/build_config.h" - -namespace base { -namespace allocator { - -// Request the allocator to report value of its waste memory size. -// Waste size corresponds to memory that has been allocated from the OS but -// not passed up to the application. It e.g. includes memory retained by free -// lists, internal data, chunks padding, etc. -// -// |size| pointer to the returned value, must be not NULL. -// Returns true if the value has been returned, false otherwise. -BASE_EXPORT bool GetAllocatorWasteSize(size_t* size); - -// Request that the allocator print a human-readable description of the current -// state of the allocator into a null-terminated string in the memory segment -// buffer[0,buffer_length-1]. -// -// |buffer| must point to a valid piece of memory -// |buffer_length| must be > 0. -BASE_EXPORT void GetStats(char* buffer, int buffer_length); - -// Request that the allocator release any free memory it knows about to the -// system. -BASE_EXPORT void ReleaseFreeMemory(); - - -// These settings allow specifying a callback used to implement the allocator -// extension functions. These are optional, but if set they must only be set -// once. These will typically called in an allocator-specific initialization -// routine. -// -// No threading promises are made. The caller is responsible for making sure -// these pointers are set before any other threads attempt to call the above -// functions. -BASE_EXPORT void SetGetAllocatorWasteSizeFunction( - thunks::GetAllocatorWasteSizeFunction get_allocator_waste_size_function); - -BASE_EXPORT void SetGetStatsFunction( - thunks::GetStatsFunction get_stats_function); - -BASE_EXPORT void SetReleaseFreeMemoryFunction( - thunks::ReleaseFreeMemoryFunction release_free_memory_function); - -} // namespace allocator -} // namespace base - -#endif diff --git a/base/allocator/allocator_extension_thunks.cc b/base/allocator/allocator_extension_thunks.cc deleted file mode 100644 index e4024fb332..0000000000 --- a/base/allocator/allocator_extension_thunks.cc +++ /dev/null @@ -1,52 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "base/allocator/allocator_extension_thunks.h" - -#include // for NULL - -namespace base { -namespace allocator { -namespace thunks { - -// This slightly odd translation unit exists because of the peculularity of how -// allocator_unittests work on windows. That target has to perform -// tcmalloc-specific initialization on windows, but it cannot depend on base -// otherwise. This target sits in the middle - base and allocator_unittests -// can depend on it. This file can't depend on anything else in base, including -// logging. - -static GetAllocatorWasteSizeFunction g_get_allocator_waste_size_function = NULL; -static GetStatsFunction g_get_stats_function = NULL; -static ReleaseFreeMemoryFunction g_release_free_memory_function = NULL; - -void SetGetAllocatorWasteSizeFunction( - GetAllocatorWasteSizeFunction get_allocator_waste_size_function) { - g_get_allocator_waste_size_function = get_allocator_waste_size_function; -} - -GetAllocatorWasteSizeFunction GetGetAllocatorWasteSizeFunction() { - return g_get_allocator_waste_size_function; -} - -void SetGetStatsFunction(GetStatsFunction get_stats_function) { - g_get_stats_function = get_stats_function; -} - -GetStatsFunction GetGetStatsFunction() { - return g_get_stats_function; -} - -void SetReleaseFreeMemoryFunction( - ReleaseFreeMemoryFunction release_free_memory_function) { - g_release_free_memory_function = release_free_memory_function; -} - -ReleaseFreeMemoryFunction GetReleaseFreeMemoryFunction() { - return g_release_free_memory_function; -} - -} // namespace thunks -} // namespace allocator -} // namespace base diff --git a/base/allocator/allocator_extension_thunks.h b/base/allocator/allocator_extension_thunks.h deleted file mode 100644 index 1e97a84b63..0000000000 --- a/base/allocator/allocator_extension_thunks.h +++ /dev/null @@ -1,36 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef BASE_ALLOCATOR_ALLOCATOR_THUNKS_EXTENSION_H -#define BASE_ALLOCATOR_ALLOCATOR_THUNKS_EXTENSION_H - -#include // for size_t - -namespace base { -namespace allocator { -namespace thunks { - -// WARNING: You probably don't want to use this file unless you are routing a -// new allocator extension from a specific allocator implementation to base. -// See allocator_extension.h to see the interface that base exports. - -typedef bool (*GetAllocatorWasteSizeFunction)(size_t* size); -void SetGetAllocatorWasteSizeFunction( - GetAllocatorWasteSizeFunction get_allocator_waste_size_function); -GetAllocatorWasteSizeFunction GetGetAllocatorWasteSizeFunction(); - -typedef void (*GetStatsFunction)(char* buffer, int buffer_length); -void SetGetStatsFunction(GetStatsFunction get_stats_function); -GetStatsFunction GetGetStatsFunction(); - -typedef void (*ReleaseFreeMemoryFunction)(); -void SetReleaseFreeMemoryFunction( - ReleaseFreeMemoryFunction release_free_memory_function); -ReleaseFreeMemoryFunction GetReleaseFreeMemoryFunction(); - -} // namespace thunks -} // namespace allocator -} // namespace base - -#endif diff --git a/base/allocator/allocator_shim.cc b/base/allocator/allocator_shim.cc deleted file mode 100644 index 1d8229117d..0000000000 --- a/base/allocator/allocator_shim.cc +++ /dev/null @@ -1,446 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "base/allocator/allocator_shim.h" - -#include -#include "base/allocator/allocator_extension_thunks.h" -#include "base/profiler/alternate_timer.h" -#include "base/sysinfo.h" -#include "jemalloc.h" - -// When defined, different heap allocators can be used via an environment -// variable set before running the program. This may reduce the amount -// of inlining that we get with malloc/free/etc. Disabling makes it -// so that only tcmalloc can be used. -#define ENABLE_DYNAMIC_ALLOCATOR_SWITCHING - -// TODO(mbelshe): Ensure that all calls to tcmalloc have the proper call depth -// from the "user code" so that debugging tools (HeapChecker) can work. - -// __THROW is defined in glibc systems. It means, counter-intuitively, -// "This function will never throw an exception." It's an optional -// optimization tool, but we may need to use it to match glibc prototypes. -#ifndef __THROW // I guess we're not on a glibc system -# define __THROW // __THROW is just an optimization, so ok to make it "" -#endif - -// new_mode behaves similarly to MSVC's _set_new_mode. -// If flag is 0 (default), calls to malloc will behave normally. -// If flag is 1, calls to malloc will behave like calls to new, -// and the std_new_handler will be invoked on failure. -// Can be set by calling _set_new_mode(). -static int new_mode = 0; - -typedef enum { - TCMALLOC, // TCMalloc is the default allocator. - JEMALLOC, // JEMalloc. - WINHEAP, // Windows Heap (standard Windows allocator). - WINLFH, // Windows LFH Heap. -} Allocator; - -// This is the default allocator. This value can be changed at startup by -// specifying environment variables shown below it. -// See SetupSubprocessAllocator() to specify a default secondary (subprocess) -// allocator. -// TODO(jar): Switch to using TCMALLOC for the renderer as well. -#if (defined(ADDRESS_SANITIZER) && defined(OS_WIN)) -// The Windows implementation of Asan requires the use of "WINHEAP". -static Allocator allocator = WINHEAP; -#else -static Allocator allocator = TCMALLOC; -#endif -// The names of the environment variables that can optionally control the -// selection of the allocator. The primary may be used to control overall -// allocator selection, and the secondary can be used to specify an allocator -// to use in sub-processes. -static const char primary_name[] = "CHROME_ALLOCATOR"; -static const char secondary_name[] = "CHROME_ALLOCATOR_2"; - -// We include tcmalloc and the win_allocator to get as much inlining as -// possible. -#include "debugallocation_shim.cc" -#include "win_allocator.cc" - -// Forward declarations from jemalloc. -extern "C" { -void* je_malloc(size_t s); -void* je_realloc(void* p, size_t s); -void je_free(void* s); -size_t je_msize(void* p); -bool je_malloc_init_hard(); -void* je_memalign(size_t a, size_t s); -} - -// Call the new handler, if one has been set. -// Returns true on successfully calling the handler, false otherwise. -inline bool call_new_handler(bool nothrow) { - // Get the current new handler. NB: this function is not - // thread-safe. We make a feeble stab at making it so here, but - // this lock only protects against tcmalloc interfering with - // itself, not with other libraries calling set_new_handler. - std::new_handler nh; - { - SpinLockHolder h(&set_new_handler_lock); - nh = std::set_new_handler(0); - (void) std::set_new_handler(nh); - } -#if (defined(__GNUC__) && !defined(__EXCEPTIONS)) || \ - (defined(_HAS_EXCEPTIONS) && !_HAS_EXCEPTIONS) - if (!nh) - return false; - // Since exceptions are disabled, we don't really know if new_handler - // failed. Assume it will abort if it fails. - (*nh)(); - return false; // break out of the retry loop. -#else - // If no new_handler is established, the allocation failed. - if (!nh) { - if (nothrow) - return false; - throw std::bad_alloc(); - } - // Otherwise, try the new_handler. If it returns, retry the - // allocation. If it throws std::bad_alloc, fail the allocation. - // if it throws something else, don't interfere. - try { - (*nh)(); - } catch (const std::bad_alloc&) { - if (!nothrow) - throw; - return true; - } -#endif // (defined(__GNUC__) && !defined(__EXCEPTIONS)) || (defined(_HAS_EXCEPTIONS) && !_HAS_EXCEPTIONS) - return false; -} - -extern "C" { -void* malloc(size_t size) __THROW { - void* ptr; - for (;;) { -#ifdef ENABLE_DYNAMIC_ALLOCATOR_SWITCHING - switch (allocator) { - case JEMALLOC: - ptr = je_malloc(size); - break; - case WINHEAP: - case WINLFH: - ptr = win_heap_malloc(size); - break; - case TCMALLOC: - default: - ptr = do_malloc(size); - break; - } -#else - // TCMalloc case. - ptr = do_malloc(size); -#endif - if (ptr) - return ptr; - - if (!new_mode || !call_new_handler(true)) - break; - } - return ptr; -} - -void free(void* p) __THROW { -#ifdef ENABLE_DYNAMIC_ALLOCATOR_SWITCHING - switch (allocator) { - case JEMALLOC: - je_free(p); - return; - case WINHEAP: - case WINLFH: - win_heap_free(p); - return; - } -#endif - // TCMalloc case. - do_free(p); -} - -void* realloc(void* ptr, size_t size) __THROW { - // Webkit is brittle for allocators that return NULL for malloc(0). The - // realloc(0, 0) code path does not guarantee a non-NULL return, so be sure - // to call malloc for this case. - if (!ptr) - return malloc(size); - - void* new_ptr; - for (;;) { -#ifdef ENABLE_DYNAMIC_ALLOCATOR_SWITCHING - switch (allocator) { - case JEMALLOC: - new_ptr = je_realloc(ptr, size); - break; - case WINHEAP: - case WINLFH: - new_ptr = win_heap_realloc(ptr, size); - break; - case TCMALLOC: - default: - new_ptr = do_realloc(ptr, size); - break; - } -#else - // TCMalloc case. - new_ptr = do_realloc(ptr, size); -#endif - - // Subtle warning: NULL return does not alwas indicate out-of-memory. If - // the requested new size is zero, realloc should free the ptr and return - // NULL. - if (new_ptr || !size) - return new_ptr; - if (!new_mode || !call_new_handler(true)) - break; - } - return new_ptr; -} - -// TODO(mbelshe): Implement this for other allocators. -void malloc_stats(void) __THROW { -#ifdef ENABLE_DYNAMIC_ALLOCATOR_SWITCHING - switch (allocator) { - case JEMALLOC: - // No stats. - return; - case WINHEAP: - case WINLFH: - // No stats. - return; - } -#endif - tc_malloc_stats(); -} - -#ifdef WIN32 - -extern "C" size_t _msize(void* p) { -#ifdef ENABLE_DYNAMIC_ALLOCATOR_SWITCHING - switch (allocator) { - case JEMALLOC: - return je_msize(p); - case WINHEAP: - case WINLFH: - return win_heap_msize(p); - } -#endif - return MallocExtension::instance()->GetAllocatedSize(p); -} - -// This is included to resolve references from libcmt. -extern "C" intptr_t _get_heap_handle() { - return 0; -} - -static bool get_allocator_waste_size_thunk(size_t* size) { -#ifdef ENABLE_DYNAMIC_ALLOCATOR_SWITCHING - switch (allocator) { - case JEMALLOC: - case WINHEAP: - case WINLFH: - // TODO(alexeif): Implement for allocators other than tcmalloc. - return false; - } -#endif - size_t heap_size, allocated_bytes, unmapped_bytes; - MallocExtension* ext = MallocExtension::instance(); - if (ext->GetNumericProperty("generic.heap_size", &heap_size) && - ext->GetNumericProperty("generic.current_allocated_bytes", - &allocated_bytes) && - ext->GetNumericProperty("tcmalloc.pageheap_unmapped_bytes", - &unmapped_bytes)) { - *size = heap_size - allocated_bytes - unmapped_bytes; - return true; - } - return false; -} - -static void get_stats_thunk(char* buffer, int buffer_length) { - MallocExtension::instance()->GetStats(buffer, buffer_length); -} - -static void release_free_memory_thunk() { - MallocExtension::instance()->ReleaseFreeMemory(); -} - -// The CRT heap initialization stub. -extern "C" int _heap_init() { -#ifdef ENABLE_DYNAMIC_ALLOCATOR_SWITCHING -// Don't use the environment variable if ADDRESS_SANITIZER is defined on -// Windows, as the implementation requires Winheap to be the allocator. -#if !(defined(ADDRESS_SANITIZER) && defined(OS_WIN)) - const char* environment_value = GetenvBeforeMain(primary_name); - if (environment_value) { - if (!stricmp(environment_value, "jemalloc")) - allocator = JEMALLOC; - else if (!stricmp(environment_value, "winheap")) - allocator = WINHEAP; - else if (!stricmp(environment_value, "winlfh")) - allocator = WINLFH; - else if (!stricmp(environment_value, "tcmalloc")) - allocator = TCMALLOC; - } -#endif - - switch (allocator) { - case JEMALLOC: - return je_malloc_init_hard() ? 0 : 1; - case WINHEAP: - return win_heap_init(false) ? 1 : 0; - case WINLFH: - return win_heap_init(true) ? 1 : 0; - case TCMALLOC: - default: - // fall through - break; - } -#endif - // Initializing tcmalloc. - // We intentionally leak this object. It lasts for the process - // lifetime. Trying to teardown at _heap_term() is so late that - // you can't do anything useful anyway. - new TCMallocGuard(); - - // Provide optional hook for monitoring allocation quantities on a per-thread - // basis. Only set the hook if the environment indicates this needs to be - // enabled. - const char* profiling = - GetenvBeforeMain(tracked_objects::kAlternateProfilerTime); - if (profiling && *profiling == '1') { - tracked_objects::SetAlternateTimeSource( - tcmalloc::ThreadCache::GetBytesAllocatedOnCurrentThread, - tracked_objects::TIME_SOURCE_TYPE_TCMALLOC); - } - - base::allocator::thunks::SetGetAllocatorWasteSizeFunction( - get_allocator_waste_size_thunk); - base::allocator::thunks::SetGetStatsFunction(get_stats_thunk); - base::allocator::thunks::SetReleaseFreeMemoryFunction( - release_free_memory_thunk); - - return 1; -} - -// The CRT heap cleanup stub. -extern "C" void _heap_term() {} - -// We set this to 1 because part of the CRT uses a check of _crtheap != 0 -// to test whether the CRT has been initialized. Once we've ripped out -// the allocators from libcmt, we need to provide this definition so that -// the rest of the CRT is still usable. -extern "C" void* _crtheap = reinterpret_cast(1); - -// Provide support for aligned memory through Windows only _aligned_malloc(). -void* _aligned_malloc(size_t size, size_t alignment) { - // _aligned_malloc guarantees parameter validation, so do so here. These - // checks are somewhat stricter than _aligned_malloc() since we're effectively - // using memalign() under the hood. - DCHECK_GT(size, 0U); - DCHECK_EQ(alignment & (alignment - 1), 0U); - DCHECK_EQ(alignment % sizeof(void*), 0U); - - void* ptr; - for (;;) { -#ifdef ENABLE_DYNAMIC_ALLOCATOR_SWITCHING - switch (allocator) { - case JEMALLOC: - ptr = je_memalign(alignment, size); - break; - case WINHEAP: - case WINLFH: - ptr = win_heap_memalign(alignment, size); - break; - case TCMALLOC: - default: - ptr = tc_memalign(alignment, size); - break; - } -#else - // TCMalloc case. - ptr = tc_memalign(alignment, size); -#endif - if (ptr) { - // Sanity check alignment. - DCHECK_EQ(reinterpret_cast(ptr) & (alignment - 1), 0U); - return ptr; - } - - if (!new_mode || !call_new_handler(true)) - break; - } - return ptr; -} - -void _aligned_free(void* p) { - // Both JEMalloc and TCMalloc return pointers from memalign() that are safe to - // use with free(). Pointers allocated with win_heap_memalign() MUST be freed - // via win_heap_memalign_free() since the aligned pointer is not the real one. -#ifdef ENABLE_DYNAMIC_ALLOCATOR_SWITCHING - switch (allocator) { - case JEMALLOC: - je_free(p); - return; - case WINHEAP: - case WINLFH: - win_heap_memalign_free(p); - return; - } -#endif - // TCMalloc case. - do_free(p); -} - -#endif // WIN32 - -#include "generic_allocators.cc" - -} // extern C - -namespace base { -namespace allocator { - -void SetupSubprocessAllocator() { -#ifdef ENABLE_DYNAMIC_ALLOCATOR_SWITCHING - size_t primary_length = 0; - getenv_s(&primary_length, NULL, 0, primary_name); - - size_t secondary_length = 0; - char buffer[20]; - getenv_s(&secondary_length, buffer, sizeof(buffer), secondary_name); - DCHECK_GT(sizeof(buffer), secondary_length); - buffer[sizeof(buffer) - 1] = '\0'; - - if (secondary_length || !primary_length) { - // Don't use the environment variable if ADDRESS_SANITIZER is defined on - // Windows, as the implementation require Winheap to be the allocator. -#if !(defined(ADDRESS_SANITIZER) && defined(OS_WIN)) - const char* secondary_value = secondary_length ? buffer : "TCMALLOC"; - // Force renderer (or other subprocesses) to use secondary_value. -#else - const char* secondary_value = "WINHEAP"; -#endif - int ret_val = _putenv_s(primary_name, secondary_value); - DCHECK_EQ(0, ret_val); - } -#endif // ENABLE_DYNAMIC_ALLOCATOR_SWITCHING -} - -void* TCMallocDoMallocForTest(size_t size) { - return do_malloc(size); -} - -void TCMallocDoFreeForTest(void* ptr) { - do_free(ptr); -} - -size_t ExcludeSpaceForMarkForTest(size_t size) { - return ExcludeSpaceForMark(size); -} - -} // namespace allocator. -} // namespace base. diff --git a/base/allocator/allocator_shim.h b/base/allocator/allocator_shim.h deleted file mode 100644 index ca70ab0e10..0000000000 --- a/base/allocator/allocator_shim.h +++ /dev/null @@ -1,27 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef BASE_ALLOCATOR_ALLOCATOR_SHIM_H_ -#define BASE_ALLOCATOR_ALLOCATOR_SHIM_H_ - -#include - -namespace base { -namespace allocator { - -// Resets the environment variable CHROME_ALLOCATOR to specify the choice to -// be used by subprocesses. Priority is given to the current value of -// CHROME_ALLOCATOR_2 (if specified), then CHROME_ALLOCATOR (if specified), and -// then a default value (typically set to TCMALLOC). -void SetupSubprocessAllocator(); - -// Expose some of tcmalloc functions for test. -void* TCMallocDoMallocForTest(size_t size); -void TCMallocDoFreeForTest(void* ptr); -size_t ExcludeSpaceForMarkForTest(size_t size); - -} // namespace allocator. -} // namespace base. - -#endif // BASE_ALLOCATOR_ALLOCATOR_SHIM_H_ diff --git a/base/allocator/allocator_unittests.cc b/base/allocator/allocator_unittests.cc deleted file mode 100644 index cf8b74d7f4..0000000000 --- a/base/allocator/allocator_unittests.cc +++ /dev/null @@ -1,521 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include -#include -#include // for min() -#include "base/atomicops.h" -#include "testing/gtest/include/gtest/gtest.h" - -// Number of bits in a size_t. -static const int kSizeBits = 8 * sizeof(size_t); -// The maximum size of a size_t. -static const size_t kMaxSize = ~static_cast(0); -// Maximum positive size of a size_t if it were signed. -static const size_t kMaxSignedSize = ((size_t(1) << (kSizeBits-1)) - 1); -// An allocation size which is not too big to be reasonable. -static const size_t kNotTooBig = 100000; -// An allocation size which is just too big. -static const size_t kTooBig = ~static_cast(0); - -namespace { - -using std::min; - -// Fill a buffer of the specified size with a predetermined pattern -static void Fill(unsigned char* buffer, int n) { - for (int i = 0; i < n; i++) { - buffer[i] = (i & 0xff); - } -} - -// Check that the specified buffer has the predetermined pattern -// generated by Fill() -static bool Valid(unsigned char* buffer, int n) { - for (int i = 0; i < n; i++) { - if (buffer[i] != (i & 0xff)) { - return false; - } - } - return true; -} - -// Check that a buffer is completely zeroed. -static bool IsZeroed(unsigned char* buffer, int n) { - for (int i = 0; i < n; i++) { - if (buffer[i] != 0) { - return false; - } - } - return true; -} - -// Check alignment -static void CheckAlignment(void* p, int align) { - EXPECT_EQ(0, reinterpret_cast(p) & (align-1)); -} - -// Return the next interesting size/delta to check. Returns -1 if no more. -static int NextSize(int size) { - if (size < 100) - return size+1; - - if (size < 100000) { - // Find next power of two - int power = 1; - while (power < size) - power <<= 1; - - // Yield (power-1, power, power+1) - if (size < power-1) - return power-1; - - if (size == power-1) - return power; - - assert(size == power); - return power+1; - } else { - return -1; - } -} - -#define GG_ULONGLONG(x) static_cast(x) - -template -static void TestAtomicIncrement() { - // For now, we just test single threaded execution - - // use a guard value to make sure the NoBarrier_AtomicIncrement doesn't go - // outside the expected address bounds. This is in particular to - // test that some future change to the asm code doesn't cause the - // 32-bit NoBarrier_AtomicIncrement to do the wrong thing on 64-bit machines. - struct { - AtomicType prev_word; - AtomicType count; - AtomicType next_word; - } s; - - AtomicType prev_word_value, next_word_value; - memset(&prev_word_value, 0xFF, sizeof(AtomicType)); - memset(&next_word_value, 0xEE, sizeof(AtomicType)); - - s.prev_word = prev_word_value; - s.count = 0; - s.next_word = next_word_value; - - EXPECT_EQ(base::subtle::NoBarrier_AtomicIncrement(&s.count, 1), 1); - EXPECT_EQ(s.count, 1); - EXPECT_EQ(s.prev_word, prev_word_value); - EXPECT_EQ(s.next_word, next_word_value); - - EXPECT_EQ(base::subtle::NoBarrier_AtomicIncrement(&s.count, 2), 3); - EXPECT_EQ(s.count, 3); - EXPECT_EQ(s.prev_word, prev_word_value); - EXPECT_EQ(s.next_word, next_word_value); - - EXPECT_EQ(base::subtle::NoBarrier_AtomicIncrement(&s.count, 3), 6); - EXPECT_EQ(s.count, 6); - EXPECT_EQ(s.prev_word, prev_word_value); - EXPECT_EQ(s.next_word, next_word_value); - - EXPECT_EQ(base::subtle::NoBarrier_AtomicIncrement(&s.count, -3), 3); - EXPECT_EQ(s.count, 3); - EXPECT_EQ(s.prev_word, prev_word_value); - EXPECT_EQ(s.next_word, next_word_value); - - EXPECT_EQ(base::subtle::NoBarrier_AtomicIncrement(&s.count, -2), 1); - EXPECT_EQ(s.count, 1); - EXPECT_EQ(s.prev_word, prev_word_value); - EXPECT_EQ(s.next_word, next_word_value); - - EXPECT_EQ(base::subtle::NoBarrier_AtomicIncrement(&s.count, -1), 0); - EXPECT_EQ(s.count, 0); - EXPECT_EQ(s.prev_word, prev_word_value); - EXPECT_EQ(s.next_word, next_word_value); - - EXPECT_EQ(base::subtle::NoBarrier_AtomicIncrement(&s.count, -1), -1); - EXPECT_EQ(s.count, -1); - EXPECT_EQ(s.prev_word, prev_word_value); - EXPECT_EQ(s.next_word, next_word_value); - - EXPECT_EQ(base::subtle::NoBarrier_AtomicIncrement(&s.count, -4), -5); - EXPECT_EQ(s.count, -5); - EXPECT_EQ(s.prev_word, prev_word_value); - EXPECT_EQ(s.next_word, next_word_value); - - EXPECT_EQ(base::subtle::NoBarrier_AtomicIncrement(&s.count, 5), 0); - EXPECT_EQ(s.count, 0); - EXPECT_EQ(s.prev_word, prev_word_value); - EXPECT_EQ(s.next_word, next_word_value); -} - - -#define NUM_BITS(T) (sizeof(T) * 8) - - -template -static void TestCompareAndSwap() { - AtomicType value = 0; - AtomicType prev = base::subtle::NoBarrier_CompareAndSwap(&value, 0, 1); - EXPECT_EQ(1, value); - EXPECT_EQ(0, prev); - - // Use test value that has non-zero bits in both halves, more for testing - // 64-bit implementation on 32-bit platforms. - const AtomicType k_test_val = (GG_ULONGLONG(1) << - (NUM_BITS(AtomicType) - 2)) + 11; - value = k_test_val; - prev = base::subtle::NoBarrier_CompareAndSwap(&value, 0, 5); - EXPECT_EQ(k_test_val, value); - EXPECT_EQ(k_test_val, prev); - - value = k_test_val; - prev = base::subtle::NoBarrier_CompareAndSwap(&value, k_test_val, 5); - EXPECT_EQ(5, value); - EXPECT_EQ(k_test_val, prev); -} - - -template -static void TestAtomicExchange() { - AtomicType value = 0; - AtomicType new_value = base::subtle::NoBarrier_AtomicExchange(&value, 1); - EXPECT_EQ(1, value); - EXPECT_EQ(0, new_value); - - // Use test value that has non-zero bits in both halves, more for testing - // 64-bit implementation on 32-bit platforms. - const AtomicType k_test_val = (GG_ULONGLONG(1) << - (NUM_BITS(AtomicType) - 2)) + 11; - value = k_test_val; - new_value = base::subtle::NoBarrier_AtomicExchange(&value, k_test_val); - EXPECT_EQ(k_test_val, value); - EXPECT_EQ(k_test_val, new_value); - - value = k_test_val; - new_value = base::subtle::NoBarrier_AtomicExchange(&value, 5); - EXPECT_EQ(5, value); - EXPECT_EQ(k_test_val, new_value); -} - - -template -static void TestAtomicIncrementBounds() { - // Test increment at the half-width boundary of the atomic type. - // It is primarily for testing at the 32-bit boundary for 64-bit atomic type. - AtomicType test_val = GG_ULONGLONG(1) << (NUM_BITS(AtomicType) / 2); - AtomicType value = test_val - 1; - AtomicType new_value = base::subtle::NoBarrier_AtomicIncrement(&value, 1); - EXPECT_EQ(test_val, value); - EXPECT_EQ(value, new_value); - - base::subtle::NoBarrier_AtomicIncrement(&value, -1); - EXPECT_EQ(test_val - 1, value); -} - -// This is a simple sanity check that values are correct. Not testing -// atomicity -template -static void TestStore() { - const AtomicType kVal1 = static_cast(0xa5a5a5a5a5a5a5a5LL); - const AtomicType kVal2 = static_cast(-1); - - AtomicType value; - - base::subtle::NoBarrier_Store(&value, kVal1); - EXPECT_EQ(kVal1, value); - base::subtle::NoBarrier_Store(&value, kVal2); - EXPECT_EQ(kVal2, value); - - base::subtle::Acquire_Store(&value, kVal1); - EXPECT_EQ(kVal1, value); - base::subtle::Acquire_Store(&value, kVal2); - EXPECT_EQ(kVal2, value); - - base::subtle::Release_Store(&value, kVal1); - EXPECT_EQ(kVal1, value); - base::subtle::Release_Store(&value, kVal2); - EXPECT_EQ(kVal2, value); -} - -// This is a simple sanity check that values are correct. Not testing -// atomicity -template -static void TestLoad() { - const AtomicType kVal1 = static_cast(0xa5a5a5a5a5a5a5a5LL); - const AtomicType kVal2 = static_cast(-1); - - AtomicType value; - - value = kVal1; - EXPECT_EQ(kVal1, base::subtle::NoBarrier_Load(&value)); - value = kVal2; - EXPECT_EQ(kVal2, base::subtle::NoBarrier_Load(&value)); - - value = kVal1; - EXPECT_EQ(kVal1, base::subtle::Acquire_Load(&value)); - value = kVal2; - EXPECT_EQ(kVal2, base::subtle::Acquire_Load(&value)); - - value = kVal1; - EXPECT_EQ(kVal1, base::subtle::Release_Load(&value)); - value = kVal2; - EXPECT_EQ(kVal2, base::subtle::Release_Load(&value)); -} - -template -static void TestAtomicOps() { - TestCompareAndSwap(); - TestAtomicExchange(); - TestAtomicIncrementBounds(); - TestStore(); - TestLoad(); -} - -static void TestCalloc(size_t n, size_t s, bool ok) { - char* p = reinterpret_cast(calloc(n, s)); - if (!ok) { - EXPECT_EQ(NULL, p) << "calloc(n, s) should not succeed"; - } else { - EXPECT_NE(reinterpret_cast(NULL), p) << - "calloc(n, s) should succeed"; - for (int i = 0; i < n*s; i++) { - EXPECT_EQ('\0', p[i]); - } - free(p); - } -} - - -// A global test counter for number of times the NewHandler is called. -static int news_handled = 0; -static void TestNewHandler() { - ++news_handled; - throw std::bad_alloc(); -} - -// Because we compile without exceptions, we expect these will not throw. -static void TestOneNewWithoutExceptions(void* (*func)(size_t), - bool should_throw) { - // success test - try { - void* ptr = (*func)(kNotTooBig); - EXPECT_NE(reinterpret_cast(NULL), ptr) << - "allocation should not have failed."; - } catch(...) { - EXPECT_EQ(0, 1) << "allocation threw unexpected exception."; - } - - // failure test - try { - void* rv = (*func)(kTooBig); - EXPECT_EQ(NULL, rv); - EXPECT_FALSE(should_throw) << "allocation should have thrown."; - } catch(...) { - EXPECT_TRUE(should_throw) << "allocation threw unexpected exception."; - } -} - -static void TestNothrowNew(void* (*func)(size_t)) { - news_handled = 0; - - // test without new_handler: - std::new_handler saved_handler = std::set_new_handler(0); - TestOneNewWithoutExceptions(func, false); - - // test with new_handler: - std::set_new_handler(TestNewHandler); - TestOneNewWithoutExceptions(func, true); - EXPECT_EQ(news_handled, 1) << "nothrow new_handler was not called."; - std::set_new_handler(saved_handler); -} - -} // namespace - -//----------------------------------------------------------------------------- - -TEST(Atomics, AtomicIncrementWord) { - TestAtomicIncrement(); -} - -TEST(Atomics, AtomicIncrement32) { - TestAtomicIncrement(); -} - -TEST(Atomics, AtomicOpsWord) { - TestAtomicIncrement(); -} - -TEST(Atomics, AtomicOps32) { - TestAtomicIncrement(); -} - -TEST(Allocators, Malloc) { - // Try allocating data with a bunch of alignments and sizes - for (int size = 1; size < 1048576; size *= 2) { - unsigned char* ptr = reinterpret_cast(malloc(size)); - CheckAlignment(ptr, 2); // Should be 2 byte aligned - Fill(ptr, size); - EXPECT_TRUE(Valid(ptr, size)); - free(ptr); - } -} - -TEST(Allocators, Calloc) { - TestCalloc(0, 0, true); - TestCalloc(0, 1, true); - TestCalloc(1, 1, true); - TestCalloc(1<<10, 0, true); - TestCalloc(1<<20, 0, true); - TestCalloc(0, 1<<10, true); - TestCalloc(0, 1<<20, true); - TestCalloc(1<<20, 2, true); - TestCalloc(2, 1<<20, true); - TestCalloc(1000, 1000, true); - - TestCalloc(kMaxSize, 2, false); - TestCalloc(2, kMaxSize, false); - TestCalloc(kMaxSize, kMaxSize, false); - - TestCalloc(kMaxSignedSize, 3, false); - TestCalloc(3, kMaxSignedSize, false); - TestCalloc(kMaxSignedSize, kMaxSignedSize, false); -} - -TEST(Allocators, New) { - TestNothrowNew(&::operator new); - TestNothrowNew(&::operator new[]); -} - -// This makes sure that reallocing a small number of bytes in either -// direction doesn't cause us to allocate new memory. -TEST(Allocators, Realloc1) { - int start_sizes[] = { 100, 1000, 10000, 100000 }; - int deltas[] = { 1, -2, 4, -8, 16, -32, 64, -128 }; - - for (int s = 0; s < sizeof(start_sizes)/sizeof(*start_sizes); ++s) { - void* p = malloc(start_sizes[s]); - ASSERT_TRUE(p); - // The larger the start-size, the larger the non-reallocing delta. - for (int d = 0; d < s*2; ++d) { - void* new_p = realloc(p, start_sizes[s] + deltas[d]); - ASSERT_EQ(p, new_p); // realloc should not allocate new memory - } - // Test again, but this time reallocing smaller first. - for (int d = 0; d < s*2; ++d) { - void* new_p = realloc(p, start_sizes[s] - deltas[d]); - ASSERT_EQ(p, new_p); // realloc should not allocate new memory - } - free(p); - } -} - -TEST(Allocators, Realloc2) { - for (int src_size = 0; src_size >= 0; src_size = NextSize(src_size)) { - for (int dst_size = 0; dst_size >= 0; dst_size = NextSize(dst_size)) { - unsigned char* src = reinterpret_cast(malloc(src_size)); - Fill(src, src_size); - unsigned char* dst = - reinterpret_cast(realloc(src, dst_size)); - EXPECT_TRUE(Valid(dst, min(src_size, dst_size))); - Fill(dst, dst_size); - EXPECT_TRUE(Valid(dst, dst_size)); - if (dst != NULL) free(dst); - } - } - - // Now make sure realloc works correctly even when we overflow the - // packed cache, so some entries are evicted from the cache. - // The cache has 2^12 entries, keyed by page number. - const int kNumEntries = 1 << 14; - int** p = reinterpret_cast(malloc(sizeof(*p) * kNumEntries)); - int sum = 0; - for (int i = 0; i < kNumEntries; i++) { - // no page size is likely to be bigger than 8192? - p[i] = reinterpret_cast(malloc(8192)); - p[i][1000] = i; // use memory deep in the heart of p - } - for (int i = 0; i < kNumEntries; i++) { - p[i] = reinterpret_cast(realloc(p[i], 9000)); - } - for (int i = 0; i < kNumEntries; i++) { - sum += p[i][1000]; - free(p[i]); - } - EXPECT_EQ(kNumEntries/2 * (kNumEntries - 1), sum); // assume kNE is even - free(p); -} - -TEST(Allocators, ReallocZero) { - // Test that realloc to zero does not return NULL. - for (int size = 0; size >= 0; size = NextSize(size)) { - char* ptr = reinterpret_cast(malloc(size)); - EXPECT_NE(static_cast(NULL), ptr); - ptr = reinterpret_cast(realloc(ptr, 0)); - EXPECT_NE(static_cast(NULL), ptr); - if (ptr) - free(ptr); - } -} - -#ifdef WIN32 -// Test recalloc -TEST(Allocators, Recalloc) { - for (int src_size = 0; src_size >= 0; src_size = NextSize(src_size)) { - for (int dst_size = 0; dst_size >= 0; dst_size = NextSize(dst_size)) { - unsigned char* src = - reinterpret_cast(_recalloc(NULL, 1, src_size)); - EXPECT_TRUE(IsZeroed(src, src_size)); - Fill(src, src_size); - unsigned char* dst = - reinterpret_cast(_recalloc(src, 1, dst_size)); - EXPECT_TRUE(Valid(dst, min(src_size, dst_size))); - Fill(dst, dst_size); - EXPECT_TRUE(Valid(dst, dst_size)); - if (dst != NULL) - free(dst); - } - } -} - -// Test windows specific _aligned_malloc() and _aligned_free() methods. -TEST(Allocators, AlignedMalloc) { - // Try allocating data with a bunch of alignments and sizes - static const int kTestAlignments[] = {8, 16, 256, 4096, 8192, 16384}; - for (int size = 1; size > 0; size = NextSize(size)) { - for (int i = 0; i < ARRAYSIZE(kTestAlignments); ++i) { - unsigned char* ptr = static_cast( - _aligned_malloc(size, kTestAlignments[i])); - CheckAlignment(ptr, kTestAlignments[i]); - Fill(ptr, size); - EXPECT_TRUE(Valid(ptr, size)); - - // Make a second allocation of the same size and alignment to prevent - // allocators from passing this test by accident. Per jar, tcmalloc - // provides allocations for new (never before seen) sizes out of a thread - // local heap of a given "size class." Each time the test requests a new - // size, it will usually get the first element of a span, which is a - // 4K aligned allocation. - unsigned char* ptr2 = static_cast( - _aligned_malloc(size, kTestAlignments[i])); - CheckAlignment(ptr2, kTestAlignments[i]); - Fill(ptr2, size); - EXPECT_TRUE(Valid(ptr2, size)); - - // Should never happen, but sanity check just in case. - ASSERT_NE(ptr, ptr2); - _aligned_free(ptr); - _aligned_free(ptr2); - } - } -} - -#endif - - -int main(int argc, char** argv) { - testing::InitGoogleTest(&argc, argv); - return RUN_ALL_TESTS(); -} diff --git a/base/allocator/debugallocation_shim.cc b/base/allocator/debugallocation_shim.cc deleted file mode 100644 index d1cf52a23e..0000000000 --- a/base/allocator/debugallocation_shim.cc +++ /dev/null @@ -1,9 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#if defined(TCMALLOC_FOR_DEBUGALLOCATION) -#include "third_party/tcmalloc/chromium/src/debugallocation.cc" -#else -#include "third_party/tcmalloc/chromium/src/tcmalloc.cc" -#endif diff --git a/base/allocator/generic_allocators.cc b/base/allocator/generic_allocators.cc deleted file mode 100644 index d4cf19e952..0000000000 --- a/base/allocator/generic_allocators.cc +++ /dev/null @@ -1,168 +0,0 @@ -// Copyright (c) 2009 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -// When possible, we implement allocator functions on top of the basic -// low-level functions malloc() and free(). This way, including a new -// allocator is as simple as providing just a small interface. -// -// As such, this file should not contain any allocator-specific code. - -// Implement a C++ style allocation, which always calls the new_handler -// on failure. -inline void* generic_cpp_alloc(size_t size, bool nothrow) { - void* ptr; - for (;;) { - ptr = malloc(size); - if (ptr) - return ptr; - if (!call_new_handler(nothrow)) - break; - } - return ptr; -} - -extern "C++" { - -void* __cdecl operator new(size_t size) { - return generic_cpp_alloc(size, false); -} - -void operator delete(void* p) __THROW { - free(p); -} - -void* operator new[](size_t size) { - return generic_cpp_alloc(size, false); -} - -void operator delete[](void* p) __THROW { - free(p); -} - -void* operator new(size_t size, const std::nothrow_t& nt) __THROW { - return generic_cpp_alloc(size, true); -} - -void* operator new[](size_t size, const std::nothrow_t& nt) __THROW { - return generic_cpp_alloc(size, true); -} - -// This function behaves similarly to MSVC's _set_new_mode. -// If flag is 0 (default), calls to malloc will behave normally. -// If flag is 1, calls to malloc will behave like calls to new, -// and the std_new_handler will be invoked on failure. -// Returns the previous mode. -int _set_new_mode(int flag) __THROW { - int old_mode = new_mode; - new_mode = flag; - return old_mode; -} - -} // extern "C++" - -extern "C" { - -void* calloc(size_t n, size_t elem_size) __THROW { - // Overflow check - const size_t size = n * elem_size; - if (elem_size != 0 && size / elem_size != n) return NULL; - - void* result = malloc(size); - if (result != NULL) { - memset(result, 0, size); - } - return result; -} - -void cfree(void* p) __THROW { - free(p); -} - -#ifdef WIN32 - -void* _recalloc(void* p, size_t n, size_t elem_size) { - if (!p) - return calloc(n, elem_size); - - // This API is a bit odd. - // Note: recalloc only guarantees zeroed memory when p is NULL. - // Generally, calls to malloc() have padding. So a request - // to malloc N bytes actually malloc's N+x bytes. Later, if - // that buffer is passed to recalloc, we don't know what N - // was anymore. We only know what N+x is. As such, there is - // no way to know what to zero out. - const size_t size = n * elem_size; - if (elem_size != 0 && size / elem_size != n) return NULL; - return realloc(p, size); -} - -void* _calloc_impl(size_t n, size_t size) { - return calloc(n, size); -} - -#ifndef NDEBUG -#undef malloc -#undef free -#undef calloc - -static int error_handler(int reportType) { - switch (reportType) { - case 0: // _CRT_WARN - __debugbreak(); - return 0; - - case 1: // _CRT_ERROR - __debugbreak(); - return 0; - - case 2: // _CRT_ASSERT - __debugbreak(); - return 0; - } - char* p = NULL; - *p = '\0'; - return 0; -} - -int _CrtDbgReport(int reportType, - const char*, - int, const char*, - const char*, - ...) { - return error_handler(reportType); -} - -int _CrtDbgReportW(int reportType, - const wchar_t*, - int, const wchar_t*, - const wchar_t*, - ...) { - return error_handler(reportType); -} - -int _CrtSetReportMode(int, int) { - return 0; -} - -void* _malloc_dbg(size_t size, int , const char*, int) { - return malloc(size); -} - -void* _realloc_dbg(void* ptr, size_t size, int, const char*, int) { - return realloc(ptr, size); -} - -void _free_dbg(void* ptr, int) { - free(ptr); -} - -void* _calloc_dbg(size_t n, size_t size, int, const char*, int) { - return calloc(n, size); -} -#endif // NDEBUG - -#endif // WIN32 - -} // extern C - diff --git a/base/allocator/prep_libc.py b/base/allocator/prep_libc.py deleted file mode 100755 index e13e9e3b7e..0000000000 --- a/base/allocator/prep_libc.py +++ /dev/null @@ -1,67 +0,0 @@ -#!/usr/bin/env python - -# Copyright (c) 2012 The Chromium Authors. All rights reserved. -# Use of this source code is governed by a BSD-style license that can be -# found in the LICENSE file. -# -# This script takes libcmt.lib for VS2005/08/10 and removes the allocation -# related functions from it. -# -# Usage: prep_libc.py -# -# VCLibDir is the path where VC is installed, something like: -# C:\Program Files\Microsoft Visual Studio 8\VC\lib -# OutputDir is the directory where the modified libcmt file should be stored. -# arch is either 'ia32' or 'x64' - -import os -import shutil -import subprocess -import sys - -def run(command, filter=None): - """Run |command|, removing any lines that match |filter|. The filter is - to remove the echoing of input filename that 'lib' does.""" - popen = subprocess.Popen( - command, stdout=subprocess.PIPE, stderr=subprocess.STDOUT) - out, _ = popen.communicate() - for line in out.splitlines(): - if filter and line.strip() != filter: - print line - return popen.returncode - -def main(): - bindir = 'SELF_X86' - objdir = 'INTEL' - vs_install_dir = sys.argv[1] - outdir = sys.argv[2] - if "x64" in sys.argv[3]: - bindir = 'SELF_64_amd64' - objdir = 'amd64' - vs_install_dir = os.path.join(vs_install_dir, 'amd64') - output_lib = os.path.join(outdir, 'libcmt.lib') - shutil.copyfile(os.path.join(vs_install_dir, 'libcmt.lib'), output_lib) - shutil.copyfile(os.path.join(vs_install_dir, 'libcmt.pdb'), - os.path.join(outdir, 'libcmt.pdb')) - - vspaths = [ - 'build\\intel\\mt_obj\\', - 'f:\\dd\\vctools\\crt_bld\\' + bindir + \ - '\\crt\\src\\build\\' + objdir + '\\mt_obj\\', - 'F:\\dd\\vctools\\crt_bld\\' + bindir + \ - '\\crt\\src\\build\\' + objdir + '\\mt_obj\\nativec\\\\', - 'F:\\dd\\vctools\\crt_bld\\' + bindir + \ - '\\crt\\src\\build\\' + objdir + '\\mt_obj\\nativecpp\\\\' ] - - objfiles = ['malloc', 'free', 'realloc', 'new', 'delete', 'new2', 'delete2', - 'align', 'msize', 'heapinit', 'expand', 'heapchk', 'heapwalk', - 'heapmin', 'sbheap', 'calloc', 'recalloc', 'calloc_impl', - 'new_mode', 'newopnt', 'newaopnt'] - for obj in objfiles: - for vspath in vspaths: - cmd = ('lib /nologo /ignore:4006,4014,4221 /remove:%s%s.obj %s' % - (vspath, obj, output_lib)) - run(cmd, obj + '.obj') - -if __name__ == "__main__": - sys.exit(main()) diff --git a/base/allocator/tcmalloc_unittest.cc b/base/allocator/tcmalloc_unittest.cc deleted file mode 100644 index 053a9d50d7..0000000000 --- a/base/allocator/tcmalloc_unittest.cc +++ /dev/null @@ -1,81 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. -#include -#include "base/allocator/allocator_shim.h" - -#include "testing/gtest/include/gtest/gtest.h" - -// TCMalloc header files -#include "common.h" // For TCMalloc constants like page size, etc. - -using base::allocator::TCMallocDoMallocForTest; -using base::allocator::TCMallocDoFreeForTest; -using base::allocator::ExcludeSpaceForMarkForTest; - -TEST(TCMallocFreeCheck, BadPointerInFirstPageOfTheLargeObject) { - char* p = reinterpret_cast( - TCMallocDoMallocForTest(ExcludeSpaceForMarkForTest(kMaxSize + 1))); - for (int offset = 1; offset < kPageSize ; offset <<= 1) { - ASSERT_DEATH(TCMallocDoFreeForTest(p + offset), - "Pointer is not pointing to the start of a span"); - } -} - -TEST(TCMallocFreeCheck, BadPageAlignedPointerInsideLargeObject) { - char* p = reinterpret_cast( - TCMallocDoMallocForTest(ExcludeSpaceForMarkForTest(kMaxSize + 1))); - - for (int offset = kPageSize; offset < kMaxSize; offset += kPageSize) { - // Only the first and last page of a span are in heap map. So for others - // tcmalloc will give a general error of invalid pointer. - ASSERT_DEATH(TCMallocDoFreeForTest(p + offset), - "Attempt to free invalid pointer"); - } - ASSERT_DEATH(TCMallocDoFreeForTest(p + kMaxSize), - "Pointer is not pointing to the start of a span"); -} - -TEST(TCMallocFreeCheck, DoubleFreeLargeObject) { - char* p = reinterpret_cast( - TCMallocDoMallocForTest(ExcludeSpaceForMarkForTest(kMaxSize + 1))); - ASSERT_DEATH(TCMallocDoFreeForTest(p); TCMallocDoFreeForTest(p), - "Object was not in-use"); -} - - -#ifdef NDEBUG -TEST(TCMallocFreeCheck, DoubleFreeSmallObject) { - for (size_t size = 1; - size <= ExcludeSpaceForMarkForTest(kMaxSize); - size <<= 1) { - char* p = reinterpret_cast(TCMallocDoMallocForTest(size)); - ASSERT_DEATH(TCMallocDoFreeForTest(p); TCMallocDoFreeForTest(p), - "Circular loop in list detected"); - } -} -#else -TEST(TCMallocFreeCheck, DoubleFreeSmallObject) { - size_t size = 1; - - // When the object is small, tcmalloc validation can not distinguish normal - // memory corruption or double free, because there's not enough space in - // freed objects to keep the mark. - for (; size <= ExcludeSpaceForMarkForTest(kMinClassSize); size <<= 1) { - char* p = reinterpret_cast(TCMallocDoMallocForTest(size)); - ASSERT_DEATH(TCMallocDoFreeForTest(p); TCMallocDoFreeForTest(p), - "Memory corrupted"); - } - - for (; size <= ExcludeSpaceForMarkForTest(kMaxSize); size <<= 1) { - char* p = reinterpret_cast(TCMallocDoMallocForTest(size)); - ASSERT_DEATH(TCMallocDoFreeForTest(p); TCMallocDoFreeForTest(p), - "Attempt to double free"); - } -} -#endif - -int main(int argc, char **argv) { - testing::InitGoogleTest(&argc, argv); - return RUN_ALL_TESTS(); -} diff --git a/base/allocator/type_profiler.cc b/base/allocator/type_profiler.cc deleted file mode 100644 index 635fbcf5ed..0000000000 --- a/base/allocator/type_profiler.cc +++ /dev/null @@ -1,63 +0,0 @@ -// Copyright 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#if defined(TYPE_PROFILING) - -#include "base/allocator/type_profiler.h" - -#include - -namespace { - -void* NopIntercept(void* ptr, size_t size, const std::type_info& type) { - return ptr; -} - -base::type_profiler::InterceptFunction* g_new_intercept = NopIntercept; -base::type_profiler::InterceptFunction* g_delete_intercept = NopIntercept; - -} - -void* __op_new_intercept__(void* ptr, - size_t size, - const std::type_info& type) { - return g_new_intercept(ptr, size, type); -} - -void* __op_delete_intercept__(void* ptr, - size_t size, - const std::type_info& type) { - return g_delete_intercept(ptr, size, type); -} - -namespace base { -namespace type_profiler { - -// static -void InterceptFunctions::SetFunctions(InterceptFunction* new_intercept, - InterceptFunction* delete_intercept) { - // Don't use DCHECK, as this file is injected into targets - // that do not and should not depend on base/base.gyp:base - assert(g_new_intercept == NopIntercept); - assert(g_delete_intercept == NopIntercept); - - g_new_intercept = new_intercept; - g_delete_intercept = delete_intercept; -} - -// static -void InterceptFunctions::ResetFunctions() { - g_new_intercept = NopIntercept; - g_delete_intercept = NopIntercept; -} - -// static -bool InterceptFunctions::IsAvailable() { - return g_new_intercept != NopIntercept || g_delete_intercept != NopIntercept; -} - -} // namespace type_profiler -} // namespace base - -#endif // defined(TYPE_PROFILING) diff --git a/base/allocator/type_profiler.h b/base/allocator/type_profiler.h deleted file mode 100644 index 86b5711a9d..0000000000 --- a/base/allocator/type_profiler.h +++ /dev/null @@ -1,40 +0,0 @@ -// Copyright 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef BASE_ALLOCATOR_TYPE_PROFILER_H_ -#define BASE_ALLOCATOR_TYPE_PROFILER_H_ - -#if defined(TYPE_PROFILING) - -#include // for size_t -#include // for std::typeinfo - -namespace base { -namespace type_profiler { - -typedef void* InterceptFunction(void*, size_t, const std::type_info&); - -class InterceptFunctions { - public: - // It must be called only once in a process while it is in single-thread. - // For now, ContentMainRunnerImpl::Initialize is the only supposed caller - // of this function except for single-threaded unit tests. - static void SetFunctions(InterceptFunction* new_intercept, - InterceptFunction* delete_intercept); - - private: - friend class TypeProfilerTest; - - // These functions are not thread safe. - // They must be used only from single-threaded unit tests. - static void ResetFunctions(); - static bool IsAvailable(); -}; - -} // namespace type_profiler -} // namespace base - -#endif // defined(TYPE_PROFILING) - -#endif // BASE_ALLOCATOR_TYPE_PROFILER_H_ diff --git a/base/allocator/type_profiler_control.cc b/base/allocator/type_profiler_control.cc deleted file mode 100644 index 6be79840ed..0000000000 --- a/base/allocator/type_profiler_control.cc +++ /dev/null @@ -1,38 +0,0 @@ -// Copyright 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "base/allocator/type_profiler_control.h" - -namespace base { -namespace type_profiler { - -namespace { - -#if defined(TYPE_PROFILING) -const bool kTypeProfilingEnabled = true; -#else -const bool kTypeProfilingEnabled = false; -#endif - -bool g_enable_intercept = kTypeProfilingEnabled; - -} // namespace - -// static -void Controller::Stop() { - g_enable_intercept = false; -} - -// static -bool Controller::IsProfiling() { - return kTypeProfilingEnabled && g_enable_intercept; -} - -// static -void Controller::Restart() { - g_enable_intercept = kTypeProfilingEnabled; -} - -} // namespace type_profiler -} // namespace base diff --git a/base/allocator/type_profiler_control.h b/base/allocator/type_profiler_control.h deleted file mode 100644 index 17cf5b65e4..0000000000 --- a/base/allocator/type_profiler_control.h +++ /dev/null @@ -1,31 +0,0 @@ -// Copyright 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef BASE_ALLOCATOR_TYPE_PROFILER_CONTROL_H_ -#define BASE_ALLOCATOR_TYPE_PROFILER_CONTROL_H_ - -#include "base/gtest_prod_util.h" - -namespace base { -namespace type_profiler { - -class Controller { - public: - static void Stop(); - static bool IsProfiling(); - - private: - FRIEND_TEST_ALL_PREFIXES(TypeProfilerTest, - TestProfileNewWithoutProfiledDelete); - - // It must be used only from allowed unit tests. The following is only - // allowed for use in unit tests. Profiling should never be restarted in - // regular use. - static void Restart(); -}; - -} // namespace type_profiler -} // namespace base - -#endif // BASE_ALLOCATOR_TYPE_PROFILER_CONTROL_H_ diff --git a/base/allocator/type_profiler_map_unittests.cc b/base/allocator/type_profiler_map_unittests.cc deleted file mode 100644 index 5ac5dd0c26..0000000000 --- a/base/allocator/type_profiler_map_unittests.cc +++ /dev/null @@ -1,99 +0,0 @@ -// Copyright 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -// This is a unittest set for type_profiler_map in third_party/tcmalloc. It is -// independent from other tests and executed manually like allocator_unittests -// since type_profiler_map is a singleton (like TCMalloc's heap-profiler), and -// it requires RTTI and different compiling/linking options from others. - -#if defined(TYPE_PROFILING) - -#include "base/memory/scoped_ptr.h" -#include "testing/gtest/include/gtest/gtest.h" -#include "third_party/tcmalloc/chromium/src/gperftools/type_profiler_map.h" - -namespace base { -namespace type_profiler { - -static const void* const g_const_null = static_cast(NULL); - -TEST(TypeProfilerMapTest, NormalOperation) { - // Allocate an object just to get a valid address. - // This 'new' is not profiled by type_profiler. - scoped_ptr dummy(new int(48)); - const std::type_info* type; - - type = LookupType(dummy.get()); - EXPECT_EQ(g_const_null, type); - - InsertType(dummy.get(), 12, typeid(int)); - type = LookupType(dummy.get()); - ASSERT_NE(g_const_null, type); - EXPECT_STREQ(typeid(int).name(), type->name()); - - EraseType(dummy.get()); - type = LookupType(dummy.get()); - EXPECT_EQ(g_const_null, type); -} - -TEST(TypeProfilerMapTest, EraseWithoutInsert) { - scoped_ptr dummy(new int(48)); - const std::type_info* type; - - for (int i = 0; i < 10; ++i) { - EraseType(dummy.get()); - type = LookupType(dummy.get()); - EXPECT_EQ(g_const_null, type); - } -} - -TEST(TypeProfilerMapTest, InsertThenMultipleErase) { - scoped_ptr dummy(new int(48)); - const std::type_info* type; - - InsertType(dummy.get(), 12, typeid(int)); - type = LookupType(dummy.get()); - ASSERT_NE(g_const_null, type); - EXPECT_STREQ(typeid(int).name(), type->name()); - - for (int i = 0; i < 10; ++i) { - EraseType(dummy.get()); - type = LookupType(dummy.get()); - EXPECT_EQ(g_const_null, type); - } -} - -TEST(TypeProfilerMapTest, MultipleInsertWithoutErase) { - scoped_ptr dummy(new int(48)); - const std::type_info* type; - - InsertType(dummy.get(), 12, typeid(int)); - type = LookupType(dummy.get()); - ASSERT_NE(g_const_null, type); - EXPECT_STREQ(typeid(int).name(), type->name()); - - InsertType(dummy.get(), 5, typeid(char)); - type = LookupType(dummy.get()); - ASSERT_NE(g_const_null, type); - EXPECT_STREQ(typeid(char).name(), type->name()); - - InsertType(dummy.get(), 129, typeid(long)); - type = LookupType(dummy.get()); - ASSERT_NE(g_const_null, type); - EXPECT_STREQ(typeid(long).name(), type->name()); - - EraseType(dummy.get()); - type = LookupType(dummy.get()); - EXPECT_EQ(g_const_null, type); -} - -} // namespace type_profiler -} // namespace base - -#endif // defined(TYPE_PROFILING) - -int main(int argc, char** argv) { - testing::InitGoogleTest(&argc, argv); - return RUN_ALL_TESTS(); -} diff --git a/base/allocator/type_profiler_tcmalloc.cc b/base/allocator/type_profiler_tcmalloc.cc deleted file mode 100644 index e5e10e0d12..0000000000 --- a/base/allocator/type_profiler_tcmalloc.cc +++ /dev/null @@ -1,37 +0,0 @@ -// Copyright 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#if defined(TYPE_PROFILING) - -#include "base/allocator/type_profiler_tcmalloc.h" - -#include "base/allocator/type_profiler_control.h" -#include "third_party/tcmalloc/chromium/src/gperftools/heap-profiler.h" -#include "third_party/tcmalloc/chromium/src/gperftools/type_profiler_map.h" - -namespace base { -namespace type_profiler { - -void* NewInterceptForTCMalloc(void* ptr, - size_t size, - const std::type_info& type) { - if (Controller::IsProfiling()) - InsertType(ptr, size, type); - - return ptr; -} - -void* DeleteInterceptForTCMalloc(void* ptr, - size_t size, - const std::type_info& type) { - if (Controller::IsProfiling()) - EraseType(ptr); - - return ptr; -} - -} // namespace type_profiler -} // namespace base - -#endif // defined(TYPE_PROFILING) diff --git a/base/allocator/type_profiler_tcmalloc.h b/base/allocator/type_profiler_tcmalloc.h deleted file mode 100644 index ac55995c82..0000000000 --- a/base/allocator/type_profiler_tcmalloc.h +++ /dev/null @@ -1,29 +0,0 @@ -// Copyright 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef BASE_ALLOCATOR_TYPE_PROFILER_TCMALLOC_H_ -#define BASE_ALLOCATOR_TYPE_PROFILER_TCMALLOC_H_ - -#if defined(TYPE_PROFILING) - -#include // for size_t -#include // for std::type_info - -namespace base { -namespace type_profiler { - -void* NewInterceptForTCMalloc(void* ptr, - size_t size, - const std::type_info& type); - -void* DeleteInterceptForTCMalloc(void* ptr, - size_t size, - const std::type_info& type); - -} // namespace type_profiler -} // namespace base - -#endif // defined(TYPE_PROFILING) - -#endif // BASE_ALLOCATOR_TYPE_PROFILER_TCMALLOC_H_ diff --git a/base/allocator/type_profiler_unittests.cc b/base/allocator/type_profiler_unittests.cc deleted file mode 100644 index e8f06eddd6..0000000000 --- a/base/allocator/type_profiler_unittests.cc +++ /dev/null @@ -1,189 +0,0 @@ -// Copyright 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -// This is a unittest set for type_profiler. It is independent from other -// tests and executed manually like allocator_unittests since type_profiler_map -// used in type_profiler is a singleton (like TCMalloc's heap-profiler), and -// it requires RTTI and different compiling/linking options from others -// -// It tests that the profiler doesn't fail in suspicous cases. For example, -// 'new' is not profiled, but 'delete' for the created object is profiled. - -#if defined(TYPE_PROFILING) - -#include "base/allocator/type_profiler.h" -#include "base/allocator/type_profiler_control.h" -#include "base/allocator/type_profiler_tcmalloc.h" -#include "base/basictypes.h" -#include "testing/gtest/include/gtest/gtest.h" -#include "third_party/tcmalloc/chromium/src/gperftools/type_profiler_map.h" - -namespace base { -namespace type_profiler { - -class TypeProfilerTest : public testing::Test { - public: - TypeProfilerTest() {} - - void SetInterceptFunctions() { - InterceptFunctions::SetFunctions(NewInterceptForTCMalloc, - DeleteInterceptForTCMalloc); - } - - void ResetInterceptFunctions() { - InterceptFunctions::ResetFunctions(); - } - - void SetUp() { - SetInterceptFunctions(); - } - - void TearDown() { - ResetInterceptFunctions(); - } - - protected: - static const size_t kDummyArraySize; - static const void* const kConstNull; - - private: - DISALLOW_COPY_AND_ASSIGN(TypeProfilerTest); -}; - -const size_t TypeProfilerTest::kDummyArraySize = 10; -const void* const TypeProfilerTest::kConstNull = static_cast(NULL); - -TEST_F(TypeProfilerTest, TestNormalProfiling) { - int* dummy = new int(48); - const std::type_info* type; - - type = LookupType(dummy); - ASSERT_NE(kConstNull, type); - EXPECT_STREQ(typeid(int).name(), type->name()); - delete dummy; - - type = LookupType(dummy); - EXPECT_EQ(kConstNull, type); -} - -TEST_F(TypeProfilerTest, TestNormalArrayProfiling) { - int* dummy = new int[kDummyArraySize]; - const std::type_info* type; - - type = LookupType(dummy); - ASSERT_NE(kConstNull, type); - // For an array, the profiler remembers its base type. - EXPECT_STREQ(typeid(int).name(), type->name()); - delete[] dummy; - - type = LookupType(dummy); - EXPECT_EQ(kConstNull, type); -} - -TEST_F(TypeProfilerTest, TestRepeatedNewAndDelete) { - int *dummy[kDummyArraySize]; - const std::type_info* type; - for (int i = 0; i < kDummyArraySize; ++i) - dummy[i] = new int(i); - - for (int i = 0; i < kDummyArraySize; ++i) { - type = LookupType(dummy[i]); - ASSERT_NE(kConstNull, type); - EXPECT_STREQ(typeid(int).name(), type->name()); - } - - for (int i = 0; i < kDummyArraySize; ++i) { - delete dummy[i]; - type = LookupType(dummy[i]); - ASSERT_EQ(kConstNull, type); - } -} - -TEST_F(TypeProfilerTest, TestMultipleNewWithDroppingDelete) { - static const size_t large_size = 256 * 1024; - - char* dummy_char = new char[large_size / sizeof(*dummy_char)]; - const std::type_info* type; - - type = LookupType(dummy_char); - ASSERT_NE(kConstNull, type); - EXPECT_STREQ(typeid(char).name(), type->name()); - - // Call "::operator delete" directly to drop __op_delete_intercept__. - ::operator delete[](dummy_char); - - type = LookupType(dummy_char); - ASSERT_NE(kConstNull, type); - EXPECT_STREQ(typeid(char).name(), type->name()); - - // Allocates a little different size. - int* dummy_int = new int[large_size / sizeof(*dummy_int) - 1]; - - // We expect that tcmalloc returns the same address for these large (over 32k) - // allocation calls. It usually happens, but maybe probablistic. - ASSERT_EQ(static_cast(dummy_char), static_cast(dummy_int)) << - "two new (malloc) calls didn't return the same address; retry it."; - - type = LookupType(dummy_int); - ASSERT_NE(kConstNull, type); - EXPECT_STREQ(typeid(int).name(), type->name()); - - delete[] dummy_int; - - type = LookupType(dummy_int); - EXPECT_EQ(kConstNull, type); -} - -TEST_F(TypeProfilerTest, TestProfileDeleteWithoutProfiledNew) { - // 'dummy' should be new'ed in this test before intercept functions are set. - ResetInterceptFunctions(); - - int* dummy = new int(48); - const std::type_info* type; - - // Set intercept functions again after 'dummy' is new'ed. - SetInterceptFunctions(); - - delete dummy; - - type = LookupType(dummy); - EXPECT_EQ(kConstNull, type); - - ResetInterceptFunctions(); -} - -TEST_F(TypeProfilerTest, TestProfileNewWithoutProfiledDelete) { - int* dummy = new int(48); - const std::type_info* type; - - EXPECT_TRUE(Controller::IsProfiling()); - - // Stop profiling before deleting 'dummy'. - Controller::Stop(); - EXPECT_FALSE(Controller::IsProfiling()); - - delete dummy; - - // NOTE: We accept that a profile entry remains when a profiled object is - // deleted after Controller::Stop(). - type = LookupType(dummy); - ASSERT_NE(kConstNull, type); - EXPECT_STREQ(typeid(int).name(), type->name()); - - Controller::Restart(); - EXPECT_TRUE(Controller::IsProfiling()); - - // Remove manually since 'dummy' is not removed from type_profiler_map. - EraseType(dummy); -} - -} // namespace type_profiler -} // namespace base - -#endif // defined(TYPE_PROFILING) - -int main(int argc, char** argv) { - testing::InitGoogleTest(&argc, argv); - return RUN_ALL_TESTS(); -} diff --git a/base/allocator/unittest_utils.cc b/base/allocator/unittest_utils.cc deleted file mode 100644 index 130ba15f53..0000000000 --- a/base/allocator/unittest_utils.cc +++ /dev/null @@ -1,18 +0,0 @@ -// Copyright (c) 2009 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -// The unittests need a this in order to link up without pulling in tons -// of other libraries - -#include - -inline int snprintf(char* buffer, size_t count, const char* format, ...) { - int result; - va_list args; - va_start(args, format); - result = _vsnprintf(buffer, count, format, args); - va_end(args); - return result; -} - diff --git a/base/allocator/win_allocator.cc b/base/allocator/win_allocator.cc deleted file mode 100644 index 899b867d11..0000000000 --- a/base/allocator/win_allocator.cc +++ /dev/null @@ -1,73 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -// This is a simple allocator based on the windows heap. - -extern "C" { - -HANDLE win_heap; - -bool win_heap_init(bool use_lfh) { - win_heap = HeapCreate(0, 0, 0); - if (win_heap == NULL) - return false; - - if (use_lfh) { - ULONG enable_lfh = 2; - HeapSetInformation(win_heap, HeapCompatibilityInformation, - &enable_lfh, sizeof(enable_lfh)); - // NOTE: Setting LFH may fail. Vista already has it enabled. - // And under the debugger, it won't use LFH. So we - // ignore any errors. - } - - return true; -} - -void* win_heap_malloc(size_t size) { - return HeapAlloc(win_heap, 0, size); -} - -void win_heap_free(void* size) { - HeapFree(win_heap, 0, size); -} - -void* win_heap_realloc(void* ptr, size_t size) { - if (!ptr) - return win_heap_malloc(size); - if (!size) { - win_heap_free(ptr); - return NULL; - } - return HeapReAlloc(win_heap, 0, ptr, size); -} - -size_t win_heap_msize(void* ptr) { - return HeapSize(win_heap, 0, ptr); -} - -void* win_heap_memalign(size_t alignment, size_t size) { - // Reserve enough space to ensure we can align and set aligned_ptr[-1] to the - // original allocation for use with win_heap_memalign_free() later. - size_t allocation_size = size + (alignment - 1) + sizeof(void*); - - // Check for overflow. Alignment and size are checked in allocator_shim. - DCHECK_LT(size, allocation_size); - DCHECK_LT(alignment, allocation_size); - - void* ptr = win_heap_malloc(allocation_size); - char* aligned_ptr = static_cast(ptr) + sizeof(void*); - aligned_ptr += - alignment - reinterpret_cast(aligned_ptr) & (alignment - 1); - - reinterpret_cast(aligned_ptr)[-1] = ptr; - return aligned_ptr; -} - -void win_heap_memalign_free(void* ptr) { - if (ptr) - win_heap_free(static_cast(ptr)[-1]); -} - -} // extern "C" diff --git a/base/android/OWNERS b/base/android/OWNERS deleted file mode 100644 index ebc6e2624f..0000000000 --- a/base/android/OWNERS +++ /dev/null @@ -1,3 +0,0 @@ -bulach@chromium.org -joth@chromium.org -yfriedman@chromium.org diff --git a/base/android/activity_state_list.h b/base/android/activity_state_list.h deleted file mode 100644 index 43c0f803da..0000000000 --- a/base/android/activity_state_list.h +++ /dev/null @@ -1,16 +0,0 @@ -// Copyright (c) 2013 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -// This file intentionally does not have header guards, it's included -// inside a macro to generate enum values. - -#ifndef DEFINE_ACTIVITY_STATE -#error "DEFINE_ACTIVITY_STATE should be defined before including this file" -#endif -DEFINE_ACTIVITY_STATE(CREATED, 1) -DEFINE_ACTIVITY_STATE(STARTED, 2) -DEFINE_ACTIVITY_STATE(RESUMED, 3) -DEFINE_ACTIVITY_STATE(PAUSED, 4) -DEFINE_ACTIVITY_STATE(STOPPED, 5) -DEFINE_ACTIVITY_STATE(DESTROYED, 6) diff --git a/base/android/activity_status.cc b/base/android/activity_status.cc deleted file mode 100644 index 4d0be32ef9..0000000000 --- a/base/android/activity_status.cc +++ /dev/null @@ -1,66 +0,0 @@ -// Copyright 2013 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "base/android/activity_status.h" - -#include - -#include "base/memory/singleton.h" -#include "jni/ActivityStatus_jni.h" - -namespace base { -namespace android { - -ActivityStatus::Listener::Listener( - const ActivityStatus::StateChangeCallback& callback) - : callback_(callback) { - ActivityStatus::GetInstance()->RegisterListener(this); -} - -ActivityStatus::Listener::~Listener() { - ActivityStatus::GetInstance()->UnregisterListener(this); -} - -void ActivityStatus::Listener::Notify(ActivityState state) { - callback_.Run(state); -} - -// static -ActivityStatus* ActivityStatus::GetInstance() { - return Singleton >::get(); -} - -static void OnActivityStateChange(JNIEnv* env, jclass clazz, int new_state) { - ActivityStatus* activity_status = ActivityStatus::GetInstance(); - ActivityState activity_state = static_cast(new_state); - activity_status->OnActivityStateChange(activity_state); -} - -bool ActivityStatus::RegisterBindings(JNIEnv* env) { - return RegisterNativesImpl(env); -} - -ActivityStatus::ActivityStatus() - : observers_(new ObserverListThreadSafe()) { - Java_ActivityStatus_registerThreadSafeNativeStateListener( - base::android::AttachCurrentThread()); -} - -ActivityStatus::~ActivityStatus() {} - -void ActivityStatus::RegisterListener(Listener* listener) { - observers_->AddObserver(listener); -} - -void ActivityStatus::UnregisterListener(Listener* listener) { - observers_->RemoveObserver(listener); -} - -void ActivityStatus::OnActivityStateChange(ActivityState new_state) { - observers_->Notify(&ActivityStatus::Listener::Notify, new_state); -} - -} // namespace android -} // namespace base diff --git a/base/android/activity_status.h b/base/android/activity_status.h deleted file mode 100644 index 7975a789cd..0000000000 --- a/base/android/activity_status.h +++ /dev/null @@ -1,98 +0,0 @@ -// Copyright 2013 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef BASE_ANDROID_ACTIVITY_STATUS_H_ -#define BASE_ANDROID_ACTIVITY_STATUS_H_ - -#include - -#include "base/android/jni_android.h" -#include "base/base_export.h" -#include "base/basictypes.h" -#include "base/memory/ref_counted.h" -#include "base/memory/singleton.h" -#include "base/observer_list_threadsafe.h" - -namespace base { -namespace android { - -// Define activity state values like ACTIVITY_STATE_CREATED in a -// way that ensures they're always the same than their Java counterpart. -enum ActivityState { -#define DEFINE_ACTIVITY_STATE(x, y) ACTIVITY_STATE_##x = y, -#include "base/android/activity_state_list.h" -#undef DEFINE_ACTIVITY_STATE -}; - -// A native helper class to listen to state changes of the current -// Android Activity. This mirrors org.chromium.base.ActivityStatus. -// any thread. -// -// To start listening, create a new instance, passing a callback to a -// function that takes an ActivityState parameter. To stop listening, -// simply delete the listener object. The implementation guarantees -// that the callback will always be called on the thread that created -// the listener. -// -// Example: -// -// void OnActivityStateChange(ActivityState state) { -// ... -// } -// -// // Start listening. -// ActivityStatus::Listener* my_listener = -// new ActivityStatus::Listener(base::Bind(&OnActivityStateChange)); -// -// ... -// -// // Stop listening. -// delete my_listener -// -class BASE_EXPORT ActivityStatus { - public: - typedef base::Callback StateChangeCallback; - - class Listener { - public: - explicit Listener(const StateChangeCallback& callback); - ~Listener(); - - private: - friend class ActivityStatus; - - void Notify(ActivityState state); - - StateChangeCallback callback_; - - DISALLOW_COPY_AND_ASSIGN(Listener); - }; - - // NOTE: The Java ActivityStatus is a singleton too. - static ActivityStatus* GetInstance(); - - // Internal use: must be public to be called from base_jni_registrar.cc - static bool RegisterBindings(JNIEnv* env); - - // Internal use only: must be public to be called from JNI and unit tests. - void OnActivityStateChange(ActivityState new_state); - - private: - friend struct DefaultSingletonTraits; - - ActivityStatus(); - ~ActivityStatus(); - - void RegisterListener(Listener* listener); - void UnregisterListener(Listener* listener); - - scoped_refptr > observers_; - - DISALLOW_COPY_AND_ASSIGN(ActivityStatus); -}; - -} // namespace android -} // namespace base - -#endif // BASE_ANDROID_ACTIVITY_STATUS_H_ diff --git a/base/android/activity_status_unittest.cc b/base/android/activity_status_unittest.cc deleted file mode 100644 index 3eb0d10f73..0000000000 --- a/base/android/activity_status_unittest.cc +++ /dev/null @@ -1,128 +0,0 @@ -// Copyright 2013 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "base/android/activity_status.h" -#include "base/bind.h" -#include "base/callback_forward.h" -#include "base/logging.h" -#include "base/memory/scoped_ptr.h" -#include "base/message_loop/message_loop_proxy.h" -#include "base/run_loop.h" -#include "base/synchronization/waitable_event.h" -#include "base/threading/thread.h" -#include "testing/gtest/include/gtest/gtest.h" - -namespace base { -namespace android { - -namespace { - -using base::android::ScopedJavaLocalRef; - -// An invalid ActivityState value. -const ActivityState kInvalidActivityState = static_cast(100); - -// Used to generate a callback that stores the new state at a given location. -void StoreStateTo(ActivityState* target, ActivityState state) { - *target = state; -} - -void RunTasksUntilIdle() { - RunLoop run_loop; - run_loop.RunUntilIdle(); -} - -// Shared state for the multi-threaded test. -// This uses a thread to register for events and listen to them, while state -// changes are forced on the main thread. -class MultiThreadedTest { - public: - MultiThreadedTest() - : activity_status_(ActivityStatus::GetInstance()), - state_(kInvalidActivityState), - event_(false, false), - thread_("ActivityStatusTest thread"), - main_() { - } - - void Run() { - // Start the thread and tell it to register for events. - thread_.Start(); - thread_.message_loop() - ->PostTask(FROM_HERE, - base::Bind(&MultiThreadedTest::RegisterThreadForEvents, - base::Unretained(this))); - - // Wait for its completion. - event_.Wait(); - - // Change state, then wait for the thread to modify state. - activity_status_->OnActivityStateChange(ACTIVITY_STATE_CREATED); - event_.Wait(); - EXPECT_EQ(ACTIVITY_STATE_CREATED, state_); - - // Again - activity_status_->OnActivityStateChange(ACTIVITY_STATE_DESTROYED); - event_.Wait(); - EXPECT_EQ(ACTIVITY_STATE_DESTROYED, state_); - } - - private: - void ExpectOnThread() { - EXPECT_EQ(thread_.message_loop(), base::MessageLoop::current()); - } - - void RegisterThreadForEvents() { - ExpectOnThread(); - listener_.reset(new ActivityStatus::Listener(base::Bind( - &MultiThreadedTest::StoreStateAndSignal, base::Unretained(this)))); - EXPECT_TRUE(listener_.get()); - event_.Signal(); - } - - void StoreStateAndSignal(ActivityState state) { - ExpectOnThread(); - state_ = state; - event_.Signal(); - } - - ActivityStatus* const activity_status_; - ActivityState state_; - base::WaitableEvent event_; - base::Thread thread_; - base::MessageLoop main_; - scoped_ptr listener_; -}; - -} // namespace - -TEST(ActivityStatusTest, SingleThread) { - MessageLoop message_loop; - - ActivityState result = kInvalidActivityState; - - // Create a new listener that stores the new state into |result| on every - // state change. - ActivityStatus::Listener listener( - base::Bind(&StoreStateTo, base::Unretained(&result))); - - EXPECT_EQ(kInvalidActivityState, result); - - ActivityStatus* const activity_status = ActivityStatus::GetInstance(); - activity_status->OnActivityStateChange(ACTIVITY_STATE_CREATED); - RunTasksUntilIdle(); - EXPECT_EQ(ACTIVITY_STATE_CREATED, result); - - activity_status->OnActivityStateChange(ACTIVITY_STATE_DESTROYED); - RunTasksUntilIdle(); - EXPECT_EQ(ACTIVITY_STATE_DESTROYED, result); -} - -TEST(ActivityStatusTest, TwoThreads) { - MultiThreadedTest test; - test.Run(); -} - -} // namespace android -} // namespace base diff --git a/base/android/base_jni_registrar.cc b/base/android/base_jni_registrar.cc deleted file mode 100644 index 0645c73030..0000000000 --- a/base/android/base_jni_registrar.cc +++ /dev/null @@ -1,58 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "base/android/base_jni_registrar.h" - -#include "base/android/activity_status.h" -#include "base/android/build_info.h" -#include "base/android/cpu_features.h" -#include "base/android/important_file_writer_android.h" -#include "base/android/java_handler_thread.h" -#include "base/android/jni_android.h" -#include "base/android/jni_registrar.h" -#include "base/android/memory_pressure_listener_android.h" -#include "base/android/path_service_android.h" -#include "base/android/path_utils.h" -#include "base/android/sys_utils.h" -#include "base/android/thread_utils.h" -#include "base/basictypes.h" -#include "base/debug/trace_event.h" -#include "base/message_loop/message_pump_android.h" -#include "base/power_monitor/power_monitor_device_source_android.h" - -#if defined(GOOGLE_TV) -#include "base/android/context_types.h" -#endif - -namespace base { -namespace android { - -static RegistrationMethod kBaseRegisteredMethods[] = { - { "ActivityStatus", base::android::ActivityStatus::RegisterBindings }, - { "BuildInfo", base::android::BuildInfo::RegisterBindings }, -#if defined(GOOGLE_TV) - { "ContextTypes", base::android::RegisterContextTypes }, -#endif - { "CpuFeatures", base::android::RegisterCpuFeatures }, - { "ImportantFileWriterAndroid", - base::android::RegisterImportantFileWriterAndroid }, - { "MemoryPressureListenerAndroid", - base::android::MemoryPressureListenerAndroid::Register }, - { "JavaHandlerThread", base::android::JavaHandlerThread::RegisterBindings }, - { "PathService", base::android::RegisterPathService }, - { "PathUtils", base::android::RegisterPathUtils }, - { "SystemMessageHandler", base::MessagePumpForUI::RegisterBindings }, - { "SysUtils", base::android::SysUtils::Register }, - { "PowerMonitor", base::RegisterPowerMonitor }, - { "ThreadUtils", base::RegisterThreadUtils }, -}; - -bool RegisterJni(JNIEnv* env) { - TRACE_EVENT0("startup", "base_android::RegisterJni"); - return RegisterNativeMethods(env, kBaseRegisteredMethods, - arraysize(kBaseRegisteredMethods)); -} - -} // namespace android -} // namespace base diff --git a/base/android/base_jni_registrar.h b/base/android/base_jni_registrar.h deleted file mode 100644 index fdaf5f2c6c..0000000000 --- a/base/android/base_jni_registrar.h +++ /dev/null @@ -1,21 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef BASE_ANDROID_BASE_JNI_REGISTRAR_H_ -#define BASE_ANDROID_BASE_JNI_REGISTRAR_H_ - -#include - -#include "base/base_export.h" - -namespace base { -namespace android { - -// Register all JNI bindings necessary for base. -BASE_EXPORT bool RegisterJni(JNIEnv* env); - -} // namespace android -} // namespace base - -#endif // BASE_ANDROID_BASE_JNI_REGISTRAR_H_ diff --git a/base/android/build_info.cc b/base/android/build_info.cc deleted file mode 100644 index cdde6a9005..0000000000 --- a/base/android/build_info.cc +++ /dev/null @@ -1,78 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "base/android/build_info.h" - -#include - -#include "base/android/jni_android.h" -#include "base/android/jni_string.h" -#include "base/android/scoped_java_ref.h" -#include "base/logging.h" -#include "base/memory/singleton.h" -#include "jni/BuildInfo_jni.h" - -namespace { - -// The caller takes ownership of the returned const char*. -const char* StrDupJString(const base::android::JavaRef& java_string) { - std::string str = ConvertJavaStringToUTF8(java_string); - return strdup(str.c_str()); -} - -} // namespace - -namespace base { -namespace android { - -struct BuildInfoSingletonTraits { - static BuildInfo* New() { - return new BuildInfo(AttachCurrentThread()); - } - - static void Delete(BuildInfo* x) { - // We're leaking this type, see kRegisterAtExit. - NOTREACHED(); - } - - static const bool kRegisterAtExit = false; - static const bool kAllowedToAccessOnNonjoinableThread = true; -}; - -BuildInfo::BuildInfo(JNIEnv* env) - : device_(StrDupJString(Java_BuildInfo_getDevice(env))), - model_(StrDupJString(Java_BuildInfo_getDeviceModel(env))), - brand_(StrDupJString(Java_BuildInfo_getBrand(env))), - android_build_id_(StrDupJString(Java_BuildInfo_getAndroidBuildId(env))), - android_build_fp_(StrDupJString( - Java_BuildInfo_getAndroidBuildFingerprint(env))), - package_version_code_(StrDupJString(Java_BuildInfo_getPackageVersionCode( - env, GetApplicationContext()))), - package_version_name_(StrDupJString(Java_BuildInfo_getPackageVersionName( - env, GetApplicationContext()))), - package_label_(StrDupJString(Java_BuildInfo_getPackageLabel( - env, GetApplicationContext()))), - package_name_(StrDupJString(Java_BuildInfo_getPackageName( - env, GetApplicationContext()))), - sdk_int_(Java_BuildInfo_getSdkInt(env)), - java_exception_info_(NULL) { -} - -// static -BuildInfo* BuildInfo::GetInstance() { - return Singleton::get(); -} - -void BuildInfo::set_java_exception_info(const std::string& info) { - DCHECK(!java_exception_info_) << "info should be set only once."; - java_exception_info_ = strndup(info.c_str(), 1024); -} - -// static -bool BuildInfo::RegisterBindings(JNIEnv* env) { - return RegisterNativesImpl(env); -} - -} // namespace android -} // namespace base diff --git a/base/android/build_info.h b/base/android/build_info.h deleted file mode 100644 index a5f44c2e0a..0000000000 --- a/base/android/build_info.h +++ /dev/null @@ -1,115 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef BASE_ANDROID_BUILD_INFO_H_ -#define BASE_ANDROID_BUILD_INFO_H_ - -#include - -#include - -#include "base/base_export.h" -#include "base/memory/singleton.h" - -namespace base { -namespace android { - -// BuildInfo is a singleton class that stores android build and device -// information. It will be called from Android specific code and gets used -// primarily in crash reporting. - -// It is also used to store the last java exception seen during JNI. -// TODO(nileshagrawal): Find a better place to store this info. -class BASE_EXPORT BuildInfo { - public: - - ~BuildInfo() {} - - // Static factory method for getting the singleton BuildInfo instance. - // Note that ownership is not conferred on the caller and the BuildInfo in - // question isn't actually freed until shutdown. This is ok because there - // should only be one instance of BuildInfo ever created. - static BuildInfo* GetInstance(); - - // Const char* is used instead of std::strings because these values must be - // available even if the process is in a crash state. Sadly - // std::string.c_str() doesn't guarantee that memory won't be allocated when - // it is called. - const char* device() const { - return device_; - } - - const char* model() const { - return model_; - } - - const char* brand() const { - return brand_; - } - - const char* android_build_id() const { - return android_build_id_; - } - - const char* android_build_fp() const { - return android_build_fp_; - } - - const char* package_version_code() const { - return package_version_code_; - } - - const char* package_version_name() const { - return package_version_name_; - } - - const char* package_label() const { - return package_label_; - } - - const char* package_name() const { - return package_name_; - } - - int sdk_int() const { - return sdk_int_; - } - - const char* java_exception_info() const { - return java_exception_info_; - } - - void set_java_exception_info(const std::string& info); - - static bool RegisterBindings(JNIEnv* env); - - private: - friend struct BuildInfoSingletonTraits; - - explicit BuildInfo(JNIEnv* env); - - // Const char* is used instead of std::strings because these values must be - // available even if the process is in a crash state. Sadly - // std::string.c_str() doesn't guarantee that memory won't be allocated when - // it is called. - const char* const device_; - const char* const model_; - const char* const brand_; - const char* const android_build_id_; - const char* const android_build_fp_; - const char* const package_version_code_; - const char* const package_version_name_; - const char* const package_label_; - const char* const package_name_; - const int sdk_int_; - // This is set via set_java_exception_info, not at constructor time. - const char* java_exception_info_; - - DISALLOW_COPY_AND_ASSIGN(BuildInfo); -}; - -} // namespace android -} // namespace base - -#endif // BASE_ANDROID_BUILD_INFO_H_ diff --git a/base/android/context_types.cc b/base/android/context_types.cc deleted file mode 100644 index 084b1365ce..0000000000 --- a/base/android/context_types.cc +++ /dev/null @@ -1,26 +0,0 @@ -// Copyright (c) 2013 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "base/android/context_types.h" - -#include "base/android/jni_android.h" -#include "base/android/scoped_java_ref.h" -#include "base/files/file_path.h" -#include "jni/ContextTypes_jni.h" - -namespace base { -namespace android { - -bool IsRunningInWebapp() { - JNIEnv* env = AttachCurrentThread(); - return static_cast( - Java_ContextTypes_isRunningInWebapp(env, GetApplicationContext())); -} - -bool RegisterContextTypes(JNIEnv* env) { - return RegisterNativesImpl(env); -} - -} // namespace android -} // namespace base diff --git a/base/android/context_types.h b/base/android/context_types.h deleted file mode 100644 index a132167199..0000000000 --- a/base/android/context_types.h +++ /dev/null @@ -1,22 +0,0 @@ -// Copyright (c) 2013 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef BASE_ANDROID_CONTEXT_TYPES_H_ -#define BASE_ANDROID_CONTEXT_TYPES_H_ - -#include - -#include "base/base_export.h" - -namespace base { -namespace android { - -BASE_EXPORT bool IsRunningInWebapp(); - -bool RegisterContextTypes(JNIEnv* env); - -} // namespace android -} // namespace base - -#endif // BASE_ANDROID_CONTEXT_TYPES_H_ diff --git a/base/android/cpu_features.cc b/base/android/cpu_features.cc deleted file mode 100644 index 6a1869534b..0000000000 --- a/base/android/cpu_features.cc +++ /dev/null @@ -1,26 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include - -#include "base/android/jni_android.h" -#include "jni/CpuFeatures_jni.h" - -namespace base { -namespace android { - -jint GetCoreCount(JNIEnv*, jclass) { - return android_getCpuCount(); -} - -jlong GetCpuFeatures(JNIEnv*, jclass) { - return android_getCpuFeatures(); -} - -bool RegisterCpuFeatures(JNIEnv* env) { - return RegisterNativesImpl(env); -} - -} // namespace android -} // namespace base diff --git a/base/android/cpu_features.h b/base/android/cpu_features.h deleted file mode 100644 index 0a278228d2..0000000000 --- a/base/android/cpu_features.h +++ /dev/null @@ -1,18 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef BASE_ANDROID_CPU_FEATURES_H_ -#define BASE_ANDROID_CPU_FEATURES_H_ - -#include - -namespace base { -namespace android { - -bool RegisterCpuFeatures(JNIEnv* env); - -} // namespace android -} // namespace base - -#endif // BASE_ANDROID_CPU_FEATURES_H_ diff --git a/base/android/fifo_utils.cc b/base/android/fifo_utils.cc deleted file mode 100644 index 8f3e95f92d..0000000000 --- a/base/android/fifo_utils.cc +++ /dev/null @@ -1,25 +0,0 @@ -// Copyright 2013 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "base/android/fifo_utils.h" - -#include - -#include "base/files/file_path.h" - -namespace base { -namespace android { - -bool CreateFIFO(const FilePath& path, int mode) { - // Default permissions for mkfifo() is ignored, chmod() is required. - return mkfifo(path.value().c_str(), mode) == 0 && - chmod(path.value().c_str(), mode) == 0; -} - -bool RedirectStream(FILE* stream, const FilePath& path, const char* mode) { - return freopen(path.value().c_str(), mode, stream) != NULL; -} - -} // namespace android -} // namespace base diff --git a/base/android/fifo_utils.h b/base/android/fifo_utils.h deleted file mode 100644 index 1936defaf6..0000000000 --- a/base/android/fifo_utils.h +++ /dev/null @@ -1,32 +0,0 @@ -// Copyright 2013 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef BASE_ANDROID_FIFO_UTILS_H_ -#define BASE_ANDROID_FIFO_UTILS_H_ - -#include - -#include "base/base_export.h" -#include "base/basictypes.h" - -namespace base { - -class FilePath; - -namespace android { - -// Creates a fifo at the given |path| with POSIX permissions set to |mode|, -// returning true if it was successfully created and permissions were set. -BASE_EXPORT bool CreateFIFO(const FilePath& path, int mode); - -// Redirects the |stream| to the file provided by |path| with |mode| -// permissions, returning true if successful. -BASE_EXPORT bool RedirectStream(FILE* stream, - const FilePath& path, - const char* mode); - -} // namespace android -} // namespace base - -#endif // BASE_ANDROID_FIFO_UTILS_H_ diff --git a/base/android/important_file_writer_android.cc b/base/android/important_file_writer_android.cc deleted file mode 100644 index bcbd785da0..0000000000 --- a/base/android/important_file_writer_android.cc +++ /dev/null @@ -1,42 +0,0 @@ -// Copyright 2013 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "base/android/important_file_writer_android.h" - -#include - -#include "base/android/jni_string.h" -#include "base/files/important_file_writer.h" -#include "base/threading/thread_restrictions.h" -#include "jni/ImportantFileWriterAndroid_jni.h" - -namespace base { -namespace android { - -static jboolean WriteFileAtomically(JNIEnv* env, - jclass /* clazz */, - jstring file_name, - jbyteArray data) { - // This is called on the UI thread during shutdown to save tab data, so - // needs to enable IO. - base::ThreadRestrictions::ScopedAllowIO allow_io; - std::string native_file_name; - base::android::ConvertJavaStringToUTF8(env, file_name, &native_file_name); - base::FilePath path(native_file_name); - int data_length = env->GetArrayLength(data); - jbyte* native_data = env->GetByteArrayElements(data, NULL); - std::string native_data_string(reinterpret_cast(native_data), - data_length); - bool result = base::ImportantFileWriter::WriteFileAtomically( - path, native_data_string); - env->ReleaseByteArrayElements(data, native_data, JNI_ABORT); - return result; -} - -bool RegisterImportantFileWriterAndroid(JNIEnv* env) { - return RegisterNativesImpl(env); -} - -} // namespace android -} // namespace base diff --git a/base/android/important_file_writer_android.h b/base/android/important_file_writer_android.h deleted file mode 100644 index 20956babce..0000000000 --- a/base/android/important_file_writer_android.h +++ /dev/null @@ -1,18 +0,0 @@ -// Copyright 2013 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef NATIVE_FRAMEWORK_CHROME_IMPORTANT_FILE_WRITE_ANDROID_H_ -#define NATIVE_FRAMEWORK_CHROME_IMPORTANT_FILE_WRITE_ANDROID_H_ - -#include - -namespace base { -namespace android { - -bool RegisterImportantFileWriterAndroid(JNIEnv* env); - -} // namespace android -} // namespace base - -#endif // NATIVE_FRAMEWORK_CHROME_IMPORTANT_FILE_WRITE_ANDROID_H_ diff --git a/base/android/java/src/org/chromium/base/AccessedByNative.java b/base/android/java/src/org/chromium/base/AccessedByNative.java deleted file mode 100644 index 0a73258721..0000000000 --- a/base/android/java/src/org/chromium/base/AccessedByNative.java +++ /dev/null @@ -1,20 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -package org.chromium.base; - -import java.lang.annotation.ElementType; -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; -import java.lang.annotation.Target; - -/** - * @AccessedByNative is used to ensure proguard will keep this field, since it's - * only accessed by native. - */ -@Target(ElementType.FIELD) -@Retention(RetentionPolicy.CLASS) -public @interface AccessedByNative { - public String value() default ""; -} diff --git a/base/android/java/src/org/chromium/base/ActivityState.template b/base/android/java/src/org/chromium/base/ActivityState.template deleted file mode 100644 index adf990a576..0000000000 --- a/base/android/java/src/org/chromium/base/ActivityState.template +++ /dev/null @@ -1,14 +0,0 @@ -// Copyright (c) 2013 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -package org.chromium.base; - -// A simple auto-generated interface used to list the various -// states of an activity as used by both org.chromium.base.ActivityStatus -// and base/android/activity_status.h -interface ActivityState { -#define DEFINE_ACTIVITY_STATE(x,y) public final int x = y; -#include "base/android/activity_state_list.h" -#undef DEFINE_ACTIVITY_STATE -} diff --git a/base/android/java/src/org/chromium/base/ActivityStatus.java b/base/android/java/src/org/chromium/base/ActivityStatus.java deleted file mode 100644 index 47472342b2..0000000000 --- a/base/android/java/src/org/chromium/base/ActivityStatus.java +++ /dev/null @@ -1,136 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -package org.chromium.base; - -import android.app.Activity; -import android.os.Handler; -import android.os.Looper; - -/** - * Provides information about the current activity's status, and a way - * to register / unregister listeners for state changes. - */ -@JNINamespace("base::android") -public class ActivityStatus { - - // Constants matching activity states reported to StateListener.onStateChange - // As an implementation detail, these are now defined in the auto-generated - // ActivityState interface, to be shared with C++. - public static final int CREATED = ActivityState.CREATED; - public static final int STARTED = ActivityState.STARTED; - public static final int RESUMED = ActivityState.RESUMED; - public static final int PAUSED = ActivityState.PAUSED; - public static final int STOPPED = ActivityState.STOPPED; - public static final int DESTROYED = ActivityState.DESTROYED; - - // Current main activity, or null if none. - private static Activity sActivity; - - // Current main activity's state. This can be set even if sActivity is null, to simplify unit - // testing. - private static int sActivityState; - - private static final ObserverList sStateListeners = - new ObserverList(); - - /** - * Interface to be implemented by listeners. - */ - public interface StateListener { - /** - * Called when the activity's state changes. - * @param newState New activity state. - */ - public void onActivityStateChange(int newState); - } - - private ActivityStatus() {} - - /** - * Must be called by the main activity when it changes state. - * @param activity Current activity. - * @param newState New state value. - */ - public static void onStateChange(Activity activity, int newState) { - if (sActivity != activity) { - // ActivityStatus is notified with the CREATED event very late during the main activity - // creation to avoid making startup performance worse than it is by notifying observers - // that could do some expensive work. This can lead to non-CREATED events being fired - // before the CREATED event which is problematic. - // TODO(pliard): fix http://crbug.com/176837. - sActivity = activity; - } - sActivityState = newState; - for (StateListener listener : sStateListeners) { - listener.onActivityStateChange(newState); - } - if (newState == DESTROYED) { - sActivity = null; - } - } - - /** - * Indicates that the parent activity is currently paused. - */ - public static boolean isPaused() { - return sActivityState == PAUSED; - } - - /** - * Returns the current main application activity. - */ - public static Activity getActivity() { - return sActivity; - } - - /** - * Returns the current main application activity's state. - */ - public static int getState() { - return sActivityState; - } - - /** - * Registers the given listener to receive activity state changes. - * @param listener Listener to receive state changes. - */ - public static void registerStateListener(StateListener listener) { - sStateListeners.addObserver(listener); - } - - /** - * Unregisters the given listener from receiving activity state changes. - * @param listener Listener that doesn't want to receive state changes. - */ - public static void unregisterStateListener(StateListener listener) { - sStateListeners.removeObserver(listener); - } - - /** - * Registers the single thread-safe native activity status listener. - * This handles the case where the caller is not on the main thread. - * Note that this is used by a leaky singleton object from the native - * side, hence lifecycle management is greatly simplified. - */ - @CalledByNative - private static void registerThreadSafeNativeStateListener() { - ThreadUtils.runOnUiThread(new Runnable () { - @Override - public void run() { - // Register a new listener that calls nativeOnActivityStateChange. - sStateListeners.addObserver(new StateListener() { - @Override - public void onActivityStateChange(int newState) { - nativeOnActivityStateChange(newState); - } - }); - } - }); - } - - // Called to notify the native side of state changes. - // IMPORTANT: This is always called on the main thread! - private static native void nativeOnActivityStateChange(int newState); -} diff --git a/base/android/java/src/org/chromium/base/ApiCompatibilityUtils.java b/base/android/java/src/org/chromium/base/ApiCompatibilityUtils.java deleted file mode 100644 index 8c4ac0fe01..0000000000 --- a/base/android/java/src/org/chromium/base/ApiCompatibilityUtils.java +++ /dev/null @@ -1,140 +0,0 @@ -// Copyright 2013 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -package org.chromium.base; - -import android.app.Notification; -import android.graphics.drawable.Drawable; -import android.os.Build; -import android.view.View; -import android.view.ViewGroup.MarginLayoutParams; -import android.view.ViewTreeObserver; - -/** - * Utility class to use new APIs that were added after ICS (API level 14). - */ -public class ApiCompatibilityUtils { - - private ApiCompatibilityUtils() { - } - - /** - * Returns true if view's layout direction is right-to-left. - * - * @param view the View whose layout is being considered - */ - public static boolean isLayoutRtl(View view) { - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) { - return view.getLayoutDirection() == View.LAYOUT_DIRECTION_RTL; - } else { - // All layouts are LTR before JB MR1. - return false; - } - } - - /** - * @see android.view.View#setLayoutDirection(int) - */ - public static void setLayoutDirection(View view, int layoutDirection) { - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) { - view.setLayoutDirection(layoutDirection); - } else { - // Do nothing. RTL layouts aren't supported before JB MR1. - } - } - - /** - * @see android.view.ViewGroup.MarginLayoutParams#setMarginEnd(int) - */ - public static void setMarginEnd(MarginLayoutParams layoutParams, int end) { - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) { - layoutParams.setMarginEnd(end); - } else { - layoutParams.rightMargin = end; - } - } - - /** - * @see android.view.ViewGroup.MarginLayoutParams#getMarginEnd() - */ - public static int getMarginEnd(MarginLayoutParams layoutParams) { - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) { - return layoutParams.getMarginEnd(); - } else { - return layoutParams.rightMargin; - } - } - - /** - * @see android.view.ViewGroup.MarginLayoutParams#setMarginStart(int) - */ - public static void setMarginStart(MarginLayoutParams layoutParams, int start) { - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) { - layoutParams.setMarginStart(start); - } else { - layoutParams.leftMargin = start; - } - } - - /** - * @see android.view.ViewGroup.MarginLayoutParams#getMarginStart() - */ - public static int getMarginStart(MarginLayoutParams layoutParams) { - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) { - return layoutParams.getMarginStart(); - } else { - return layoutParams.leftMargin; - } - } - - /** - * @see android.view.View#postInvalidateOnAnimation() - */ - public static void postInvalidateOnAnimation(View view) { - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) { - view.postInvalidateOnAnimation(); - } else { - view.postInvalidate(); - } - } - - // These methods have a new name, and the old name is deprecated. - - /** - * @see android.view.View#setBackground(Drawable) - */ - @SuppressWarnings("deprecation") - public static void setBackgroundForView(View view, Drawable drawable) { - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) { - view.setBackground(drawable); - } else { - view.setBackgroundDrawable(drawable); - } - } - - /** - * @see android.view.ViewTreeObserver#removeOnGlobalLayoutListener() - */ - @SuppressWarnings("deprecation") - public static void removeOnGlobalLayoutListener( - View view, ViewTreeObserver.OnGlobalLayoutListener listener) { - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) { - view.getViewTreeObserver().removeOnGlobalLayoutListener(listener); - } else { - view.getViewTreeObserver().removeGlobalOnLayoutListener(listener); - } - } - - /** - * @see android.app.Notification.Builder#build() - */ - @SuppressWarnings("deprecation") - public static Notification buildNotification(Notification.Builder builder) { - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) { - return builder.build(); - } else { - return builder.getNotification(); - } - } -} diff --git a/base/android/java/src/org/chromium/base/BuildInfo.java b/base/android/java/src/org/chromium/base/BuildInfo.java deleted file mode 100644 index 81a8f34559..0000000000 --- a/base/android/java/src/org/chromium/base/BuildInfo.java +++ /dev/null @@ -1,117 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -package org.chromium.base; - -import android.content.Context; -import android.content.pm.ApplicationInfo; -import android.content.pm.PackageInfo; -import android.content.pm.PackageManager; -import android.content.pm.PackageManager.NameNotFoundException; -import android.os.Build; -import android.util.Log; - -import org.chromium.base.CalledByNative; - -/** - * BuildInfo is a utility class providing easy access to {@link PackageInfo} - * information. This is primarly of use for accessesing package information - * from native code. - */ -public class BuildInfo { - private static final String TAG = "BuildInfo"; - private static final int MAX_FINGERPRINT_LENGTH = 128; - - /** - * BuildInfo is a static utility class and therefore shouldn't be - * instantiated. - */ - private BuildInfo() { - } - - @CalledByNative - public static String getDevice() { - return Build.DEVICE; - } - - @CalledByNative - public static String getBrand() { - return Build.BRAND; - } - - @CalledByNative - public static String getAndroidBuildId() { - return Build.ID; - } - - /** - * @return The build fingerprint for the current Android install. The value is truncated to a - * 128 characters as this is used for crash and UMA reporting, which should avoid huge - * strings. - */ - @CalledByNative - public static String getAndroidBuildFingerprint() { - return Build.FINGERPRINT.substring( - 0, Math.min(Build.FINGERPRINT.length(), MAX_FINGERPRINT_LENGTH)); - } - - @CalledByNative - public static String getDeviceModel() { - return Build.MODEL; - } - - @CalledByNative - public static String getPackageVersionCode(Context context) { - String msg = "versionCode not available."; - try { - PackageManager pm = context.getPackageManager(); - PackageInfo pi = pm.getPackageInfo(context.getPackageName(), 0); - msg = ""; - if (pi.versionCode > 0) { - msg = Integer.toString(pi.versionCode); - } - } catch (NameNotFoundException e) { - Log.d(TAG, msg); - } - return msg; - - } - - @CalledByNative - public static String getPackageVersionName(Context context) { - String msg = "versionName not available"; - try { - PackageManager pm = context.getPackageManager(); - PackageInfo pi = pm.getPackageInfo(context.getPackageName(), 0); - msg = pi.versionName; - } catch (NameNotFoundException e) { - Log.d(TAG, msg); - } - return msg; - } - - @CalledByNative - public static String getPackageLabel(Context context) { - try { - PackageManager packageManager = context.getPackageManager(); - ApplicationInfo appInfo = packageManager.getApplicationInfo(context.getPackageName(), - PackageManager.GET_META_DATA); - CharSequence label = packageManager.getApplicationLabel(appInfo); - return label != null ? label.toString() : ""; - } catch (NameNotFoundException e) { - return ""; - } - } - - @CalledByNative - public static String getPackageName(Context context) { - String packageName = context != null ? context.getPackageName() : null; - return packageName != null ? packageName : ""; - } - - @CalledByNative - public static int getSdkInt() { - return Build.VERSION.SDK_INT; - } -} diff --git a/base/android/java/src/org/chromium/base/CalledByNative.java b/base/android/java/src/org/chromium/base/CalledByNative.java deleted file mode 100644 index db01b0d072..0000000000 --- a/base/android/java/src/org/chromium/base/CalledByNative.java +++ /dev/null @@ -1,23 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -package org.chromium.base; - -import java.lang.annotation.ElementType; -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; -import java.lang.annotation.Target; - -/** - * @CalledByNative is used by the JNI generator to create the necessary JNI - * bindings and expose this method to native code. - */ -@Target(ElementType.METHOD) -@Retention(RetentionPolicy.CLASS) -public @interface CalledByNative { - /* - * If present, tells which inner class the method belongs to. - */ - public String value() default ""; -} diff --git a/base/android/java/src/org/chromium/base/CalledByNativeUnchecked.java b/base/android/java/src/org/chromium/base/CalledByNativeUnchecked.java deleted file mode 100644 index 38bb0c0450..0000000000 --- a/base/android/java/src/org/chromium/base/CalledByNativeUnchecked.java +++ /dev/null @@ -1,27 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -package org.chromium.base; - -import java.lang.annotation.ElementType; -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; -import java.lang.annotation.Target; - -/** - * @CalledByNativeUnchecked is used to generate JNI bindings that do not check for exceptions. - * It only makes sense to use this annotation on methods that declare a throws... spec. - * However, note that the exception received native side maybe an 'unchecked' (RuntimeExpception) - * such as NullPointerException, so the native code should differentiate these cases. - * Usage of this should be very rare; where possible handle exceptions in the Java side and use a - * return value to indicate success / failure. - */ -@Target(ElementType.METHOD) -@Retention(RetentionPolicy.CLASS) -public @interface CalledByNativeUnchecked { - /* - * If present, tells which inner class the method belongs to. - */ - public String value() default ""; -} diff --git a/base/android/java/src/org/chromium/base/ChromiumActivity.java b/base/android/java/src/org/chromium/base/ChromiumActivity.java deleted file mode 100644 index 65f5ce929b..0000000000 --- a/base/android/java/src/org/chromium/base/ChromiumActivity.java +++ /dev/null @@ -1,49 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -package org.chromium.base; - -import android.app.Activity; -import android.os.Bundle; - -// All Chromium main activities should extend this class. This allows various sub-systems to -// properly react to activity state changes. -public class ChromiumActivity extends Activity { - - @Override - protected void onCreate(Bundle savedInstance) { - super.onCreate(savedInstance); - ActivityStatus.onStateChange(this, ActivityStatus.CREATED); - } - - @Override - protected void onStart() { - super.onStart(); - ActivityStatus.onStateChange(this, ActivityStatus.STARTED); - } - - @Override - protected void onResume() { - super.onResume(); - ActivityStatus.onStateChange(this, ActivityStatus.RESUMED); - } - - @Override - protected void onPause() { - ActivityStatus.onStateChange(this, ActivityStatus.PAUSED); - super.onPause(); - } - - @Override - protected void onStop() { - ActivityStatus.onStateChange(this, ActivityStatus.STOPPED); - super.onStop(); - } - - @Override - protected void onDestroy() { - ActivityStatus.onStateChange(this, ActivityStatus.DESTROYED); - super.onDestroy(); - } -} diff --git a/base/android/java/src/org/chromium/base/ContextTypes.java b/base/android/java/src/org/chromium/base/ContextTypes.java deleted file mode 100644 index 35ecd8fd82..0000000000 --- a/base/android/java/src/org/chromium/base/ContextTypes.java +++ /dev/null @@ -1,96 +0,0 @@ -// Copyright (c) 2013 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -package org.chromium.base; - -import android.content.Context; - -import java.util.concurrent.ConcurrentHashMap; -import java.util.Map; - -/** - * Maintains the {@link Context}-to-"context type" mapping. The context type - * {@code MODE_APP} is chosen for the application context associated with - * the activity running in application mode, while {@code MODE_NORMAL} for main - * Chromium activity. - * - *

Used as singleton instance. - */ -public class ContextTypes { - - // Available context types. - public static final int CONTEXT_TYPE_NORMAL = 1; - public static final int CONTEXT_TYPE_WEBAPP = 2; - - private final Map mContextMap; - - private ContextTypes() { - mContextMap = new ConcurrentHashMap(); - } - - private static class ContextTypesHolder { - private static final ContextTypes INSTANCE = new ContextTypes(); - } - - public static ContextTypes getInstance() { - return ContextTypesHolder.INSTANCE; - } - - /** - * Adds the mapping for the given {@link Context}. - * - * @param context {@link Context} in interest - * @param type the type associated with the context - * @throws IllegalArgumentException if type is not a valid one. - */ - public void put(Context context, int type) throws IllegalArgumentException { - if (type != CONTEXT_TYPE_NORMAL && type != CONTEXT_TYPE_WEBAPP) { - throw new IllegalArgumentException("Wrong context type"); - } - mContextMap.put(context, type); - } - - /** - * Removes the mapping for the given context. - * - * @param context {@link Context} in interest - */ - public void remove(Context context) { - mContextMap.remove(context); - } - - /** - * Returns type of the given context. - * - * @param context {@link Context} in interest - * @return type associated with the context. Returns {@code MODE_NORMAL} by - * default if the mapping for the queried context is not present. - */ - public int getType(Context context) { - Integer contextType = mContextMap.get(context); - return contextType == null ? CONTEXT_TYPE_NORMAL : contextType; - } - - /** - * Returns whether activity is running in web app mode. - * - * @param appContext {@link Context} in interest - * @return {@code true} when activity is running in web app mode. - */ - @CalledByNative - public static boolean isRunningInWebapp(Context appContext) { - return ContextTypes.getInstance().getType(appContext) - == CONTEXT_TYPE_WEBAPP; - } - - /** - * Checks if the mapping exists for the given context. - * - * @param context {@link Context} in interest - * @return {@code true} if the mapping exists; otherwise {@code false} - */ - public boolean contains(Context context) { - return mContextMap.containsKey(context); - } -} diff --git a/base/android/java/src/org/chromium/base/CpuFeatures.java b/base/android/java/src/org/chromium/base/CpuFeatures.java deleted file mode 100644 index f298fb1e16..0000000000 --- a/base/android/java/src/org/chromium/base/CpuFeatures.java +++ /dev/null @@ -1,40 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -package org.chromium.base; - -// The only purpose of this class is to allow sending CPU properties -// from the browser process to sandboxed renderer processes. This is -// needed because sandboxed processes cannot, on ARM, query the kernel -// about the CPU's properties by parsing /proc, so this operation must -// be performed in the browser process, and the result passed to -// renderer ones. -// -// For more context, see http://crbug.com/164154 -// -// Technically, this is a wrapper around the native NDK cpufeatures -// library. The exact CPU features bits are never used in Java so -// there is no point in duplicating their definitions here. -// -@JNINamespace("base::android") -public abstract class CpuFeatures { - /** - * Return the number of CPU Cores on the device. - */ - public static int getCount() { - return nativeGetCoreCount(); - } - - /** - * Return the CPU feature mask. - * This is a 64-bit integer that corresponds to the CPU's features. - * The value comes directly from android_getCpuFeatures(). - */ - public static long getMask() { - return nativeGetCpuFeatures(); - } - - private static native int nativeGetCoreCount(); - private static native long nativeGetCpuFeatures(); -} diff --git a/base/android/java/src/org/chromium/base/ImportantFileWriterAndroid.java b/base/android/java/src/org/chromium/base/ImportantFileWriterAndroid.java deleted file mode 100644 index 1c7c0185da..0000000000 --- a/base/android/java/src/org/chromium/base/ImportantFileWriterAndroid.java +++ /dev/null @@ -1,29 +0,0 @@ -// Copyright (c) 2013 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -package org.chromium.base; - -/** - * This class provides an interface to the native class for writing - * important data files without risking data loss. - */ -@JNINamespace("base::android") -public class ImportantFileWriterAndroid { - - /** - * Write a binary file atomically. - * - * This either writes all the data or leaves the file unchanged. - * - * @param fileName The complete path of the file to be written - * @param data The data to be written to the file - * @return true if the data was written to the file, false if not. - */ - public static boolean writeFileAtomically(String fileName, byte[] data) { - return nativeWriteFileAtomically(fileName, data); - } - - private static native boolean nativeWriteFileAtomically( - String fileName, byte[] data); -} diff --git a/base/android/java/src/org/chromium/base/JNINamespace.java b/base/android/java/src/org/chromium/base/JNINamespace.java deleted file mode 100644 index cfffc91a34..0000000000 --- a/base/android/java/src/org/chromium/base/JNINamespace.java +++ /dev/null @@ -1,20 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -package org.chromium.base; - -import java.lang.annotation.ElementType; -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; -import java.lang.annotation.Target; - -/** - * @JNINamespace is used by the JNI generator to create the necessary JNI - * bindings and expose this method to native code using the specified namespace. - */ -@Target(ElementType.TYPE) -@Retention(RetentionPolicy.RUNTIME) -public @interface JNINamespace { - public String value(); -} diff --git a/base/android/java/src/org/chromium/base/JavaHandlerThread.java b/base/android/java/src/org/chromium/base/JavaHandlerThread.java deleted file mode 100644 index 5f9960e53c..0000000000 --- a/base/android/java/src/org/chromium/base/JavaHandlerThread.java +++ /dev/null @@ -1,41 +0,0 @@ -// Copyright 2013 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -package org.chromium.base; - -import android.os.Handler; -import android.os.HandlerThread; -import android.os.Looper; -import android.os.Message; - -/** - * This class is an internal detail of the native counterpart. - * It is instantiated and owned by the native object. - */ -@JNINamespace("base::android") -class JavaHandlerThread { - final HandlerThread mThread; - - private JavaHandlerThread(String name) { - mThread = new HandlerThread(name); - } - - @CalledByNative - private static JavaHandlerThread create(String name) { - return new JavaHandlerThread(name); - } - - @CalledByNative - private void start(final int nativeThread, final int nativeEvent) { - mThread.start(); - new Handler(mThread.getLooper()).post(new Runnable() { - @Override - public void run() { - nativeInitializeThread(nativeThread, nativeEvent); - } - }); - } - - private native void nativeInitializeThread(int nativeJavaHandlerThread, int nativeEvent); -} \ No newline at end of file diff --git a/base/android/java/src/org/chromium/base/MemoryPressureLevelList.template b/base/android/java/src/org/chromium/base/MemoryPressureLevelList.template deleted file mode 100644 index cebca842e3..0000000000 --- a/base/android/java/src/org/chromium/base/MemoryPressureLevelList.template +++ /dev/null @@ -1,12 +0,0 @@ -// Copyright 2013 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -package org.chromium.base; - -class MemoryPressureLevelList { -#define DEFINE_MEMORY_PRESSURE_LEVEL(name, value) \ - static final int name = value; -#include "base/memory/memory_pressure_level_list.h" -#undef DEFINE_MEMORY_PRESSURE_LEVEL -} diff --git a/base/android/java/src/org/chromium/base/MemoryPressureListener.java b/base/android/java/src/org/chromium/base/MemoryPressureListener.java deleted file mode 100644 index 311b0f6ff4..0000000000 --- a/base/android/java/src/org/chromium/base/MemoryPressureListener.java +++ /dev/null @@ -1,55 +0,0 @@ -// Copyright 2013 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -package org.chromium.base; - -import android.content.ComponentCallbacks2; -import android.content.Context; -import android.content.res.Configuration; - - -/** - * This is an internal implementation of the C++ counterpart. - * It registers a ComponentCallbacks2 with the system, and dispatches into - * native. - */ -public class MemoryPressureListener { - @CalledByNative - private static void registerSystemCallback(Context context) { - context.registerComponentCallbacks( - new ComponentCallbacks2() { - @Override - public void onTrimMemory(int level) { - maybeNotifyMemoryPresure(level); - } - - @Override - public void onLowMemory() { - nativeOnMemoryPressure(MemoryPressureLevelList.MEMORY_PRESSURE_CRITICAL); - } - - @Override - public void onConfigurationChanged(Configuration configuration) { - } - }); - } - - /** - * Used by applications to simulate a memory pressure signal. - */ - public static void simulateMemoryPressureSignal(int level) { - maybeNotifyMemoryPresure(level); - } - - private static void maybeNotifyMemoryPresure(int level) { - if (level == ComponentCallbacks2.TRIM_MEMORY_COMPLETE) { - nativeOnMemoryPressure(MemoryPressureLevelList.MEMORY_PRESSURE_CRITICAL); - } else if (level >= ComponentCallbacks2.TRIM_MEMORY_BACKGROUND || - level == ComponentCallbacks2.TRIM_MEMORY_RUNNING_CRITICAL) { - nativeOnMemoryPressure(MemoryPressureLevelList.MEMORY_PRESSURE_MODERATE); - } - } - - private static native void nativeOnMemoryPressure(int memoryPressureType); -} diff --git a/base/android/java/src/org/chromium/base/NativeClassQualifiedName.java b/base/android/java/src/org/chromium/base/NativeClassQualifiedName.java deleted file mode 100644 index 309169bb1d..0000000000 --- a/base/android/java/src/org/chromium/base/NativeClassQualifiedName.java +++ /dev/null @@ -1,25 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -package org.chromium.base; - -import java.lang.annotation.ElementType; -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; -import java.lang.annotation.Target; - -/** - * @NativeClassQualifiedName is used by the JNI generator to create the necessary JNI - * bindings to call into the specified native class name. - */ -@Target(ElementType.METHOD) -@Retention(RetentionPolicy.RUNTIME) -public @interface NativeClassQualifiedName { - /* - * Tells which native class the method is going to be bound to. - * The first parameter of the annotated method must be an int nativePtr pointing to - * an instance of this class. - */ - public String value(); -} diff --git a/base/android/java/src/org/chromium/base/ObserverList.java b/base/android/java/src/org/chromium/base/ObserverList.java deleted file mode 100644 index 13a81c5c19..0000000000 --- a/base/android/java/src/org/chromium/base/ObserverList.java +++ /dev/null @@ -1,177 +0,0 @@ -// Copyright 2013 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -package org.chromium.base; - -import java.lang.Iterable; -import java.util.ArrayList; -import java.util.Iterator; -import java.util.List; -import java.util.NoSuchElementException; - -import javax.annotation.concurrent.NotThreadSafe; - -/** - * A container for a list of observers. - *

- * This container can be modified during iteration without invalidating the iterator. - * So, it safely handles the case of an observer removing itself or other observers from the list - * while observers are being notified. - *

- * The implementation (and the interface) is heavily influenced by the C++ ObserverList. - * Notable differences: - * - The iterator implements NOTIFY_EXISTING_ONLY. - * - The FOR_EACH_OBSERVER closure is left to the clients to implement in terms of iterator(). - *

- * This class is not threadsafe. Observers MUST be added, removed and will be notified on the same - * thread this is created. - */ -@NotThreadSafe -public class ObserverList implements Iterable { - public final List mObservers = new ArrayList(); - private int mIterationDepth = 0; - - public ObserverList() {} - - /** - * Add an observer to the list. - *

- * An observer should not be added to the same list more than once. If an iteration is already - * in progress, this observer will be not be visible during that iteration. - */ - public void addObserver(E obs) { - // Avoid adding null elements to the list as they may be removed on a compaction. - if (obs == null || mObservers.contains(obs)) { - assert false; - return; - } - - // Structurally modifying the underlying list here. This means we - // cannot use the underlying list's iterator to iterate over the list. - mObservers.add(obs); - } - - /** - * Remove an observer from the list if it is in the list. - */ - public void removeObserver(E obs) { - int index = mObservers.indexOf(obs); - - if (index == -1) - return; - - if (mIterationDepth == 0) { - // No one is iterating over the list. - mObservers.remove(obs); - } else { - mObservers.set(index, null); - } - } - - public boolean hasObserver(E obs) { - return mObservers.contains(obs); - } - - public void clear() { - if (mIterationDepth == 0) { - mObservers.clear(); - return; - } - - int size = mObservers.size(); - for (int i = 0; i < size; i++) - mObservers.set(i, null); - } - - @Override - public Iterator iterator() { - return new ObserverListIterator(); - } - - /** - * Compact the underlying list be removing null elements. - *

- * Should only be called when mIterationDepth is zero. - */ - private void compact() { - assert mIterationDepth == 0; - // Safe to use the underlying list's iterator, as we know that no-one else - // is iterating over the list. - Iterator it = mObservers.iterator(); - while (it.hasNext()) { - E el = it.next(); - if (el == null) - it.remove(); - } - } - - private void incrementIterationDepth() { - mIterationDepth++; - } - - private void decrementIterationDepthAndCompactIfNeeded() { - mIterationDepth--; - assert mIterationDepth >= 0; - if (mIterationDepth == 0) - compact(); - } - - private int getSize() { - return mObservers.size(); - } - - private E getObserverAt(int index) { - return mObservers.get(index); - } - - private class ObserverListIterator implements Iterator { - private final int mListEndMarker; - private int mIndex = 0; - private boolean mIsExhausted = false; - - private ObserverListIterator() { - ObserverList.this.incrementIterationDepth(); - mListEndMarker = ObserverList.this.getSize(); - } - - @Override - public boolean hasNext() { - int lookupIndex = mIndex; - while (lookupIndex < mListEndMarker && - ObserverList.this.getObserverAt(lookupIndex) == null) - lookupIndex++; - if (lookupIndex < mListEndMarker) - return true; - - // We have reached the end of the list, allow for compaction. - compactListIfNeeded(); - return false; - } - - @Override - public E next() { - // Advance if the current element is null. - while (mIndex < mListEndMarker && ObserverList.this.getObserverAt(mIndex) == null) - mIndex++; - if (mIndex < mListEndMarker) - return ObserverList.this.getObserverAt(mIndex++); - - // We have reached the end of the list, allow for compaction. - compactListIfNeeded(); - throw new NoSuchElementException(); - } - - @Override - public void remove() { - throw new UnsupportedOperationException(); - } - - private void compactListIfNeeded() { - if (!mIsExhausted) { - mIsExhausted = true; - ObserverList.this.decrementIterationDepthAndCompactIfNeeded(); - } - } - } -} diff --git a/base/android/java/src/org/chromium/base/PathService.java b/base/android/java/src/org/chromium/base/PathService.java deleted file mode 100644 index dfda736d01..0000000000 --- a/base/android/java/src/org/chromium/base/PathService.java +++ /dev/null @@ -1,24 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -package org.chromium.base; - -/** - * This class provides java side access to the native PathService. - */ -@JNINamespace("base::android") -public abstract class PathService { - - // Must match the value of DIR_MODULE in base/base_paths.h! - public static final int DIR_MODULE = 3; - - // Prevent instantiation. - private PathService() {} - - public static void override(int what, String path) { - nativeOverride(what, path); - } - - private static native void nativeOverride(int what, String path); -} diff --git a/base/android/java/src/org/chromium/base/PathUtils.java b/base/android/java/src/org/chromium/base/PathUtils.java deleted file mode 100644 index aee5c050c3..0000000000 --- a/base/android/java/src/org/chromium/base/PathUtils.java +++ /dev/null @@ -1,108 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -package org.chromium.base; - -import android.content.Context; -import android.content.pm.ApplicationInfo; -import android.os.Environment; - -import java.io.File; - -/** - * This class provides the path related methods for the native library. - */ -public abstract class PathUtils { - - private static String sDataDirectorySuffix; - private static String sWebappDirectorySuffix; - private static String sWebappCacheDirectory; - - // Prevent instantiation. - private PathUtils() {} - - /** - * Sets the suffix that should be used for the directory where private data is to be stored - * by the application. - * @param suffix The private data directory suffix. - * @see Context#getDir(String, int) - */ - public static void setPrivateDataDirectorySuffix(String suffix) { - sDataDirectorySuffix = suffix; - } - - /** - * Sets the directory info used for chrome process running in application mode. - * - * @param webappSuffix The suffix of the directory used for storing webapp-specific profile - * @param cacheDir Cache directory name for web apps. - */ - public static void setWebappDirectoryInfo(String webappSuffix, String cacheDir) { - sWebappDirectorySuffix = webappSuffix; - sWebappCacheDirectory = cacheDir; - } - - /** - * @return the private directory that is used to store application data. - */ - @CalledByNative - public static String getDataDirectory(Context appContext) { - if (sDataDirectorySuffix == null) { - throw new IllegalStateException( - "setDataDirectorySuffix must be called before getDataDirectory"); - } - return appContext.getDir(sDataDirectorySuffix, Context.MODE_PRIVATE).getPath(); - } - - /** - * @return the cache directory. - */ - @SuppressWarnings("unused") - @CalledByNative - public static String getCacheDirectory(Context appContext) { - if (ContextTypes.getInstance().getType(appContext) == ContextTypes.CONTEXT_TYPE_NORMAL) { - return appContext.getCacheDir().getPath(); - } - if (sWebappDirectorySuffix == null || sWebappCacheDirectory == null) { - throw new IllegalStateException( - "setWebappDirectoryInfo must be called before getCacheDirectory"); - } - return new File(appContext.getDir(sWebappDirectorySuffix, appContext.MODE_PRIVATE), - sWebappCacheDirectory).getPath(); - } - - /** - * @return the public downloads directory. - */ - @SuppressWarnings("unused") - @CalledByNative - private static String getDownloadsDirectory(Context appContext) { - return Environment.getExternalStoragePublicDirectory( - Environment.DIRECTORY_DOWNLOADS).getPath(); - } - - /** - * @return the path to native libraries. - */ - @SuppressWarnings("unused") - @CalledByNative - private static String getNativeLibraryDirectory(Context appContext) { - ApplicationInfo ai = appContext.getApplicationInfo(); - if ((ai.flags & ApplicationInfo.FLAG_UPDATED_SYSTEM_APP) != 0 || - (ai.flags & ApplicationInfo.FLAG_SYSTEM) == 0) { - return ai.nativeLibraryDir; - } - - return "/system/lib/"; - } - - /** - * @return the external storage directory. - */ - @SuppressWarnings("unused") - @CalledByNative - public static String getExternalStorageDirectory() { - return Environment.getExternalStorageDirectory().getAbsolutePath(); - } -} diff --git a/base/android/java/src/org/chromium/base/PowerMonitor.java b/base/android/java/src/org/chromium/base/PowerMonitor.java deleted file mode 100644 index b7a691e3ce..0000000000 --- a/base/android/java/src/org/chromium/base/PowerMonitor.java +++ /dev/null @@ -1,92 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -package org.chromium.base; - -import android.content.Context; -import android.content.Intent; -import android.content.IntentFilter; -import android.os.BatteryManager; -import android.os.Handler; -import android.os.Looper; - - -/** - * Integrates native PowerMonitor with the java side. - */ -@JNINamespace("base::android") -public class PowerMonitor implements ActivityStatus.StateListener { - private static final long SUSPEND_DELAY_MS = 1 * 60 * 1000; // 1 minute. - private static class LazyHolder { - private static final PowerMonitor INSTANCE = new PowerMonitor(); - } - private static PowerMonitor sInstance; - - private boolean mIsBatteryPower; - private final Handler mHandler = new Handler(Looper.getMainLooper()); - - // Asynchronous task used to fire the "paused" event to the native side 1 minute after the main - // activity transitioned to the "paused" state. This event is not sent immediately because it - // would be too aggressive. An Android activity can be in the "paused" state quite often. This - // can happen when a dialog window shows up for instance. - private static final Runnable sSuspendTask = new Runnable() { - @Override - public void run() { - nativeOnMainActivitySuspended(); - } - }; - - public static void createForTests(Context context) { - // Applications will create this once the JNI side has been fully wired up both sides. For - // tests, we just need native -> java, that is, we don't need to notify java -> native on - // creation. - sInstance = LazyHolder.INSTANCE; - } - - public static void create(Context context) { - if (sInstance == null) { - sInstance = LazyHolder.INSTANCE; - ActivityStatus.registerStateListener(sInstance); - IntentFilter ifilter = new IntentFilter(Intent.ACTION_BATTERY_CHANGED); - Intent batteryStatusIntent = context.registerReceiver(null, ifilter); - onBatteryChargingChanged(batteryStatusIntent); - } - } - - private PowerMonitor() { - } - - public static void onBatteryChargingChanged(Intent intent) { - if (sInstance == null) { - // We may be called by the framework intent-filter before being fully initialized. This - // is not a problem, since our constructor will check for the state later on. - return; - } - int chargePlug = intent.getIntExtra(BatteryManager.EXTRA_PLUGGED, -1); - // If we're not plugged, assume we're running on battery power. - sInstance.mIsBatteryPower = chargePlug != BatteryManager.BATTERY_PLUGGED_USB && - chargePlug != BatteryManager.BATTERY_PLUGGED_AC; - nativeOnBatteryChargingChanged(); - } - - @Override - public void onActivityStateChange(int newState) { - if (newState == ActivityStatus.RESUMED) { - // Remove the callback from the message loop in case it hasn't been executed yet. - mHandler.removeCallbacks(sSuspendTask); - nativeOnMainActivityResumed(); - } else if (newState == ActivityStatus.PAUSED) { - mHandler.postDelayed(sSuspendTask, SUSPEND_DELAY_MS); - } - } - - @CalledByNative - private static boolean isBatteryPower() { - return sInstance.mIsBatteryPower; - } - - private static native void nativeOnBatteryChargingChanged(); - private static native void nativeOnMainActivitySuspended(); - private static native void nativeOnMainActivityResumed(); -} diff --git a/base/android/java/src/org/chromium/base/PowerStatusReceiver.java b/base/android/java/src/org/chromium/base/PowerStatusReceiver.java deleted file mode 100644 index f36c146273..0000000000 --- a/base/android/java/src/org/chromium/base/PowerStatusReceiver.java +++ /dev/null @@ -1,23 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -package org.chromium.base; - -import android.content.BroadcastReceiver; -import android.content.Context; -import android.content.Intent; - - -/** - * A BroadcastReceiver that listens to changes in power status and notifies - * PowerMonitor. - * It's instantiated by the framework via the application intent-filter - * declared in its manifest. - */ -public class PowerStatusReceiver extends BroadcastReceiver { - @Override - public void onReceive(Context context, Intent intent) { - PowerMonitor.onBatteryChargingChanged(intent); - } -} diff --git a/base/android/java/src/org/chromium/base/SysUtils.java b/base/android/java/src/org/chromium/base/SysUtils.java deleted file mode 100644 index 7af5a40069..0000000000 --- a/base/android/java/src/org/chromium/base/SysUtils.java +++ /dev/null @@ -1,30 +0,0 @@ -// Copyright 2013 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -package org.chromium.base; - -import android.app.ActivityManager; -import android.app.ActivityManager.MemoryInfo; -import android.content.Context; -import android.os.Build; - -/** - * Exposes system related information about the current device. - */ -public class SysUtils { - private static Boolean sLowEndDevice; - - private SysUtils() { } - - /** - * @return Whether or not this device should be considered a low end device. - */ - public static boolean isLowEndDevice() { - if (sLowEndDevice == null) sLowEndDevice = nativeIsLowEndDevice(); - - return sLowEndDevice.booleanValue(); - } - - private static native boolean nativeIsLowEndDevice(); -} diff --git a/base/android/java/src/org/chromium/base/SystemMessageHandler.java b/base/android/java/src/org/chromium/base/SystemMessageHandler.java deleted file mode 100644 index fc25ff8457..0000000000 --- a/base/android/java/src/org/chromium/base/SystemMessageHandler.java +++ /dev/null @@ -1,55 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -package org.chromium.base; - -import android.os.Handler; -import android.os.Message; -import android.os.SystemClock; - -import java.util.concurrent.atomic.AtomicBoolean; - -class SystemMessageHandler extends Handler { - - private static final int TIMER_MESSAGE = 1; - private static final int DELAYED_TIMER_MESSAGE = 2; - - // Native class pointer set by the constructor of the SharedClient native class. - private int mMessagePumpDelegateNative = 0; - - private SystemMessageHandler(int messagePumpDelegateNative) { - mMessagePumpDelegateNative = messagePumpDelegateNative; - } - - @Override - public void handleMessage(Message msg) { - nativeDoRunLoopOnce(mMessagePumpDelegateNative); - } - - @SuppressWarnings("unused") - @CalledByNative - private void setTimer() { - sendEmptyMessage(TIMER_MESSAGE); - } - - @SuppressWarnings("unused") - @CalledByNative - private void setDelayedTimer(long millis) { - removeMessages(DELAYED_TIMER_MESSAGE); - sendEmptyMessageDelayed(DELAYED_TIMER_MESSAGE, millis); - } - - @SuppressWarnings("unused") - @CalledByNative - private void removeTimer() { - removeMessages(TIMER_MESSAGE); - } - - @CalledByNative - private static SystemMessageHandler create(int messagePumpDelegateNative) { - return new SystemMessageHandler(messagePumpDelegateNative); - } - - private native void nativeDoRunLoopOnce(int messagePumpDelegateNative); -} diff --git a/base/android/java/src/org/chromium/base/ThreadUtils.java b/base/android/java/src/org/chromium/base/ThreadUtils.java deleted file mode 100644 index a880ede1e3..0000000000 --- a/base/android/java/src/org/chromium/base/ThreadUtils.java +++ /dev/null @@ -1,172 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -package org.chromium.base; - -import android.os.Handler; -import android.os.Looper; -import android.os.Process; - -import java.util.concurrent.Callable; -import java.util.concurrent.ExecutionException; -import java.util.concurrent.FutureTask; - -/** - * Helper methods to deal with threading related tasks. - */ -public class ThreadUtils { - - /** - * Run the supplied Runnable on the main thread. The method will block until the Runnable - * completes. - * - * @param r The Runnable to run. - */ - public static void runOnUiThreadBlocking(final Runnable r) { - if (runningOnUiThread()) { - r.run(); - } else { - FutureTask task = new FutureTask(r, null); - postOnUiThread(task); - try { - task.get(); - } catch (Exception e) { - throw new RuntimeException("Exception occured while waiting for runnable", e); - } - } - } - - /** - * Run the supplied Callable on the main thread, wrapping any exceptions in a RuntimeException. - * The method will block until the Callable completes. - * - * @param c The Callable to run - * @return The result of the callable - */ - public static T runOnUiThreadBlockingNoException(Callable c) { - try { - return runOnUiThreadBlocking(c); - } catch (ExecutionException e) { - throw new RuntimeException("Error occured waiting for callable", e); - } - } - - /** - * Run the supplied Callable on the main thread, The method will block until the Callable - * completes. - * - * @param c The Callable to run - * @return The result of the callable - * @throws ExecutionException c's exception - */ - public static T runOnUiThreadBlocking(Callable c) throws ExecutionException { - FutureTask task = new FutureTask(c); - runOnUiThread(task); - try { - return task.get(); - } catch (InterruptedException e) { - throw new RuntimeException("Interrupted waiting for callable", e); - } - } - - /** - * Run the supplied FutureTask on the main thread. The method will block only if the current - * thread is the main thread. - * - * @param task The FutureTask to run - * @return The queried task (to aid inline construction) - */ - public static FutureTask runOnUiThread(FutureTask task) { - if (runningOnUiThread()) { - task.run(); - } else { - postOnUiThread(task); - } - return task; - } - - /** - * Run the supplied Callable on the main thread. The method will block only if the current - * thread is the main thread. - * - * @param c The Callable to run - * @return A FutureTask wrapping the callable to retrieve results - */ - public static FutureTask runOnUiThread(Callable c) { - return runOnUiThread(new FutureTask(c)); - } - - /** - * Run the supplied Runnable on the main thread. The method will block only if the current - * thread is the main thread. - * - * @param r The Runnable to run - */ - public static void runOnUiThread(Runnable r) { - if (runningOnUiThread()) { - r.run(); - } else { - LazyHolder.sUiThreadHandler.post(r); - } - } - - /** - * Post the supplied FutureTask to run on the main thread. The method will not block, even if - * called on the UI thread. - * - * @param task The FutureTask to run - * @return The queried task (to aid inline construction) - */ - public static FutureTask postOnUiThread(FutureTask task) { - LazyHolder.sUiThreadHandler.post(task); - return task; - } - - /** - * Post the supplied Runnable to run on the main thread. The method will not block, even if - * called on the UI thread. - * - * @param task The Runnable to run - */ - public static void postOnUiThread(Runnable r) { - LazyHolder.sUiThreadHandler.post(r); - } - - /** - * Post the supplied Runnable to run on the main thread after the given amount of time. The - * method will not block, even if called on the UI thread. - * - * @param task The Runnable to run - * @param delayMillis The delay in milliseconds until the Runnable will be run - */ - public static void postOnUiThreadDelayed(Runnable r, long delayMillis) { - LazyHolder.sUiThreadHandler.postDelayed(r, delayMillis); - } - - /** - * Asserts that the current thread is running on the main thread. - */ - public static void assertOnUiThread() { - assert runningOnUiThread(); - } - - /** - * @return true iff the current thread is the main (UI) thread. - */ - public static boolean runningOnUiThread() { - return Looper.getMainLooper() == Looper.myLooper(); - } - - /** - * Set thread priority to audio. - */ - @CalledByNative - public static void setThreadPriorityAudio(int tid) { - Process.setThreadPriority(tid, Process.THREAD_PRIORITY_AUDIO); - } - - private static class LazyHolder { - private static Handler sUiThreadHandler = new Handler(Looper.getMainLooper()); - } -} diff --git a/base/android/java/src/org/chromium/base/WeakContext.java b/base/android/java/src/org/chromium/base/WeakContext.java deleted file mode 100644 index d660cc9940..0000000000 --- a/base/android/java/src/org/chromium/base/WeakContext.java +++ /dev/null @@ -1,45 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -package org.chromium.base; - -import android.content.Context; - -import java.lang.ref.WeakReference; -import java.util.concurrent.Callable; - -// Holds a WeakReference to Context to allow it to be GC'd. -// Also provides utility functions to getSystemService from the UI or any -// other thread (may return null, if the Context has been nullified). -public class WeakContext { - private static WeakReference sWeakContext; - - public static void initializeWeakContext(final Context context) { - sWeakContext = new WeakReference(context); - } - - public static Context getContext() { - return sWeakContext.get(); - } - - // Returns a system service. May be called from any thread. - // If necessary, it will send a message to the main thread to acquire the - // service, and block waiting for it to complete. - // May return null if context is no longer available. - public static Object getSystemService(final String name) { - final Context context = sWeakContext.get(); - if (context == null) { - return null; - } - if (ThreadUtils.runningOnUiThread()) { - return context.getSystemService(name); - } - return ThreadUtils.runOnUiThreadBlockingNoException(new Callable() { - @Override - public Object call() { - return context.getSystemService(name); - } - }); - } -} diff --git a/base/android/java_handler_thread.cc b/base/android/java_handler_thread.cc deleted file mode 100644 index 0528fe74ba..0000000000 --- a/base/android/java_handler_thread.cc +++ /dev/null @@ -1,62 +0,0 @@ -// Copyright 2013 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "base/android/java_handler_thread.h" - -#include - -#include "base/android/jni_android.h" -#include "base/android/jni_string.h" -#include "base/message_loop/message_loop.h" -#include "base/synchronization/waitable_event.h" -#include "base/threading/thread_restrictions.h" -#include "jni/JavaHandlerThread_jni.h" - -namespace base { - -namespace android { - -JavaHandlerThread::JavaHandlerThread(const char* name) { - JNIEnv* env = base::android::AttachCurrentThread(); - - java_thread_.Reset(Java_JavaHandlerThread_create( - env, ConvertUTF8ToJavaString(env, name).Release())); -} - -JavaHandlerThread::~JavaHandlerThread() { -} - -void JavaHandlerThread::Start() { - // Check the thread has not already been started. - DCHECK(!message_loop_); - - JNIEnv* env = base::android::AttachCurrentThread(); - base::WaitableEvent initialize_event(false, false); - Java_JavaHandlerThread_start(env, - java_thread_.obj(), - reinterpret_cast(this), - reinterpret_cast(&initialize_event)); - // Wait for thread to be initialized so it is ready to be used when Start - // returns. - base::ThreadRestrictions::ScopedAllowWait wait_allowed; - initialize_event.Wait(); -} - -void JavaHandlerThread::Stop() { -} - -void JavaHandlerThread::InitializeThread(JNIEnv* env, jobject obj, jint event) { - // TYPE_JAVA to get the Android java style message loop. - message_loop_.reset(new base::MessageLoop(base::MessageLoop::TYPE_JAVA)); - static_cast(message_loop_.get())->Start(); - reinterpret_cast(event)->Signal(); -} - -// static -bool JavaHandlerThread::RegisterBindings(JNIEnv* env) { - return RegisterNativesImpl(env); -} - -} // namespace android -} // namespace base diff --git a/base/android/java_handler_thread.h b/base/android/java_handler_thread.h deleted file mode 100644 index 9f66d660c8..0000000000 --- a/base/android/java_handler_thread.h +++ /dev/null @@ -1,48 +0,0 @@ -// Copyright 2013 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef BASE_THREADING_JAVA_THREAD_H_ -#define BASE_THREADING_JAVA_THREAD_H_ - -#include - -#include "base/android/scoped_java_ref.h" -#include "base/memory/scoped_ptr.h" - -namespace base { - -class MessageLoop; -class WaitableEvent; - -namespace android { - -// A Java Thread with a native message loop. To run tasks, post them -// to the message loop and they will be scheduled along with Java tasks -// on the thread. -// This is useful for callbacks where the receiver expects a thread -// with a prepared Looper. -class BASE_EXPORT JavaHandlerThread { - public: - JavaHandlerThread(const char* name); - virtual ~JavaHandlerThread(); - - base::MessageLoop* message_loop() const { return message_loop_.get(); } - void Start(); - void Stop(); - - // Called from java on the newly created thread. - // Start() will not return before this methods has finished. - void InitializeThread(JNIEnv* env, jobject obj, jint event); - - static bool RegisterBindings(JNIEnv* env); - - private: - scoped_ptr message_loop_; - ScopedJavaGlobalRef java_thread_; -}; - -} // namespace android -} // namespace base - -#endif // BASE_THREADING_JAVA_THREAD_H_ diff --git a/base/android/javatests/src/org/chromium/base/ContextTypesTest.java b/base/android/javatests/src/org/chromium/base/ContextTypesTest.java deleted file mode 100644 index a26b3177d8..0000000000 --- a/base/android/javatests/src/org/chromium/base/ContextTypesTest.java +++ /dev/null @@ -1,43 +0,0 @@ -// Copyright 2013 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -package org.chromium.base; - -import android.content.Context; -import android.test.AndroidTestCase; -import android.test.mock.MockContext; -import android.test.suitebuilder.annotation.SmallTest; - -import static org.chromium.base.ContextTypes.CONTEXT_TYPE_NORMAL; -import static org.chromium.base.ContextTypes.CONTEXT_TYPE_WEBAPP; - -public class ContextTypesTest extends AndroidTestCase { - - @SmallTest - public void testReturnsExpectedType() { - ContextTypes contextTypes = ContextTypes.getInstance(); - Context normal = new MockContext(); - Context webapp = new MockContext(); - contextTypes.put(normal, CONTEXT_TYPE_NORMAL); - contextTypes.put(webapp, CONTEXT_TYPE_WEBAPP); - assertEquals(CONTEXT_TYPE_NORMAL, contextTypes.getType(normal)); - assertEquals(CONTEXT_TYPE_WEBAPP, contextTypes.getType(webapp)); - } - - @SmallTest - public void testAbsentContextReturnsNormalType() { - assertEquals(CONTEXT_TYPE_NORMAL, ContextTypes.getInstance().getType(new MockContext())); - } - - @SmallTest - public void testPutInvalidTypeThrowsException() { - boolean exceptionThrown = false; - try { - ContextTypes.getInstance().put(new MockContext(), -1); - } catch (IllegalArgumentException e) { - exceptionThrown = true; - } - assertTrue(exceptionThrown); - } -} diff --git a/base/android/javatests/src/org/chromium/base/ObserverListTest.java b/base/android/javatests/src/org/chromium/base/ObserverListTest.java deleted file mode 100644 index 10c898c2a3..0000000000 --- a/base/android/javatests/src/org/chromium/base/ObserverListTest.java +++ /dev/null @@ -1,180 +0,0 @@ -// Copyright 2013 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -package org.chromium.base; - -import android.test.InstrumentationTestCase; -import android.test.suitebuilder.annotation.SmallTest; - -import org.chromium.base.test.util.Feature; - -import java.lang.Iterable; -import java.util.Iterator; -import java.util.NoSuchElementException; - -/** - * Tests for (@link ObserverList}. - */ -public class ObserverListTest extends InstrumentationTestCase { - interface Observer { - void observe(int x); - } - - private static class Foo implements Observer { - private final int mScalar; - private int mTotal = 0; - - Foo(int scalar) { - mScalar = scalar; - } - - @Override - public void observe(int x) { - mTotal += x * mScalar; - } - } - - /** - * An observer which add a given Observer object to the list when observe is called. - */ - private static class FooAdder implements Observer { - private final ObserverList mList; - private final Observer mLucky; - - FooAdder(ObserverList list, Observer oblivious) { - mList = list; - mLucky = oblivious; - } - - @Override - public void observe(int x) { - mList.addObserver(mLucky); - } - } - - /** - * An observer which removes a given Observer object from the list when observe is called. - */ - private static class FooRemover implements Observer { - private final ObserverList mList; - private final Observer mDoomed; - - FooRemover(ObserverList list, Observer innocent) { - mList = list; - mDoomed = innocent; - } - - @Override - public void observe(int x) { - mList.removeObserver(mDoomed); - } - } - - private static int getSizeOfIterable(Iterable iterable) { - int num = 0; - for (T el : iterable) - num++; - return num; - } - - @SmallTest - @Feature({"Android-AppBase"}) - public void testRemoveWhileIteration() { - ObserverList observerList = new ObserverList(); - Foo a = new Foo(1); - Foo b = new Foo(-1); - Foo c = new Foo(1); - Foo d = new Foo(-1); - Foo e = new Foo(-1); - FooRemover evil = new FooRemover(observerList, c); - - observerList.addObserver(a); - observerList.addObserver(b); - - for (Observer obs : observerList) - obs.observe(10); - - // Removing an observer not in the list should do nothing. - observerList.removeObserver(e); - - observerList.addObserver(evil); - observerList.addObserver(c); - observerList.addObserver(d); - - for (Observer obs : observerList) - obs.observe(10); - - // observe should be called twice on a. - assertEquals(20, a.mTotal); - // observe should be called twice on b. - assertEquals(-20, b.mTotal); - // evil removed c from the observerList before it got any callbacks. - assertEquals(0, c.mTotal); - // observe should be called once on d. - assertEquals(-10, d.mTotal); - // e was never added to the list, observe should not be called. - assertEquals(0, e.mTotal); - } - - @SmallTest - @Feature({"Android-AppBase"}) - public void testAddWhileIteration() { - ObserverList observerList = new ObserverList(); - Foo a = new Foo(1); - Foo b = new Foo(-1); - Foo c = new Foo(1); - FooAdder evil = new FooAdder(observerList, c); - - observerList.addObserver(evil); - observerList.addObserver(a); - observerList.addObserver(b); - - for (Observer obs : observerList) - obs.observe(10); - - assertTrue(observerList.hasObserver(c)); - assertEquals(10, a.mTotal); - assertEquals(-10, b.mTotal); - assertEquals(0, c.mTotal); - } - - @SmallTest - @Feature({"Android-AppBase"}) - public void testIterator() { - ObserverList observerList = new ObserverList(); - observerList.addObserver(5); - observerList.addObserver(10); - observerList.addObserver(15); - assertEquals(3, getSizeOfIterable(observerList)); - - observerList.removeObserver(10); - assertEquals(2, getSizeOfIterable(observerList)); - - Iterator it = observerList.iterator(); - assertTrue(it.hasNext()); - assertTrue(5 == it.next()); - assertTrue(it.hasNext()); - assertTrue(15 == it.next()); - assertFalse(it.hasNext()); - - boolean removeExceptionThrown = false; - try { - it.remove(); - fail("Expecting UnsupportedOperationException to be thrown here."); - } catch (UnsupportedOperationException e) { - removeExceptionThrown = true; - } - assertTrue(removeExceptionThrown); - assertEquals(2, getSizeOfIterable(observerList)); - - boolean noElementExceptionThrown = false; - try { - it.next(); - fail("Expecting NoSuchElementException to be thrown here."); - } catch (NoSuchElementException e) { - noElementExceptionThrown = true; - } - assertTrue(noElementExceptionThrown); - } -} diff --git a/base/android/jni_android.cc b/base/android/jni_android.cc deleted file mode 100644 index fc89b5403f..0000000000 --- a/base/android/jni_android.cc +++ /dev/null @@ -1,323 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "base/android/jni_android.h" - -#include - -#include "base/android/build_info.h" -#include "base/android/jni_string.h" -#include "base/lazy_instance.h" -#include "base/logging.h" -#include "base/threading/platform_thread.h" - -namespace { -using base::android::GetClass; -using base::android::MethodID; -using base::android::ScopedJavaLocalRef; - -struct MethodIdentifier { - const char* class_name; - const char* method; - const char* jni_signature; - - bool operator<(const MethodIdentifier& other) const { - int r = strcmp(class_name, other.class_name); - if (r < 0) { - return true; - } else if (r > 0) { - return false; - } - - r = strcmp(method, other.method); - if (r < 0) { - return true; - } else if (r > 0) { - return false; - } - - return strcmp(jni_signature, other.jni_signature) < 0; - } -}; - -typedef std::map MethodIDMap; - -const base::subtle::AtomicWord kUnlocked = 0; -const base::subtle::AtomicWord kLocked = 1; -base::subtle::AtomicWord g_method_id_map_lock = kUnlocked; -JavaVM* g_jvm = NULL; -// Leak the global app context, as it is used from a non-joinable worker thread -// that may still be running at shutdown. There is no harm in doing this. -base::LazyInstance >::Leaky - g_application_context = LAZY_INSTANCE_INITIALIZER; -base::LazyInstance g_method_id_map = LAZY_INSTANCE_INITIALIZER; - -std::string GetJavaExceptionInfo(JNIEnv* env, jthrowable java_throwable) { - ScopedJavaLocalRef throwable_clazz = - GetClass(env, "java/lang/Throwable"); - jmethodID throwable_printstacktrace = - MethodID::Get( - env, throwable_clazz.obj(), "printStackTrace", - "(Ljava/io/PrintStream;)V"); - - // Create an instance of ByteArrayOutputStream. - ScopedJavaLocalRef bytearray_output_stream_clazz = - GetClass(env, "java/io/ByteArrayOutputStream"); - jmethodID bytearray_output_stream_constructor = - MethodID::Get( - env, bytearray_output_stream_clazz.obj(), "", "()V"); - jmethodID bytearray_output_stream_tostring = - MethodID::Get( - env, bytearray_output_stream_clazz.obj(), "toString", - "()Ljava/lang/String;"); - ScopedJavaLocalRef bytearray_output_stream(env, - env->NewObject(bytearray_output_stream_clazz.obj(), - bytearray_output_stream_constructor)); - - // Create an instance of PrintStream. - ScopedJavaLocalRef printstream_clazz = - GetClass(env, "java/io/PrintStream"); - jmethodID printstream_constructor = - MethodID::Get( - env, printstream_clazz.obj(), "", - "(Ljava/io/OutputStream;)V"); - ScopedJavaLocalRef printstream(env, - env->NewObject(printstream_clazz.obj(), printstream_constructor, - bytearray_output_stream.obj())); - - // Call Throwable.printStackTrace(PrintStream) - env->CallVoidMethod(java_throwable, throwable_printstacktrace, - printstream.obj()); - - // Call ByteArrayOutputStream.toString() - ScopedJavaLocalRef exception_string( - env, static_cast( - env->CallObjectMethod(bytearray_output_stream.obj(), - bytearray_output_stream_tostring))); - - return ConvertJavaStringToUTF8(exception_string); -} - -} // namespace - -namespace base { -namespace android { - -JNIEnv* AttachCurrentThread() { - DCHECK(g_jvm); - JNIEnv* env = NULL; - jint ret = g_jvm->AttachCurrentThread(&env, NULL); - DCHECK_EQ(JNI_OK, ret); - return env; -} - -void DetachFromVM() { - // Ignore the return value, if the thread is not attached, DetachCurrentThread - // will fail. But it is ok as the native thread may never be attached. - if (g_jvm) - g_jvm->DetachCurrentThread(); -} - -void InitVM(JavaVM* vm) { - DCHECK(!g_jvm); - g_jvm = vm; -} - -void InitApplicationContext(const JavaRef& context) { - DCHECK(g_application_context.Get().is_null()); - g_application_context.Get().Reset(context); -} - -const jobject GetApplicationContext() { - DCHECK(!g_application_context.Get().is_null()); - return g_application_context.Get().obj(); -} - -ScopedJavaLocalRef GetClass(JNIEnv* env, const char* class_name) { - jclass clazz = env->FindClass(class_name); - CHECK(!ClearException(env) && clazz) << "Failed to find class " << class_name; - return ScopedJavaLocalRef(env, clazz); -} - -bool HasClass(JNIEnv* env, const char* class_name) { - ScopedJavaLocalRef clazz(env, env->FindClass(class_name)); - if (!clazz.obj()) { - ClearException(env); - return false; - } - bool error = ClearException(env); - DCHECK(!error); - return true; -} - -template -jmethodID MethodID::Get(JNIEnv* env, - jclass clazz, - const char* method_name, - const char* jni_signature) { - jmethodID id = type == TYPE_STATIC ? - env->GetStaticMethodID(clazz, method_name, jni_signature) : - env->GetMethodID(clazz, method_name, jni_signature); - CHECK(base::android::ClearException(env) || id) << - "Failed to find " << - (type == TYPE_STATIC ? "static " : "") << - "method " << method_name << " " << jni_signature; - return id; -} - -// If |atomic_method_id| set, it'll return immediately. Otherwise, it'll call -// into ::Get() above. If there's a race, it's ok since the values are the same -// (and the duplicated effort will happen only once). -template -jmethodID MethodID::LazyGet(JNIEnv* env, - jclass clazz, - const char* method_name, - const char* jni_signature, - base::subtle::AtomicWord* atomic_method_id) { - COMPILE_ASSERT(sizeof(subtle::AtomicWord) >= sizeof(jmethodID), - AtomicWord_SmallerThan_jMethodID); - subtle::AtomicWord value = base::subtle::Acquire_Load(atomic_method_id); - if (value) - return reinterpret_cast(value); - jmethodID id = MethodID::Get(env, clazz, method_name, jni_signature); - base::subtle::Release_Store( - atomic_method_id, reinterpret_cast(id)); - return id; -} - -// Various template instantiations. -template jmethodID MethodID::Get( - JNIEnv* env, jclass clazz, const char* method_name, - const char* jni_signature); - -template jmethodID MethodID::Get( - JNIEnv* env, jclass clazz, const char* method_name, - const char* jni_signature); - -template jmethodID MethodID::LazyGet( - JNIEnv* env, jclass clazz, const char* method_name, - const char* jni_signature, base::subtle::AtomicWord* atomic_method_id); - -template jmethodID MethodID::LazyGet( - JNIEnv* env, jclass clazz, const char* method_name, - const char* jni_signature, base::subtle::AtomicWord* atomic_method_id); - -jfieldID GetFieldID(JNIEnv* env, - const JavaRef& clazz, - const char* field_name, - const char* jni_signature) { - jfieldID field_id = env->GetFieldID(clazz.obj(), field_name, jni_signature); - CHECK(!ClearException(env) && field_id) << "Failed to find field " << - field_name << " " << jni_signature; - return field_id; -} - -bool HasField(JNIEnv* env, - const JavaRef& clazz, - const char* field_name, - const char* jni_signature) { - jfieldID field_id = env->GetFieldID(clazz.obj(), field_name, jni_signature); - if (!field_id) { - ClearException(env); - return false; - } - bool error = ClearException(env); - DCHECK(!error); - return true; -} - -jfieldID GetStaticFieldID(JNIEnv* env, - const JavaRef& clazz, - const char* field_name, - const char* jni_signature) { - jfieldID field_id = - env->GetStaticFieldID(clazz.obj(), field_name, jni_signature); - CHECK(!ClearException(env) && field_id) << "Failed to find static field " << - field_name << " " << jni_signature; - return field_id; -} - -jmethodID GetMethodIDFromClassName(JNIEnv* env, - const char* class_name, - const char* method, - const char* jni_signature) { - MethodIdentifier key; - key.class_name = class_name; - key.method = method; - key.jni_signature = jni_signature; - - MethodIDMap* map = g_method_id_map.Pointer(); - bool found = false; - - while (base::subtle::Acquire_CompareAndSwap(&g_method_id_map_lock, - kUnlocked, - kLocked) != kUnlocked) { - base::PlatformThread::YieldCurrentThread(); - } - MethodIDMap::const_iterator iter = map->find(key); - if (iter != map->end()) { - found = true; - } - base::subtle::Release_Store(&g_method_id_map_lock, kUnlocked); - - // Addition to the map does not invalidate this iterator. - if (found) { - return iter->second; - } - - ScopedJavaLocalRef clazz(env, env->FindClass(class_name)); - jmethodID id = MethodID::Get( - env, clazz.obj(), method, jni_signature); - - while (base::subtle::Acquire_CompareAndSwap(&g_method_id_map_lock, - kUnlocked, - kLocked) != kUnlocked) { - base::PlatformThread::YieldCurrentThread(); - } - // Another thread may have populated the map already. - std::pair result = - map->insert(std::make_pair(key, id)); - DCHECK_EQ(id, result.first->second); - base::subtle::Release_Store(&g_method_id_map_lock, kUnlocked); - - return id; -} - -bool HasException(JNIEnv* env) { - return env->ExceptionCheck() != JNI_FALSE; -} - -bool ClearException(JNIEnv* env) { - if (!HasException(env)) - return false; - env->ExceptionDescribe(); - env->ExceptionClear(); - return true; -} - -void CheckException(JNIEnv* env) { - if (!HasException(env)) return; - - // Exception has been found, might as well tell breakpad about it. - jthrowable java_throwable = env->ExceptionOccurred(); - if (!java_throwable) { - // Do nothing but return false. - CHECK(false); - } - - // Clear the pending exception, since a local reference is now held. - env->ExceptionDescribe(); - env->ExceptionClear(); - - // Set the exception_string in BuildInfo so that breakpad can read it. - // RVO should avoid any extra copies of the exception string. - base::android::BuildInfo::GetInstance()->set_java_exception_info( - GetJavaExceptionInfo(env, java_throwable)); - - // Now, feel good about it and die. - CHECK(false); -} - -} // namespace android -} // namespace base diff --git a/base/android/jni_android.h b/base/android/jni_android.h deleted file mode 100644 index e8f68acfb7..0000000000 --- a/base/android/jni_android.h +++ /dev/null @@ -1,132 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef BASE_ANDROID_JNI_ANDROID_H_ -#define BASE_ANDROID_JNI_ANDROID_H_ - -#include -#include - -#include "base/android/scoped_java_ref.h" -#include "base/atomicops.h" -#include "base/base_export.h" -#include "base/compiler_specific.h" - -namespace base { -namespace android { - -// Used to mark symbols to be exported in a shared library's symbol table. -#define JNI_EXPORT __attribute__ ((visibility("default"))) - -// Contains the registration method information for initializing JNI bindings. -struct RegistrationMethod { - const char* name; - bool (*func)(JNIEnv* env); -}; - -// Attach the current thread to the VM (if necessary) and return the JNIEnv*. -BASE_EXPORT JNIEnv* AttachCurrentThread(); - -// Detach the current thread from VM if it is attached. -BASE_EXPORT void DetachFromVM(); - -// Initializes the global JVM. It is not necessarily called before -// InitApplicationContext(). -BASE_EXPORT void InitVM(JavaVM* vm); - -// Initializes the global application context object. The |context| can be any -// valid reference to the application context. Internally holds a global ref to -// the context. InitVM and InitApplicationContext maybe called in either order. -BASE_EXPORT void InitApplicationContext(const JavaRef& context); - -// Gets a global ref to the application context set with -// InitApplicationContext(). Ownership is retained by the function - the caller -// must NOT release it. -const BASE_EXPORT jobject GetApplicationContext(); - -// Finds the class named |class_name| and returns it. -// Use this method instead of invoking directly the JNI FindClass method (to -// prevent leaking local references). -// This method triggers a fatal assertion if the class could not be found. -// Use HasClass if you need to check whether the class exists. -BASE_EXPORT ScopedJavaLocalRef GetClass(JNIEnv* env, - const char* class_name); - -// Returns true iff the class |class_name| could be found. -BASE_EXPORT bool HasClass(JNIEnv* env, const char* class_name); - -// This class is a wrapper for JNIEnv Get(Static)MethodID. -class BASE_EXPORT MethodID { - public: - enum Type { - TYPE_STATIC, - TYPE_INSTANCE, - }; - - // Returns the method ID for the method with the specified name and signature. - // This method triggers a fatal assertion if the method could not be found. - template - static jmethodID Get(JNIEnv* env, - jclass clazz, - const char* method_name, - const char* jni_signature); - - // The caller is responsible to zero-initialize |atomic_method_id|. - // It's fine to simultaneously call this on multiple threads referencing the - // same |atomic_method_id|. - template - static jmethodID LazyGet(JNIEnv* env, - jclass clazz, - const char* method_name, - const char* jni_signature, - base::subtle::AtomicWord* atomic_method_id); -}; - -// Gets the method ID from the class name. Clears the pending Java exception -// and returns NULL if the method is not found. Caches results. Note that -// MethodID::Get() above avoids a class lookup, but does not cache results. -// Strings passed to this function are held in the cache and MUST remain valid -// beyond the duration of all future calls to this function, across all -// threads. In practice, this means that the function should only be used with -// string constants. -BASE_EXPORT jmethodID GetMethodIDFromClassName(JNIEnv* env, - const char* class_name, - const char* method, - const char* jni_signature); - -// Gets the field ID for a class field. -// This method triggers a fatal assertion if the field could not be found. -BASE_EXPORT jfieldID GetFieldID(JNIEnv* env, - const JavaRef& clazz, - const char* field_name, - const char* jni_signature); - -// Returns true if |clazz| as a field with the given name and signature. -// TODO(jcivelli): Determine whether we explicitly have to pass the environment. -BASE_EXPORT bool HasField(JNIEnv* env, - const JavaRef& clazz, - const char* field_name, - const char* jni_signature); - -// Gets the field ID for a static class field. -// This method triggers a fatal assertion if the field could not be found. -BASE_EXPORT jfieldID GetStaticFieldID(JNIEnv* env, - const JavaRef& clazz, - const char* field_name, - const char* jni_signature); - -// Returns true if an exception is pending in the provided JNIEnv*. -BASE_EXPORT bool HasException(JNIEnv* env); - -// If an exception is pending in the provided JNIEnv*, this function clears it -// and returns true. -BASE_EXPORT bool ClearException(JNIEnv* env); - -// This function will call CHECK() macro if there's any pending exception. -BASE_EXPORT void CheckException(JNIEnv* env); - -} // namespace android -} // namespace base - -#endif // BASE_ANDROID_JNI_ANDROID_H_ diff --git a/base/android/jni_android_unittest.cc b/base/android/jni_android_unittest.cc deleted file mode 100644 index 920b395659..0000000000 --- a/base/android/jni_android_unittest.cc +++ /dev/null @@ -1,141 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "base/android/jni_android.h" - -#include "base/at_exit.h" -#include "base/logging.h" -#include "testing/gtest/include/gtest/gtest.h" - -namespace base { -namespace android { - -namespace { - -const char kJavaLangObject[] = "java/lang/Object"; -const char kGetClass[] = "getClass"; -const char kToString[] = "toString"; -const char kReturningJavaLangClass[] = "()Ljava/lang/Class;"; -const char kReturningJavaLangString[] = "()Ljava/lang/String;"; - -const char* g_last_method; -const char* g_last_jni_signature; -jmethodID g_last_method_id; - -const JNINativeInterface* g_previous_functions; - -jmethodID GetMethodIDWrapper(JNIEnv* env, jclass clazz, const char* method, - const char* jni_signature) { - g_last_method = method; - g_last_jni_signature = jni_signature; - g_last_method_id = g_previous_functions->GetMethodID(env, clazz, method, - jni_signature); - return g_last_method_id; -} - -} // namespace - -class JNIAndroidTest : public testing::Test { - protected: - virtual void SetUp() { - JNIEnv* env = AttachCurrentThread(); - g_previous_functions = env->functions; - hooked_functions = *g_previous_functions; - env->functions = &hooked_functions; - hooked_functions.GetMethodID = &GetMethodIDWrapper; - } - - virtual void TearDown() { - JNIEnv* env = AttachCurrentThread(); - env->functions = g_previous_functions; - Reset(); - } - - void Reset() { - g_last_method = 0; - g_last_jni_signature = 0; - g_last_method_id = NULL; - } - // Needed to cleanup the cached method map in the implementation between - // runs (e.g. if using --gtest_repeat) - base::ShadowingAtExitManager exit_manager; - // From JellyBean release, the instance of this struct provided in JNIEnv is - // read-only, so we deep copy it to allow individual functions to be hooked. - JNINativeInterface hooked_functions; -}; - -TEST_F(JNIAndroidTest, GetMethodIDFromClassNameCaching) { - JNIEnv* env = AttachCurrentThread(); - - Reset(); - jmethodID id1 = GetMethodIDFromClassName(env, kJavaLangObject, kGetClass, - kReturningJavaLangClass); - EXPECT_STREQ(kGetClass, g_last_method); - EXPECT_STREQ(kReturningJavaLangClass, g_last_jni_signature); - EXPECT_EQ(g_last_method_id, id1); - - Reset(); - jmethodID id2 = GetMethodIDFromClassName(env, kJavaLangObject, kGetClass, - kReturningJavaLangClass); - EXPECT_STREQ(0, g_last_method); - EXPECT_STREQ(0, g_last_jni_signature); - EXPECT_EQ(NULL, g_last_method_id); - EXPECT_EQ(id1, id2); - - Reset(); - jmethodID id3 = GetMethodIDFromClassName(env, kJavaLangObject, kToString, - kReturningJavaLangString); - EXPECT_STREQ(kToString, g_last_method); - EXPECT_STREQ(kReturningJavaLangString, g_last_jni_signature); - EXPECT_EQ(g_last_method_id, id3); -} - -namespace { - -base::subtle::AtomicWord g_atomic_id = 0; -int LazyMethodIDCall(JNIEnv* env, jclass clazz, int p) { - jmethodID id = base::android::MethodID::LazyGet< - base::android::MethodID::TYPE_STATIC>( - env, clazz, - "abs", - "(I)I", - &g_atomic_id); - - return env->CallStaticIntMethod(clazz, id, p); -} - -int MethodIDCall(JNIEnv* env, jclass clazz, jmethodID id, int p) { - return env->CallStaticIntMethod(clazz, id, p); -} - -} // namespace - -TEST(JNIAndroidMicrobenchmark, MethodId) { - JNIEnv* env = AttachCurrentThread(); - ScopedJavaLocalRef clazz(GetClass(env, "java/lang/Math")); - base::Time start_lazy = base::Time::Now(); - int o = 0; - for (int i = 0; i < 1024; ++i) - o += LazyMethodIDCall(env, clazz.obj(), i); - base::Time end_lazy = base::Time::Now(); - - jmethodID id = reinterpret_cast(g_atomic_id); - base::Time start = base::Time::Now(); - for (int i = 0; i < 1024; ++i) - o += MethodIDCall(env, clazz.obj(), id, i); - base::Time end = base::Time::Now(); - - // On a Galaxy Nexus, results were in the range of: - // JNI LazyMethodIDCall (us) 1984 - // JNI MethodIDCall (us) 1861 - LOG(ERROR) << "JNI LazyMethodIDCall (us) " << - base::TimeDelta(end_lazy - start_lazy).InMicroseconds(); - LOG(ERROR) << "JNI MethodIDCall (us) " << - base::TimeDelta(end - start).InMicroseconds(); - LOG(ERROR) << "JNI " << o; -} - - -} // namespace android -} // namespace base diff --git a/base/android/jni_array.cc b/base/android/jni_array.cc deleted file mode 100644 index bbe00c6129..0000000000 --- a/base/android/jni_array.cc +++ /dev/null @@ -1,186 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "base/android/jni_array.h" - -#include "base/android/jni_android.h" -#include "base/android/jni_string.h" -#include "base/logging.h" - -namespace base { -namespace android { - -ScopedJavaLocalRef ToJavaByteArray( - JNIEnv* env, const uint8* bytes, size_t len) { - jbyteArray byte_array = env->NewByteArray(len); - CheckException(env); - DCHECK(byte_array); - - jbyte* elements = env->GetByteArrayElements(byte_array, NULL); - memcpy(elements, bytes, len); - env->ReleaseByteArrayElements(byte_array, elements, 0); - CheckException(env); - - return ScopedJavaLocalRef(env, byte_array); -} - -ScopedJavaLocalRef ToJavaLongArray( - JNIEnv* env, const int64* longs, size_t len) { - jlongArray long_array = env->NewLongArray(len); - CheckException(env); - DCHECK(long_array); - - jlong* elements = env->GetLongArrayElements(long_array, NULL); - memcpy(elements, longs, len * sizeof(*longs)); - env->ReleaseLongArrayElements(long_array, elements, 0); - CheckException(env); - - return ScopedJavaLocalRef(env, long_array); -} - -// Returns a new Java long array converted from the given int64 array. -BASE_EXPORT ScopedJavaLocalRef ToJavaLongArray( - JNIEnv* env, const std::vector& longs) { - return ToJavaLongArray(env, longs.begin(), longs.size()); -} - -ScopedJavaLocalRef ToJavaArrayOfByteArray( - JNIEnv* env, const std::vector& v) { - ScopedJavaLocalRef byte_array_clazz = GetClass(env, "[B"); - jobjectArray joa = env->NewObjectArray(v.size(), - byte_array_clazz.obj(), NULL); - CheckException(env); - - for (size_t i = 0; i < v.size(); ++i) { - ScopedJavaLocalRef byte_array = ToJavaByteArray(env, - reinterpret_cast(v[i].data()), v[i].length()); - env->SetObjectArrayElement(joa, i, byte_array.obj()); - } - return ScopedJavaLocalRef(env, joa); -} - -ScopedJavaLocalRef ToJavaArrayOfStrings( - JNIEnv* env, const std::vector& v) { - ScopedJavaLocalRef string_clazz = GetClass(env, "java/lang/String"); - jobjectArray joa = env->NewObjectArray(v.size(), string_clazz.obj(), NULL); - CheckException(env); - - for (size_t i = 0; i < v.size(); ++i) { - ScopedJavaLocalRef item = ConvertUTF8ToJavaString(env, v[i]); - env->SetObjectArrayElement(joa, i, item.obj()); - } - return ScopedJavaLocalRef(env, joa); -} - -ScopedJavaLocalRef ToJavaArrayOfStrings( - JNIEnv* env, const std::vector& v) { - ScopedJavaLocalRef string_clazz = GetClass(env, "java/lang/String"); - jobjectArray joa = env->NewObjectArray(v.size(), string_clazz.obj(), NULL); - CheckException(env); - - for (size_t i = 0; i < v.size(); ++i) { - ScopedJavaLocalRef item = ConvertUTF16ToJavaString(env, v[i]); - env->SetObjectArrayElement(joa, i, item.obj()); - } - return ScopedJavaLocalRef(env, joa); -} - -void AppendJavaStringArrayToStringVector(JNIEnv* env, - jobjectArray array, - std::vector* out) { - DCHECK(out); - if (!array) - return; - jsize len = env->GetArrayLength(array); - size_t back = out->size(); - out->resize(back + len); - for (jsize i = 0; i < len; ++i) { - ScopedJavaLocalRef str(env, - static_cast(env->GetObjectArrayElement(array, i))); - ConvertJavaStringToUTF16(env, str.obj(), &((*out)[back + i])); - } -} - -void AppendJavaStringArrayToStringVector(JNIEnv* env, - jobjectArray array, - std::vector* out) { - DCHECK(out); - if (!array) - return; - jsize len = env->GetArrayLength(array); - size_t back = out->size(); - out->resize(back + len); - for (jsize i = 0; i < len; ++i) { - ScopedJavaLocalRef str(env, - static_cast(env->GetObjectArrayElement(array, i))); - ConvertJavaStringToUTF8(env, str.obj(), &((*out)[back + i])); - } -} - -void AppendJavaByteArrayToByteVector(JNIEnv* env, - jbyteArray byte_array, - std::vector* out) { - DCHECK(out); - if (!byte_array) - return; - jsize len = env->GetArrayLength(byte_array); - jbyte* bytes = env->GetByteArrayElements(byte_array, NULL); - out->insert(out->end(), bytes, bytes + len); - env->ReleaseByteArrayElements(byte_array, bytes, JNI_ABORT); -} - -void JavaByteArrayToByteVector(JNIEnv* env, - jbyteArray byte_array, - std::vector* out) { - DCHECK(out); - out->clear(); - AppendJavaByteArrayToByteVector(env, byte_array, out); -} - -void JavaIntArrayToIntVector(JNIEnv* env, - jintArray int_array, - std::vector* out) { - DCHECK(out); - out->clear(); - jsize len = env->GetArrayLength(int_array); - jint* ints = env->GetIntArrayElements(int_array, NULL); - for (jsize i = 0; i < len; ++i) { - out->push_back(static_cast(ints[i])); - } - env->ReleaseIntArrayElements(int_array, ints, JNI_ABORT); -} - -void JavaFloatArrayToFloatVector(JNIEnv* env, - jfloatArray float_array, - std::vector* out) { - DCHECK(out); - out->clear(); - jsize len = env->GetArrayLength(float_array); - jfloat* floats = env->GetFloatArrayElements(float_array, NULL); - for (jsize i = 0; i < len; ++i) { - out->push_back(static_cast(floats[i])); - } - env->ReleaseFloatArrayElements(float_array, floats, JNI_ABORT); -} - -void JavaArrayOfByteArrayToStringVector( - JNIEnv* env, - jobjectArray array, - std::vector* out) { - DCHECK(out); - out->clear(); - jsize len = env->GetArrayLength(array); - out->resize(len); - for (jsize i = 0; i < len; ++i) { - jbyteArray bytes_array = static_cast( - env->GetObjectArrayElement(array, i)); - jsize bytes_len = env->GetArrayLength(bytes_array); - jbyte* bytes = env->GetByteArrayElements(bytes_array, NULL); - (*out)[i].assign(reinterpret_cast(bytes), bytes_len); - env->ReleaseByteArrayElements(bytes_array, bytes, JNI_ABORT); - } -} - -} // namespace android -} // namespace base diff --git a/base/android/jni_array.h b/base/android/jni_array.h deleted file mode 100644 index efa6aa8ffe..0000000000 --- a/base/android/jni_array.h +++ /dev/null @@ -1,86 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef BASE_ANDROID_JNI_ARRAY_H_ -#define BASE_ANDROID_JNI_ARRAY_H_ - -#include -#include -#include - -#include "base/android/scoped_java_ref.h" -#include "base/basictypes.h" -#include "base/strings/string16.h" - -namespace base { -namespace android { - -// Returns a new Java byte array converted from the given bytes array. -BASE_EXPORT ScopedJavaLocalRef ToJavaByteArray( - JNIEnv* env, const uint8* bytes, size_t len); - -// Returns a new Java long array converted from the given int64 array. -BASE_EXPORT ScopedJavaLocalRef ToJavaLongArray( - JNIEnv* env, const int64* longs, size_t len); - -BASE_EXPORT ScopedJavaLocalRef ToJavaLongArray( - JNIEnv* env, const std::vector& longs); - -// Returns a array of Java byte array converted from |v|. -BASE_EXPORT ScopedJavaLocalRef ToJavaArrayOfByteArray( - JNIEnv* env, const std::vector& v); - -BASE_EXPORT ScopedJavaLocalRef ToJavaArrayOfStrings( - JNIEnv* env, const std::vector& v); - -BASE_EXPORT ScopedJavaLocalRef ToJavaArrayOfStrings( - JNIEnv* env, const std::vector& v); - -// Converts a Java string array to a native array. -BASE_EXPORT void AppendJavaStringArrayToStringVector( - JNIEnv* env, - jobjectArray array, - std::vector* out); - -BASE_EXPORT void AppendJavaStringArrayToStringVector( - JNIEnv* env, - jobjectArray array, - std::vector* out); - -// Appends the Java bytes in |bytes_array| onto the end of |out|. -BASE_EXPORT void AppendJavaByteArrayToByteVector( - JNIEnv* env, - jbyteArray byte_array, - std::vector* out); - -// Replaces the content of |out| with the Java bytes in |bytes_array|. -BASE_EXPORT void JavaByteArrayToByteVector( - JNIEnv* env, - jbyteArray byte_array, - std::vector* out); - -// Replaces the content of |out| with the Java ints in |int_array|. -BASE_EXPORT void JavaIntArrayToIntVector( - JNIEnv* env, - jintArray int_array, - std::vector* out); - -// Replaces the content of |out| with the Java floats in |float_array|. -BASE_EXPORT void JavaFloatArrayToFloatVector( - JNIEnv* env, - jfloatArray float_array, - std::vector* out); - -// Assuming |array| is an byte[][] (array of byte arrays), replaces the -// content of |out| with the corresponding vector of strings. No UTF-8 -// conversion is performed. -BASE_EXPORT void JavaArrayOfByteArrayToStringVector( - JNIEnv* env, - jobjectArray array, - std::vector* out); - -} // namespace android -} // namespace base - -#endif // BASE_ANDROID_JNI_ARRAY_H_ diff --git a/base/android/jni_array_unittest.cc b/base/android/jni_array_unittest.cc deleted file mode 100644 index 3ac7855e40..0000000000 --- a/base/android/jni_array_unittest.cc +++ /dev/null @@ -1,148 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "base/android/jni_array.h" - -#include "base/android/jni_android.h" -#include "base/android/scoped_java_ref.h" -#include "testing/gtest/include/gtest/gtest.h" - -namespace base { -namespace android { - -TEST(JniArray, BasicConversions) { - const uint8 kBytes[] = { 0, 1, 2, 3 }; - const size_t kLen = arraysize(kBytes); - JNIEnv* env = AttachCurrentThread(); - ScopedJavaLocalRef bytes = ToJavaByteArray(env, kBytes, kLen); - ASSERT_TRUE(bytes.obj()); - - std::vector vec(5); - JavaByteArrayToByteVector(env, bytes.obj(), &vec); - EXPECT_EQ(4U, vec.size()); - EXPECT_EQ(std::vector(kBytes, kBytes + kLen), vec); - - AppendJavaByteArrayToByteVector(env, bytes.obj(), &vec); - EXPECT_EQ(8U, vec.size()); -} - -void CheckLongConversion( - JNIEnv* env, - const int64* long_array, - const size_t len, - const ScopedJavaLocalRef& longs) { - ASSERT_TRUE(longs.obj()); - - jsize java_array_len = env->GetArrayLength(longs.obj()); - ASSERT_EQ(static_cast(len), java_array_len); - - jlong value; - for (size_t i = 0; i < len; ++i) { - env->GetLongArrayRegion(longs.obj(), i, 1, &value); - ASSERT_EQ(long_array[i], value); - } -} - -TEST(JniArray, LongConversions) { - const int64 kLongs[] = { 0, 1, -1, kint64min, kint64max}; - const size_t kLen = arraysize(kLongs); - - JNIEnv* env = AttachCurrentThread(); - CheckLongConversion(env, kLongs, kLen, ToJavaLongArray(env, kLongs, kLen)); - - const std::vector vec(kLongs, kLongs + kLen); - CheckLongConversion(env, kLongs, kLen, ToJavaLongArray(env, vec)); -} - -TEST(JniArray, JavaIntArrayToIntVector) { - const int kInts[] = {0, 1, -1}; - const size_t kLen = arraysize(kInts); - - JNIEnv* env = AttachCurrentThread(); - ScopedJavaLocalRef jints(env, env->NewIntArray(kLen)); - ASSERT_TRUE(jints.obj()); - - for (size_t i = 0; i < kLen; ++i) { - jint j = static_cast(kInts[i]); - env->SetIntArrayRegion(jints.obj(), i, 1, &j); - ASSERT_FALSE(HasException(env)); - } - - std::vector ints; - JavaIntArrayToIntVector(env, jints.obj(), &ints); - - ASSERT_EQ(static_cast(ints.size()), env->GetArrayLength(jints.obj())); - - jint value; - for (size_t i = 0; i < kLen; ++i) { - env->GetIntArrayRegion(jints.obj(), i, 1, &value); - ASSERT_EQ(ints[i], value); - } -} - -TEST(JniArray, JavaFloatArrayToFloatVector) { - const float kFloats[] = {0.0, 0.5, -0.5}; - const size_t kLen = arraysize(kFloats); - - JNIEnv* env = AttachCurrentThread(); - ScopedJavaLocalRef jfloats(env, env->NewFloatArray(kLen)); - ASSERT_TRUE(jfloats.obj()); - - for (size_t i = 0; i < kLen; ++i) { - jfloat j = static_cast(kFloats[i]); - env->SetFloatArrayRegion(jfloats.obj(), i, 1, &j); - ASSERT_FALSE(HasException(env)); - } - - std::vector floats; - JavaFloatArrayToFloatVector(env, jfloats.obj(), &floats); - - ASSERT_EQ(static_cast(floats.size()), - env->GetArrayLength(jfloats.obj())); - - jfloat value; - for (size_t i = 0; i < kLen; ++i) { - env->GetFloatArrayRegion(jfloats.obj(), i, 1, &value); - ASSERT_EQ(floats[i], value); - } -} - -TEST(JniArray, JavaArrayOfByteArrayToStringVector) { - const int kMaxItems = 50; - JNIEnv* env = AttachCurrentThread(); - - // Create a byte[][] object. - ScopedJavaLocalRef byte_array_clazz(env, env->FindClass("[B")); - ASSERT_TRUE(byte_array_clazz.obj()); - - ScopedJavaLocalRef array( - env, env->NewObjectArray(kMaxItems, byte_array_clazz.obj(), NULL)); - ASSERT_TRUE(array.obj()); - - // Create kMaxItems byte buffers. - char text[16]; - for (int i = 0; i < kMaxItems; ++i) { - snprintf(text, sizeof text, "%d", i); - ScopedJavaLocalRef byte_array = ToJavaByteArray( - env, reinterpret_cast(text), - static_cast(strlen(text))); - ASSERT_TRUE(byte_array.obj()); - - env->SetObjectArrayElement(array.obj(), i, byte_array.obj()); - ASSERT_FALSE(HasException(env)); - } - - // Convert to std::vector, check the content. - std::vector vec; - JavaArrayOfByteArrayToStringVector(env, array.obj(), &vec); - - EXPECT_EQ(static_cast(kMaxItems), vec.size()); - for (int i = 0; i < kMaxItems; ++i) { - snprintf(text, sizeof text, "%d", i); - EXPECT_STREQ(text, vec[i].c_str()); - } -} - -} // namespace android -} // namespace base diff --git a/base/android/jni_generator/golden_sample_for_tests_jni.h b/base/android/jni_generator/golden_sample_for_tests_jni.h deleted file mode 100644 index 2c5f6c0025..0000000000 --- a/base/android/jni_generator/golden_sample_for_tests_jni.h +++ /dev/null @@ -1,373 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -// This file is autogenerated by -// base/android/jni_generator/jni_generator_tests.py -// For -// org/chromium/example/jni_generator/SampleForTests - -#ifndef org_chromium_example_jni_generator_SampleForTests_JNI -#define org_chromium_example_jni_generator_SampleForTests_JNI - -#include - -#include "base/android/jni_android.h" -#include "base/android/scoped_java_ref.h" -#include "base/basictypes.h" -#include "base/logging.h" - -using base::android::ScopedJavaLocalRef; - -// Step 1: forward declarations. -namespace { -const char kInnerStructAClassPath[] = - "org/chromium/example/jni_generator/SampleForTests$InnerStructA"; -const char kSampleForTestsClassPath[] = - "org/chromium/example/jni_generator/SampleForTests"; -const char kInnerStructBClassPath[] = - "org/chromium/example/jni_generator/SampleForTests$InnerStructB"; -// Leaking this jclass as we cannot use LazyInstance from some threads. -jclass g_InnerStructA_clazz = NULL; -// Leaking this jclass as we cannot use LazyInstance from some threads. -jclass g_SampleForTests_clazz = NULL; -// Leaking this jclass as we cannot use LazyInstance from some threads. -jclass g_InnerStructB_clazz = NULL; -} // namespace - -namespace base { -namespace android { - -static jint Init(JNIEnv* env, jobject obj, - jstring param); - -static jdouble GetDoubleFunction(JNIEnv* env, jobject obj); - -static jfloat GetFloatFunction(JNIEnv* env, jclass clazz); - -static void SetNonPODDatatype(JNIEnv* env, jobject obj, - jobject rect); - -static jobject GetNonPODDatatype(JNIEnv* env, jobject obj); - -// Step 2: method stubs. -static void Destroy(JNIEnv* env, jobject obj, - jint nativeCPPClass) { - DCHECK(nativeCPPClass) << "Destroy"; - CPPClass* native = reinterpret_cast(nativeCPPClass); - return native->Destroy(env, obj); -} - -static jint Method(JNIEnv* env, jobject obj, - jint nativeCPPClass) { - DCHECK(nativeCPPClass) << "Method"; - CPPClass* native = reinterpret_cast(nativeCPPClass); - return native->Method(env, obj); -} - -static jdouble MethodOtherP0(JNIEnv* env, jobject obj, - jint nativePtr) { - DCHECK(nativePtr) << "MethodOtherP0"; - CPPClass::InnerClass* native = - reinterpret_cast(nativePtr); - return native->MethodOtherP0(env, obj); -} - -static void AddStructB(JNIEnv* env, jobject obj, - jint nativeCPPClass, - jobject b) { - DCHECK(nativeCPPClass) << "AddStructB"; - CPPClass* native = reinterpret_cast(nativeCPPClass); - return native->AddStructB(env, obj, b); -} - -static void IterateAndDoSomethingWithStructB(JNIEnv* env, jobject obj, - jint nativeCPPClass) { - DCHECK(nativeCPPClass) << "IterateAndDoSomethingWithStructB"; - CPPClass* native = reinterpret_cast(nativeCPPClass); - return native->IterateAndDoSomethingWithStructB(env, obj); -} - -static base::subtle::AtomicWord g_SampleForTests_javaMethod = 0; -static jint Java_SampleForTests_javaMethod(JNIEnv* env, jobject obj, jint foo, - jint bar) { - /* Must call RegisterNativesImpl() */ - DCHECK(g_SampleForTests_clazz); - jmethodID method_id = - base::android::MethodID::LazyGet< - base::android::MethodID::TYPE_INSTANCE>( - env, g_SampleForTests_clazz, - "javaMethod", - -"(" -"I" -"I" -")" -"I", - &g_SampleForTests_javaMethod); - - jint ret = - env->CallIntMethod(obj, - method_id, foo, bar); - base::android::CheckException(env); - return ret; -} - -static base::subtle::AtomicWord g_SampleForTests_staticJavaMethod = 0; -static jboolean Java_SampleForTests_staticJavaMethod(JNIEnv* env) { - /* Must call RegisterNativesImpl() */ - DCHECK(g_SampleForTests_clazz); - jmethodID method_id = - base::android::MethodID::LazyGet< - base::android::MethodID::TYPE_STATIC>( - env, g_SampleForTests_clazz, - "staticJavaMethod", - -"(" -")" -"Z", - &g_SampleForTests_staticJavaMethod); - - jboolean ret = - env->CallStaticBooleanMethod(g_SampleForTests_clazz, - method_id); - base::android::CheckException(env); - return ret; -} - -static base::subtle::AtomicWord g_SampleForTests_packagePrivateJavaMethod = 0; -static void Java_SampleForTests_packagePrivateJavaMethod(JNIEnv* env, jobject - obj) { - /* Must call RegisterNativesImpl() */ - DCHECK(g_SampleForTests_clazz); - jmethodID method_id = - base::android::MethodID::LazyGet< - base::android::MethodID::TYPE_INSTANCE>( - env, g_SampleForTests_clazz, - "packagePrivateJavaMethod", - -"(" -")" -"V", - &g_SampleForTests_packagePrivateJavaMethod); - - env->CallVoidMethod(obj, - method_id); - base::android::CheckException(env); - -} - -static base::subtle::AtomicWord g_SampleForTests_methodThatThrowsException = 0; -static void Java_SampleForTests_methodThatThrowsException(JNIEnv* env, jobject - obj) { - /* Must call RegisterNativesImpl() */ - DCHECK(g_SampleForTests_clazz); - jmethodID method_id = - base::android::MethodID::LazyGet< - base::android::MethodID::TYPE_INSTANCE>( - env, g_SampleForTests_clazz, - "methodThatThrowsException", - -"(" -")" -"V", - &g_SampleForTests_methodThatThrowsException); - - env->CallVoidMethod(obj, - method_id); - -} - -static base::subtle::AtomicWord g_InnerStructA_create = 0; -static ScopedJavaLocalRef Java_InnerStructA_create(JNIEnv* env, jlong - l, - jint i, - jstring s) { - /* Must call RegisterNativesImpl() */ - DCHECK(g_InnerStructA_clazz); - jmethodID method_id = - base::android::MethodID::LazyGet< - base::android::MethodID::TYPE_STATIC>( - env, g_InnerStructA_clazz, - "create", - -"(" -"J" -"I" -"Ljava/lang/String;" -")" -"Lorg/chromium/example/jni_generator/SampleForTests$InnerStructA;", - &g_InnerStructA_create); - - jobject ret = - env->CallStaticObjectMethod(g_InnerStructA_clazz, - method_id, l, i, s); - base::android::CheckException(env); - return ScopedJavaLocalRef(env, ret); -} - -static base::subtle::AtomicWord g_SampleForTests_addStructA = 0; -static void Java_SampleForTests_addStructA(JNIEnv* env, jobject obj, jobject a) - { - /* Must call RegisterNativesImpl() */ - DCHECK(g_SampleForTests_clazz); - jmethodID method_id = - base::android::MethodID::LazyGet< - base::android::MethodID::TYPE_INSTANCE>( - env, g_SampleForTests_clazz, - "addStructA", - -"(" -"Lorg/chromium/example/jni_generator/SampleForTests$InnerStructA;" -")" -"V", - &g_SampleForTests_addStructA); - - env->CallVoidMethod(obj, - method_id, a); - base::android::CheckException(env); - -} - -static base::subtle::AtomicWord g_SampleForTests_iterateAndDoSomething = 0; -static void Java_SampleForTests_iterateAndDoSomething(JNIEnv* env, jobject obj) - { - /* Must call RegisterNativesImpl() */ - DCHECK(g_SampleForTests_clazz); - jmethodID method_id = - base::android::MethodID::LazyGet< - base::android::MethodID::TYPE_INSTANCE>( - env, g_SampleForTests_clazz, - "iterateAndDoSomething", - -"(" -")" -"V", - &g_SampleForTests_iterateAndDoSomething); - - env->CallVoidMethod(obj, - method_id); - base::android::CheckException(env); - -} - -static base::subtle::AtomicWord g_InnerStructB_getKey = 0; -static jlong Java_InnerStructB_getKey(JNIEnv* env, jobject obj) { - /* Must call RegisterNativesImpl() */ - DCHECK(g_InnerStructB_clazz); - jmethodID method_id = - base::android::MethodID::LazyGet< - base::android::MethodID::TYPE_INSTANCE>( - env, g_InnerStructB_clazz, - "getKey", - -"(" -")" -"J", - &g_InnerStructB_getKey); - - jlong ret = - env->CallLongMethod(obj, - method_id); - base::android::CheckException(env); - return ret; -} - -static base::subtle::AtomicWord g_InnerStructB_getValue = 0; -static ScopedJavaLocalRef Java_InnerStructB_getValue(JNIEnv* env, - jobject obj) { - /* Must call RegisterNativesImpl() */ - DCHECK(g_InnerStructB_clazz); - jmethodID method_id = - base::android::MethodID::LazyGet< - base::android::MethodID::TYPE_INSTANCE>( - env, g_InnerStructB_clazz, - "getValue", - -"(" -")" -"Ljava/lang/String;", - &g_InnerStructB_getValue); - - jstring ret = - static_cast(env->CallObjectMethod(obj, - method_id)); - base::android::CheckException(env); - return ScopedJavaLocalRef(env, ret); -} - -// Step 3: RegisterNatives. - -static bool RegisterNativesImpl(JNIEnv* env) { - - g_InnerStructA_clazz = reinterpret_cast(env->NewGlobalRef( - base::android::GetClass(env, kInnerStructAClassPath).obj())); - g_SampleForTests_clazz = reinterpret_cast(env->NewGlobalRef( - base::android::GetClass(env, kSampleForTestsClassPath).obj())); - g_InnerStructB_clazz = reinterpret_cast(env->NewGlobalRef( - base::android::GetClass(env, kInnerStructBClassPath).obj())); - static const JNINativeMethod kMethodsSampleForTests[] = { - { "nativeInit", -"(" -"Ljava/lang/String;" -")" -"I", reinterpret_cast(Init) }, - { "nativeDestroy", -"(" -"I" -")" -"V", reinterpret_cast(Destroy) }, - { "nativeGetDoubleFunction", -"(" -")" -"D", reinterpret_cast(GetDoubleFunction) }, - { "nativeGetFloatFunction", -"(" -")" -"F", reinterpret_cast(GetFloatFunction) }, - { "nativeSetNonPODDatatype", -"(" -"Landroid/graphics/Rect;" -")" -"V", reinterpret_cast(SetNonPODDatatype) }, - { "nativeGetNonPODDatatype", -"(" -")" -"Ljava/lang/Object;", reinterpret_cast(GetNonPODDatatype) }, - { "nativeMethod", -"(" -"I" -")" -"I", reinterpret_cast(Method) }, - { "nativeMethodOtherP0", -"(" -"I" -")" -"D", reinterpret_cast(MethodOtherP0) }, - { "nativeAddStructB", -"(" -"I" -"Lorg/chromium/example/jni_generator/SampleForTests$InnerStructB;" -")" -"V", reinterpret_cast(AddStructB) }, - { "nativeIterateAndDoSomethingWithStructB", -"(" -"I" -")" -"V", reinterpret_cast(IterateAndDoSomethingWithStructB) }, - }; - const int kMethodsSampleForTestsSize = arraysize(kMethodsSampleForTests); - - if (env->RegisterNatives(g_SampleForTests_clazz, - kMethodsSampleForTests, - kMethodsSampleForTestsSize) < 0) { - LOG(ERROR) << "RegisterNatives failed in " << __FILE__; - return false; - } - - return true; -} -} // namespace android -} // namespace base - -#endif // org_chromium_example_jni_generator_SampleForTests_JNI diff --git a/base/android/jni_generator/java/src/org/chromium/example/jni_generator/SampleForTests.java b/base/android/jni_generator/java/src/org/chromium/example/jni_generator/SampleForTests.java deleted file mode 100644 index 71cfc72d7e..0000000000 --- a/base/android/jni_generator/java/src/org/chromium/example/jni_generator/SampleForTests.java +++ /dev/null @@ -1,288 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -package org.chromium.example.jni_generator; - -import android.graphics.Rect; - -import java.util.ArrayList; -import java.util.Iterator; -import java.util.List; -import java.util.Map; - -import org.chromium.base.AccessedByNative; -import org.chromium.base.CalledByNative; -import org.chromium.base.CalledByNativeUnchecked; -import org.chromium.base.JNINamespace; -import org.chromium.base.NativeClassQualifiedName; - - -// This class serves as a reference test for the bindings generator, and as example documentation -// for how to use the jni generator. -// The C++ counter-part is sample_for_tests.cc. -// jni_generator.gyp has a jni_generator_tests target that will: -// * Generate a header file for the JNI bindings based on this file. -// * Compile sample_for_tests.cc using the generated header file. -// * link a native executable to prove the generated header + cc file are self-contained. -// All comments are informational only, and are ignored by the jni generator. -// -// Binding C/C++ with Java is not trivial, specially when ownership and object lifetime -// semantics needs to be managed across boundaries. -// Following a few guidelines will make the code simpler and less buggy: -// -// - Never write any JNI "by hand". Rely on the bindings generator to have a thin -// layer of type-safety. -// -// - Treat the types from the other side as "opaque" as possible. Do not inspect any -// object directly, but rather, rely on well-defined getters / setters. -// -// - Minimize the surface API between the two sides, and rather than calling multiple -// functions across boundaries, call only one (and then, internally in the other side, -// call as many little functions as required). -// -// - If a Java object "owns" a native object, stash the pointer in a "int mNativeClassName". -// Note that it needs to have a "destruction path", i.e., it must eventually call a method -// to delete the native object (for example, the java object has a "close()" method that -// in turn deletes the native object). Avoid relying on finalizers: those run in a different -// thread and makes the native lifetime management more difficult. -// -// - For native object "owning" java objects: -// - If there's a strong 1:1 to relationship between native and java, the best way is to -// stash the java object into a base::android::ScopedJavaGlobalRef. This will ensure the -// java object can be GC'd once the native object is destroyed but note that this global strong -// ref implies a new GC root, so be sure it will not leak and it must never rely on being -// triggered (transitively) from a java side GC. -// - In all other cases, the native side should keep a JavaObjectWeakGlobalRef, and check whether -// that reference is still valid before de-referencing it. Note that you will need another -// java-side object to be holding a strong reference to this java object while it is in use, to -// avoid unpredictable GC of the object before native side has finished with it. -// -// - The best way to pass "compound" datatypes across in either direction is to create an inner -// class with PODs and a factory function. If possible, make it immutable (i.e., mark all the -// fields as "final"). See examples with "InnerStructB" below. -// -// - It's simpler to create thin wrappers with a well defined JNI interface than to -// expose a lot of internal details. This is specially significant for system classes where it's -// simpler to wrap factory methods and a few getters / setters than expose the entire class. -// -// - Use static factory functions annotated with @CalledByNative rather than calling the -// constructors directly. -// -// - Iterate over containers where they are originally owned, then create inner structs or -// directly call methods on the other side. It's much simpler than trying to amalgamate -// java and stl containers. -// -// This JNINamespace annotation indicates that all native methods should be -// generated inside this namespace, including the native class that this -// object binds to. -@JNINamespace("base::android") -class SampleForTests { - // Classes can store their C++ pointer counter part as an int that is normally initialized by - // calling out a nativeInit() function. - int mNativeCPPObject; - - // You can define methods and attributes on the java class just like any other. - // Methods without the @CalledByNative annotation won't be exposed to JNI. - public SampleForTests() { - } - - public void startExample() { - // Calls native code and holds a pointer to the C++ class. - mNativeCPPObject = nativeInit("myParam"); - } - - public void doStuff() { - // This will call CPPClass::Method() using nativePtr as a pointer to the object. This must be - // done to: - // * avoid leaks. - // * using finalizers are not allowed to destroy the cpp class. - nativeMethod(mNativeCPPObject); - } - - public void finishExample() { - // We're done, so let's destroy nativePtr object. - nativeDestroy(mNativeCPPObject); - } - - // ----------------------------------------------------------------------------------------------- - // The following methods demonstrate exporting Java methods for invocation from C++ code. - // Java functions are mapping into C global functions by prefixing the method name with - // "Java__" - // This is triggered by the @CalledByNative annotation; the methods may be named as you wish. - - // Exported to C++ as: - // Java_Example_javaMethod(JNIEnv* env, jobject obj, jint foo, jint bar) - // Typically the C++ code would have obtained the jobject via the Init() call described above. - @CalledByNative - public int javaMethod(int foo, - int bar) { - return 0; - } - - // Exported to C++ as Java_Example_staticJavaMethod(JNIEnv* env) - // Note no jobject argument, as it is static. - @CalledByNative - public static boolean staticJavaMethod() { - return true; - } - - // No prefix, so this method is package private. It will still be exported. - @CalledByNative - void packagePrivateJavaMethod() {} - - // Note the "Unchecked" suffix. By default, @CalledByNative will always generate bindings that - // call CheckException(). With "@CalledByNativeUnchecked", the client C++ code is responsible to - // call ClearException() and act as appropriate. - // See more details at the "@CalledByNativeUnchecked" annotation. - @CalledByNativeUnchecked - void methodThatThrowsException() throws Exception {} - - // The generator is not confused by inline comments: - // @CalledByNative void thisShouldNotAppearInTheOutput(); - // @CalledByNativeUnchecked public static void neitherShouldThis(int foo); - - /** - * The generator is not confused by block comments: - * @CalledByNative void thisShouldNotAppearInTheOutputEither(); - * @CalledByNativeUnchecked public static void andDefinitelyNotThis(int foo); - */ - - // String constants that look like comments don't confuse the generator: - private String arrgh = "*/*"; - - //------------------------------------------------------------------------------------------------ - // Java fields which are accessed from C++ code only must be annotated with @AccessedByNative to - // prevent them being eliminated when unreferenced code is stripped. - @AccessedByNative - private int javaField; - - //------------------------------------------------------------------------------------------------ - // The following methods demonstrate declaring methods to call into C++ from Java. - // The generator detects the "native" and "static" keywords, the type and name of the first - // parameter, and the "native" prefix to the function name to determine the C++ function - // signatures. Besides these constraints the methods can be freely named. - - // This declares a C++ function which the application code must implement: - // static jint Init(JNIEnv* env, jobject obj); - // The jobject parameter refers back to this java side object instance. - // The implementation must return the pointer to the C++ object cast to jint. - // The caller of this method should store it, and supply it as a the nativeCPPClass param to - // subsequent native method calls (see the methods below that take an "int native..." as first - // param). - private native int nativeInit(String param); - - // This defines a function binding to the associated C++ class member function. The name is - // derived from |nativeDestroy| and |nativeCPPClass| to arrive at CPPClass::Destroy() (i.e. native - // prefixes stripped). - // The |nativeCPPClass| is automatically cast to type CPPClass* in order to obtain the object on - // which to invoke the member function. - private native void nativeDestroy(int nativeCPPClass); - - // This declares a C++ function which the application code must implement: - // static jdouble GetDoubleFunction(JNIEnv* env, jobject obj); - // The jobject parameter refers back to this java side object instance. - private native double nativeGetDoubleFunction(); - - // Similar to nativeGetDoubleFunction(), but here the C++ side will receive a jclass rather than - // jobject param, as the function is declared static. - private static native float nativeGetFloatFunction(); - - // This function takes a non-POD datatype. We have a list mapping them to their full classpath in - // jni_generator.py JavaParamToJni. If you require a new datatype, make sure you add to that - // function. - private native void nativeSetNonPODDatatype(Rect rect); - - // This declares a C++ function which the application code must implement: - // static ScopedJavaLocalRef GetNonPODDatatype(JNIEnv* env, jobject obj); - // The jobject parameter refers back to this java side object instance. - // Note that it returns a ScopedJavaLocalRef so that you don' have to worry about - // deleting the JNI local reference. This is similar with Strings and arrays. - private native Object nativeGetNonPODDatatype(); - - // Similar to nativeDestroy above, this will cast nativeCPPClass into pointer of CPPClass type and - // call its Method member function. - private native int nativeMethod(int nativeCPPClass); - - // Similar to nativeMethod above, but here the C++ fully qualified class name is taken from the - // annotation rather than parameter name, which can thus be chosen freely. - @NativeClassQualifiedName("CPPClass::InnerClass") - private native double nativeMethodOtherP0(int nativePtr); - - // This "struct" will be created by the native side using |createInnerStructA|, - // and used by the java-side somehow. - // Note that |@CalledByNative| has to contain the inner class name. - static class InnerStructA { - private final long mLong; - private final int mInt; - private final String mString; - - private InnerStructA(long l, int i, String s) { - mLong = l; - mInt = i; - mString = s; - } - - @CalledByNative("InnerStructA") - private static InnerStructA create(long l, int i, String s) { - return new InnerStructA(l, i, s); - } - } - - private List mListInnerStructA = new ArrayList(); - - @CalledByNative - private void addStructA(InnerStructA a) { - // Called by the native side to append another element. - mListInnerStructA.add(a); - } - - @CalledByNative - private void iterateAndDoSomething() { - Iterator it = mListInnerStructA.iterator(); - while (it.hasNext()) { - InnerStructA element = it.next(); - // Now, do something with element. - } - // Done, clear the list. - mListInnerStructA.clear(); - } - - // This "struct" will be created by the java side passed to native, which - // will use its getters. - // Note that |@CalledByNative| has to contain the inner class name. - static class InnerStructB { - private final long mKey; - private final String mValue; - - private InnerStructB(long k, String v) { - mKey = k; - mValue = v; - } - - @CalledByNative("InnerStructB") - private long getKey() { - return mKey; - } - - @CalledByNative("InnerStructB") - private String getValue() { - return mValue; - } - } - - List mListInnerStructB = new ArrayList(); - - void iterateAndDoSomethingWithMap() { - Iterator it = mListInnerStructB.iterator(); - while (it.hasNext()) { - InnerStructB element = it.next(); - // Now, do something with element. - nativeAddStructB(mNativeCPPObject, element); - } - nativeIterateAndDoSomethingWithStructB(mNativeCPPObject); - } - - native void nativeAddStructB(int nativeCPPClass, InnerStructB b); - native void nativeIterateAndDoSomethingWithStructB(int nativeCPPClass); -} diff --git a/base/android/jni_generator/jni_generator.gyp b/base/android/jni_generator/jni_generator.gyp deleted file mode 100644 index 4bad0dc483..0000000000 --- a/base/android/jni_generator/jni_generator.gyp +++ /dev/null @@ -1,67 +0,0 @@ -# Copyright (c) 2012 The Chromium Authors. All rights reserved. -# Use of this source code is governed by a BSD-style license that can be -# found in the LICENSE file. - -{ - 'targets': [ - { - 'target_name': 'jni_generator_py_tests', - 'type': 'none', - 'actions': [ - { - 'action_name': 'run_jni_generator_py_tests', - 'inputs': [ - 'jni_generator.py', - 'jni_generator_tests.py', - 'java/src/org/chromium/example/jni_generator/SampleForTests.java', - 'golden_sample_for_tests_jni.h', - ], - 'outputs': [ - '', - ], - 'action': [ - 'python', 'jni_generator_tests.py', - ], - }, - ], - }, - { - 'target_name': 'jni_sample_header', - 'type': 'none', - 'sources': [ - 'java/src/org/chromium/example/jni_generator/SampleForTests.java', - ], - 'variables': { - 'jni_gen_package': 'example', - }, - 'includes': [ '../../../build/jni_generator.gypi' ], - }, - { - 'target_name': 'jni_sample_java', - 'type': 'none', - 'variables': { - 'java_in_dir': '../../../base/android/jni_generator/java', - }, - 'dependencies': [ - '<(DEPTH)/base/base.gyp:base_java', - ], - 'includes': [ '../../../build/java.gypi' ], - }, - { - 'target_name': 'jni_generator_tests', - 'type': 'executable', - 'dependencies': [ - '../../base.gyp:test_support_base', - 'jni_generator_py_tests', - 'jni_sample_header', - 'jni_sample_java', - ], - 'include_dirs': [ - '<(SHARED_INTERMEDIATE_DIR)/example', - ], - 'sources': [ - 'sample_for_tests.cc', - ], - }, - ], -} diff --git a/base/android/jni_generator/jni_generator.py b/base/android/jni_generator/jni_generator.py deleted file mode 100755 index de865d527b..0000000000 --- a/base/android/jni_generator/jni_generator.py +++ /dev/null @@ -1,1065 +0,0 @@ -#!/usr/bin/env python -# Copyright (c) 2012 The Chromium Authors. All rights reserved. -# Use of this source code is governed by a BSD-style license that can be -# found in the LICENSE file. - -"""Extracts native methods from a Java file and generates the JNI bindings. -If you change this, please run and update the tests.""" - -import collections -import errno -import optparse -import os -import re -import string -from string import Template -import subprocess -import sys -import textwrap -import zipfile - - -class ParseError(Exception): - """Exception thrown when we can't parse the input file.""" - - def __init__(self, description, *context_lines): - Exception.__init__(self) - self.description = description - self.context_lines = context_lines - - def __str__(self): - context = '\n'.join(self.context_lines) - return '***\nERROR: %s\n\n%s\n***' % (self.description, context) - - -class Param(object): - """Describes a param for a method, either java or native.""" - - def __init__(self, **kwargs): - self.datatype = kwargs['datatype'] - self.name = kwargs['name'] - - -class NativeMethod(object): - """Describes a C/C++ method that is called by Java code""" - - def __init__(self, **kwargs): - self.static = kwargs['static'] - self.java_class_name = kwargs['java_class_name'] - self.return_type = kwargs['return_type'] - self.name = kwargs['name'] - self.params = kwargs['params'] - if self.params: - assert type(self.params) is list - assert type(self.params[0]) is Param - if (self.params and - self.params[0].datatype == 'int' and - self.params[0].name.startswith('native')): - self.type = 'method' - self.p0_type = self.params[0].name[len('native'):] - if kwargs.get('native_class_name'): - self.p0_type = kwargs['native_class_name'] - else: - self.type = 'function' - self.method_id_var_name = kwargs.get('method_id_var_name', None) - - -class CalledByNative(object): - """Describes a java method exported to c/c++""" - - def __init__(self, **kwargs): - self.system_class = kwargs['system_class'] - self.unchecked = kwargs['unchecked'] - self.static = kwargs['static'] - self.java_class_name = kwargs['java_class_name'] - self.return_type = kwargs['return_type'] - self.name = kwargs['name'] - self.params = kwargs['params'] - self.method_id_var_name = kwargs.get('method_id_var_name', None) - self.is_constructor = kwargs.get('is_constructor', False) - self.env_call = GetEnvCall(self.is_constructor, self.static, - self.return_type) - self.static_cast = GetStaticCastForReturnType(self.return_type) - - -def JavaDataTypeToC(java_type): - """Returns a C datatype for the given java type.""" - java_pod_type_map = { - 'int': 'jint', - 'byte': 'jbyte', - 'char': 'jchar', - 'short': 'jshort', - 'boolean': 'jboolean', - 'long': 'jlong', - 'double': 'jdouble', - 'float': 'jfloat', - } - java_type_map = { - 'void': 'void', - 'String': 'jstring', - 'java/lang/String': 'jstring', - 'Class': 'jclass', - 'java/lang/Class': 'jclass', - } - - if java_type in java_pod_type_map: - return java_pod_type_map[java_type] - elif java_type in java_type_map: - return java_type_map[java_type] - elif java_type.endswith('[]'): - if java_type[:-2] in java_pod_type_map: - return java_pod_type_map[java_type[:-2]] + 'Array' - return 'jobjectArray' - else: - return 'jobject' - - -class JniParams(object): - _imports = [] - _fully_qualified_class = '' - _package = '' - _inner_classes = [] - _remappings = [] - - @staticmethod - def SetFullyQualifiedClass(fully_qualified_class): - JniParams._fully_qualified_class = 'L' + fully_qualified_class - JniParams._package = '/'.join(fully_qualified_class.split('/')[:-1]) - - @staticmethod - def ExtractImportsAndInnerClasses(contents): - contents = contents.replace('\n', '') - re_import = re.compile(r'import.*?(?P\S*?);') - for match in re.finditer(re_import, contents): - JniParams._imports += ['L' + match.group('class').replace('.', '/')] - - re_inner = re.compile(r'(class|interface)\s+?(?P\w+?)\W') - for match in re.finditer(re_inner, contents): - inner = match.group('name') - if not JniParams._fully_qualified_class.endswith(inner): - JniParams._inner_classes += [JniParams._fully_qualified_class + '$' + - inner] - - @staticmethod - def JavaToJni(param): - """Converts a java param into a JNI signature type.""" - pod_param_map = { - 'int': 'I', - 'boolean': 'Z', - 'char': 'C', - 'short': 'S', - 'long': 'J', - 'double': 'D', - 'float': 'F', - 'byte': 'B', - 'void': 'V', - } - object_param_list = [ - 'Ljava/lang/Boolean', - 'Ljava/lang/Integer', - 'Ljava/lang/Long', - 'Ljava/lang/Object', - 'Ljava/lang/String', - 'Ljava/lang/Class', - ] - prefix = '' - # Array? - while param[-2:] == '[]': - prefix += '[' - param = param[:-2] - # Generic? - if '<' in param: - param = param[:param.index('<')] - if param in pod_param_map: - return prefix + pod_param_map[param] - if '/' in param: - # Coming from javap, use the fully qualified param directly. - return prefix + 'L' + JniParams.RemapClassName(param) + ';' - for qualified_name in (object_param_list + - [JniParams._fully_qualified_class] + - JniParams._inner_classes): - if (qualified_name.endswith('/' + param) or - qualified_name.endswith('$' + param.replace('.', '$')) or - qualified_name == 'L' + param): - return prefix + JniParams.RemapClassName(qualified_name) + ';' - - # Is it from an import? (e.g. referecing Class from import pkg.Class; - # note that referencing an inner class Inner from import pkg.Class.Inner - # is not supported). - for qualified_name in JniParams._imports: - if qualified_name.endswith('/' + param): - # Ensure it's not an inner class. - components = qualified_name.split('/') - if len(components) > 2 and components[-2][0].isupper(): - raise SyntaxError('Inner class (%s) can not be imported ' - 'and used by JNI (%s). Please import the outer ' - 'class and use Outer.Inner instead.' % - (qualified_name, param)) - return prefix + JniParams.RemapClassName(qualified_name) + ';' - - # Is it an inner class from an outer class import? (e.g. referencing - # Class.Inner from import pkg.Class). - if '.' in param: - components = param.split('.') - outer = '/'.join(components[:-1]) - inner = components[-1] - for qualified_name in JniParams._imports: - if qualified_name.endswith('/' + outer): - return (prefix + JniParams.RemapClassName(qualified_name) + - '$' + inner + ';') - - # Type not found, falling back to same package as this class. - return (prefix + 'L' + - JniParams.RemapClassName(JniParams._package + '/' + param) + ';') - - @staticmethod - def Signature(params, returns, wrap): - """Returns the JNI signature for the given datatypes.""" - items = ['('] - items += [JniParams.JavaToJni(param.datatype) for param in params] - items += [')'] - items += [JniParams.JavaToJni(returns)] - if wrap: - return '\n' + '\n'.join(['"' + item + '"' for item in items]) - else: - return '"' + ''.join(items) + '"' - - @staticmethod - def Parse(params): - """Parses the params into a list of Param objects.""" - if not params: - return [] - ret = [] - for p in [p.strip() for p in params.split(',')]: - items = p.split(' ') - if 'final' in items: - items.remove('final') - param = Param( - datatype=items[0], - name=(items[1] if len(items) > 1 else 'p%s' % len(ret)), - ) - ret += [param] - return ret - - @staticmethod - def RemapClassName(class_name): - """Remaps class names using the jarjar mapping table.""" - for old, new in JniParams._remappings: - if old in class_name: - return class_name.replace(old, new, 1) - return class_name - - @staticmethod - def SetJarJarMappings(mappings): - """Parse jarjar mappings from a string.""" - JniParams._remappings = [] - for line in mappings.splitlines(): - keyword, src, dest = line.split() - if keyword != 'rule': - continue - assert src.endswith('.**') - src = src[:-2].replace('.', '/') - dest = dest.replace('.', '/') - if dest.endswith('@0'): - JniParams._remappings.append((src, dest[:-2] + src)) - else: - assert dest.endswith('@1') - JniParams._remappings.append((src, dest[:-2])) - - -def ExtractJNINamespace(contents): - re_jni_namespace = re.compile('.*?@JNINamespace\("(.*?)"\)') - m = re.findall(re_jni_namespace, contents) - if not m: - return '' - return m[0] - - -def ExtractFullyQualifiedJavaClassName(java_file_name, contents): - re_package = re.compile('.*?package (.*?);') - matches = re.findall(re_package, contents) - if not matches: - raise SyntaxError('Unable to find "package" line in %s' % java_file_name) - return (matches[0].replace('.', '/') + '/' + - os.path.splitext(os.path.basename(java_file_name))[0]) - - -def ExtractNatives(contents): - """Returns a list of dict containing information about a native method.""" - contents = contents.replace('\n', '') - natives = [] - re_native = re.compile(r'(@NativeClassQualifiedName' - '\(\"(?P.*?)\"\))?\s*' - '(@NativeCall(\(\"(?P.*?)\"\)))?\s*' - '(?P\w+\s\w+|\w+|\s+)\s*?native ' - '(?P\S*?) ' - '(?P\w+?)\((?P.*?)\);') - for match in re.finditer(re_native, contents): - native = NativeMethod( - static='static' in match.group('qualifiers'), - java_class_name=match.group('java_class_name'), - native_class_name=match.group('native_class_name'), - return_type=match.group('return_type'), - name=match.group('name').replace('native', ''), - params=JniParams.Parse(match.group('params'))) - natives += [native] - return natives - - -def GetStaticCastForReturnType(return_type): - type_map = { 'String' : 'jstring', - 'java/lang/String' : 'jstring', - 'boolean[]': 'jbooleanArray', - 'byte[]': 'jbyteArray', - 'char[]': 'jcharArray', - 'short[]': 'jshortArray', - 'int[]': 'jintArray', - 'long[]': 'jlongArray', - 'double[]': 'jdoubleArray' } - ret = type_map.get(return_type, None) - if ret: - return ret - if return_type.endswith('[]'): - return 'jobjectArray' - return None - - -def GetEnvCall(is_constructor, is_static, return_type): - """Maps the types availabe via env->Call__Method.""" - if is_constructor: - return 'NewObject' - env_call_map = {'boolean': 'Boolean', - 'byte': 'Byte', - 'char': 'Char', - 'short': 'Short', - 'int': 'Int', - 'long': 'Long', - 'float': 'Float', - 'void': 'Void', - 'double': 'Double', - 'Object': 'Object', - } - call = env_call_map.get(return_type, 'Object') - if is_static: - call = 'Static' + call - return 'Call' + call + 'Method' - - -def GetMangledParam(datatype): - """Returns a mangled identifier for the datatype.""" - if len(datatype) <= 2: - return datatype.replace('[', 'A') - ret = '' - for i in range(1, len(datatype)): - c = datatype[i] - if c == '[': - ret += 'A' - elif c.isupper() or datatype[i - 1] in ['/', 'L']: - ret += c.upper() - return ret - - -def GetMangledMethodName(name, params, return_type): - """Returns a mangled method name for the given signature. - - The returned name can be used as a C identifier and will be unique for all - valid overloads of the same method. - - Args: - name: string. - params: list of Param. - return_type: string. - - Returns: - A mangled name. - """ - mangled_items = [] - for datatype in [return_type] + [x.datatype for x in params]: - mangled_items += [GetMangledParam(JniParams.JavaToJni(datatype))] - mangled_name = name + '_'.join(mangled_items) - assert re.match(r'[0-9a-zA-Z_]+', mangled_name) - return mangled_name - - -def MangleCalledByNatives(called_by_natives): - """Mangles all the overloads from the call_by_natives list.""" - method_counts = collections.defaultdict( - lambda: collections.defaultdict(lambda: 0)) - for called_by_native in called_by_natives: - java_class_name = called_by_native.java_class_name - name = called_by_native.name - method_counts[java_class_name][name] += 1 - for called_by_native in called_by_natives: - java_class_name = called_by_native.java_class_name - method_name = called_by_native.name - method_id_var_name = method_name - if method_counts[java_class_name][method_name] > 1: - method_id_var_name = GetMangledMethodName(method_name, - called_by_native.params, - called_by_native.return_type) - called_by_native.method_id_var_name = method_id_var_name - return called_by_natives - - -# Regex to match the JNI return types that should be included in a -# ScopedJavaLocalRef. -RE_SCOPED_JNI_RETURN_TYPES = re.compile('jobject|jclass|jstring|.*Array') - -# Regex to match a string like "@CalledByNative public void foo(int bar)". -RE_CALLED_BY_NATIVE = re.compile( - '@CalledByNative(?P(Unchecked)*?)(?:\("(?P.*)"\))?' - '\s+(?P[\w ]*?)' - '\s*(?P\S+?)' - '\s+(?P\w+)' - '\s*\((?P[^\)]*)\)') - - -def ExtractCalledByNatives(contents): - """Parses all methods annotated with @CalledByNative. - - Args: - contents: the contents of the java file. - - Returns: - A list of dict with information about the annotated methods. - TODO(bulach): return a CalledByNative object. - - Raises: - ParseError: if unable to parse. - """ - called_by_natives = [] - for match in re.finditer(RE_CALLED_BY_NATIVE, contents): - called_by_natives += [CalledByNative( - system_class=False, - unchecked='Unchecked' in match.group('Unchecked'), - static='static' in match.group('prefix'), - java_class_name=match.group('annotation') or '', - return_type=match.group('return_type'), - name=match.group('name'), - params=JniParams.Parse(match.group('params')))] - # Check for any @CalledByNative occurrences that weren't matched. - unmatched_lines = re.sub(RE_CALLED_BY_NATIVE, '', contents).split('\n') - for line1, line2 in zip(unmatched_lines, unmatched_lines[1:]): - if '@CalledByNative' in line1: - raise ParseError('could not parse @CalledByNative method signature', - line1, line2) - return MangleCalledByNatives(called_by_natives) - - -class JNIFromJavaP(object): - """Uses 'javap' to parse a .class file and generate the JNI header file.""" - - def __init__(self, contents, namespace): - self.contents = contents - self.namespace = namespace - self.fully_qualified_class = re.match( - '.*?(class|interface) (?P.*?)( |{)', - contents[1]).group('class_name') - self.fully_qualified_class = self.fully_qualified_class.replace('.', '/') - JniParams.SetFullyQualifiedClass(self.fully_qualified_class) - self.java_class_name = self.fully_qualified_class.split('/')[-1] - if not self.namespace: - self.namespace = 'JNI_' + self.java_class_name - re_method = re.compile('(?P.*?)(?P\S+?) (?P\w+?)' - '\((?P.*?)\)') - self.called_by_natives = [] - for content in contents[2:]: - match = re.match(re_method, content) - if not match: - continue - self.called_by_natives += [CalledByNative( - system_class=True, - unchecked=False, - static='static' in match.group('prefix'), - java_class_name='', - return_type=match.group('return_type').replace('.', '/'), - name=match.group('name'), - params=JniParams.Parse(match.group('params').replace('.', '/')))] - re_constructor = re.compile('.*? public ' + - self.fully_qualified_class.replace('/', '.') + - '\((?P.*?)\)') - for content in contents[2:]: - match = re.match(re_constructor, content) - if not match: - continue - self.called_by_natives += [CalledByNative( - system_class=True, - unchecked=False, - static=False, - java_class_name='', - return_type=self.fully_qualified_class, - name='Constructor', - params=JniParams.Parse(match.group('params').replace('.', '/')), - is_constructor=True)] - self.called_by_natives = MangleCalledByNatives(self.called_by_natives) - self.inl_header_file_generator = InlHeaderFileGenerator( - self.namespace, self.fully_qualified_class, [], self.called_by_natives) - - def GetContent(self): - return self.inl_header_file_generator.GetContent() - - @staticmethod - def CreateFromClass(class_file, namespace): - class_name = os.path.splitext(os.path.basename(class_file))[0] - p = subprocess.Popen(args=['javap', class_name], - cwd=os.path.dirname(class_file), - stdout=subprocess.PIPE, - stderr=subprocess.PIPE) - stdout, _ = p.communicate() - jni_from_javap = JNIFromJavaP(stdout.split('\n'), namespace) - return jni_from_javap - - -class JNIFromJavaSource(object): - """Uses the given java source file to generate the JNI header file.""" - - def __init__(self, contents, fully_qualified_class): - contents = self._RemoveComments(contents) - JniParams.SetFullyQualifiedClass(fully_qualified_class) - JniParams.ExtractImportsAndInnerClasses(contents) - jni_namespace = ExtractJNINamespace(contents) - natives = ExtractNatives(contents) - called_by_natives = ExtractCalledByNatives(contents) - if len(natives) == 0 and len(called_by_natives) == 0: - raise SyntaxError('Unable to find any JNI methods for %s.' % - fully_qualified_class) - inl_header_file_generator = InlHeaderFileGenerator( - jni_namespace, fully_qualified_class, natives, called_by_natives) - self.content = inl_header_file_generator.GetContent() - - def _RemoveComments(self, contents): - # We need to support both inline and block comments, and we need to handle - # strings that contain '//' or '/*'. Rather than trying to do all that with - # regexps, we just pipe the contents through the C preprocessor. We tell cpp - # the file has already been preprocessed, so it just removes comments and - # doesn't try to parse #include, #pragma etc. - # - # TODO(husky): This is a bit hacky. It would be cleaner to use a real Java - # parser. Maybe we could ditch JNIFromJavaSource and just always use - # JNIFromJavaP; or maybe we could rewrite this script in Java and use APT. - # http://code.google.com/p/chromium/issues/detail?id=138941 - p = subprocess.Popen(args=['cpp', '-fpreprocessed'], - stdin=subprocess.PIPE, - stdout=subprocess.PIPE, - stderr=subprocess.PIPE) - stdout, _ = p.communicate(contents) - return stdout - - def GetContent(self): - return self.content - - @staticmethod - def CreateFromFile(java_file_name): - contents = file(java_file_name).read() - fully_qualified_class = ExtractFullyQualifiedJavaClassName(java_file_name, - contents) - return JNIFromJavaSource(contents, fully_qualified_class) - - -class InlHeaderFileGenerator(object): - """Generates an inline header file for JNI integration.""" - - def __init__(self, namespace, fully_qualified_class, natives, - called_by_natives): - self.namespace = namespace - self.fully_qualified_class = fully_qualified_class - self.class_name = self.fully_qualified_class.split('/')[-1] - self.natives = natives - self.called_by_natives = called_by_natives - self.header_guard = fully_qualified_class.replace('/', '_') + '_JNI' - - def GetContent(self): - """Returns the content of the JNI binding file.""" - template = Template("""\ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - - -// This file is autogenerated by -// ${SCRIPT_NAME} -// For -// ${FULLY_QUALIFIED_CLASS} - -#ifndef ${HEADER_GUARD} -#define ${HEADER_GUARD} - -#include - -#include "base/android/jni_android.h" -#include "base/android/scoped_java_ref.h" -#include "base/basictypes.h" -#include "base/logging.h" - -using base::android::ScopedJavaLocalRef; - -// Step 1: forward declarations. -namespace { -$CLASS_PATH_DEFINITIONS -} // namespace - -$OPEN_NAMESPACE -$FORWARD_DECLARATIONS - -// Step 2: method stubs. -$METHOD_STUBS - -// Step 3: RegisterNatives. - -static bool RegisterNativesImpl(JNIEnv* env) { -$REGISTER_NATIVES_IMPL - return true; -} -$CLOSE_NAMESPACE -#endif // ${HEADER_GUARD} -""") - script_components = os.path.abspath(sys.argv[0]).split(os.path.sep) - base_index = script_components.index('base') - script_name = os.sep.join(script_components[base_index:]) - values = { - 'SCRIPT_NAME': script_name, - 'FULLY_QUALIFIED_CLASS': self.fully_qualified_class, - 'CLASS_PATH_DEFINITIONS': self.GetClassPathDefinitionsString(), - 'FORWARD_DECLARATIONS': self.GetForwardDeclarationsString(), - 'METHOD_STUBS': self.GetMethodStubsString(), - 'OPEN_NAMESPACE': self.GetOpenNamespaceString(), - 'REGISTER_NATIVES_IMPL': self.GetRegisterNativesImplString(), - 'CLOSE_NAMESPACE': self.GetCloseNamespaceString(), - 'HEADER_GUARD': self.header_guard, - } - return WrapOutput(template.substitute(values)) - - def GetClassPathDefinitionsString(self): - ret = [] - ret += [self.GetClassPathDefinitions()] - return '\n'.join(ret) - - def GetForwardDeclarationsString(self): - ret = [] - for native in self.natives: - if native.type != 'method': - ret += [self.GetForwardDeclaration(native)] - return '\n'.join(ret) - - def GetMethodStubsString(self): - ret = [] - for native in self.natives: - if native.type == 'method': - ret += [self.GetNativeMethodStub(native)] - for called_by_native in self.called_by_natives: - ret += [self.GetCalledByNativeMethodStub(called_by_native)] - return '\n'.join(ret) - - def GetKMethodsString(self, clazz): - ret = [] - for native in self.natives: - if (native.java_class_name == clazz or - (not native.java_class_name and clazz == self.class_name)): - ret += [self.GetKMethodArrayEntry(native)] - return '\n'.join(ret) - - def GetRegisterNativesImplString(self): - """Returns the implementation for RegisterNatives.""" - template = Template("""\ - static const JNINativeMethod kMethods${JAVA_CLASS}[] = { -${KMETHODS} - }; - const int kMethods${JAVA_CLASS}Size = arraysize(kMethods${JAVA_CLASS}); - - if (env->RegisterNatives(g_${JAVA_CLASS}_clazz, - kMethods${JAVA_CLASS}, - kMethods${JAVA_CLASS}Size) < 0) { - LOG(ERROR) << "RegisterNatives failed in " << __FILE__; - return false; - } -""") - ret = [self.GetFindClasses()] - all_classes = self.GetUniqueClasses(self.natives) - all_classes[self.class_name] = self.fully_qualified_class - for clazz in all_classes: - kmethods = self.GetKMethodsString(clazz) - if kmethods: - values = {'JAVA_CLASS': clazz, - 'KMETHODS': kmethods} - ret += [template.substitute(values)] - if not ret: return '' - return '\n' + '\n'.join(ret) - - def GetOpenNamespaceString(self): - if self.namespace: - all_namespaces = ['namespace %s {' % ns - for ns in self.namespace.split('::')] - return '\n'.join(all_namespaces) - return '' - - def GetCloseNamespaceString(self): - if self.namespace: - all_namespaces = ['} // namespace %s' % ns - for ns in self.namespace.split('::')] - all_namespaces.reverse() - return '\n'.join(all_namespaces) + '\n' - return '' - - def GetJNIFirstParam(self, native): - ret = [] - if native.type == 'method': - ret = ['jobject obj'] - elif native.type == 'function': - if native.static: - ret = ['jclass clazz'] - else: - ret = ['jobject obj'] - return ret - - def GetParamsInDeclaration(self, native): - """Returns the params for the stub declaration. - - Args: - native: the native dictionary describing the method. - - Returns: - A string containing the params. - """ - return ',\n '.join(self.GetJNIFirstParam(native) + - [JavaDataTypeToC(param.datatype) + ' ' + - param.name - for param in native.params]) - - def GetCalledByNativeParamsInDeclaration(self, called_by_native): - return ',\n '.join([JavaDataTypeToC(param.datatype) + ' ' + - param.name - for param in called_by_native.params]) - - def GetForwardDeclaration(self, native): - template = Template(""" -static ${RETURN} ${NAME}(JNIEnv* env, ${PARAMS}); -""") - values = {'RETURN': JavaDataTypeToC(native.return_type), - 'NAME': native.name, - 'PARAMS': self.GetParamsInDeclaration(native)} - return template.substitute(values) - - def GetNativeMethodStub(self, native): - """Returns stubs for native methods.""" - template = Template("""\ -static ${RETURN} ${NAME}(JNIEnv* env, ${PARAMS_IN_DECLARATION}) { - DCHECK(${PARAM0_NAME}) << "${NAME}"; - ${P0_TYPE}* native = reinterpret_cast<${P0_TYPE}*>(${PARAM0_NAME}); - return native->${NAME}(env, obj${PARAMS_IN_CALL})${POST_CALL}; -} -""") - params_for_call = ', '.join(p.name for p in native.params[1:]) - if params_for_call: - params_for_call = ', ' + params_for_call - - return_type = JavaDataTypeToC(native.return_type) - if re.match(RE_SCOPED_JNI_RETURN_TYPES, return_type): - scoped_return_type = 'ScopedJavaLocalRef<' + return_type + '>' - post_call = '.Release()' - else: - scoped_return_type = return_type - post_call = '' - values = { - 'RETURN': return_type, - 'SCOPED_RETURN': scoped_return_type, - 'NAME': native.name, - 'PARAMS_IN_DECLARATION': self.GetParamsInDeclaration(native), - 'PARAM0_NAME': native.params[0].name, - 'P0_TYPE': native.p0_type, - 'PARAMS_IN_CALL': params_for_call, - 'POST_CALL': post_call - } - return template.substitute(values) - - def GetCalledByNativeMethodStub(self, called_by_native): - """Returns a string.""" - function_signature_template = Template("""\ -static ${RETURN_TYPE} Java_${JAVA_CLASS}_${METHOD_ID_VAR_NAME}(\ -JNIEnv* env${FIRST_PARAM_IN_DECLARATION}${PARAMS_IN_DECLARATION})""") - function_header_template = Template("""\ -${FUNCTION_SIGNATURE} {""") - function_header_with_unused_template = Template("""\ -${FUNCTION_SIGNATURE} __attribute__ ((unused)); -${FUNCTION_SIGNATURE} {""") - template = Template(""" -static base::subtle::AtomicWord g_${JAVA_CLASS}_${METHOD_ID_VAR_NAME} = 0; -${FUNCTION_HEADER} - /* Must call RegisterNativesImpl() */ - DCHECK(g_${JAVA_CLASS}_clazz); - jmethodID method_id = - ${GET_METHOD_ID_IMPL} - ${RETURN_DECLARATION} - ${PRE_CALL}env->${ENV_CALL}(${FIRST_PARAM_IN_CALL}, - method_id${PARAMS_IN_CALL})${POST_CALL}; - ${CHECK_EXCEPTION} - ${RETURN_CLAUSE} -}""") - if called_by_native.static or called_by_native.is_constructor: - first_param_in_declaration = '' - first_param_in_call = ('g_%s_clazz' % - (called_by_native.java_class_name or - self.class_name)) - else: - first_param_in_declaration = ', jobject obj' - first_param_in_call = 'obj' - params_in_declaration = self.GetCalledByNativeParamsInDeclaration( - called_by_native) - if params_in_declaration: - params_in_declaration = ', ' + params_in_declaration - params_for_call = ', '.join(param.name - for param in called_by_native.params) - if params_for_call: - params_for_call = ', ' + params_for_call - pre_call = '' - post_call = '' - if called_by_native.static_cast: - pre_call = 'static_cast<%s>(' % called_by_native.static_cast - post_call = ')' - check_exception = '' - if not called_by_native.unchecked: - check_exception = 'base::android::CheckException(env);' - return_type = JavaDataTypeToC(called_by_native.return_type) - return_declaration = '' - return_clause = '' - if return_type != 'void': - pre_call = ' ' + pre_call - return_declaration = return_type + ' ret =' - if re.match(RE_SCOPED_JNI_RETURN_TYPES, return_type): - return_type = 'ScopedJavaLocalRef<' + return_type + '>' - return_clause = 'return ' + return_type + '(env, ret);' - else: - return_clause = 'return ret;' - values = { - 'JAVA_CLASS': called_by_native.java_class_name or self.class_name, - 'METHOD': called_by_native.name, - 'RETURN_TYPE': return_type, - 'RETURN_DECLARATION': return_declaration, - 'RETURN_CLAUSE': return_clause, - 'FIRST_PARAM_IN_DECLARATION': first_param_in_declaration, - 'PARAMS_IN_DECLARATION': params_in_declaration, - 'STATIC': 'Static' if called_by_native.static else '', - 'PRE_CALL': pre_call, - 'POST_CALL': post_call, - 'ENV_CALL': called_by_native.env_call, - 'FIRST_PARAM_IN_CALL': first_param_in_call, - 'PARAMS_IN_CALL': params_for_call, - 'METHOD_ID_VAR_NAME': called_by_native.method_id_var_name, - 'CHECK_EXCEPTION': check_exception, - 'GET_METHOD_ID_IMPL': self.GetMethodIDImpl(called_by_native) - } - values['FUNCTION_SIGNATURE'] = ( - function_signature_template.substitute(values)) - if called_by_native.system_class: - values['FUNCTION_HEADER'] = ( - function_header_with_unused_template.substitute(values)) - else: - values['FUNCTION_HEADER'] = function_header_template.substitute(values) - return template.substitute(values) - - def GetKMethodArrayEntry(self, native): - template = Template("""\ - { "native${NAME}", ${JNI_SIGNATURE}, reinterpret_cast(${NAME}) },""") - values = {'NAME': native.name, - 'JNI_SIGNATURE': JniParams.Signature(native.params, - native.return_type, - True)} - return template.substitute(values) - - def GetUniqueClasses(self, origin): - ret = {self.class_name: self.fully_qualified_class} - for entry in origin: - class_name = self.class_name - jni_class_path = self.fully_qualified_class - if entry.java_class_name: - class_name = entry.java_class_name - jni_class_path = self.fully_qualified_class + '$' + class_name - ret[class_name] = jni_class_path - return ret - - def GetClassPathDefinitions(self): - """Returns the ClassPath constants.""" - ret = [] - template = Template("""\ -const char k${JAVA_CLASS}ClassPath[] = "${JNI_CLASS_PATH}";""") - native_classes = self.GetUniqueClasses(self.natives) - called_by_native_classes = self.GetUniqueClasses(self.called_by_natives) - all_classes = native_classes - all_classes.update(called_by_native_classes) - for clazz in all_classes: - values = { - 'JAVA_CLASS': clazz, - 'JNI_CLASS_PATH': JniParams.RemapClassName(all_classes[clazz]), - } - ret += [template.substitute(values)] - ret += '' - for clazz in called_by_native_classes: - template = Template("""\ -// Leaking this jclass as we cannot use LazyInstance from some threads. -jclass g_${JAVA_CLASS}_clazz = NULL;""") - values = { - 'JAVA_CLASS': clazz, - } - ret += [template.substitute(values)] - return '\n'.join(ret) - - def GetFindClasses(self): - """Returns the imlementation of FindClass for all known classes.""" - template = Template("""\ - g_${JAVA_CLASS}_clazz = reinterpret_cast(env->NewGlobalRef( - base::android::GetClass(env, k${JAVA_CLASS}ClassPath).obj()));""") - ret = [] - for clazz in self.GetUniqueClasses(self.called_by_natives): - values = {'JAVA_CLASS': clazz} - ret += [template.substitute(values)] - return '\n'.join(ret) - - def GetMethodIDImpl(self, called_by_native): - """Returns the implementation of GetMethodID.""" - template = Template("""\ - base::android::MethodID::LazyGet< - base::android::MethodID::TYPE_${STATIC}>( - env, g_${JAVA_CLASS}_clazz, - "${JNI_NAME}", - ${JNI_SIGNATURE}, - &g_${JAVA_CLASS}_${METHOD_ID_VAR_NAME}); -""") - jni_name = called_by_native.name - jni_return_type = called_by_native.return_type - if called_by_native.is_constructor: - jni_name = '' - jni_return_type = 'void' - values = { - 'JAVA_CLASS': called_by_native.java_class_name or self.class_name, - 'JNI_NAME': jni_name, - 'METHOD_ID_VAR_NAME': called_by_native.method_id_var_name, - 'STATIC': 'STATIC' if called_by_native.static else 'INSTANCE', - 'JNI_SIGNATURE': JniParams.Signature(called_by_native.params, - jni_return_type, - True) - } - return template.substitute(values) - - -def WrapOutput(output): - ret = [] - for line in output.splitlines(): - # Do not wrap lines under 80 characters or preprocessor directives. - if len(line) < 80 or line.lstrip()[:1] == '#': - stripped = line.rstrip() - if len(ret) == 0 or len(ret[-1]) or len(stripped): - ret.append(stripped) - else: - first_line_indent = ' ' * (len(line) - len(line.lstrip())) - subsequent_indent = first_line_indent + ' ' * 4 - if line.startswith('//'): - subsequent_indent = '//' + subsequent_indent - wrapper = textwrap.TextWrapper(width=80, - subsequent_indent=subsequent_indent, - break_long_words=False) - ret += [wrapped.rstrip() for wrapped in wrapper.wrap(line)] - ret += [''] - return '\n'.join(ret) - - -def ExtractJarInputFile(jar_file, input_file, out_dir): - """Extracts input file from jar and returns the filename. - - The input file is extracted to the same directory that the generated jni - headers will be placed in. This is passed as an argument to script. - - Args: - jar_file: the jar file containing the input files to extract. - input_files: the list of files to extract from the jar file. - out_dir: the name of the directories to extract to. - - Returns: - the name of extracted input file. - """ - jar_file = zipfile.ZipFile(jar_file) - - out_dir = os.path.join(out_dir, os.path.dirname(input_file)) - try: - os.makedirs(out_dir) - except OSError as e: - if e.errno != errno.EEXIST: - raise - extracted_file_name = os.path.join(out_dir, os.path.basename(input_file)) - with open(extracted_file_name, 'w') as outfile: - outfile.write(jar_file.read(input_file)) - - return extracted_file_name - - -def GenerateJNIHeader(input_file, output_file, namespace, skip_if_same): - try: - if os.path.splitext(input_file)[1] == '.class': - jni_from_javap = JNIFromJavaP.CreateFromClass(input_file, namespace) - content = jni_from_javap.GetContent() - else: - jni_from_java_source = JNIFromJavaSource.CreateFromFile(input_file) - content = jni_from_java_source.GetContent() - except ParseError, e: - print e - sys.exit(1) - if output_file: - if not os.path.exists(os.path.dirname(os.path.abspath(output_file))): - os.makedirs(os.path.dirname(os.path.abspath(output_file))) - if skip_if_same and os.path.exists(output_file): - with file(output_file, 'r') as f: - existing_content = f.read() - if existing_content == content: - return - with file(output_file, 'w') as f: - f.write(content) - else: - print output - - -def main(argv): - usage = """usage: %prog [OPTIONS] -This script will parse the given java source code extracting the native -declarations and print the header file to stdout (or a file). -See SampleForTests.java for more details. - """ - option_parser = optparse.OptionParser(usage=usage) - option_parser.add_option('-j', dest='jar_file', - help='Extract the list of input files from' - ' a specified jar file.' - ' Uses javap to extract the methods from a' - ' pre-compiled class. --input should point' - ' to pre-compiled Java .class files.') - option_parser.add_option('-n', dest='namespace', - help='Uses as a namespace in the generated header,' - ' instead of the javap class name.') - option_parser.add_option('--input_file', - help='Single input file name. The output file name ' - 'will be derived from it. Must be used with ' - '--output_dir.') - option_parser.add_option('--output_dir', - help='The output directory. Must be used with ' - '--input') - option_parser.add_option('--optimize_generation', type="int", - default=0, help='Whether we should optimize JNI ' - 'generation by not regenerating files if they have ' - 'not changed.') - option_parser.add_option('--jarjar', - help='Path to optional jarjar rules file.') - options, args = option_parser.parse_args(argv) - if options.jar_file: - input_file = ExtractJarInputFile(options.jar_file, options.input_file, - options.output_dir) - else: - input_file = options.input_file - output_file = None - if options.output_dir: - root_name = os.path.splitext(os.path.basename(input_file))[0] - output_file = os.path.join(options.output_dir, root_name) + '_jni.h' - if options.jarjar: - with open(options.jarjar) as f: - JniParams.SetJarJarMappings(f.read()) - GenerateJNIHeader(input_file, output_file, options.namespace, - options.optimize_generation) - - -if __name__ == '__main__': - sys.exit(main(sys.argv)) diff --git a/base/android/jni_generator/jni_generator_tests.py b/base/android/jni_generator/jni_generator_tests.py deleted file mode 100755 index f008f394ce..0000000000 --- a/base/android/jni_generator/jni_generator_tests.py +++ /dev/null @@ -1,2084 +0,0 @@ -#!/usr/bin/env python -# Copyright (c) 2012 The Chromium Authors. All rights reserved. -# Use of this source code is governed by a BSD-style license that can be -# found in the LICENSE file. - -"""Tests for jni_generator.py. - -This test suite contains various tests for the JNI generator. -It exercises the low-level parser all the way up to the -code generator and ensures the output matches a golden -file. -""" - -import difflib -import os -import sys -import unittest -import jni_generator -from jni_generator import CalledByNative, JniParams, NativeMethod, Param - - -class TestGenerator(unittest.TestCase): - def assertObjEquals(self, first, second): - dict_first = first.__dict__ - dict_second = second.__dict__ - self.assertEquals(dict_first.keys(), dict_second.keys()) - for key, value in dict_first.iteritems(): - if (type(value) is list and len(value) and - isinstance(type(value[0]), object)): - self.assertListEquals(value, second.__getattribute__(key)) - else: - actual = second.__getattribute__(key) - self.assertEquals(value, actual, - 'Key ' + key + ': ' + str(value) + '!=' + str(actual)) - - def assertListEquals(self, first, second): - self.assertEquals(len(first), len(second)) - for i in xrange(len(first)): - if isinstance(first[i], object): - self.assertObjEquals(first[i], second[i]) - else: - self.assertEquals(first[i], second[i]) - - def assertTextEquals(self, golden_text, generated_text): - stripped_golden = [l.strip() for l in golden_text.split('\n')] - stripped_generated = [l.strip() for l in generated_text.split('\n')] - if stripped_golden != stripped_generated: - print self.id() - for line in difflib.context_diff(stripped_golden, stripped_generated): - print line - print '\n\nGenerated' - print '=' * 80 - print generated_text - print '=' * 80 - self.fail('Golden text mismatch') - - def testNatives(self): - test_data = """" - interface OnFrameAvailableListener {} - private native int nativeInit(); - private native void nativeDestroy(int nativeChromeBrowserProvider); - private native long nativeAddBookmark( - int nativeChromeBrowserProvider, - String url, String title, boolean isFolder, long parentId); - private static native String nativeGetDomainAndRegistry(String url); - private static native void nativeCreateHistoricalTabFromState( - byte[] state, int tab_index); - private native byte[] nativeGetStateAsByteArray(View view); - private static native String[] nativeGetAutofillProfileGUIDs(); - private native void nativeSetRecognitionResults( - int sessionId, String[] results); - private native long nativeAddBookmarkFromAPI( - int nativeChromeBrowserProvider, - String url, Long created, Boolean isBookmark, - Long date, byte[] favicon, String title, Integer visits); - native int nativeFindAll(String find); - private static native OnFrameAvailableListener nativeGetInnerClass(); - private native Bitmap nativeQueryBitmap( - int nativeChromeBrowserProvider, - String[] projection, String selection, - String[] selectionArgs, String sortOrder); - private native void nativeGotOrientation( - int nativeDataFetcherImplAndroid, - double alpha, double beta, double gamma); - """ - jni_generator.JniParams.ExtractImportsAndInnerClasses(test_data) - natives = jni_generator.ExtractNatives(test_data) - golden_natives = [ - NativeMethod(return_type='int', static=False, - name='Init', - params=[], - java_class_name=None, - type='function'), - NativeMethod(return_type='void', static=False, name='Destroy', - params=[Param(datatype='int', - name='nativeChromeBrowserProvider')], - java_class_name=None, - type='method', - p0_type='ChromeBrowserProvider'), - NativeMethod(return_type='long', static=False, name='AddBookmark', - params=[Param(datatype='int', - name='nativeChromeBrowserProvider'), - Param(datatype='String', - name='url'), - Param(datatype='String', - name='title'), - Param(datatype='boolean', - name='isFolder'), - Param(datatype='long', - name='parentId')], - java_class_name=None, - type='method', - p0_type='ChromeBrowserProvider'), - NativeMethod(return_type='String', static=True, - name='GetDomainAndRegistry', - params=[Param(datatype='String', - name='url')], - java_class_name=None, - type='function'), - NativeMethod(return_type='void', static=True, - name='CreateHistoricalTabFromState', - params=[Param(datatype='byte[]', - name='state'), - Param(datatype='int', - name='tab_index')], - java_class_name=None, - type='function'), - NativeMethod(return_type='byte[]', static=False, - name='GetStateAsByteArray', - params=[Param(datatype='View', name='view')], - java_class_name=None, - type='function'), - NativeMethod(return_type='String[]', static=True, - name='GetAutofillProfileGUIDs', params=[], - java_class_name=None, - type='function'), - NativeMethod(return_type='void', static=False, - name='SetRecognitionResults', - params=[Param(datatype='int', name='sessionId'), - Param(datatype='String[]', name='results')], - java_class_name=None, - type='function'), - NativeMethod(return_type='long', static=False, - name='AddBookmarkFromAPI', - params=[Param(datatype='int', - name='nativeChromeBrowserProvider'), - Param(datatype='String', - name='url'), - Param(datatype='Long', - name='created'), - Param(datatype='Boolean', - name='isBookmark'), - Param(datatype='Long', - name='date'), - Param(datatype='byte[]', - name='favicon'), - Param(datatype='String', - name='title'), - Param(datatype='Integer', - name='visits')], - java_class_name=None, - type='method', - p0_type='ChromeBrowserProvider'), - NativeMethod(return_type='int', static=False, - name='FindAll', - params=[Param(datatype='String', - name='find')], - java_class_name=None, - type='function'), - NativeMethod(return_type='OnFrameAvailableListener', static=True, - name='GetInnerClass', - params=[], - java_class_name=None, - type='function'), - NativeMethod(return_type='Bitmap', - static=False, - name='QueryBitmap', - params=[Param(datatype='int', - name='nativeChromeBrowserProvider'), - Param(datatype='String[]', - name='projection'), - Param(datatype='String', - name='selection'), - Param(datatype='String[]', - name='selectionArgs'), - Param(datatype='String', - name='sortOrder'), - ], - java_class_name=None, - type='method', - p0_type='ChromeBrowserProvider'), - NativeMethod(return_type='void', static=False, - name='GotOrientation', - params=[Param(datatype='int', - name='nativeDataFetcherImplAndroid'), - Param(datatype='double', - name='alpha'), - Param(datatype='double', - name='beta'), - Param(datatype='double', - name='gamma'), - ], - java_class_name=None, - type='method', - p0_type='content::DataFetcherImplAndroid'), - ] - self.assertListEquals(golden_natives, natives) - h = jni_generator.InlHeaderFileGenerator('', 'org/chromium/TestJni', - natives, []) - golden_content = """\ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -// This file is autogenerated by -// base/android/jni_generator/jni_generator_tests.py -// For -// org/chromium/TestJni - -#ifndef org_chromium_TestJni_JNI -#define org_chromium_TestJni_JNI - -#include - -#include "base/android/jni_android.h" -#include "base/android/scoped_java_ref.h" -#include "base/basictypes.h" -#include "base/logging.h" - -using base::android::ScopedJavaLocalRef; - -// Step 1: forward declarations. -namespace { -const char kTestJniClassPath[] = "org/chromium/TestJni"; -// Leaking this jclass as we cannot use LazyInstance from some threads. -jclass g_TestJni_clazz = NULL; -} // namespace - -static jint Init(JNIEnv* env, jobject obj); - -static jstring GetDomainAndRegistry(JNIEnv* env, jclass clazz, - jstring url); - -static void CreateHistoricalTabFromState(JNIEnv* env, jclass clazz, - jbyteArray state, - jint tab_index); - -static jbyteArray GetStateAsByteArray(JNIEnv* env, jobject obj, - jobject view); - -static jobjectArray GetAutofillProfileGUIDs(JNIEnv* env, jclass clazz); - -static void SetRecognitionResults(JNIEnv* env, jobject obj, - jint sessionId, - jobjectArray results); - -static jint FindAll(JNIEnv* env, jobject obj, - jstring find); - -static jobject GetInnerClass(JNIEnv* env, jclass clazz); - -// Step 2: method stubs. -static void Destroy(JNIEnv* env, jobject obj, - jint nativeChromeBrowserProvider) { - DCHECK(nativeChromeBrowserProvider) << "Destroy"; - ChromeBrowserProvider* native = - reinterpret_cast(nativeChromeBrowserProvider); - return native->Destroy(env, obj); -} - -static jlong AddBookmark(JNIEnv* env, jobject obj, - jint nativeChromeBrowserProvider, - jstring url, - jstring title, - jboolean isFolder, - jlong parentId) { - DCHECK(nativeChromeBrowserProvider) << "AddBookmark"; - ChromeBrowserProvider* native = - reinterpret_cast(nativeChromeBrowserProvider); - return native->AddBookmark(env, obj, url, title, isFolder, parentId); -} - -static jlong AddBookmarkFromAPI(JNIEnv* env, jobject obj, - jint nativeChromeBrowserProvider, - jstring url, - jobject created, - jobject isBookmark, - jobject date, - jbyteArray favicon, - jstring title, - jobject visits) { - DCHECK(nativeChromeBrowserProvider) << "AddBookmarkFromAPI"; - ChromeBrowserProvider* native = - reinterpret_cast(nativeChromeBrowserProvider); - return native->AddBookmarkFromAPI(env, obj, url, created, isBookmark, date, - favicon, title, visits); -} - -static jobject QueryBitmap(JNIEnv* env, jobject obj, - jint nativeChromeBrowserProvider, - jobjectArray projection, - jstring selection, - jobjectArray selectionArgs, - jstring sortOrder) { - DCHECK(nativeChromeBrowserProvider) << "QueryBitmap"; - ChromeBrowserProvider* native = - reinterpret_cast(nativeChromeBrowserProvider); - return native->QueryBitmap(env, obj, projection, selection, selectionArgs, - sortOrder).Release(); -} - -static void GotOrientation(JNIEnv* env, jobject obj, - jint nativeDataFetcherImplAndroid, - jdouble alpha, - jdouble beta, - jdouble gamma) { - DCHECK(nativeDataFetcherImplAndroid) << "GotOrientation"; - DataFetcherImplAndroid* native = - reinterpret_cast(nativeDataFetcherImplAndroid); - return native->GotOrientation(env, obj, alpha, beta, gamma); -} - -// Step 3: RegisterNatives. - -static bool RegisterNativesImpl(JNIEnv* env) { - - g_TestJni_clazz = reinterpret_cast(env->NewGlobalRef( - base::android::GetClass(env, kTestJniClassPath).obj())); - static const JNINativeMethod kMethodsTestJni[] = { - { "nativeInit", -"(" -")" -"I", reinterpret_cast(Init) }, - { "nativeDestroy", -"(" -"I" -")" -"V", reinterpret_cast(Destroy) }, - { "nativeAddBookmark", -"(" -"I" -"Ljava/lang/String;" -"Ljava/lang/String;" -"Z" -"J" -")" -"J", reinterpret_cast(AddBookmark) }, - { "nativeGetDomainAndRegistry", -"(" -"Ljava/lang/String;" -")" -"Ljava/lang/String;", reinterpret_cast(GetDomainAndRegistry) }, - { "nativeCreateHistoricalTabFromState", -"(" -"[B" -"I" -")" -"V", reinterpret_cast(CreateHistoricalTabFromState) }, - { "nativeGetStateAsByteArray", -"(" -"Landroid/view/View;" -")" -"[B", reinterpret_cast(GetStateAsByteArray) }, - { "nativeGetAutofillProfileGUIDs", -"(" -")" -"[Ljava/lang/String;", reinterpret_cast(GetAutofillProfileGUIDs) }, - { "nativeSetRecognitionResults", -"(" -"I" -"[Ljava/lang/String;" -")" -"V", reinterpret_cast(SetRecognitionResults) }, - { "nativeAddBookmarkFromAPI", -"(" -"I" -"Ljava/lang/String;" -"Ljava/lang/Long;" -"Ljava/lang/Boolean;" -"Ljava/lang/Long;" -"[B" -"Ljava/lang/String;" -"Ljava/lang/Integer;" -")" -"J", reinterpret_cast(AddBookmarkFromAPI) }, - { "nativeFindAll", -"(" -"Ljava/lang/String;" -")" -"I", reinterpret_cast(FindAll) }, - { "nativeGetInnerClass", -"(" -")" -"Lorg/chromium/example/jni_generator/SampleForTests$OnFrameAvailableListener;", - reinterpret_cast(GetInnerClass) }, - { "nativeQueryBitmap", -"(" -"I" -"[Ljava/lang/String;" -"Ljava/lang/String;" -"[Ljava/lang/String;" -"Ljava/lang/String;" -")" -"Landroid/graphics/Bitmap;", reinterpret_cast(QueryBitmap) }, - { "nativeGotOrientation", -"(" -"I" -"D" -"D" -"D" -")" -"V", reinterpret_cast(GotOrientation) }, - }; - const int kMethodsTestJniSize = arraysize(kMethodsTestJni); - - if (env->RegisterNatives(g_TestJni_clazz, - kMethodsTestJni, - kMethodsTestJniSize) < 0) { - LOG(ERROR) << "RegisterNatives failed in " << __FILE__; - return false; - } - - return true; -} - -#endif // org_chromium_TestJni_JNI -""" - self.assertTextEquals(golden_content, h.GetContent()) - - def testInnerClassNatives(self): - test_data = """ - class MyInnerClass { - @NativeCall("MyInnerClass") - private native int nativeInit(); - } - """ - natives = jni_generator.ExtractNatives(test_data) - golden_natives = [ - NativeMethod(return_type='int', static=False, - name='Init', params=[], - java_class_name='MyInnerClass', - type='function') - ] - self.assertListEquals(golden_natives, natives) - h = jni_generator.InlHeaderFileGenerator('', 'org/chromium/TestJni', - natives, []) - golden_content = """\ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -// This file is autogenerated by -// base/android/jni_generator/jni_generator_tests.py -// For -// org/chromium/TestJni - -#ifndef org_chromium_TestJni_JNI -#define org_chromium_TestJni_JNI - -#include - -#include "base/android/jni_android.h" -#include "base/android/scoped_java_ref.h" -#include "base/basictypes.h" -#include "base/logging.h" - -using base::android::ScopedJavaLocalRef; - -// Step 1: forward declarations. -namespace { -const char kTestJniClassPath[] = "org/chromium/TestJni"; -const char kMyInnerClassClassPath[] = "org/chromium/TestJni$MyInnerClass"; -// Leaking this jclass as we cannot use LazyInstance from some threads. -jclass g_TestJni_clazz = NULL; -} // namespace - -static jint Init(JNIEnv* env, jobject obj); - -// Step 2: method stubs. - -// Step 3: RegisterNatives. - -static bool RegisterNativesImpl(JNIEnv* env) { - - g_TestJni_clazz = reinterpret_cast(env->NewGlobalRef( - base::android::GetClass(env, kTestJniClassPath).obj())); - static const JNINativeMethod kMethodsMyInnerClass[] = { - { "nativeInit", -"(" -")" -"I", reinterpret_cast(Init) }, - }; - const int kMethodsMyInnerClassSize = arraysize(kMethodsMyInnerClass); - - if (env->RegisterNatives(g_MyInnerClass_clazz, - kMethodsMyInnerClass, - kMethodsMyInnerClassSize) < 0) { - LOG(ERROR) << "RegisterNatives failed in " << __FILE__; - return false; - } - - return true; -} - -#endif // org_chromium_TestJni_JNI -""" - self.assertTextEquals(golden_content, h.GetContent()) - - def testInnerClassNativesMultiple(self): - test_data = """ - class MyInnerClass { - @NativeCall("MyInnerClass") - private native int nativeInit(); - } - class MyOtherInnerClass { - @NativeCall("MyOtherInnerClass") - private native int nativeInit(); - } - """ - natives = jni_generator.ExtractNatives(test_data) - golden_natives = [ - NativeMethod(return_type='int', static=False, - name='Init', params=[], - java_class_name='MyInnerClass', - type='function'), - NativeMethod(return_type='int', static=False, - name='Init', params=[], - java_class_name='MyOtherInnerClass', - type='function') - ] - self.assertListEquals(golden_natives, natives) - h = jni_generator.InlHeaderFileGenerator('', 'org/chromium/TestJni', - natives, []) - golden_content = """\ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -// This file is autogenerated by -// base/android/jni_generator/jni_generator_tests.py -// For -// org/chromium/TestJni - -#ifndef org_chromium_TestJni_JNI -#define org_chromium_TestJni_JNI - -#include - -#include "base/android/jni_android.h" -#include "base/android/scoped_java_ref.h" -#include "base/basictypes.h" -#include "base/logging.h" - -using base::android::ScopedJavaLocalRef; - -// Step 1: forward declarations. -namespace { -const char kMyOtherInnerClassClassPath[] = - "org/chromium/TestJni$MyOtherInnerClass"; -const char kTestJniClassPath[] = "org/chromium/TestJni"; -const char kMyInnerClassClassPath[] = "org/chromium/TestJni$MyInnerClass"; -// Leaking this jclass as we cannot use LazyInstance from some threads. -jclass g_TestJni_clazz = NULL; -} // namespace - -static jint Init(JNIEnv* env, jobject obj); - -static jint Init(JNIEnv* env, jobject obj); - -// Step 2: method stubs. - -// Step 3: RegisterNatives. - -static bool RegisterNativesImpl(JNIEnv* env) { - - g_TestJni_clazz = reinterpret_cast(env->NewGlobalRef( - base::android::GetClass(env, kTestJniClassPath).obj())); - static const JNINativeMethod kMethodsMyOtherInnerClass[] = { - { "nativeInit", -"(" -")" -"I", reinterpret_cast(Init) }, - }; - const int kMethodsMyOtherInnerClassSize = - arraysize(kMethodsMyOtherInnerClass); - - if (env->RegisterNatives(g_MyOtherInnerClass_clazz, - kMethodsMyOtherInnerClass, - kMethodsMyOtherInnerClassSize) < 0) { - LOG(ERROR) << "RegisterNatives failed in " << __FILE__; - return false; - } - - static const JNINativeMethod kMethodsMyInnerClass[] = { - { "nativeInit", -"(" -")" -"I", reinterpret_cast(Init) }, - }; - const int kMethodsMyInnerClassSize = arraysize(kMethodsMyInnerClass); - - if (env->RegisterNatives(g_MyInnerClass_clazz, - kMethodsMyInnerClass, - kMethodsMyInnerClassSize) < 0) { - LOG(ERROR) << "RegisterNatives failed in " << __FILE__; - return false; - } - - return true; -} - -#endif // org_chromium_TestJni_JNI -""" - self.assertTextEquals(golden_content, h.GetContent()) - - def testInnerClassNativesBothInnerAndOuter(self): - test_data = """ - class MyOuterClass { - private native int nativeInit(); - class MyOtherInnerClass { - @NativeCall("MyOtherInnerClass") - private native int nativeInit(); - } - } - """ - natives = jni_generator.ExtractNatives(test_data) - golden_natives = [ - NativeMethod(return_type='int', static=False, - name='Init', params=[], - java_class_name=None, - type='function'), - NativeMethod(return_type='int', static=False, - name='Init', params=[], - java_class_name='MyOtherInnerClass', - type='function') - ] - self.assertListEquals(golden_natives, natives) - h = jni_generator.InlHeaderFileGenerator('', 'org/chromium/TestJni', - natives, []) - golden_content = """\ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -// This file is autogenerated by -// base/android/jni_generator/jni_generator_tests.py -// For -// org/chromium/TestJni - -#ifndef org_chromium_TestJni_JNI -#define org_chromium_TestJni_JNI - -#include - -#include "base/android/jni_android.h" -#include "base/android/scoped_java_ref.h" -#include "base/basictypes.h" -#include "base/logging.h" - -using base::android::ScopedJavaLocalRef; - -// Step 1: forward declarations. -namespace { -const char kMyOtherInnerClassClassPath[] = - "org/chromium/TestJni$MyOtherInnerClass"; -const char kTestJniClassPath[] = "org/chromium/TestJni"; -// Leaking this jclass as we cannot use LazyInstance from some threads. -jclass g_TestJni_clazz = NULL; -} // namespace - -static jint Init(JNIEnv* env, jobject obj); - -static jint Init(JNIEnv* env, jobject obj); - -// Step 2: method stubs. - -// Step 3: RegisterNatives. - -static bool RegisterNativesImpl(JNIEnv* env) { - - g_TestJni_clazz = reinterpret_cast(env->NewGlobalRef( - base::android::GetClass(env, kTestJniClassPath).obj())); - static const JNINativeMethod kMethodsMyOtherInnerClass[] = { - { "nativeInit", -"(" -")" -"I", reinterpret_cast(Init) }, - }; - const int kMethodsMyOtherInnerClassSize = - arraysize(kMethodsMyOtherInnerClass); - - if (env->RegisterNatives(g_MyOtherInnerClass_clazz, - kMethodsMyOtherInnerClass, - kMethodsMyOtherInnerClassSize) < 0) { - LOG(ERROR) << "RegisterNatives failed in " << __FILE__; - return false; - } - - static const JNINativeMethod kMethodsTestJni[] = { - { "nativeInit", -"(" -")" -"I", reinterpret_cast(Init) }, - }; - const int kMethodsTestJniSize = arraysize(kMethodsTestJni); - - if (env->RegisterNatives(g_TestJni_clazz, - kMethodsTestJni, - kMethodsTestJniSize) < 0) { - LOG(ERROR) << "RegisterNatives failed in " << __FILE__; - return false; - } - - return true; -} - -#endif // org_chromium_TestJni_JNI -""" - self.assertTextEquals(golden_content, h.GetContent()) - - def testCalledByNatives(self): - test_data = """" - import android.graphics.Bitmap; - import android.view.View; - import java.io.InputStream; - import java.util.List; - - class InnerClass {} - - @CalledByNative - InnerClass showConfirmInfoBar(int nativeInfoBar, - String buttonOk, String buttonCancel, String title, Bitmap icon) { - InfoBar infobar = new ConfirmInfoBar(nativeInfoBar, mContext, - buttonOk, buttonCancel, - title, icon); - return infobar; - } - @CalledByNative - InnerClass showAutoLoginInfoBar(int nativeInfoBar, - String realm, String account, String args) { - AutoLoginInfoBar infobar = new AutoLoginInfoBar(nativeInfoBar, mContext, - realm, account, args); - if (infobar.displayedAccountCount() == 0) - infobar = null; - return infobar; - } - @CalledByNative("InfoBar") - void dismiss(); - @SuppressWarnings("unused") - @CalledByNative - private static boolean shouldShowAutoLogin(View view, - String realm, String account, String args) { - AccountManagerContainer accountManagerContainer = - new AccountManagerContainer((Activity)contentView.getContext(), - realm, account, args); - String[] logins = accountManagerContainer.getAccountLogins(null); - return logins.length != 0; - } - @CalledByNative - static InputStream openUrl(String url) { - return null; - } - @CalledByNative - private void activateHardwareAcceleration(final boolean activated, - final int iPid, final int iType, - final int iPrimaryID, final int iSecondaryID) { - if (!activated) { - return - } - } - @CalledByNativeUnchecked - private void uncheckedCall(int iParam); - - @CalledByNative - public byte[] returnByteArray(); - - @CalledByNative - public boolean[] returnBooleanArray(); - - @CalledByNative - public char[] returnCharArray(); - - @CalledByNative - public short[] returnShortArray(); - - @CalledByNative - public int[] returnIntArray(); - - @CalledByNative - public long[] returnLongArray(); - - @CalledByNative - public double[] returnDoubleArray(); - - @CalledByNative - public Object[] returnObjectArray(); - - @CalledByNative - public byte[][] returnArrayOfByteArray(); - - @CalledByNative - public Bitmap.CompressFormat getCompressFormat(); - - @CalledByNative - public List getCompressFormatList(); - """ - jni_generator.JniParams.SetFullyQualifiedClass('org/chromium/Foo') - jni_generator.JniParams.ExtractImportsAndInnerClasses(test_data) - called_by_natives = jni_generator.ExtractCalledByNatives(test_data) - golden_called_by_natives = [ - CalledByNative( - return_type='InnerClass', - system_class=False, - static=False, - name='showConfirmInfoBar', - method_id_var_name='showConfirmInfoBar', - java_class_name='', - params=[Param(datatype='int', name='nativeInfoBar'), - Param(datatype='String', name='buttonOk'), - Param(datatype='String', name='buttonCancel'), - Param(datatype='String', name='title'), - Param(datatype='Bitmap', name='icon')], - env_call=('Object', ''), - unchecked=False, - ), - CalledByNative( - return_type='InnerClass', - system_class=False, - static=False, - name='showAutoLoginInfoBar', - method_id_var_name='showAutoLoginInfoBar', - java_class_name='', - params=[Param(datatype='int', name='nativeInfoBar'), - Param(datatype='String', name='realm'), - Param(datatype='String', name='account'), - Param(datatype='String', name='args')], - env_call=('Object', ''), - unchecked=False, - ), - CalledByNative( - return_type='void', - system_class=False, - static=False, - name='dismiss', - method_id_var_name='dismiss', - java_class_name='InfoBar', - params=[], - env_call=('Void', ''), - unchecked=False, - ), - CalledByNative( - return_type='boolean', - system_class=False, - static=True, - name='shouldShowAutoLogin', - method_id_var_name='shouldShowAutoLogin', - java_class_name='', - params=[Param(datatype='View', name='view'), - Param(datatype='String', name='realm'), - Param(datatype='String', name='account'), - Param(datatype='String', name='args')], - env_call=('Boolean', ''), - unchecked=False, - ), - CalledByNative( - return_type='InputStream', - system_class=False, - static=True, - name='openUrl', - method_id_var_name='openUrl', - java_class_name='', - params=[Param(datatype='String', name='url')], - env_call=('Object', ''), - unchecked=False, - ), - CalledByNative( - return_type='void', - system_class=False, - static=False, - name='activateHardwareAcceleration', - method_id_var_name='activateHardwareAcceleration', - java_class_name='', - params=[Param(datatype='boolean', name='activated'), - Param(datatype='int', name='iPid'), - Param(datatype='int', name='iType'), - Param(datatype='int', name='iPrimaryID'), - Param(datatype='int', name='iSecondaryID'), - ], - env_call=('Void', ''), - unchecked=False, - ), - CalledByNative( - return_type='void', - system_class=False, - static=False, - name='uncheckedCall', - method_id_var_name='uncheckedCall', - java_class_name='', - params=[Param(datatype='int', name='iParam')], - env_call=('Void', ''), - unchecked=True, - ), - CalledByNative( - return_type='byte[]', - system_class=False, - static=False, - name='returnByteArray', - method_id_var_name='returnByteArray', - java_class_name='', - params=[], - env_call=('Void', ''), - unchecked=False, - ), - CalledByNative( - return_type='boolean[]', - system_class=False, - static=False, - name='returnBooleanArray', - method_id_var_name='returnBooleanArray', - java_class_name='', - params=[], - env_call=('Void', ''), - unchecked=False, - ), - CalledByNative( - return_type='char[]', - system_class=False, - static=False, - name='returnCharArray', - method_id_var_name='returnCharArray', - java_class_name='', - params=[], - env_call=('Void', ''), - unchecked=False, - ), - CalledByNative( - return_type='short[]', - system_class=False, - static=False, - name='returnShortArray', - method_id_var_name='returnShortArray', - java_class_name='', - params=[], - env_call=('Void', ''), - unchecked=False, - ), - CalledByNative( - return_type='int[]', - system_class=False, - static=False, - name='returnIntArray', - method_id_var_name='returnIntArray', - java_class_name='', - params=[], - env_call=('Void', ''), - unchecked=False, - ), - CalledByNative( - return_type='long[]', - system_class=False, - static=False, - name='returnLongArray', - method_id_var_name='returnLongArray', - java_class_name='', - params=[], - env_call=('Void', ''), - unchecked=False, - ), - CalledByNative( - return_type='double[]', - system_class=False, - static=False, - name='returnDoubleArray', - method_id_var_name='returnDoubleArray', - java_class_name='', - params=[], - env_call=('Void', ''), - unchecked=False, - ), - CalledByNative( - return_type='Object[]', - system_class=False, - static=False, - name='returnObjectArray', - method_id_var_name='returnObjectArray', - java_class_name='', - params=[], - env_call=('Void', ''), - unchecked=False, - ), - CalledByNative( - return_type='byte[][]', - system_class=False, - static=False, - name='returnArrayOfByteArray', - method_id_var_name='returnArrayOfByteArray', - java_class_name='', - params=[], - env_call=('Void', ''), - unchecked=False, - ), - CalledByNative( - return_type='Bitmap.CompressFormat', - system_class=False, - static=False, - name='getCompressFormat', - method_id_var_name='getCompressFormat', - java_class_name='', - params=[], - env_call=('Void', ''), - unchecked=False, - ), - CalledByNative( - return_type='List', - system_class=False, - static=False, - name='getCompressFormatList', - method_id_var_name='getCompressFormatList', - java_class_name='', - params=[], - env_call=('Void', ''), - unchecked=False, - ), - ] - self.assertListEquals(golden_called_by_natives, called_by_natives) - h = jni_generator.InlHeaderFileGenerator('', 'org/chromium/TestJni', - [], called_by_natives) - golden_content = """\ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -// This file is autogenerated by -// base/android/jni_generator/jni_generator_tests.py -// For -// org/chromium/TestJni - -#ifndef org_chromium_TestJni_JNI -#define org_chromium_TestJni_JNI - -#include - -#include "base/android/jni_android.h" -#include "base/android/scoped_java_ref.h" -#include "base/basictypes.h" -#include "base/logging.h" - -using base::android::ScopedJavaLocalRef; - -// Step 1: forward declarations. -namespace { -const char kTestJniClassPath[] = "org/chromium/TestJni"; -const char kInfoBarClassPath[] = "org/chromium/TestJni$InfoBar"; -// Leaking this jclass as we cannot use LazyInstance from some threads. -jclass g_TestJni_clazz = NULL; -// Leaking this jclass as we cannot use LazyInstance from some threads. -jclass g_InfoBar_clazz = NULL; -} // namespace - -// Step 2: method stubs. - -static base::subtle::AtomicWord g_TestJni_showConfirmInfoBar = 0; -static ScopedJavaLocalRef Java_TestJni_showConfirmInfoBar(JNIEnv* env, - jobject obj, jint nativeInfoBar, - jstring buttonOk, - jstring buttonCancel, - jstring title, - jobject icon) { - /* Must call RegisterNativesImpl() */ - DCHECK(g_TestJni_clazz); - jmethodID method_id = - base::android::MethodID::LazyGet< - base::android::MethodID::TYPE_INSTANCE>( - env, g_TestJni_clazz, - "showConfirmInfoBar", - -"(" -"I" -"Ljava/lang/String;" -"Ljava/lang/String;" -"Ljava/lang/String;" -"Landroid/graphics/Bitmap;" -")" -"Lorg/chromium/Foo$InnerClass;", - &g_TestJni_showConfirmInfoBar); - - jobject ret = - env->CallObjectMethod(obj, - method_id, nativeInfoBar, buttonOk, buttonCancel, title, icon); - base::android::CheckException(env); - return ScopedJavaLocalRef(env, ret); -} - -static base::subtle::AtomicWord g_TestJni_showAutoLoginInfoBar = 0; -static ScopedJavaLocalRef Java_TestJni_showAutoLoginInfoBar(JNIEnv* - env, jobject obj, jint nativeInfoBar, - jstring realm, - jstring account, - jstring args) { - /* Must call RegisterNativesImpl() */ - DCHECK(g_TestJni_clazz); - jmethodID method_id = - base::android::MethodID::LazyGet< - base::android::MethodID::TYPE_INSTANCE>( - env, g_TestJni_clazz, - "showAutoLoginInfoBar", - -"(" -"I" -"Ljava/lang/String;" -"Ljava/lang/String;" -"Ljava/lang/String;" -")" -"Lorg/chromium/Foo$InnerClass;", - &g_TestJni_showAutoLoginInfoBar); - - jobject ret = - env->CallObjectMethod(obj, - method_id, nativeInfoBar, realm, account, args); - base::android::CheckException(env); - return ScopedJavaLocalRef(env, ret); -} - -static base::subtle::AtomicWord g_InfoBar_dismiss = 0; -static void Java_InfoBar_dismiss(JNIEnv* env, jobject obj) { - /* Must call RegisterNativesImpl() */ - DCHECK(g_InfoBar_clazz); - jmethodID method_id = - base::android::MethodID::LazyGet< - base::android::MethodID::TYPE_INSTANCE>( - env, g_InfoBar_clazz, - "dismiss", - -"(" -")" -"V", - &g_InfoBar_dismiss); - - env->CallVoidMethod(obj, - method_id); - base::android::CheckException(env); - -} - -static base::subtle::AtomicWord g_TestJni_shouldShowAutoLogin = 0; -static jboolean Java_TestJni_shouldShowAutoLogin(JNIEnv* env, jobject view, - jstring realm, - jstring account, - jstring args) { - /* Must call RegisterNativesImpl() */ - DCHECK(g_TestJni_clazz); - jmethodID method_id = - base::android::MethodID::LazyGet< - base::android::MethodID::TYPE_STATIC>( - env, g_TestJni_clazz, - "shouldShowAutoLogin", - -"(" -"Landroid/view/View;" -"Ljava/lang/String;" -"Ljava/lang/String;" -"Ljava/lang/String;" -")" -"Z", - &g_TestJni_shouldShowAutoLogin); - - jboolean ret = - env->CallStaticBooleanMethod(g_TestJni_clazz, - method_id, view, realm, account, args); - base::android::CheckException(env); - return ret; -} - -static base::subtle::AtomicWord g_TestJni_openUrl = 0; -static ScopedJavaLocalRef Java_TestJni_openUrl(JNIEnv* env, jstring - url) { - /* Must call RegisterNativesImpl() */ - DCHECK(g_TestJni_clazz); - jmethodID method_id = - base::android::MethodID::LazyGet< - base::android::MethodID::TYPE_STATIC>( - env, g_TestJni_clazz, - "openUrl", - -"(" -"Ljava/lang/String;" -")" -"Ljava/io/InputStream;", - &g_TestJni_openUrl); - - jobject ret = - env->CallStaticObjectMethod(g_TestJni_clazz, - method_id, url); - base::android::CheckException(env); - return ScopedJavaLocalRef(env, ret); -} - -static base::subtle::AtomicWord g_TestJni_activateHardwareAcceleration = 0; -static void Java_TestJni_activateHardwareAcceleration(JNIEnv* env, jobject obj, - jboolean activated, - jint iPid, - jint iType, - jint iPrimaryID, - jint iSecondaryID) { - /* Must call RegisterNativesImpl() */ - DCHECK(g_TestJni_clazz); - jmethodID method_id = - base::android::MethodID::LazyGet< - base::android::MethodID::TYPE_INSTANCE>( - env, g_TestJni_clazz, - "activateHardwareAcceleration", - -"(" -"Z" -"I" -"I" -"I" -"I" -")" -"V", - &g_TestJni_activateHardwareAcceleration); - - env->CallVoidMethod(obj, - method_id, activated, iPid, iType, iPrimaryID, iSecondaryID); - base::android::CheckException(env); - -} - -static base::subtle::AtomicWord g_TestJni_uncheckedCall = 0; -static void Java_TestJni_uncheckedCall(JNIEnv* env, jobject obj, jint iParam) { - /* Must call RegisterNativesImpl() */ - DCHECK(g_TestJni_clazz); - jmethodID method_id = - base::android::MethodID::LazyGet< - base::android::MethodID::TYPE_INSTANCE>( - env, g_TestJni_clazz, - "uncheckedCall", - -"(" -"I" -")" -"V", - &g_TestJni_uncheckedCall); - - env->CallVoidMethod(obj, - method_id, iParam); - -} - -static base::subtle::AtomicWord g_TestJni_returnByteArray = 0; -static ScopedJavaLocalRef Java_TestJni_returnByteArray(JNIEnv* env, - jobject obj) { - /* Must call RegisterNativesImpl() */ - DCHECK(g_TestJni_clazz); - jmethodID method_id = - base::android::MethodID::LazyGet< - base::android::MethodID::TYPE_INSTANCE>( - env, g_TestJni_clazz, - "returnByteArray", - -"(" -")" -"[B", - &g_TestJni_returnByteArray); - - jbyteArray ret = - static_cast(env->CallObjectMethod(obj, - method_id)); - base::android::CheckException(env); - return ScopedJavaLocalRef(env, ret); -} - -static base::subtle::AtomicWord g_TestJni_returnBooleanArray = 0; -static ScopedJavaLocalRef Java_TestJni_returnBooleanArray(JNIEnv* - env, jobject obj) { - /* Must call RegisterNativesImpl() */ - DCHECK(g_TestJni_clazz); - jmethodID method_id = - base::android::MethodID::LazyGet< - base::android::MethodID::TYPE_INSTANCE>( - env, g_TestJni_clazz, - "returnBooleanArray", - -"(" -")" -"[Z", - &g_TestJni_returnBooleanArray); - - jbooleanArray ret = - static_cast(env->CallObjectMethod(obj, - method_id)); - base::android::CheckException(env); - return ScopedJavaLocalRef(env, ret); -} - -static base::subtle::AtomicWord g_TestJni_returnCharArray = 0; -static ScopedJavaLocalRef Java_TestJni_returnCharArray(JNIEnv* env, - jobject obj) { - /* Must call RegisterNativesImpl() */ - DCHECK(g_TestJni_clazz); - jmethodID method_id = - base::android::MethodID::LazyGet< - base::android::MethodID::TYPE_INSTANCE>( - env, g_TestJni_clazz, - "returnCharArray", - -"(" -")" -"[C", - &g_TestJni_returnCharArray); - - jcharArray ret = - static_cast(env->CallObjectMethod(obj, - method_id)); - base::android::CheckException(env); - return ScopedJavaLocalRef(env, ret); -} - -static base::subtle::AtomicWord g_TestJni_returnShortArray = 0; -static ScopedJavaLocalRef Java_TestJni_returnShortArray(JNIEnv* - env, jobject obj) { - /* Must call RegisterNativesImpl() */ - DCHECK(g_TestJni_clazz); - jmethodID method_id = - base::android::MethodID::LazyGet< - base::android::MethodID::TYPE_INSTANCE>( - env, g_TestJni_clazz, - "returnShortArray", - -"(" -")" -"[S", - &g_TestJni_returnShortArray); - - jshortArray ret = - static_cast(env->CallObjectMethod(obj, - method_id)); - base::android::CheckException(env); - return ScopedJavaLocalRef(env, ret); -} - -static base::subtle::AtomicWord g_TestJni_returnIntArray = 0; -static ScopedJavaLocalRef Java_TestJni_returnIntArray(JNIEnv* env, - jobject obj) { - /* Must call RegisterNativesImpl() */ - DCHECK(g_TestJni_clazz); - jmethodID method_id = - base::android::MethodID::LazyGet< - base::android::MethodID::TYPE_INSTANCE>( - env, g_TestJni_clazz, - "returnIntArray", - -"(" -")" -"[I", - &g_TestJni_returnIntArray); - - jintArray ret = - static_cast(env->CallObjectMethod(obj, - method_id)); - base::android::CheckException(env); - return ScopedJavaLocalRef(env, ret); -} - -static base::subtle::AtomicWord g_TestJni_returnLongArray = 0; -static ScopedJavaLocalRef Java_TestJni_returnLongArray(JNIEnv* env, - jobject obj) { - /* Must call RegisterNativesImpl() */ - DCHECK(g_TestJni_clazz); - jmethodID method_id = - base::android::MethodID::LazyGet< - base::android::MethodID::TYPE_INSTANCE>( - env, g_TestJni_clazz, - "returnLongArray", - -"(" -")" -"[J", - &g_TestJni_returnLongArray); - - jlongArray ret = - static_cast(env->CallObjectMethod(obj, - method_id)); - base::android::CheckException(env); - return ScopedJavaLocalRef(env, ret); -} - -static base::subtle::AtomicWord g_TestJni_returnDoubleArray = 0; -static ScopedJavaLocalRef Java_TestJni_returnDoubleArray(JNIEnv* - env, jobject obj) { - /* Must call RegisterNativesImpl() */ - DCHECK(g_TestJni_clazz); - jmethodID method_id = - base::android::MethodID::LazyGet< - base::android::MethodID::TYPE_INSTANCE>( - env, g_TestJni_clazz, - "returnDoubleArray", - -"(" -")" -"[D", - &g_TestJni_returnDoubleArray); - - jdoubleArray ret = - static_cast(env->CallObjectMethod(obj, - method_id)); - base::android::CheckException(env); - return ScopedJavaLocalRef(env, ret); -} - -static base::subtle::AtomicWord g_TestJni_returnObjectArray = 0; -static ScopedJavaLocalRef Java_TestJni_returnObjectArray(JNIEnv* - env, jobject obj) { - /* Must call RegisterNativesImpl() */ - DCHECK(g_TestJni_clazz); - jmethodID method_id = - base::android::MethodID::LazyGet< - base::android::MethodID::TYPE_INSTANCE>( - env, g_TestJni_clazz, - "returnObjectArray", - -"(" -")" -"[Ljava/lang/Object;", - &g_TestJni_returnObjectArray); - - jobjectArray ret = - static_cast(env->CallObjectMethod(obj, - method_id)); - base::android::CheckException(env); - return ScopedJavaLocalRef(env, ret); -} - -static base::subtle::AtomicWord g_TestJni_returnArrayOfByteArray = 0; -static ScopedJavaLocalRef - Java_TestJni_returnArrayOfByteArray(JNIEnv* env, jobject obj) { - /* Must call RegisterNativesImpl() */ - DCHECK(g_TestJni_clazz); - jmethodID method_id = - base::android::MethodID::LazyGet< - base::android::MethodID::TYPE_INSTANCE>( - env, g_TestJni_clazz, - "returnArrayOfByteArray", - -"(" -")" -"[[B", - &g_TestJni_returnArrayOfByteArray); - - jobjectArray ret = - static_cast(env->CallObjectMethod(obj, - method_id)); - base::android::CheckException(env); - return ScopedJavaLocalRef(env, ret); -} - -static base::subtle::AtomicWord g_TestJni_getCompressFormat = 0; -static ScopedJavaLocalRef Java_TestJni_getCompressFormat(JNIEnv* env, - jobject obj) { - /* Must call RegisterNativesImpl() */ - DCHECK(g_TestJni_clazz); - jmethodID method_id = - base::android::MethodID::LazyGet< - base::android::MethodID::TYPE_INSTANCE>( - env, g_TestJni_clazz, - "getCompressFormat", - -"(" -")" -"Landroid/graphics/Bitmap$CompressFormat;", - &g_TestJni_getCompressFormat); - - jobject ret = - env->CallObjectMethod(obj, - method_id); - base::android::CheckException(env); - return ScopedJavaLocalRef(env, ret); -} - -static base::subtle::AtomicWord g_TestJni_getCompressFormatList = 0; -static ScopedJavaLocalRef Java_TestJni_getCompressFormatList(JNIEnv* - env, jobject obj) { - /* Must call RegisterNativesImpl() */ - DCHECK(g_TestJni_clazz); - jmethodID method_id = - base::android::MethodID::LazyGet< - base::android::MethodID::TYPE_INSTANCE>( - env, g_TestJni_clazz, - "getCompressFormatList", - -"(" -")" -"Ljava/util/List;", - &g_TestJni_getCompressFormatList); - - jobject ret = - env->CallObjectMethod(obj, - method_id); - base::android::CheckException(env); - return ScopedJavaLocalRef(env, ret); -} - -// Step 3: RegisterNatives. - -static bool RegisterNativesImpl(JNIEnv* env) { - - g_TestJni_clazz = reinterpret_cast(env->NewGlobalRef( - base::android::GetClass(env, kTestJniClassPath).obj())); - g_InfoBar_clazz = reinterpret_cast(env->NewGlobalRef( - base::android::GetClass(env, kInfoBarClassPath).obj())); - return true; -} - -#endif // org_chromium_TestJni_JNI -""" - self.assertTextEquals(golden_content, h.GetContent()) - - def testCalledByNativeParseError(self): - try: - jni_generator.ExtractCalledByNatives(""" -@CalledByNative -public static int foo(); // This one is fine - -@CalledByNative -scooby doo -""") - self.fail('Expected a ParseError') - except jni_generator.ParseError, e: - self.assertEquals(('@CalledByNative', 'scooby doo'), e.context_lines) - - def testFullyQualifiedClassName(self): - contents = """ -// Copyright (c) 2010 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -package org.chromium.content.browser; - -import org.chromium.base.BuildInfo; -""" - self.assertEquals('org/chromium/content/browser/Foo', - jni_generator.ExtractFullyQualifiedJavaClassName( - 'org/chromium/content/browser/Foo.java', contents)) - self.assertEquals('org/chromium/content/browser/Foo', - jni_generator.ExtractFullyQualifiedJavaClassName( - 'frameworks/Foo.java', contents)) - self.assertRaises(SyntaxError, - jni_generator.ExtractFullyQualifiedJavaClassName, - 'com/foo/Bar', 'no PACKAGE line') - - def testMethodNameMangling(self): - self.assertEquals('closeV', - jni_generator.GetMangledMethodName('close', [], 'void')) - self.assertEquals('readI_AB_I_I', - jni_generator.GetMangledMethodName('read', - [Param(name='p1', - datatype='byte[]'), - Param(name='p2', - datatype='int'), - Param(name='p3', - datatype='int'),], - 'int')) - self.assertEquals('openJIIS_JLS', - jni_generator.GetMangledMethodName('open', - [Param(name='p1', - datatype='java/lang/String'),], - 'java/io/InputStream')) - - def testFromJavaP(self): - contents = """ -public abstract class java.io.InputStream extends java.lang.Object - implements java.io.Closeable{ - public java.io.InputStream(); - public int available() throws java.io.IOException; - public void close() throws java.io.IOException; - public void mark(int); - public boolean markSupported(); - public abstract int read() throws java.io.IOException; - public int read(byte[]) throws java.io.IOException; - public int read(byte[], int, int) throws java.io.IOException; - public synchronized void reset() throws java.io.IOException; - public long skip(long) throws java.io.IOException; -} -""" - jni_from_javap = jni_generator.JNIFromJavaP(contents.split('\n'), None) - self.assertEquals(10, len(jni_from_javap.called_by_natives)) - golden_content = """\ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -// This file is autogenerated by -// base/android/jni_generator/jni_generator_tests.py -// For -// java/io/InputStream - -#ifndef java_io_InputStream_JNI -#define java_io_InputStream_JNI - -#include - -#include "base/android/jni_android.h" -#include "base/android/scoped_java_ref.h" -#include "base/basictypes.h" -#include "base/logging.h" - -using base::android::ScopedJavaLocalRef; - -// Step 1: forward declarations. -namespace { -const char kInputStreamClassPath[] = "java/io/InputStream"; -// Leaking this jclass as we cannot use LazyInstance from some threads. -jclass g_InputStream_clazz = NULL; -} // namespace - -namespace JNI_InputStream { - -// Step 2: method stubs. - -static base::subtle::AtomicWord g_InputStream_available = 0; -static jint Java_InputStream_available(JNIEnv* env, jobject obj) __attribute__ - ((unused)); -static jint Java_InputStream_available(JNIEnv* env, jobject obj) { - /* Must call RegisterNativesImpl() */ - DCHECK(g_InputStream_clazz); - jmethodID method_id = - base::android::MethodID::LazyGet< - base::android::MethodID::TYPE_INSTANCE>( - env, g_InputStream_clazz, - "available", - -"(" -")" -"I", - &g_InputStream_available); - - jint ret = - env->CallIntMethod(obj, - method_id); - base::android::CheckException(env); - return ret; -} - -static base::subtle::AtomicWord g_InputStream_close = 0; -static void Java_InputStream_close(JNIEnv* env, jobject obj) __attribute__ - ((unused)); -static void Java_InputStream_close(JNIEnv* env, jobject obj) { - /* Must call RegisterNativesImpl() */ - DCHECK(g_InputStream_clazz); - jmethodID method_id = - base::android::MethodID::LazyGet< - base::android::MethodID::TYPE_INSTANCE>( - env, g_InputStream_clazz, - "close", - -"(" -")" -"V", - &g_InputStream_close); - - env->CallVoidMethod(obj, - method_id); - base::android::CheckException(env); - -} - -static base::subtle::AtomicWord g_InputStream_mark = 0; -static void Java_InputStream_mark(JNIEnv* env, jobject obj, jint p0) - __attribute__ ((unused)); -static void Java_InputStream_mark(JNIEnv* env, jobject obj, jint p0) { - /* Must call RegisterNativesImpl() */ - DCHECK(g_InputStream_clazz); - jmethodID method_id = - base::android::MethodID::LazyGet< - base::android::MethodID::TYPE_INSTANCE>( - env, g_InputStream_clazz, - "mark", - -"(" -"I" -")" -"V", - &g_InputStream_mark); - - env->CallVoidMethod(obj, - method_id, p0); - base::android::CheckException(env); - -} - -static base::subtle::AtomicWord g_InputStream_markSupported = 0; -static jboolean Java_InputStream_markSupported(JNIEnv* env, jobject obj) - __attribute__ ((unused)); -static jboolean Java_InputStream_markSupported(JNIEnv* env, jobject obj) { - /* Must call RegisterNativesImpl() */ - DCHECK(g_InputStream_clazz); - jmethodID method_id = - base::android::MethodID::LazyGet< - base::android::MethodID::TYPE_INSTANCE>( - env, g_InputStream_clazz, - "markSupported", - -"(" -")" -"Z", - &g_InputStream_markSupported); - - jboolean ret = - env->CallBooleanMethod(obj, - method_id); - base::android::CheckException(env); - return ret; -} - -static base::subtle::AtomicWord g_InputStream_readI = 0; -static jint Java_InputStream_readI(JNIEnv* env, jobject obj) __attribute__ - ((unused)); -static jint Java_InputStream_readI(JNIEnv* env, jobject obj) { - /* Must call RegisterNativesImpl() */ - DCHECK(g_InputStream_clazz); - jmethodID method_id = - base::android::MethodID::LazyGet< - base::android::MethodID::TYPE_INSTANCE>( - env, g_InputStream_clazz, - "read", - -"(" -")" -"I", - &g_InputStream_readI); - - jint ret = - env->CallIntMethod(obj, - method_id); - base::android::CheckException(env); - return ret; -} - -static base::subtle::AtomicWord g_InputStream_readI_AB = 0; -static jint Java_InputStream_readI_AB(JNIEnv* env, jobject obj, jbyteArray p0) - __attribute__ ((unused)); -static jint Java_InputStream_readI_AB(JNIEnv* env, jobject obj, jbyteArray p0) { - /* Must call RegisterNativesImpl() */ - DCHECK(g_InputStream_clazz); - jmethodID method_id = - base::android::MethodID::LazyGet< - base::android::MethodID::TYPE_INSTANCE>( - env, g_InputStream_clazz, - "read", - -"(" -"[B" -")" -"I", - &g_InputStream_readI_AB); - - jint ret = - env->CallIntMethod(obj, - method_id, p0); - base::android::CheckException(env); - return ret; -} - -static base::subtle::AtomicWord g_InputStream_readI_AB_I_I = 0; -static jint Java_InputStream_readI_AB_I_I(JNIEnv* env, jobject obj, jbyteArray - p0, - jint p1, - jint p2) __attribute__ ((unused)); -static jint Java_InputStream_readI_AB_I_I(JNIEnv* env, jobject obj, jbyteArray - p0, - jint p1, - jint p2) { - /* Must call RegisterNativesImpl() */ - DCHECK(g_InputStream_clazz); - jmethodID method_id = - base::android::MethodID::LazyGet< - base::android::MethodID::TYPE_INSTANCE>( - env, g_InputStream_clazz, - "read", - -"(" -"[B" -"I" -"I" -")" -"I", - &g_InputStream_readI_AB_I_I); - - jint ret = - env->CallIntMethod(obj, - method_id, p0, p1, p2); - base::android::CheckException(env); - return ret; -} - -static base::subtle::AtomicWord g_InputStream_reset = 0; -static void Java_InputStream_reset(JNIEnv* env, jobject obj) __attribute__ - ((unused)); -static void Java_InputStream_reset(JNIEnv* env, jobject obj) { - /* Must call RegisterNativesImpl() */ - DCHECK(g_InputStream_clazz); - jmethodID method_id = - base::android::MethodID::LazyGet< - base::android::MethodID::TYPE_INSTANCE>( - env, g_InputStream_clazz, - "reset", - -"(" -")" -"V", - &g_InputStream_reset); - - env->CallVoidMethod(obj, - method_id); - base::android::CheckException(env); - -} - -static base::subtle::AtomicWord g_InputStream_skip = 0; -static jlong Java_InputStream_skip(JNIEnv* env, jobject obj, jlong p0) - __attribute__ ((unused)); -static jlong Java_InputStream_skip(JNIEnv* env, jobject obj, jlong p0) { - /* Must call RegisterNativesImpl() */ - DCHECK(g_InputStream_clazz); - jmethodID method_id = - base::android::MethodID::LazyGet< - base::android::MethodID::TYPE_INSTANCE>( - env, g_InputStream_clazz, - "skip", - -"(" -"J" -")" -"J", - &g_InputStream_skip); - - jlong ret = - env->CallLongMethod(obj, - method_id, p0); - base::android::CheckException(env); - return ret; -} - -static base::subtle::AtomicWord g_InputStream_Constructor = 0; -static ScopedJavaLocalRef Java_InputStream_Constructor(JNIEnv* env) - __attribute__ ((unused)); -static ScopedJavaLocalRef Java_InputStream_Constructor(JNIEnv* env) { - /* Must call RegisterNativesImpl() */ - DCHECK(g_InputStream_clazz); - jmethodID method_id = - base::android::MethodID::LazyGet< - base::android::MethodID::TYPE_INSTANCE>( - env, g_InputStream_clazz, - "", - -"(" -")" -"V", - &g_InputStream_Constructor); - - jobject ret = - env->NewObject(g_InputStream_clazz, - method_id); - base::android::CheckException(env); - return ScopedJavaLocalRef(env, ret); -} - -// Step 3: RegisterNatives. - -static bool RegisterNativesImpl(JNIEnv* env) { - - g_InputStream_clazz = reinterpret_cast(env->NewGlobalRef( - base::android::GetClass(env, kInputStreamClassPath).obj())); - return true; -} -} // namespace JNI_InputStream - -#endif // java_io_InputStream_JNI -""" - self.assertTextEquals(golden_content, jni_from_javap.GetContent()) - - def testREForNatives(self): - # We should not match "native SyncSetupFlow" inside the comment. - test_data = """ - /** - * Invoked when the setup process is complete so we can disconnect from the - * native-side SyncSetupFlowHandler. - */ - public void destroy() { - Log.v(TAG, "Destroying native SyncSetupFlow"); - if (mNativeSyncSetupFlow != 0) { - nativeSyncSetupEnded(mNativeSyncSetupFlow); - mNativeSyncSetupFlow = 0; - } - } - private native void nativeSyncSetupEnded( - int nativeAndroidSyncSetupFlowHandler); - """ - jni_from_java = jni_generator.JNIFromJavaSource(test_data, 'foo/bar') - - def testRaisesOnNonJNIMethod(self): - test_data = """ - class MyInnerClass { - private int Foo(int p0) { - } - } - """ - self.assertRaises(SyntaxError, - jni_generator.JNIFromJavaSource, - test_data, 'foo/bar') - - def testJniSelfDocumentingExample(self): - script_dir = os.path.dirname(sys.argv[0]) - content = file(os.path.join(script_dir, - 'java/src/org/chromium/example/jni_generator/SampleForTests.java') - ).read() - golden_content = file(os.path.join(script_dir, - 'golden_sample_for_tests_jni.h')).read() - jni_from_java = jni_generator.JNIFromJavaSource( - content, 'org/chromium/example/jni_generator/SampleForTests') - self.assertTextEquals(golden_content, jni_from_java.GetContent()) - - def testNoWrappingPreprocessorLines(self): - test_data = """ - package com.google.lookhowextremelylongiam.snarf.icankeepthisupallday; - - class ReallyLongClassNamesAreAllTheRage { - private static native int nativeTest(); - } - """ - jni_from_java = jni_generator.JNIFromJavaSource( - test_data, ('com/google/lookhowextremelylongiam/snarf/' - 'icankeepthisupallday/ReallyLongClassNamesAreAllTheRage')) - jni_lines = jni_from_java.GetContent().split('\n') - line = filter(lambda line: line.lstrip().startswith('#ifndef'), - jni_lines)[0] - self.assertTrue(len(line) > 80, - ('Expected #ifndef line to be > 80 chars: ', line)) - - def testJarJarRemapping(self): - test_data = """ - package org.chromium.example.jni_generator; - - import org.chromium.example2.Test; - - class Example { - private static native void nativeTest(Test t); - } - """ - jni_generator.JniParams.SetJarJarMappings( - """rule org.chromium.example.** com.test.@1 - rule org.chromium.example2.** org.test2.@0""") - jni_from_java = jni_generator.JNIFromJavaSource( - test_data, 'org/chromium/example/jni_generator/Example') - jni_generator.JniParams.SetJarJarMappings('') - golden_content = """\ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -// This file is autogenerated by -// base/android/jni_generator/jni_generator_tests.py -// For -// org/chromium/example/jni_generator/Example - -#ifndef org_chromium_example_jni_generator_Example_JNI -#define org_chromium_example_jni_generator_Example_JNI - -#include - -#include "base/android/jni_android.h" -#include "base/android/scoped_java_ref.h" -#include "base/basictypes.h" -#include "base/logging.h" - -using base::android::ScopedJavaLocalRef; - -// Step 1: forward declarations. -namespace { -const char kExampleClassPath[] = "com/test/jni_generator/Example"; -// Leaking this jclass as we cannot use LazyInstance from some threads. -jclass g_Example_clazz = NULL; -} // namespace - -static void Test(JNIEnv* env, jclass clazz, - jobject t); - -// Step 2: method stubs. - -// Step 3: RegisterNatives. - -static bool RegisterNativesImpl(JNIEnv* env) { - - g_Example_clazz = reinterpret_cast(env->NewGlobalRef( - base::android::GetClass(env, kExampleClassPath).obj())); - static const JNINativeMethod kMethodsExample[] = { - { "nativeTest", -"(" -"Lorg/test2/org/chromium/example2/Test;" -")" -"V", reinterpret_cast(Test) }, - }; - const int kMethodsExampleSize = arraysize(kMethodsExample); - - if (env->RegisterNatives(g_Example_clazz, - kMethodsExample, - kMethodsExampleSize) < 0) { - LOG(ERROR) << "RegisterNatives failed in " << __FILE__; - return false; - } - - return true; -} - -#endif // org_chromium_example_jni_generator_Example_JNI -""" - self.assertTextEquals(golden_content, jni_from_java.GetContent()) - - def testImports(self): - import_header = """ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -package org.chromium.content.app; - -import android.app.Service; -import android.content.Context; -import android.content.Intent; -import android.graphics.SurfaceTexture; -import android.os.Bundle; -import android.os.IBinder; -import android.os.ParcelFileDescriptor; -import android.os.Process; -import android.os.RemoteException; -import android.util.Log; -import android.view.Surface; - -import java.util.ArrayList; - -import org.chromium.base.CalledByNative; -import org.chromium.base.JNINamespace; -import org.chromium.content.app.ContentMain; -import org.chromium.content.browser.SandboxedProcessConnection; -import org.chromium.content.common.ISandboxedProcessCallback; -import org.chromium.content.common.ISandboxedProcessService; -import org.chromium.content.common.WillNotRaise.AnException; -import org.chromium.content.common.WillRaise.AnException; - -import static org.chromium.Bar.Zoo; - -class Foo { - public static class BookmarkNode implements Parcelable { - } - public interface PasswordListObserver { - } -} - """ - jni_generator.JniParams.SetFullyQualifiedClass( - 'org/chromium/content/app/Foo') - jni_generator.JniParams.ExtractImportsAndInnerClasses(import_header) - self.assertTrue('Lorg/chromium/content/common/ISandboxedProcessService' in - jni_generator.JniParams._imports) - self.assertTrue('Lorg/chromium/Bar/Zoo' in - jni_generator.JniParams._imports) - self.assertTrue('Lorg/chromium/content/app/Foo$BookmarkNode' in - jni_generator.JniParams._inner_classes) - self.assertTrue('Lorg/chromium/content/app/Foo$PasswordListObserver' in - jni_generator.JniParams._inner_classes) - self.assertEquals('Lorg/chromium/content/app/ContentMain$Inner;', - jni_generator.JniParams.JavaToJni('ContentMain.Inner')) - self.assertRaises(SyntaxError, - jni_generator.JniParams.JavaToJni, - 'AnException') - - def testJniParamsJavaToJni(self): - self.assertTextEquals('I', JniParams.JavaToJni('int')) - self.assertTextEquals('[B', JniParams.JavaToJni('byte[]')) - self.assertTextEquals( - '[Ljava/nio/ByteBuffer;', JniParams.JavaToJni('java/nio/ByteBuffer[]')) - - -if __name__ == '__main__': - unittest.main() diff --git a/base/android/jni_generator/sample_for_tests.cc b/base/android/jni_generator/sample_for_tests.cc deleted file mode 100644 index 30b9940635..0000000000 --- a/base/android/jni_generator/sample_for_tests.cc +++ /dev/null @@ -1,106 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "base/android/jni_generator/sample_for_tests.h" - -#include "base/android/jni_android.h" -#include "base/android/jni_string.h" -#include "base/android/scoped_java_ref.h" -#include "jni/SampleForTests_jni.h" - - -using base::android::AttachCurrentThread; -using base::android::ScopedJavaLocalRef; - -namespace base { -namespace android { - -jdouble CPPClass::InnerClass::MethodOtherP0(JNIEnv* env, jobject obj) { - return 0.0; -} - -CPPClass::CPPClass() { -} - -CPPClass::~CPPClass() { -} - -void CPPClass::Destroy(JNIEnv* env, jobject obj) { - delete this; -} - -jint CPPClass::Method(JNIEnv* env, jobject obj) { - return 0; -} - -void CPPClass::AddStructB(JNIEnv* env, jobject obj, jobject structb) { - long key = Java_InnerStructB_getKey(env, structb); - std::string value = ConvertJavaStringToUTF8( - env, Java_InnerStructB_getValue(env, structb).obj()); - map_[key] = value; -} - -void CPPClass::IterateAndDoSomethingWithStructB(JNIEnv* env, jobject obj) { - // Iterate over the elements and do something with them. - for (std::map::const_iterator it = map_.begin(); - it != map_.end(); ++it) { - long key = it->first; - std::string value = it->second; - } - map_.clear(); -} - -// Static free functions declared and called directly from java. -static jint Init(JNIEnv* env, jobject obj, jstring param) { - return 0; -} - -static jdouble GetDoubleFunction(JNIEnv*, jobject) { - return 0; -} - -static jfloat GetFloatFunction(JNIEnv*, jclass) { - return 0; -} - -static void SetNonPODDatatype(JNIEnv*, jobject, jobject) { -} - -static jobject GetNonPODDatatype(JNIEnv*, jobject) { - return NULL; -} - -static jint InnerFunction(JNIEnv*, jclass) { - return 0; -} - -} // namespace android -} // namespace base - -int main() { - // On a regular application, you'd call AttachCurrentThread(). This sample is - // not yet linking with all the libraries. - JNIEnv* env = /* AttachCurrentThread() */ NULL; - - // This is how you call a java static method from C++. - bool foo = base::android::Java_SampleForTests_staticJavaMethod(env); - - // This is how you call a java method from C++. Note that you must have - // obtained the jobject somehow. - jobject my_java_object = NULL; - int bar = base::android::Java_SampleForTests_javaMethod( - env, my_java_object, 1, 2); - - for (int i = 0; i < 10; ++i) { - // Creates a "struct" that will then be used by the java side. - ScopedJavaLocalRef struct_a = - base::android::Java_InnerStructA_create( - env, 0, 1, - base::android::ConvertUTF8ToJavaString(env, "test").obj()); - base::android::Java_SampleForTests_addStructA( - env, my_java_object, struct_a.obj()); - } - base::android::Java_SampleForTests_iterateAndDoSomething(env, my_java_object); - return 0; -} diff --git a/base/android/jni_generator/sample_for_tests.h b/base/android/jni_generator/sample_for_tests.h deleted file mode 100644 index 278008b2df..0000000000 --- a/base/android/jni_generator/sample_for_tests.h +++ /dev/null @@ -1,46 +0,0 @@ -// Copyright (c) 2013 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include -#include -#include - -#include "base/basictypes.h" - -namespace base { -namespace android { - -// This file is used to: -// - document the best practices and guidelines on JNI usage. -// - ensure sample_for_tests_jni.h compiles and the functions declared in it -// as expected. -// -// All methods are called directly from Java. See more documentation in -// SampleForTests.java. -class CPPClass { - public: - CPPClass(); - ~CPPClass(); - - class InnerClass { - public: - jdouble MethodOtherP0(JNIEnv* env, jobject obj); - }; - - void Destroy(JNIEnv* env, jobject obj); - - jint Method(JNIEnv* env, jobject obj); - - void AddStructB(JNIEnv* env, jobject obj, jobject structb); - - void IterateAndDoSomethingWithStructB(JNIEnv* env, jobject obj); - - private: - std::map map_; - - DISALLOW_COPY_AND_ASSIGN(CPPClass); -}; - -} // namespace android -} // namespace base diff --git a/base/android/jni_helper.cc b/base/android/jni_helper.cc deleted file mode 100644 index fcb610e188..0000000000 --- a/base/android/jni_helper.cc +++ /dev/null @@ -1,67 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "base/android/jni_helper.h" - -#include "base/android/jni_android.h" -#include "base/logging.h" - -using base::android::AttachCurrentThread; - -JavaObjectWeakGlobalRef::JavaObjectWeakGlobalRef() - : obj_(NULL) { -} - -JavaObjectWeakGlobalRef::JavaObjectWeakGlobalRef( - const JavaObjectWeakGlobalRef& orig) - : obj_(NULL) { - Assign(orig); -} - -JavaObjectWeakGlobalRef::JavaObjectWeakGlobalRef(JNIEnv* env, jobject obj) - : obj_(env->NewWeakGlobalRef(obj)) { - DCHECK(obj_); -} - -JavaObjectWeakGlobalRef::~JavaObjectWeakGlobalRef() { - reset(); -} - -void JavaObjectWeakGlobalRef::operator=(const JavaObjectWeakGlobalRef& rhs) { - Assign(rhs); -} - -void JavaObjectWeakGlobalRef::reset() { - if (obj_) { - AttachCurrentThread()->DeleteWeakGlobalRef(obj_); - obj_ = NULL; - } -} - -base::android::ScopedJavaLocalRef - JavaObjectWeakGlobalRef::get(JNIEnv* env) const { - return GetRealObject(env, obj_); -} - -base::android::ScopedJavaLocalRef GetRealObject( - JNIEnv* env, jweak obj) { - jobject real = NULL; - if (obj) { - real = env->NewLocalRef(obj); - if (!real) - DLOG(ERROR) << "The real object has been deleted!"; - } - return base::android::ScopedJavaLocalRef(env, real); -} - -void JavaObjectWeakGlobalRef::Assign(const JavaObjectWeakGlobalRef& other) { - if (&other == this) - return; - - JNIEnv* env = AttachCurrentThread(); - if (obj_) - env->DeleteWeakGlobalRef(obj_); - - obj_ = other.obj_ ? env->NewWeakGlobalRef(other.obj_) : NULL; -} diff --git a/base/android/jni_helper.h b/base/android/jni_helper.h deleted file mode 100644 index 895bf95a9d..0000000000 --- a/base/android/jni_helper.h +++ /dev/null @@ -1,41 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef BASE_ANDROID_JNI_HELPER_H_ -#define BASE_ANDROID_JNI_HELPER_H_ - -#include - -#include "base/base_export.h" -#include "base/android/scoped_java_ref.h" - -// Manages WeakGlobalRef lifecycle. -// This class is not thread-safe w.r.t. get() and reset(). Multiple threads may -// safely use get() concurrently, but if the user calls reset() (or of course, -// calls the destructor) they'll need to provide their own synchronization. -class BASE_EXPORT JavaObjectWeakGlobalRef { - public: - JavaObjectWeakGlobalRef(); - JavaObjectWeakGlobalRef(const JavaObjectWeakGlobalRef& orig); - JavaObjectWeakGlobalRef(JNIEnv* env, jobject obj); - virtual ~JavaObjectWeakGlobalRef(); - - void operator=(const JavaObjectWeakGlobalRef& rhs); - - base::android::ScopedJavaLocalRef get(JNIEnv* env) const; - - void reset(); - - private: - void Assign(const JavaObjectWeakGlobalRef& rhs); - - jweak obj_; -}; - -// Get the real object stored in the weak reference returned as a -// ScopedJavaLocalRef. -BASE_EXPORT base::android::ScopedJavaLocalRef GetRealObject( - JNIEnv* env, jweak obj); - -#endif // BASE_ANDROID_JNI_HELPER_H_ diff --git a/base/android/jni_registrar.cc b/base/android/jni_registrar.cc deleted file mode 100644 index 0f32089d18..0000000000 --- a/base/android/jni_registrar.cc +++ /dev/null @@ -1,30 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "base/android/jni_registrar.h" - -#include "base/debug/trace_event.h" -#include "base/logging.h" -#include "base/android/jni_android.h" - -namespace base { -namespace android { - -bool RegisterNativeMethods(JNIEnv* env, - const RegistrationMethod* method, - size_t count) { - TRACE_EVENT0("startup", "base_android::RegisterNativeMethods") - const RegistrationMethod* end = method + count; - while (method != end) { - if (!method->func(env)) { - DLOG(ERROR) << method->name << " failed registration!"; - return false; - } - method++; - } - return true; -} - -} // namespace android -} // namespace base diff --git a/base/android/jni_registrar.h b/base/android/jni_registrar.h deleted file mode 100644 index 849d07f939..0000000000 --- a/base/android/jni_registrar.h +++ /dev/null @@ -1,27 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef BASE_ANDROID_JNI_REGISTRAR_H_ -#define BASE_ANDROID_JNI_REGISTRAR_H_ - -#include -#include "base/base_export.h" -#include "base/basictypes.h" - -namespace base { -namespace android { - -struct RegistrationMethod; - -// Registers the JNI bindings for the specified |method| definition containing -// |count| elements. Returns whether the registration of the given methods -// succeeded. -BASE_EXPORT bool RegisterNativeMethods(JNIEnv* env, - const RegistrationMethod* method, - size_t count); - -} // namespace android -} // namespace base - -#endif // BASE_ANDROID_JNI_REGISTRAR_H_ diff --git a/base/android/jni_string.cc b/base/android/jni_string.cc deleted file mode 100644 index d25fed822b..0000000000 --- a/base/android/jni_string.cc +++ /dev/null @@ -1,99 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "base/android/jni_string.h" - -#include "base/android/jni_android.h" -#include "base/logging.h" -#include "base/strings/utf_string_conversions.h" - -namespace { - -// Internal version that does not use a scoped local pointer. -jstring ConvertUTF16ToJavaStringImpl(JNIEnv* env, - const base::StringPiece16& str) { - jstring result = env->NewString(str.data(), str.length()); - base::android::CheckException(env); - return result; -} - -} - -namespace base { -namespace android { - -void ConvertJavaStringToUTF8(JNIEnv* env, jstring str, std::string* result) { - if (!str) { - LOG(WARNING) << "ConvertJavaStringToUTF8 called with null string."; - result->clear(); - return; - } - // JNI's GetStringUTFChars() returns strings in Java "modified" UTF8, so - // instead get the String in UTF16 and convert using chromium's conversion - // function that yields plain (non Java-modified) UTF8. - const jchar* chars = env->GetStringChars(str, NULL); - DCHECK(chars); - UTF16ToUTF8(chars, env->GetStringLength(str), result); - env->ReleaseStringChars(str, chars); - CheckException(env); -} - -std::string ConvertJavaStringToUTF8(JNIEnv* env, jstring str) { - std::string result; - ConvertJavaStringToUTF8(env, str, &result); - return result; -} - -std::string ConvertJavaStringToUTF8(const JavaRef& str) { - return ConvertJavaStringToUTF8(AttachCurrentThread(), str.obj()); -} - -ScopedJavaLocalRef ConvertUTF8ToJavaString( - JNIEnv* env, - const base::StringPiece& str) { - // JNI's NewStringUTF expects "modified" UTF8 so instead create the string - // via our own UTF16 conversion utility. - // Further, Dalvik requires the string passed into NewStringUTF() to come from - // a trusted source. We can't guarantee that all UTF8 will be sanitized before - // it gets here, so constructing via UTF16 side-steps this issue. - // (Dalvik stores strings internally as UTF16 anyway, so there shouldn't be - // a significant performance hit by doing it this way). - return ScopedJavaLocalRef(env, ConvertUTF16ToJavaStringImpl( - env, UTF8ToUTF16(str))); -} - -void ConvertJavaStringToUTF16(JNIEnv* env, jstring str, string16* result) { - if (!str) { - LOG(WARNING) << "ConvertJavaStringToUTF16 called with null string."; - result->clear(); - return; - } - const jchar* chars = env->GetStringChars(str, NULL); - DCHECK(chars); - // GetStringChars isn't required to NULL-terminate the strings - // it returns, so the length must be explicitly checked. - result->assign(chars, env->GetStringLength(str)); - env->ReleaseStringChars(str, chars); - CheckException(env); -} - -string16 ConvertJavaStringToUTF16(JNIEnv* env, jstring str) { - string16 result; - ConvertJavaStringToUTF16(env, str, &result); - return result; -} - -string16 ConvertJavaStringToUTF16(const JavaRef& str) { - return ConvertJavaStringToUTF16(AttachCurrentThread(), str.obj()); -} - -ScopedJavaLocalRef ConvertUTF16ToJavaString( - JNIEnv* env, - const base::StringPiece16& str) { - return ScopedJavaLocalRef(env, - ConvertUTF16ToJavaStringImpl(env, str)); -} - -} // namespace android -} // namespace base diff --git a/base/android/jni_string.h b/base/android/jni_string.h deleted file mode 100644 index 89af5b0a89..0000000000 --- a/base/android/jni_string.h +++ /dev/null @@ -1,45 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef BASE_ANDROID_JNI_STRING_H_ -#define BASE_ANDROID_JNI_STRING_H_ - -#include -#include - -#include "base/android/scoped_java_ref.h" -#include "base/base_export.h" -#include "base/strings/string_piece.h" - -namespace base { -namespace android { - -// Convert a Java string to UTF8. Returns a std string. -BASE_EXPORT void ConvertJavaStringToUTF8(JNIEnv* env, - jstring str, - std::string* result); -BASE_EXPORT std::string ConvertJavaStringToUTF8(JNIEnv* env, jstring str); -BASE_EXPORT std::string ConvertJavaStringToUTF8(const JavaRef& str); - -// Convert a std string to Java string. -BASE_EXPORT ScopedJavaLocalRef ConvertUTF8ToJavaString( - JNIEnv* env, - const base::StringPiece& str); - -// Convert a Java string to UTF16. Returns a string16. -BASE_EXPORT void ConvertJavaStringToUTF16(JNIEnv* env, - jstring str, - string16* result); -BASE_EXPORT string16 ConvertJavaStringToUTF16(JNIEnv* env, jstring str); -BASE_EXPORT string16 ConvertJavaStringToUTF16(const JavaRef& str); - -// Convert a string16 to a Java string. -BASE_EXPORT ScopedJavaLocalRef ConvertUTF16ToJavaString( - JNIEnv* env, - const base::StringPiece16& str); - -} // namespace android -} // namespace base - -#endif // BASE_ANDROID_JNI_STRING_H_ diff --git a/base/android/jni_string_unittest.cc b/base/android/jni_string_unittest.cc deleted file mode 100644 index abd0683170..0000000000 --- a/base/android/jni_string_unittest.cc +++ /dev/null @@ -1,32 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "base/android/jni_string.h" - -#include "base/android/jni_android.h" -#include "base/android/scoped_java_ref.h" -#include "base/strings/utf_string_conversions.h" -#include "testing/gtest/include/gtest/gtest.h" - -namespace base { -namespace android { - -TEST(JniString, BasicConversionsUTF8) { - const std::string kSimpleString = "SimpleTest8"; - JNIEnv* env = AttachCurrentThread(); - std::string result = - ConvertJavaStringToUTF8(ConvertUTF8ToJavaString(env, kSimpleString)); - EXPECT_EQ(kSimpleString, result); -} - -TEST(JniString, BasicConversionsUTF16) { - const string16 kSimpleString = UTF8ToUTF16("SimpleTest16"); - JNIEnv* env = AttachCurrentThread(); - string16 result = - ConvertJavaStringToUTF16(ConvertUTF16ToJavaString(env, kSimpleString)); - EXPECT_EQ(kSimpleString, result); -} - -} // namespace android -} // namespace base diff --git a/base/android/memory_pressure_listener_android.cc b/base/android/memory_pressure_listener_android.cc deleted file mode 100644 index 80c07bcf9c..0000000000 --- a/base/android/memory_pressure_listener_android.cc +++ /dev/null @@ -1,31 +0,0 @@ -// Copyright 2013 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "base/android/memory_pressure_listener_android.h" - -#include "base/memory/memory_pressure_listener.h" -#include "jni/MemoryPressureListener_jni.h" - -// Defined and called by JNI. -static void OnMemoryPressure( - JNIEnv* env, jclass clazz, jint memory_pressure_level) { - base::MemoryPressureListener::NotifyMemoryPressure( - static_cast( - memory_pressure_level)); -} - -namespace base { -namespace android { - -bool MemoryPressureListenerAndroid::Register(JNIEnv* env) { - return RegisterNativesImpl(env); -} - -void MemoryPressureListenerAndroid::RegisterSystemCallback(JNIEnv* env) { - Java_MemoryPressureListener_registerSystemCallback( - env, GetApplicationContext()); -} - -} // namespace android -} // namespace base diff --git a/base/android/memory_pressure_listener_android.h b/base/android/memory_pressure_listener_android.h deleted file mode 100644 index eed8dbb575..0000000000 --- a/base/android/memory_pressure_listener_android.h +++ /dev/null @@ -1,30 +0,0 @@ -// Copyright 2013 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef BASE_ANDROID_MEMORY_PRESSURE_LISTENER_ANDROID_H_ -#define BASE_ANDROID_MEMORY_PRESSURE_LISTENER_ANDROID_H_ - -#include "base/android/jni_android.h" - -namespace base { -namespace android { - -// Implements the C++ counter part of MemoryPressureListener.java -class BASE_EXPORT MemoryPressureListenerAndroid { - public: - static bool Register(JNIEnv* env); - - static void RegisterSystemCallback(JNIEnv* env); - - // Called by JNI. - static void OnMemoryPressure(int memory_pressure_type); - - private: - DISALLOW_COPY_AND_ASSIGN(MemoryPressureListenerAndroid); -}; - -} // namespace android -} // namespace base - -#endif // BASE_ANDROID_MEMORY_PRESSURE_LISTENER_ANDROID_H_ diff --git a/base/android/path_service_android.cc b/base/android/path_service_android.cc deleted file mode 100644 index 18ca70c8ab..0000000000 --- a/base/android/path_service_android.cc +++ /dev/null @@ -1,26 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "base/android/path_service_android.h" - -#include "base/android/jni_android.h" -#include "base/android/jni_string.h" -#include "base/files/file_path.h" -#include "base/path_service.h" -#include "jni/PathService_jni.h" - -namespace base { -namespace android { - -void Override(JNIEnv* env, jclass clazz, jint what, jstring path) { - FilePath file_path(ConvertJavaStringToUTF8(env, path)); - PathService::Override(what, file_path); -} - -bool RegisterPathService(JNIEnv* env) { - return RegisterNativesImpl(env); -} - -} // namespace android -} // namespace base diff --git a/base/android/path_service_android.h b/base/android/path_service_android.h deleted file mode 100644 index 26040f97be..0000000000 --- a/base/android/path_service_android.h +++ /dev/null @@ -1,18 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef BASE_ANDROID_PATH_SERVICE_ANDROID_H_ -#define BASE_ANDROID_PATH_SERVICE_ANDROID_H_ - -#include - -namespace base { -namespace android { - -bool RegisterPathService(JNIEnv* env); - -} // namespace android -} // namespace base - -#endif // BASE_ANDROID_PATH_SERVICE_ANDROID_H_ diff --git a/base/android/path_utils.cc b/base/android/path_utils.cc deleted file mode 100644 index 5737227f38..0000000000 --- a/base/android/path_utils.cc +++ /dev/null @@ -1,67 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "base/android/path_utils.h" - -#include "base/android/jni_android.h" -#include "base/android/jni_string.h" -#include "base/android/scoped_java_ref.h" -#include "base/files/file_path.h" - -#include "jni/PathUtils_jni.h" - -namespace base { -namespace android { - -bool GetDataDirectory(FilePath* result) { - JNIEnv* env = AttachCurrentThread(); - ScopedJavaLocalRef path = - Java_PathUtils_getDataDirectory(env, GetApplicationContext()); - FilePath data_path(ConvertJavaStringToUTF8(path)); - *result = data_path; - return true; -} - -bool GetCacheDirectory(FilePath* result) { - JNIEnv* env = AttachCurrentThread(); - ScopedJavaLocalRef path = - Java_PathUtils_getCacheDirectory(env, GetApplicationContext()); - FilePath cache_path(ConvertJavaStringToUTF8(path)); - *result = cache_path; - return true; -} - -bool GetDownloadsDirectory(FilePath* result) { - JNIEnv* env = AttachCurrentThread(); - ScopedJavaLocalRef path = - Java_PathUtils_getDownloadsDirectory(env, GetApplicationContext()); - FilePath downloads_path(ConvertJavaStringToUTF8(path)); - *result = downloads_path; - return true; -} - -bool GetNativeLibraryDirectory(FilePath* result) { - JNIEnv* env = AttachCurrentThread(); - ScopedJavaLocalRef path = - Java_PathUtils_getNativeLibraryDirectory(env, GetApplicationContext()); - FilePath library_path(ConvertJavaStringToUTF8(path)); - *result = library_path; - return true; -} - -bool GetExternalStorageDirectory(FilePath* result) { - JNIEnv* env = AttachCurrentThread(); - ScopedJavaLocalRef path = - Java_PathUtils_getExternalStorageDirectory(env); - FilePath storage_path(ConvertJavaStringToUTF8(path)); - *result = storage_path; - return true; -} - -bool RegisterPathUtils(JNIEnv* env) { - return RegisterNativesImpl(env); -} - -} // namespace android -} // namespace base diff --git a/base/android/path_utils.h b/base/android/path_utils.h deleted file mode 100644 index 60f8a79b1e..0000000000 --- a/base/android/path_utils.h +++ /dev/null @@ -1,48 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef BASE_ANDROID_PATH_UTILS_H_ -#define BASE_ANDROID_PATH_UTILS_H_ - -#include - -#include "base/base_export.h" - -namespace base { - -class FilePath; - -namespace android { - -// Retrieves the absolute path to the data directory of the current -// application. The result is placed in the FilePath pointed to by 'result'. -// This method is dedicated for base_paths_android.c, Using -// PathService::Get(base::DIR_ANDROID_APP_DATA, ...) gets the data dir. -BASE_EXPORT bool GetDataDirectory(FilePath* result); - -// Retrieves the absolute path to the cache directory. The result is placed in -// the FilePath pointed to by 'result'. This method is dedicated for -// base_paths_android.c, Using PathService::Get(base::DIR_CACHE, ...) gets the -// cache dir. -BASE_EXPORT bool GetCacheDirectory(FilePath* result); - -// Retrieves the path to the public downloads directory. The result is placed -// in the FilePath pointed to by 'result'. -BASE_EXPORT bool GetDownloadsDirectory(FilePath* result); - -// Retrieves the path to the native JNI libraries via -// ApplicationInfo.nativeLibraryDir on the Java side. The result is placed in -// the FilePath pointed to by 'result'. -BASE_EXPORT bool GetNativeLibraryDirectory(FilePath* result); - -// Retrieves the absolute path to the external storage directory. The result -// is placed in the FilePath pointed to by 'result'. -BASE_EXPORT bool GetExternalStorageDirectory(FilePath* result); - -bool RegisterPathUtils(JNIEnv* env); - -} // namespace android -} // namespace base - -#endif // BASE_ANDROID_PATH_UTILS_H_ diff --git a/base/android/path_utils_unittest.cc b/base/android/path_utils_unittest.cc deleted file mode 100644 index c4c12fea13..0000000000 --- a/base/android/path_utils_unittest.cc +++ /dev/null @@ -1,46 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "base/android/path_utils.h" -#include "base/file_util.h" -#include "base/files/file_path.h" - -#include "testing/gtest/include/gtest/gtest.h" - -namespace base { -namespace android { - -typedef testing::Test PathUtilsTest; - -TEST_F(PathUtilsTest, TestGetDataDirectory) { - // The string comes from the Java side and depends on the APK - // we are running in. Assumes that we are packaged in - // org.chromium.native_test - FilePath path; - GetDataDirectory(&path); - EXPECT_STREQ("/data/data/org.chromium.native_test/app_chrome", - path.value().c_str()); -} - -TEST_F(PathUtilsTest, TestGetCacheDirectory) { - // The string comes from the Java side and depends on the APK - // we are running in. Assumes that we are packaged in - // org.chromium.native_test - FilePath path; - GetCacheDirectory(&path); - EXPECT_STREQ("/data/data/org.chromium.native_test/cache", - path.value().c_str()); -} - -TEST_F(PathUtilsTest, TestGetNativeLibraryDirectory) { - // The string comes from the Java side and depends on the APK - // we are running in. Assumes that the directory contains - // the base tests shared object. - FilePath path; - GetNativeLibraryDirectory(&path); - EXPECT_TRUE(base::PathExists(path.Append(("libbase_unittests.so")))); -} - -} // namespace android -} // namespace base diff --git a/base/android/scoped_java_ref.cc b/base/android/scoped_java_ref.cc deleted file mode 100644 index 21b466e958..0000000000 --- a/base/android/scoped_java_ref.cc +++ /dev/null @@ -1,73 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "base/android/scoped_java_ref.h" - -#include "base/android/jni_android.h" -#include "base/logging.h" - -namespace base { -namespace android { - -JavaRef::JavaRef() : obj_(NULL) {} - -JavaRef::JavaRef(JNIEnv* env, jobject obj) : obj_(obj) { - if (obj) { - DCHECK(env && env->GetObjectRefType(obj) == JNILocalRefType); - } -} - -JavaRef::~JavaRef() { -} - -JNIEnv* JavaRef::SetNewLocalRef(JNIEnv* env, jobject obj) { - if (!env) { - env = AttachCurrentThread(); - } else { - DCHECK_EQ(env, AttachCurrentThread()); // Is |env| on correct thread. - } - if (obj) - obj = env->NewLocalRef(obj); - if (obj_) - env->DeleteLocalRef(obj_); - obj_ = obj; - return env; -} - -void JavaRef::SetNewGlobalRef(JNIEnv* env, jobject obj) { - if (!env) { - env = AttachCurrentThread(); - } else { - DCHECK_EQ(env, AttachCurrentThread()); // Is |env| on correct thread. - } - if (obj) - obj = env->NewGlobalRef(obj); - if (obj_) - env->DeleteGlobalRef(obj_); - obj_ = obj; -} - -void JavaRef::ResetLocalRef(JNIEnv* env) { - if (obj_) { - DCHECK_EQ(env, AttachCurrentThread()); // Is |env| on correct thread. - env->DeleteLocalRef(obj_); - obj_ = NULL; - } -} - -void JavaRef::ResetGlobalRef() { - if (obj_) { - AttachCurrentThread()->DeleteGlobalRef(obj_); - obj_ = NULL; - } -} - -jobject JavaRef::ReleaseInternal() { - jobject obj = obj_; - obj_ = NULL; - return obj; -} - -} // namespace android -} // namespace base diff --git a/base/android/scoped_java_ref.h b/base/android/scoped_java_ref.h deleted file mode 100644 index a5d71e2d23..0000000000 --- a/base/android/scoped_java_ref.h +++ /dev/null @@ -1,198 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef BASE_ANDROID_SCOPED_JAVA_REF_H_ -#define BASE_ANDROID_SCOPED_JAVA_REF_H_ - -#include -#include - -#include "base/base_export.h" -#include "base/basictypes.h" - -namespace base { -namespace android { - -// Forward declare the generic java reference template class. -template class JavaRef; - -// Template specialization of JavaRef, which acts as the base class for all -// other JavaRef<> template types. This allows you to e.g. pass -// ScopedJavaLocalRef into a function taking const JavaRef& -template<> -class BASE_EXPORT JavaRef { - public: - jobject obj() const { return obj_; } - - bool is_null() const { return obj_ == NULL; } - - protected: - // Initializes a NULL reference. - JavaRef(); - - // Takes ownership of the |obj| reference passed; requires it to be a local - // reference type. - JavaRef(JNIEnv* env, jobject obj); - - ~JavaRef(); - - // The following are implementation detail convenience methods, for - // use by the sub-classes. - JNIEnv* SetNewLocalRef(JNIEnv* env, jobject obj); - void SetNewGlobalRef(JNIEnv* env, jobject obj); - void ResetLocalRef(JNIEnv* env); - void ResetGlobalRef(); - jobject ReleaseInternal(); - - private: - jobject obj_; - - DISALLOW_COPY_AND_ASSIGN(JavaRef); -}; - -// Generic base class for ScopedJavaLocalRef and ScopedJavaGlobalRef. Useful -// for allowing functions to accept a reference without having to mandate -// whether it is a local or global type. -template -class JavaRef : public JavaRef { - public: - T obj() const { return static_cast(JavaRef::obj()); } - - protected: - JavaRef() {} - ~JavaRef() {} - - JavaRef(JNIEnv* env, T obj) : JavaRef(env, obj) {} - - private: - DISALLOW_COPY_AND_ASSIGN(JavaRef); -}; - -// Holds a local reference to a Java object. The local reference is scoped -// to the lifetime of this object. -// Instances of this class may hold onto any JNIEnv passed into it until -// destroyed. Therefore, since a JNIEnv is only suitable for use on a single -// thread, objects of this class must be created, used, and destroyed, on a -// single thread. -// Therefore, this class should only be used as a stack-based object and from a -// single thread. If you wish to have the reference outlive the current -// callstack (e.g. as a class member) or you wish to pass it across threads, -// use a ScopedJavaGlobalRef instead. -template -class ScopedJavaLocalRef : public JavaRef { - public: - ScopedJavaLocalRef() : env_(NULL) {} - - // Non-explicit copy constructor, to allow ScopedJavaLocalRef to be returned - // by value as this is the normal usage pattern. - ScopedJavaLocalRef(const ScopedJavaLocalRef& other) - : env_(other.env_) { - this->SetNewLocalRef(env_, other.obj()); - } - - template - explicit ScopedJavaLocalRef(const U& other) - : env_(NULL) { - this->Reset(other); - } - - // Assumes that |obj| is a local reference to a Java object and takes - // ownership of this local reference. - ScopedJavaLocalRef(JNIEnv* env, T obj) : JavaRef(env, obj), env_(env) {} - - ~ScopedJavaLocalRef() { - this->Reset(); - } - - // Overloaded assignment operator defined for consistency with the implicit - // copy constructor. - void operator=(const ScopedJavaLocalRef& other) { - this->Reset(other); - } - - void Reset() { - this->ResetLocalRef(env_); - } - - template - void Reset(const ScopedJavaLocalRef& other) { - // We can copy over env_ here as |other| instance must be from the same - // thread as |this| local ref. (See class comment for multi-threading - // limitations, and alternatives). - this->Reset(other.env_, other.obj()); - } - - template - void Reset(const U& other) { - // If |env_| was not yet set (is still NULL) it will be attached to the - // current thread in SetNewLocalRef(). - this->Reset(env_, other.obj()); - } - - template - void Reset(JNIEnv* env, U obj) { - implicit_cast(obj); // Ensure U is assignable to T - env_ = this->SetNewLocalRef(env, obj); - } - - // Releases the local reference to the caller. The caller *must* delete the - // local reference when it is done with it. - T Release() { - return static_cast(this->ReleaseInternal()); - } - - private: - // This class is only good for use on the thread it was created on so - // it's safe to cache the non-threadsafe JNIEnv* inside this object. - JNIEnv* env_; -}; - -// Holds a global reference to a Java object. The global reference is scoped -// to the lifetime of this object. This class does not hold onto any JNIEnv* -// passed to it, hence it is safe to use across threads (within the constraints -// imposed by the underlying Java object that it references). -template -class ScopedJavaGlobalRef : public JavaRef { - public: - ScopedJavaGlobalRef() {} - - explicit ScopedJavaGlobalRef(const ScopedJavaGlobalRef& other) { - this->Reset(other); - } - - template - explicit ScopedJavaGlobalRef(const U& other) { - this->Reset(other); - } - - ~ScopedJavaGlobalRef() { - this->Reset(); - } - - void Reset() { - this->ResetGlobalRef(); - } - - template - void Reset(const U& other) { - this->Reset(NULL, other.obj()); - } - - template - void Reset(JNIEnv* env, U obj) { - implicit_cast(obj); // Ensure U is assignable to T - this->SetNewGlobalRef(env, obj); - } - - // Releases the global reference to the caller. The caller *must* delete the - // global reference when it is done with it. - T Release() { - return static_cast(this->ReleaseInternal()); - } -}; - -} // namespace android -} // namespace base - -#endif // BASE_ANDROID_SCOPED_JAVA_REF_H_ diff --git a/base/android/scoped_java_ref_unittest.cc b/base/android/scoped_java_ref_unittest.cc deleted file mode 100644 index 36f253c4e9..0000000000 --- a/base/android/scoped_java_ref_unittest.cc +++ /dev/null @@ -1,122 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "base/android/scoped_java_ref.h" - -#include "base/android/jni_android.h" -#include "base/android/jni_string.h" -#include "testing/gtest/include/gtest/gtest.h" - -namespace base { -namespace android { - -namespace { -int g_local_refs = 0; -int g_global_refs = 0; - -const JNINativeInterface* g_previous_functions; - -jobject NewGlobalRef(JNIEnv* env, jobject obj) { - ++g_global_refs; - return g_previous_functions->NewGlobalRef(env, obj); -} - -void DeleteGlobalRef(JNIEnv* env, jobject obj) { - --g_global_refs; - return g_previous_functions->DeleteGlobalRef(env, obj); -} - -jobject NewLocalRef(JNIEnv* env, jobject obj) { - ++g_local_refs; - return g_previous_functions->NewLocalRef(env, obj); -} - -void DeleteLocalRef(JNIEnv* env, jobject obj) { - --g_local_refs; - return g_previous_functions->DeleteLocalRef(env, obj); -} -} // namespace - -class ScopedJavaRefTest : public testing::Test { - protected: - virtual void SetUp() { - g_local_refs = 0; - g_global_refs = 0; - JNIEnv* env = AttachCurrentThread(); - g_previous_functions = env->functions; - hooked_functions = *g_previous_functions; - env->functions = &hooked_functions; - // We inject our own functions in JNINativeInterface so we can keep track - // of the reference counting ourselves. - hooked_functions.NewGlobalRef = &NewGlobalRef; - hooked_functions.DeleteGlobalRef = &DeleteGlobalRef; - hooked_functions.NewLocalRef = &NewLocalRef; - hooked_functions.DeleteLocalRef = &DeleteLocalRef; - } - - virtual void TearDown() { - JNIEnv* env = AttachCurrentThread(); - env->functions = g_previous_functions; - } - // From JellyBean release, the instance of this struct provided in JNIEnv is - // read-only, so we deep copy it to allow individual functions to be hooked. - JNINativeInterface hooked_functions; -}; - -// The main purpose of this is testing the various conversions compile. -TEST_F(ScopedJavaRefTest, Conversions) { - JNIEnv* env = AttachCurrentThread(); - ScopedJavaLocalRef str = ConvertUTF8ToJavaString(env, "string"); - ScopedJavaGlobalRef global(str); - { - ScopedJavaGlobalRef global_obj(str); - ScopedJavaLocalRef local_obj(global); - const JavaRef& obj_ref1(str); - const JavaRef& obj_ref2(global); - EXPECT_TRUE(env->IsSameObject(obj_ref1.obj(), obj_ref2.obj())); - EXPECT_TRUE(env->IsSameObject(global_obj.obj(), obj_ref2.obj())); - } - global.Reset(str); - const JavaRef& str_ref = str; - EXPECT_EQ("string", ConvertJavaStringToUTF8(str_ref)); - str.Reset(); -} - -TEST_F(ScopedJavaRefTest, RefCounts) { - JNIEnv* env = AttachCurrentThread(); - ScopedJavaLocalRef str; - // The ConvertJavaStringToUTF8 below creates a new string that would normally - // return a local ref. We simulate that by starting the g_local_refs count at - // 1. - g_local_refs = 1; - str.Reset(ConvertUTF8ToJavaString(env, "string")); - EXPECT_EQ(1, g_local_refs); - EXPECT_EQ(0, g_global_refs); - { - ScopedJavaGlobalRef global_str(str); - ScopedJavaGlobalRef global_obj(global_str); - EXPECT_EQ(1, g_local_refs); - EXPECT_EQ(2, g_global_refs); - - ScopedJavaLocalRef str2(env, str.Release()); - EXPECT_EQ(1, g_local_refs); - { - ScopedJavaLocalRef str3(str2); - EXPECT_EQ(2, g_local_refs); - } - EXPECT_EQ(1, g_local_refs); - str2.Reset(); - EXPECT_EQ(0, g_local_refs); - global_str.Reset(); - EXPECT_EQ(1, g_global_refs); - ScopedJavaGlobalRef global_obj2(global_obj); - EXPECT_EQ(2, g_global_refs); - } - - EXPECT_EQ(0, g_local_refs); - EXPECT_EQ(0, g_global_refs); -} - -} // namespace android -} // namespace base diff --git a/base/android/sys_utils.cc b/base/android/sys_utils.cc deleted file mode 100644 index c23125390d..0000000000 --- a/base/android/sys_utils.cc +++ /dev/null @@ -1,31 +0,0 @@ -// Copyright 2013 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "base/android/sys_utils.h" - -#include "base/sys_info.h" -#include "jni/SysUtils_jni.h" - -const int64 kLowEndMemoryThreshold = 1024 * 1024 * 512; // 512 mb. - -// Defined and called by JNI -static jboolean IsLowEndDevice(JNIEnv* env, jclass clazz) { - return base::android::SysUtils::IsLowEndDevice(); -} - -namespace base { -namespace android { - -bool SysUtils::Register(JNIEnv* env) { - return RegisterNativesImpl(env); -} - -bool SysUtils::IsLowEndDevice() { - return SysInfo::AmountOfPhysicalMemory() <= kLowEndMemoryThreshold; -} - -SysUtils::SysUtils() { } - -} // namespace android -} // namespace base diff --git a/base/android/sys_utils.h b/base/android/sys_utils.h deleted file mode 100644 index 78122ff572..0000000000 --- a/base/android/sys_utils.h +++ /dev/null @@ -1,26 +0,0 @@ -// Copyright 2013 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef BASE_ANDROID_SYS_UTILS_H_ -#define BASE_ANDROID_SYS_UTILS_H_ - -#include "base/android/jni_android.h" - -namespace base { -namespace android { - -class BASE_EXPORT SysUtils { - public: - static bool Register(JNIEnv* env); - - static bool IsLowEndDevice(); - - private: - SysUtils(); -}; - -} // namespace android -} // namespace base - -#endif // BASE_ANDROID_SYS_UTILS_H_ diff --git a/base/android/thread_utils.h b/base/android/thread_utils.h deleted file mode 100644 index cbe65f0813..0000000000 --- a/base/android/thread_utils.h +++ /dev/null @@ -1,16 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef BASE_ANDROID_THREAD_UTILS_H_ -#define BASE_ANDROID_THREAD_UTILS_H_ - -#include "base/android/jni_android.h" - -namespace base { - -bool RegisterThreadUtils(JNIEnv* env); - -} // namespace base - -#endif // BASE_ANDROID_THREAD_UTILS_H_ diff --git a/base/at_exit.cc b/base/at_exit.cc deleted file mode 100644 index 0fba355698..0000000000 --- a/base/at_exit.cc +++ /dev/null @@ -1,82 +0,0 @@ -// Copyright (c) 2011 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "base/at_exit.h" - -#include -#include - -#include "base/bind.h" -#include "base/callback.h" -#include "base/logging.h" - -namespace base { - -// Keep a stack of registered AtExitManagers. We always operate on the most -// recent, and we should never have more than one outside of testing (for a -// statically linked version of this library). Testing may use the shadow -// version of the constructor, and if we are building a dynamic library we may -// end up with multiple AtExitManagers on the same process. We don't protect -// this for thread-safe access, since it will only be modified in testing. -static AtExitManager* g_top_manager = NULL; - -AtExitManager::AtExitManager() : next_manager_(g_top_manager) { -// If multiple modules instantiate AtExitManagers they'll end up living in this -// module... they have to coexist. -#if !defined(COMPONENT_BUILD) - DCHECK(!g_top_manager); -#endif - g_top_manager = this; -} - -AtExitManager::~AtExitManager() { - if (!g_top_manager) { - NOTREACHED() << "Tried to ~AtExitManager without an AtExitManager"; - return; - } - DCHECK_EQ(this, g_top_manager); - - ProcessCallbacksNow(); - g_top_manager = next_manager_; -} - -// static -void AtExitManager::RegisterCallback(AtExitCallbackType func, void* param) { - DCHECK(func); - RegisterTask(base::Bind(func, param)); -} - -// static -void AtExitManager::RegisterTask(base::Closure task) { - if (!g_top_manager) { - NOTREACHED() << "Tried to RegisterCallback without an AtExitManager"; - return; - } - - AutoLock lock(g_top_manager->lock_); - g_top_manager->stack_.push(task); -} - -// static -void AtExitManager::ProcessCallbacksNow() { - if (!g_top_manager) { - NOTREACHED() << "Tried to ProcessCallbacksNow without an AtExitManager"; - return; - } - - AutoLock lock(g_top_manager->lock_); - - while (!g_top_manager->stack_.empty()) { - base::Closure task = g_top_manager->stack_.top(); - task.Run(); - g_top_manager->stack_.pop(); - } -} - -AtExitManager::AtExitManager(bool shadow) : next_manager_(g_top_manager) { - DCHECK(shadow || !g_top_manager); - g_top_manager = this; -} - -} // namespace base diff --git a/base/at_exit.h b/base/at_exit.h deleted file mode 100644 index 6fe7361a85..0000000000 --- a/base/at_exit.h +++ /dev/null @@ -1,76 +0,0 @@ -// Copyright (c) 2011 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef BASE_AT_EXIT_H_ -#define BASE_AT_EXIT_H_ - -#include - -#include "base/base_export.h" -#include "base/basictypes.h" -#include "base/callback.h" -#include "base/synchronization/lock.h" - -namespace base { - -// This class provides a facility similar to the CRT atexit(), except that -// we control when the callbacks are executed. Under Windows for a DLL they -// happen at a really bad time and under the loader lock. This facility is -// mostly used by base::Singleton. -// -// The usage is simple. Early in the main() or WinMain() scope create an -// AtExitManager object on the stack: -// int main(...) { -// base::AtExitManager exit_manager; -// -// } -// When the exit_manager object goes out of scope, all the registered -// callbacks and singleton destructors will be called. - -class BASE_EXPORT AtExitManager { - public: - typedef void (*AtExitCallbackType)(void*); - - AtExitManager(); - - // The dtor calls all the registered callbacks. Do not try to register more - // callbacks after this point. - ~AtExitManager(); - - // Registers the specified function to be called at exit. The prototype of - // the callback function is void func(void*). - static void RegisterCallback(AtExitCallbackType func, void* param); - - // Registers the specified task to be called at exit. - static void RegisterTask(base::Closure task); - - // Calls the functions registered with RegisterCallback in LIFO order. It - // is possible to register new callbacks after calling this function. - static void ProcessCallbacksNow(); - - protected: - // This constructor will allow this instance of AtExitManager to be created - // even if one already exists. This should only be used for testing! - // AtExitManagers are kept on a global stack, and it will be removed during - // destruction. This allows you to shadow another AtExitManager. - explicit AtExitManager(bool shadow); - - private: - base::Lock lock_; - std::stack stack_; - AtExitManager* next_manager_; // Stack of managers to allow shadowing. - - DISALLOW_COPY_AND_ASSIGN(AtExitManager); -}; - -#if defined(UNIT_TEST) -class ShadowingAtExitManager : public AtExitManager { - public: - ShadowingAtExitManager() : AtExitManager(true) {} -}; -#endif // defined(UNIT_TEST) - -} // namespace base - -#endif // BASE_AT_EXIT_H_ diff --git a/base/at_exit_unittest.cc b/base/at_exit_unittest.cc deleted file mode 100644 index cda73403fb..0000000000 --- a/base/at_exit_unittest.cc +++ /dev/null @@ -1,87 +0,0 @@ -// Copyright (c) 2011 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "base/at_exit.h" -#include "base/bind.h" - -#include "testing/gtest/include/gtest/gtest.h" - -namespace { - -int g_test_counter_1 = 0; -int g_test_counter_2 = 0; - -void IncrementTestCounter1(void* unused) { - ++g_test_counter_1; -} - -void IncrementTestCounter2(void* unused) { - ++g_test_counter_2; -} - -void ZeroTestCounters() { - g_test_counter_1 = 0; - g_test_counter_2 = 0; -} - -void ExpectCounter1IsZero(void* unused) { - EXPECT_EQ(0, g_test_counter_1); -} - -void ExpectParamIsNull(void* param) { - EXPECT_EQ(static_cast(NULL), param); -} - -void ExpectParamIsCounter(void* param) { - EXPECT_EQ(&g_test_counter_1, param); -} - -} // namespace - -class AtExitTest : public testing::Test { - private: - // Don't test the global AtExitManager, because asking it to process its - // AtExit callbacks can ruin the global state that other tests may depend on. - base::ShadowingAtExitManager exit_manager_; -}; - -TEST_F(AtExitTest, Basic) { - ZeroTestCounters(); - base::AtExitManager::RegisterCallback(&IncrementTestCounter1, NULL); - base::AtExitManager::RegisterCallback(&IncrementTestCounter2, NULL); - base::AtExitManager::RegisterCallback(&IncrementTestCounter1, NULL); - - EXPECT_EQ(0, g_test_counter_1); - EXPECT_EQ(0, g_test_counter_2); - base::AtExitManager::ProcessCallbacksNow(); - EXPECT_EQ(2, g_test_counter_1); - EXPECT_EQ(1, g_test_counter_2); -} - -TEST_F(AtExitTest, LIFOOrder) { - ZeroTestCounters(); - base::AtExitManager::RegisterCallback(&IncrementTestCounter1, NULL); - base::AtExitManager::RegisterCallback(&ExpectCounter1IsZero, NULL); - base::AtExitManager::RegisterCallback(&IncrementTestCounter2, NULL); - - EXPECT_EQ(0, g_test_counter_1); - EXPECT_EQ(0, g_test_counter_2); - base::AtExitManager::ProcessCallbacksNow(); - EXPECT_EQ(1, g_test_counter_1); - EXPECT_EQ(1, g_test_counter_2); -} - -TEST_F(AtExitTest, Param) { - base::AtExitManager::RegisterCallback(&ExpectParamIsNull, NULL); - base::AtExitManager::RegisterCallback(&ExpectParamIsCounter, - &g_test_counter_1); - base::AtExitManager::ProcessCallbacksNow(); -} - -TEST_F(AtExitTest, Task) { - ZeroTestCounters(); - base::AtExitManager::RegisterTask(base::Bind(&ExpectParamIsCounter, - &g_test_counter_1)); - base::AtExitManager::ProcessCallbacksNow(); -} diff --git a/base/atomic_ref_count.h b/base/atomic_ref_count.h deleted file mode 100644 index 5130860ab0..0000000000 --- a/base/atomic_ref_count.h +++ /dev/null @@ -1,80 +0,0 @@ -// Copyright (c) 2011 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -// This is a low level implementation of atomic semantics for reference -// counting. Please use base/memory/ref_counted.h directly instead. -// -// The implementation includes annotations to avoid some false positives -// when using data race detection tools. - -#ifndef BASE_ATOMIC_REF_COUNT_H_ -#define BASE_ATOMIC_REF_COUNT_H_ - -#include "base/atomicops.h" -#include "base/third_party/dynamic_annotations/dynamic_annotations.h" - -namespace base { - -typedef subtle::Atomic32 AtomicRefCount; - -// Increment a reference count by "increment", which must exceed 0. -inline void AtomicRefCountIncN(volatile AtomicRefCount *ptr, - AtomicRefCount increment) { - subtle::NoBarrier_AtomicIncrement(ptr, increment); -} - -// Decrement a reference count by "decrement", which must exceed 0, -// and return whether the result is non-zero. -// Insert barriers to ensure that state written before the reference count -// became zero will be visible to a thread that has just made the count zero. -inline bool AtomicRefCountDecN(volatile AtomicRefCount *ptr, - AtomicRefCount decrement) { - ANNOTATE_HAPPENS_BEFORE(ptr); - bool res = (subtle::Barrier_AtomicIncrement(ptr, -decrement) != 0); - if (!res) { - ANNOTATE_HAPPENS_AFTER(ptr); - } - return res; -} - -// Increment a reference count by 1. -inline void AtomicRefCountInc(volatile AtomicRefCount *ptr) { - base::AtomicRefCountIncN(ptr, 1); -} - -// Decrement a reference count by 1 and return whether the result is non-zero. -// Insert barriers to ensure that state written before the reference count -// became zero will be visible to a thread that has just made the count zero. -inline bool AtomicRefCountDec(volatile AtomicRefCount *ptr) { - return base::AtomicRefCountDecN(ptr, 1); -} - -// Return whether the reference count is one. If the reference count is used -// in the conventional way, a refrerence count of 1 implies that the current -// thread owns the reference and no other thread shares it. This call performs -// the test for a reference count of one, and performs the memory barrier -// needed for the owning thread to act on the object, knowing that it has -// exclusive access to the object. -inline bool AtomicRefCountIsOne(volatile AtomicRefCount *ptr) { - bool res = (subtle::Acquire_Load(ptr) == 1); - if (res) { - ANNOTATE_HAPPENS_AFTER(ptr); - } - return res; -} - -// Return whether the reference count is zero. With conventional object -// referencing counting, the object will be destroyed, so the reference count -// should never be zero. Hence this is generally used for a debug check. -inline bool AtomicRefCountIsZero(volatile AtomicRefCount *ptr) { - bool res = (subtle::Acquire_Load(ptr) == 0); - if (res) { - ANNOTATE_HAPPENS_AFTER(ptr); - } - return res; -} - -} // namespace base - -#endif // BASE_ATOMIC_REF_COUNT_H_ diff --git a/base/atomic_sequence_num.h b/base/atomic_sequence_num.h deleted file mode 100644 index 7bf2778991..0000000000 --- a/base/atomic_sequence_num.h +++ /dev/null @@ -1,60 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef BASE_ATOMIC_SEQUENCE_NUM_H_ -#define BASE_ATOMIC_SEQUENCE_NUM_H_ - -#include "base/atomicops.h" -#include "base/basictypes.h" - -namespace base { - -class AtomicSequenceNumber; - -// Static (POD) AtomicSequenceNumber that MUST be used in global scope (or -// non-function scope) ONLY. This implementation does not generate any static -// initializer. Note that it does not implement any constructor which means -// that its fields are not initialized except when it is stored in the global -// data section (.data in ELF). If you want to allocate an atomic sequence -// number on the stack (or heap), please use the AtomicSequenceNumber class -// declared below. -class StaticAtomicSequenceNumber { - public: - inline int GetNext() { - return static_cast( - base::subtle::NoBarrier_AtomicIncrement(&seq_, 1) - 1); - } - - private: - friend class AtomicSequenceNumber; - - inline void Reset() { - base::subtle::Release_Store(&seq_, 0); - } - - base::subtle::Atomic32 seq_; -}; - -// AtomicSequenceNumber that can be stored and used safely (i.e. its fields are -// always initialized as opposed to StaticAtomicSequenceNumber declared above). -// Please use StaticAtomicSequenceNumber if you want to declare an atomic -// sequence number in the global scope. -class AtomicSequenceNumber { - public: - AtomicSequenceNumber() { - seq_.Reset(); - } - - inline int GetNext() { - return seq_.GetNext(); - } - - private: - StaticAtomicSequenceNumber seq_; - DISALLOW_COPY_AND_ASSIGN(AtomicSequenceNumber); -}; - -} // namespace base - -#endif // BASE_ATOMIC_SEQUENCE_NUM_H_ diff --git a/base/atomicops.h b/base/atomicops.h deleted file mode 100644 index 7f03492e84..0000000000 --- a/base/atomicops.h +++ /dev/null @@ -1,164 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -// For atomic operations on reference counts, see atomic_refcount.h. -// For atomic operations on sequence numbers, see atomic_sequence_num.h. - -// The routines exported by this module are subtle. If you use them, even if -// you get the code right, it will depend on careful reasoning about atomicity -// and memory ordering; it will be less readable, and harder to maintain. If -// you plan to use these routines, you should have a good reason, such as solid -// evidence that performance would otherwise suffer, or there being no -// alternative. You should assume only properties explicitly guaranteed by the -// specifications in this file. You are almost certainly _not_ writing code -// just for the x86; if you assume x86 semantics, x86 hardware bugs and -// implementations on other archtectures will cause your code to break. If you -// do not know what you are doing, avoid these routines, and use a Mutex. -// -// It is incorrect to make direct assignments to/from an atomic variable. -// You should use one of the Load or Store routines. The NoBarrier -// versions are provided when no barriers are needed: -// NoBarrier_Store() -// NoBarrier_Load() -// Although there are currently no compiler enforcement, you are encouraged -// to use these. -// - -#ifndef BASE_ATOMICOPS_H_ -#define BASE_ATOMICOPS_H_ - -#include "base/basictypes.h" -#include "build/build_config.h" - -#if defined(OS_WIN) && defined(ARCH_CPU_64_BITS) -// windows.h #defines this (only on x64). This causes problems because the -// public API also uses MemoryBarrier at the public name for this fence. So, on -// X64, undef it, and call its documented -// (http://msdn.microsoft.com/en-us/library/windows/desktop/ms684208.aspx) -// implementation directly. -#undef MemoryBarrier -#endif - -namespace base { -namespace subtle { - -typedef int32 Atomic32; -#ifdef ARCH_CPU_64_BITS -// We need to be able to go between Atomic64 and AtomicWord implicitly. This -// means Atomic64 and AtomicWord should be the same type on 64-bit. -#if defined(__ILP32__) || defined(OS_NACL) -// NaCl's intptr_t is not actually 64-bits on 64-bit! -// http://code.google.com/p/nativeclient/issues/detail?id=1162 -typedef int64_t Atomic64; -#else -typedef intptr_t Atomic64; -#endif -#endif - -// Use AtomicWord for a machine-sized pointer. It will use the Atomic32 or -// Atomic64 routines below, depending on your architecture. -typedef intptr_t AtomicWord; - -// Atomically execute: -// result = *ptr; -// if (*ptr == old_value) -// *ptr = new_value; -// return result; -// -// I.e., replace "*ptr" with "new_value" if "*ptr" used to be "old_value". -// Always return the old value of "*ptr" -// -// This routine implies no memory barriers. -Atomic32 NoBarrier_CompareAndSwap(volatile Atomic32* ptr, - Atomic32 old_value, - Atomic32 new_value); - -// Atomically store new_value into *ptr, returning the previous value held in -// *ptr. This routine implies no memory barriers. -Atomic32 NoBarrier_AtomicExchange(volatile Atomic32* ptr, Atomic32 new_value); - -// Atomically increment *ptr by "increment". Returns the new value of -// *ptr with the increment applied. This routine implies no memory barriers. -Atomic32 NoBarrier_AtomicIncrement(volatile Atomic32* ptr, Atomic32 increment); - -Atomic32 Barrier_AtomicIncrement(volatile Atomic32* ptr, - Atomic32 increment); - -// These following lower-level operations are typically useful only to people -// implementing higher-level synchronization operations like spinlocks, -// mutexes, and condition-variables. They combine CompareAndSwap(), a load, or -// a store with appropriate memory-ordering instructions. "Acquire" operations -// ensure that no later memory access can be reordered ahead of the operation. -// "Release" operations ensure that no previous memory access can be reordered -// after the operation. "Barrier" operations have both "Acquire" and "Release" -// semantics. A MemoryBarrier() has "Barrier" semantics, but does no memory -// access. -Atomic32 Acquire_CompareAndSwap(volatile Atomic32* ptr, - Atomic32 old_value, - Atomic32 new_value); -Atomic32 Release_CompareAndSwap(volatile Atomic32* ptr, - Atomic32 old_value, - Atomic32 new_value); - -void MemoryBarrier(); -void NoBarrier_Store(volatile Atomic32* ptr, Atomic32 value); -void Acquire_Store(volatile Atomic32* ptr, Atomic32 value); -void Release_Store(volatile Atomic32* ptr, Atomic32 value); - -Atomic32 NoBarrier_Load(volatile const Atomic32* ptr); -Atomic32 Acquire_Load(volatile const Atomic32* ptr); -Atomic32 Release_Load(volatile const Atomic32* ptr); - -// 64-bit atomic operations (only available on 64-bit processors). -#ifdef ARCH_CPU_64_BITS -Atomic64 NoBarrier_CompareAndSwap(volatile Atomic64* ptr, - Atomic64 old_value, - Atomic64 new_value); -Atomic64 NoBarrier_AtomicExchange(volatile Atomic64* ptr, Atomic64 new_value); -Atomic64 NoBarrier_AtomicIncrement(volatile Atomic64* ptr, Atomic64 increment); -Atomic64 Barrier_AtomicIncrement(volatile Atomic64* ptr, Atomic64 increment); - -Atomic64 Acquire_CompareAndSwap(volatile Atomic64* ptr, - Atomic64 old_value, - Atomic64 new_value); -Atomic64 Release_CompareAndSwap(volatile Atomic64* ptr, - Atomic64 old_value, - Atomic64 new_value); -void NoBarrier_Store(volatile Atomic64* ptr, Atomic64 value); -void Acquire_Store(volatile Atomic64* ptr, Atomic64 value); -void Release_Store(volatile Atomic64* ptr, Atomic64 value); -Atomic64 NoBarrier_Load(volatile const Atomic64* ptr); -Atomic64 Acquire_Load(volatile const Atomic64* ptr); -Atomic64 Release_Load(volatile const Atomic64* ptr); -#endif // ARCH_CPU_64_BITS - -} // namespace base::subtle -} // namespace base - -// Include our platform specific implementation. -#if defined(THREAD_SANITIZER) -#include "base/atomicops_internals_tsan.h" -#elif defined(OS_WIN) && defined(COMPILER_MSVC) && defined(ARCH_CPU_X86_FAMILY) -#include "base/atomicops_internals_x86_msvc.h" -#elif defined(OS_MACOSX) -#include "base/atomicops_internals_mac.h" -#elif defined(OS_NACL) -#include "base/atomicops_internals_gcc.h" -#elif defined(COMPILER_GCC) && defined(ARCH_CPU_ARM_FAMILY) -#include "base/atomicops_internals_arm_gcc.h" -#elif defined(COMPILER_GCC) && defined(ARCH_CPU_X86_FAMILY) -#include "base/atomicops_internals_x86_gcc.h" -#elif defined(COMPILER_GCC) && defined(ARCH_CPU_MIPS_FAMILY) -#include "base/atomicops_internals_mips_gcc.h" -#else -#error "Atomic operations are not supported on your platform" -#endif - -// On some platforms we need additional declarations to make -// AtomicWord compatible with our other Atomic* types. -#if defined(OS_MACOSX) || defined(OS_OPENBSD) -#include "base/atomicops_internals_atomicword_compat.h" -#endif - -#endif // BASE_ATOMICOPS_H_ diff --git a/base/atomicops_internals_arm_gcc.h b/base/atomicops_internals_arm_gcc.h deleted file mode 100644 index 9f4fe2e586..0000000000 --- a/base/atomicops_internals_arm_gcc.h +++ /dev/null @@ -1,285 +0,0 @@ -// Copyright 2013 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -// This file is an internal atomic implementation, use base/atomicops.h instead. -// -// LinuxKernelCmpxchg and Barrier_AtomicIncrement are from Google Gears. - -#ifndef BASE_ATOMICOPS_INTERNALS_ARM_GCC_H_ -#define BASE_ATOMICOPS_INTERNALS_ARM_GCC_H_ - -namespace base { -namespace subtle { - -// Memory barriers on ARM are funky, but the kernel is here to help: -// -// * ARMv5 didn't support SMP, there is no memory barrier instruction at -// all on this architecture, or when targeting its machine code. -// -// * Some ARMv6 CPUs support SMP. A full memory barrier can be produced by -// writing a random value to a very specific coprocessor register. -// -// * On ARMv7, the "dmb" instruction is used to perform a full memory -// barrier (though writing to the co-processor will still work). -// However, on single core devices (e.g. Nexus One, or Nexus S), -// this instruction will take up to 200 ns, which is huge, even though -// it's completely un-needed on these devices. -// -// * There is no easy way to determine at runtime if the device is -// single or multi-core. However, the kernel provides a useful helper -// function at a fixed memory address (0xffff0fa0), which will always -// perform a memory barrier in the most efficient way. I.e. on single -// core devices, this is an empty function that exits immediately. -// On multi-core devices, it implements a full memory barrier. -// -// * This source could be compiled to ARMv5 machine code that runs on a -// multi-core ARMv6 or ARMv7 device. In this case, memory barriers -// are needed for correct execution. Always call the kernel helper, even -// when targeting ARMv5TE. -// - -inline void MemoryBarrier() { - // Note: This is a function call, which is also an implicit compiler - // barrier. - typedef void (*KernelMemoryBarrierFunc)(); - ((KernelMemoryBarrierFunc)0xffff0fa0)(); -} - -// An ARM toolchain would only define one of these depending on which -// variant of the target architecture is being used. This tests against -// any known ARMv6 or ARMv7 variant, where it is possible to directly -// use ldrex/strex instructions to implement fast atomic operations. -#if defined(__ARM_ARCH_7__) || defined(__ARM_ARCH_7A__) || \ - defined(__ARM_ARCH_7R__) || defined(__ARM_ARCH_7M__) || \ - defined(__ARM_ARCH_6__) || defined(__ARM_ARCH_6J__) || \ - defined(__ARM_ARCH_6K__) || defined(__ARM_ARCH_6Z__) || \ - defined(__ARM_ARCH_6KZ__) || defined(__ARM_ARCH_6T2__) - -inline Atomic32 NoBarrier_CompareAndSwap(volatile Atomic32* ptr, - Atomic32 old_value, - Atomic32 new_value) { - Atomic32 prev_value; - int reloop; - do { - // The following is equivalent to: - // - // prev_value = LDREX(ptr) - // reloop = 0 - // if (prev_value != old_value) - // reloop = STREX(ptr, new_value) - __asm__ __volatile__(" ldrex %0, [%3]\n" - " mov %1, #0\n" - " cmp %0, %4\n" -#ifdef __thumb2__ - " it eq\n" -#endif - " strexeq %1, %5, [%3]\n" - : "=&r"(prev_value), "=&r"(reloop), "+m"(*ptr) - : "r"(ptr), "r"(old_value), "r"(new_value) - : "cc", "memory"); - } while (reloop != 0); - return prev_value; -} - -inline Atomic32 Acquire_CompareAndSwap(volatile Atomic32* ptr, - Atomic32 old_value, - Atomic32 new_value) { - Atomic32 result = NoBarrier_CompareAndSwap(ptr, old_value, new_value); - MemoryBarrier(); - return result; -} - -inline Atomic32 Release_CompareAndSwap(volatile Atomic32* ptr, - Atomic32 old_value, - Atomic32 new_value) { - MemoryBarrier(); - return NoBarrier_CompareAndSwap(ptr, old_value, new_value); -} - -inline Atomic32 NoBarrier_AtomicIncrement(volatile Atomic32* ptr, - Atomic32 increment) { - Atomic32 value; - int reloop; - do { - // Equivalent to: - // - // value = LDREX(ptr) - // value += increment - // reloop = STREX(ptr, value) - // - __asm__ __volatile__(" ldrex %0, [%3]\n" - " add %0, %0, %4\n" - " strex %1, %0, [%3]\n" - : "=&r"(value), "=&r"(reloop), "+m"(*ptr) - : "r"(ptr), "r"(increment) - : "cc", "memory"); - } while (reloop); - return value; -} - -inline Atomic32 Barrier_AtomicIncrement(volatile Atomic32* ptr, - Atomic32 increment) { - // TODO(digit): Investigate if it's possible to implement this with - // a single MemoryBarrier() operation between the LDREX and STREX. - // See http://crbug.com/246514 - MemoryBarrier(); - Atomic32 result = NoBarrier_AtomicIncrement(ptr, increment); - MemoryBarrier(); - return result; -} - -inline Atomic32 NoBarrier_AtomicExchange(volatile Atomic32* ptr, - Atomic32 new_value) { - Atomic32 old_value; - int reloop; - do { - // old_value = LDREX(ptr) - // reloop = STREX(ptr, new_value) - __asm__ __volatile__(" ldrex %0, [%3]\n" - " strex %1, %4, [%3]\n" - : "=&r"(old_value), "=&r"(reloop), "+m"(*ptr) - : "r"(ptr), "r"(new_value) - : "cc", "memory"); - } while (reloop != 0); - return old_value; -} - -// This tests against any known ARMv5 variant. -#elif defined(__ARM_ARCH_5__) || defined(__ARM_ARCH_5T__) || \ - defined(__ARM_ARCH_5TE__) || defined(__ARM_ARCH_5TEJ__) - -// The kernel also provides a helper function to perform an atomic -// compare-and-swap operation at the hard-wired address 0xffff0fc0. -// On ARMv5, this is implemented by a special code path that the kernel -// detects and treats specially when thread pre-emption happens. -// On ARMv6 and higher, it uses LDREX/STREX instructions instead. -// -// Note that this always perform a full memory barrier, there is no -// need to add calls MemoryBarrier() before or after it. It also -// returns 0 on success, and 1 on exit. -// -// Available and reliable since Linux 2.6.24. Both Android and ChromeOS -// use newer kernel revisions, so this should not be a concern. -namespace { - -inline int LinuxKernelCmpxchg(Atomic32 old_value, - Atomic32 new_value, - volatile Atomic32* ptr) { - typedef int (*KernelCmpxchgFunc)(Atomic32, Atomic32, volatile Atomic32*); - return ((KernelCmpxchgFunc)0xffff0fc0)(old_value, new_value, ptr); -} - -} // namespace - -inline Atomic32 NoBarrier_CompareAndSwap(volatile Atomic32* ptr, - Atomic32 old_value, - Atomic32 new_value) { - Atomic32 prev_value; - for (;;) { - prev_value = *ptr; - if (prev_value != old_value) - return prev_value; - if (!LinuxKernelCmpxchg(old_value, new_value, ptr)) - return old_value; - } -} - -inline Atomic32 NoBarrier_AtomicExchange(volatile Atomic32* ptr, - Atomic32 new_value) { - Atomic32 old_value; - do { - old_value = *ptr; - } while (LinuxKernelCmpxchg(old_value, new_value, ptr)); - return old_value; -} - -inline Atomic32 NoBarrier_AtomicIncrement(volatile Atomic32* ptr, - Atomic32 increment) { - return Barrier_AtomicIncrement(ptr, increment); -} - -inline Atomic32 Barrier_AtomicIncrement(volatile Atomic32* ptr, - Atomic32 increment) { - for (;;) { - // Atomic exchange the old value with an incremented one. - Atomic32 old_value = *ptr; - Atomic32 new_value = old_value + increment; - if (!LinuxKernelCmpxchg(old_value, new_value, ptr)) { - // The exchange took place as expected. - return new_value; - } - // Otherwise, *ptr changed mid-loop and we need to retry. - } -} - -inline Atomic32 Acquire_CompareAndSwap(volatile Atomic32* ptr, - Atomic32 old_value, - Atomic32 new_value) { - Atomic32 prev_value; - for (;;) { - prev_value = *ptr; - if (prev_value != old_value) { - // Always ensure acquire semantics. - MemoryBarrier(); - return prev_value; - } - if (!LinuxKernelCmpxchg(old_value, new_value, ptr)) - return old_value; - } -} - -inline Atomic32 Release_CompareAndSwap(volatile Atomic32* ptr, - Atomic32 old_value, - Atomic32 new_value) { - // This could be implemented as: - // MemoryBarrier(); - // return NoBarrier_CompareAndSwap(); - // - // But would use 3 barriers per succesful CAS. To save performance, - // use Acquire_CompareAndSwap(). Its implementation guarantees that: - // - A succesful swap uses only 2 barriers (in the kernel helper). - // - An early return due to (prev_value != old_value) performs - // a memory barrier with no store, which is equivalent to the - // generic implementation above. - return Acquire_CompareAndSwap(ptr, old_value, new_value); -} - -#else -# error "Your CPU's ARM architecture is not supported yet" -#endif - -// NOTE: Atomicity of the following load and store operations is only -// guaranteed in case of 32-bit alignement of |ptr| values. - -inline void NoBarrier_Store(volatile Atomic32* ptr, Atomic32 value) { - *ptr = value; -} - -inline void Acquire_Store(volatile Atomic32* ptr, Atomic32 value) { - *ptr = value; - MemoryBarrier(); -} - -inline void Release_Store(volatile Atomic32* ptr, Atomic32 value) { - MemoryBarrier(); - *ptr = value; -} - -inline Atomic32 NoBarrier_Load(volatile const Atomic32* ptr) { return *ptr; } - -inline Atomic32 Acquire_Load(volatile const Atomic32* ptr) { - Atomic32 value = *ptr; - MemoryBarrier(); - return value; -} - -inline Atomic32 Release_Load(volatile const Atomic32* ptr) { - MemoryBarrier(); - return *ptr; -} - -} // namespace base::subtle -} // namespace base - -#endif // BASE_ATOMICOPS_INTERNALS_ARM_GCC_H_ diff --git a/base/atomicops_internals_atomicword_compat.h b/base/atomicops_internals_atomicword_compat.h deleted file mode 100644 index e02d11d29b..0000000000 --- a/base/atomicops_internals_atomicword_compat.h +++ /dev/null @@ -1,100 +0,0 @@ -// Copyright (c) 2011 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -// This file is an internal atomic implementation, use base/atomicops.h instead. - -#ifndef BASE_ATOMICOPS_INTERNALS_ATOMICWORD_COMPAT_H_ -#define BASE_ATOMICOPS_INTERNALS_ATOMICWORD_COMPAT_H_ - -// AtomicWord is a synonym for intptr_t, and Atomic32 is a synonym for int32, -// which in turn means int. On some LP32 platforms, intptr_t is an int, but -// on others, it's a long. When AtomicWord and Atomic32 are based on different -// fundamental types, their pointers are incompatible. -// -// This file defines function overloads to allow both AtomicWord and Atomic32 -// data to be used with this interface. -// -// On LP64 platforms, AtomicWord and Atomic64 are both always long, -// so this problem doesn't occur. - -#if !defined(ARCH_CPU_64_BITS) - -namespace base { -namespace subtle { - -inline AtomicWord NoBarrier_CompareAndSwap(volatile AtomicWord* ptr, - AtomicWord old_value, - AtomicWord new_value) { - return NoBarrier_CompareAndSwap( - reinterpret_cast(ptr), old_value, new_value); -} - -inline AtomicWord NoBarrier_AtomicExchange(volatile AtomicWord* ptr, - AtomicWord new_value) { - return NoBarrier_AtomicExchange( - reinterpret_cast(ptr), new_value); -} - -inline AtomicWord NoBarrier_AtomicIncrement(volatile AtomicWord* ptr, - AtomicWord increment) { - return NoBarrier_AtomicIncrement( - reinterpret_cast(ptr), increment); -} - -inline AtomicWord Barrier_AtomicIncrement(volatile AtomicWord* ptr, - AtomicWord increment) { - return Barrier_AtomicIncrement( - reinterpret_cast(ptr), increment); -} - -inline AtomicWord Acquire_CompareAndSwap(volatile AtomicWord* ptr, - AtomicWord old_value, - AtomicWord new_value) { - return base::subtle::Acquire_CompareAndSwap( - reinterpret_cast(ptr), old_value, new_value); -} - -inline AtomicWord Release_CompareAndSwap(volatile AtomicWord* ptr, - AtomicWord old_value, - AtomicWord new_value) { - return base::subtle::Release_CompareAndSwap( - reinterpret_cast(ptr), old_value, new_value); -} - -inline void NoBarrier_Store(volatile AtomicWord *ptr, AtomicWord value) { - NoBarrier_Store( - reinterpret_cast(ptr), value); -} - -inline void Acquire_Store(volatile AtomicWord* ptr, AtomicWord value) { - return base::subtle::Acquire_Store( - reinterpret_cast(ptr), value); -} - -inline void Release_Store(volatile AtomicWord* ptr, AtomicWord value) { - return base::subtle::Release_Store( - reinterpret_cast(ptr), value); -} - -inline AtomicWord NoBarrier_Load(volatile const AtomicWord *ptr) { - return NoBarrier_Load( - reinterpret_cast(ptr)); -} - -inline AtomicWord Acquire_Load(volatile const AtomicWord* ptr) { - return base::subtle::Acquire_Load( - reinterpret_cast(ptr)); -} - -inline AtomicWord Release_Load(volatile const AtomicWord* ptr) { - return base::subtle::Release_Load( - reinterpret_cast(ptr)); -} - -} // namespace base::subtle -} // namespace base - -#endif // !defined(ARCH_CPU_64_BITS) - -#endif // BASE_ATOMICOPS_INTERNALS_ATOMICWORD_COMPAT_H_ diff --git a/base/atomicops_internals_gcc.h b/base/atomicops_internals_gcc.h deleted file mode 100644 index ed1b2d7913..0000000000 --- a/base/atomicops_internals_gcc.h +++ /dev/null @@ -1,106 +0,0 @@ -// Copyright (c) 2009 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -// This file is an internal atomic implementation, include base/atomicops.h -// instead. This file is for platforms that use GCC intrinsics rather than -// platform-specific assembly code for atomic operations. - -#ifndef BASE_ATOMICOPS_INTERNALS_GCC_H_ -#define BASE_ATOMICOPS_INTERNALS_GCC_H_ - -namespace base { -namespace subtle { - -inline Atomic32 NoBarrier_CompareAndSwap(volatile Atomic32* ptr, - Atomic32 old_value, - Atomic32 new_value) { - Atomic32 prev_value; - do { - if (__sync_bool_compare_and_swap(ptr, old_value, new_value)) - return old_value; - prev_value = *ptr; - } while (prev_value == old_value); - return prev_value; -} - -inline Atomic32 NoBarrier_AtomicExchange(volatile Atomic32* ptr, - Atomic32 new_value) { - Atomic32 old_value; - do { - old_value = *ptr; - } while (!__sync_bool_compare_and_swap(ptr, old_value, new_value)); - return old_value; -} - -inline Atomic32 NoBarrier_AtomicIncrement(volatile Atomic32* ptr, - Atomic32 increment) { - return Barrier_AtomicIncrement(ptr, increment); -} - -inline Atomic32 Barrier_AtomicIncrement(volatile Atomic32* ptr, - Atomic32 increment) { - for (;;) { - // Atomic exchange the old value with an incremented one. - Atomic32 old_value = *ptr; - Atomic32 new_value = old_value + increment; - if (__sync_bool_compare_and_swap(ptr, old_value, new_value)) { - // The exchange took place as expected. - return new_value; - } - // Otherwise, *ptr changed mid-loop and we need to retry. - } -} - -inline Atomic32 Acquire_CompareAndSwap(volatile Atomic32* ptr, - Atomic32 old_value, - Atomic32 new_value) { - // Since NoBarrier_CompareAndSwap uses __sync_bool_compare_and_swap, which - // is a full memory barrier, none is needed here or below in Release. - return NoBarrier_CompareAndSwap(ptr, old_value, new_value); -} - -inline Atomic32 Release_CompareAndSwap(volatile Atomic32* ptr, - Atomic32 old_value, - Atomic32 new_value) { - return NoBarrier_CompareAndSwap(ptr, old_value, new_value); -} - -inline void NoBarrier_Store(volatile Atomic32* ptr, Atomic32 value) { - *ptr = value; -} - -inline void MemoryBarrier() { - __sync_synchronize(); -} - -inline void Acquire_Store(volatile Atomic32* ptr, Atomic32 value) { - *ptr = value; - MemoryBarrier(); -} - -inline void Release_Store(volatile Atomic32* ptr, Atomic32 value) { - MemoryBarrier(); - *ptr = value; -} - -inline Atomic32 NoBarrier_Load(volatile const Atomic32* ptr) { - return *ptr; -} - -inline Atomic32 Acquire_Load(volatile const Atomic32* ptr) { - Atomic32 value = *ptr; - MemoryBarrier(); - return value; -} - -inline Atomic32 Release_Load(volatile const Atomic32* ptr) { - MemoryBarrier(); - return *ptr; -} - -} // namespace base::subtle -} // namespace base - -#endif // BASE_ATOMICOPS_INTERNALS_GCC_H_ - diff --git a/base/atomicops_internals_mac.h b/base/atomicops_internals_mac.h deleted file mode 100644 index 658ed54879..0000000000 --- a/base/atomicops_internals_mac.h +++ /dev/null @@ -1,197 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -// This file is an internal atomic implementation, use base/atomicops.h instead. - -#ifndef BASE_ATOMICOPS_INTERNALS_MAC_H_ -#define BASE_ATOMICOPS_INTERNALS_MAC_H_ - -#include - -namespace base { -namespace subtle { - -inline Atomic32 NoBarrier_CompareAndSwap(volatile Atomic32 *ptr, - Atomic32 old_value, - Atomic32 new_value) { - Atomic32 prev_value; - do { - if (OSAtomicCompareAndSwap32(old_value, new_value, - const_cast(ptr))) { - return old_value; - } - prev_value = *ptr; - } while (prev_value == old_value); - return prev_value; -} - -inline Atomic32 NoBarrier_AtomicExchange(volatile Atomic32 *ptr, - Atomic32 new_value) { - Atomic32 old_value; - do { - old_value = *ptr; - } while (!OSAtomicCompareAndSwap32(old_value, new_value, - const_cast(ptr))); - return old_value; -} - -inline Atomic32 NoBarrier_AtomicIncrement(volatile Atomic32 *ptr, - Atomic32 increment) { - return OSAtomicAdd32(increment, const_cast(ptr)); -} - -inline Atomic32 Barrier_AtomicIncrement(volatile Atomic32 *ptr, - Atomic32 increment) { - return OSAtomicAdd32Barrier(increment, const_cast(ptr)); -} - -inline void MemoryBarrier() { - OSMemoryBarrier(); -} - -inline Atomic32 Acquire_CompareAndSwap(volatile Atomic32 *ptr, - Atomic32 old_value, - Atomic32 new_value) { - Atomic32 prev_value; - do { - if (OSAtomicCompareAndSwap32Barrier(old_value, new_value, - const_cast(ptr))) { - return old_value; - } - prev_value = *ptr; - } while (prev_value == old_value); - return prev_value; -} - -inline Atomic32 Release_CompareAndSwap(volatile Atomic32 *ptr, - Atomic32 old_value, - Atomic32 new_value) { - return Acquire_CompareAndSwap(ptr, old_value, new_value); -} - -inline void NoBarrier_Store(volatile Atomic32* ptr, Atomic32 value) { - *ptr = value; -} - -inline void Acquire_Store(volatile Atomic32 *ptr, Atomic32 value) { - *ptr = value; - MemoryBarrier(); -} - -inline void Release_Store(volatile Atomic32 *ptr, Atomic32 value) { - MemoryBarrier(); - *ptr = value; -} - -inline Atomic32 NoBarrier_Load(volatile const Atomic32* ptr) { - return *ptr; -} - -inline Atomic32 Acquire_Load(volatile const Atomic32 *ptr) { - Atomic32 value = *ptr; - MemoryBarrier(); - return value; -} - -inline Atomic32 Release_Load(volatile const Atomic32 *ptr) { - MemoryBarrier(); - return *ptr; -} - -#ifdef __LP64__ - -// 64-bit implementation on 64-bit platform - -inline Atomic64 NoBarrier_CompareAndSwap(volatile Atomic64 *ptr, - Atomic64 old_value, - Atomic64 new_value) { - Atomic64 prev_value; - do { - if (OSAtomicCompareAndSwap64(old_value, new_value, - reinterpret_cast(ptr))) { - return old_value; - } - prev_value = *ptr; - } while (prev_value == old_value); - return prev_value; -} - -inline Atomic64 NoBarrier_AtomicExchange(volatile Atomic64 *ptr, - Atomic64 new_value) { - Atomic64 old_value; - do { - old_value = *ptr; - } while (!OSAtomicCompareAndSwap64(old_value, new_value, - reinterpret_cast(ptr))); - return old_value; -} - -inline Atomic64 NoBarrier_AtomicIncrement(volatile Atomic64 *ptr, - Atomic64 increment) { - return OSAtomicAdd64(increment, reinterpret_cast(ptr)); -} - -inline Atomic64 Barrier_AtomicIncrement(volatile Atomic64 *ptr, - Atomic64 increment) { - return OSAtomicAdd64Barrier(increment, - reinterpret_cast(ptr)); -} - -inline Atomic64 Acquire_CompareAndSwap(volatile Atomic64 *ptr, - Atomic64 old_value, - Atomic64 new_value) { - Atomic64 prev_value; - do { - if (OSAtomicCompareAndSwap64Barrier( - old_value, new_value, reinterpret_cast(ptr))) { - return old_value; - } - prev_value = *ptr; - } while (prev_value == old_value); - return prev_value; -} - -inline Atomic64 Release_CompareAndSwap(volatile Atomic64 *ptr, - Atomic64 old_value, - Atomic64 new_value) { - // The lib kern interface does not distinguish between - // Acquire and Release memory barriers; they are equivalent. - return Acquire_CompareAndSwap(ptr, old_value, new_value); -} - -inline void NoBarrier_Store(volatile Atomic64* ptr, Atomic64 value) { - *ptr = value; -} - -inline void Acquire_Store(volatile Atomic64 *ptr, Atomic64 value) { - *ptr = value; - MemoryBarrier(); -} - -inline void Release_Store(volatile Atomic64 *ptr, Atomic64 value) { - MemoryBarrier(); - *ptr = value; -} - -inline Atomic64 NoBarrier_Load(volatile const Atomic64* ptr) { - return *ptr; -} - -inline Atomic64 Acquire_Load(volatile const Atomic64 *ptr) { - Atomic64 value = *ptr; - MemoryBarrier(); - return value; -} - -inline Atomic64 Release_Load(volatile const Atomic64 *ptr) { - MemoryBarrier(); - return *ptr; -} - -#endif // defined(__LP64__) - -} // namespace base::subtle -} // namespace base - -#endif // BASE_ATOMICOPS_INTERNALS_MAC_H_ diff --git a/base/atomicops_internals_mips_gcc.h b/base/atomicops_internals_mips_gcc.h deleted file mode 100644 index 29947b37af..0000000000 --- a/base/atomicops_internals_mips_gcc.h +++ /dev/null @@ -1,154 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -// This file is an internal atomic implementation, use base/atomicops.h instead. -// -// LinuxKernelCmpxchg and Barrier_AtomicIncrement are from Google Gears. - -#ifndef BASE_ATOMICOPS_INTERNALS_MIPS_GCC_H_ -#define BASE_ATOMICOPS_INTERNALS_MIPS_GCC_H_ - -namespace base { -namespace subtle { - -// Atomically execute: -// result = *ptr; -// if (*ptr == old_value) -// *ptr = new_value; -// return result; -// -// I.e., replace "*ptr" with "new_value" if "*ptr" used to be "old_value". -// Always return the old value of "*ptr" -// -// This routine implies no memory barriers. -inline Atomic32 NoBarrier_CompareAndSwap(volatile Atomic32* ptr, - Atomic32 old_value, - Atomic32 new_value) { - Atomic32 prev, tmp; - __asm__ __volatile__(".set push\n" - ".set noreorder\n" - "1:\n" - "ll %0, %5\n" // prev = *ptr - "bne %0, %3, 2f\n" // if (prev != old_value) goto 2 - "move %2, %4\n" // tmp = new_value - "sc %2, %1\n" // *ptr = tmp (with atomic check) - "beqz %2, 1b\n" // start again on atomic error - "nop\n" // delay slot nop - "2:\n" - ".set pop\n" - : "=&r" (prev), "=m" (*ptr), "=&r" (tmp) - : "Ir" (old_value), "r" (new_value), "m" (*ptr) - : "memory"); - return prev; -} - -// Atomically store new_value into *ptr, returning the previous value held in -// *ptr. This routine implies no memory barriers. -inline Atomic32 NoBarrier_AtomicExchange(volatile Atomic32* ptr, - Atomic32 new_value) { - Atomic32 temp, old; - __asm__ __volatile__(".set push\n" - ".set noreorder\n" - "1:\n" - "ll %1, %2\n" // old = *ptr - "move %0, %3\n" // temp = new_value - "sc %0, %2\n" // *ptr = temp (with atomic check) - "beqz %0, 1b\n" // start again on atomic error - "nop\n" // delay slot nop - ".set pop\n" - : "=&r" (temp), "=&r" (old), "=m" (*ptr) - : "r" (new_value), "m" (*ptr) - : "memory"); - - return old; -} - -// Atomically increment *ptr by "increment". Returns the new value of -// *ptr with the increment applied. This routine implies no memory barriers. -inline Atomic32 NoBarrier_AtomicIncrement(volatile Atomic32* ptr, - Atomic32 increment) { - Atomic32 temp, temp2; - - __asm__ __volatile__(".set push\n" - ".set noreorder\n" - "1:\n" - "ll %0, %2\n" // temp = *ptr - "addu %1, %0, %3\n" // temp2 = temp + increment - "sc %1, %2\n" // *ptr = temp2 (with atomic check) - "beqz %1, 1b\n" // start again on atomic error - "addu %1, %0, %3\n" // temp2 = temp + increment - ".set pop\n" - : "=&r" (temp), "=&r" (temp2), "=m" (*ptr) - : "Ir" (increment), "m" (*ptr) - : "memory"); - // temp2 now holds the final value. - return temp2; -} - -inline Atomic32 Barrier_AtomicIncrement(volatile Atomic32* ptr, - Atomic32 increment) { - MemoryBarrier(); - Atomic32 res = NoBarrier_AtomicIncrement(ptr, increment); - MemoryBarrier(); - return res; -} - -// "Acquire" operations -// ensure that no later memory access can be reordered ahead of the operation. -// "Release" operations ensure that no previous memory access can be reordered -// after the operation. "Barrier" operations have both "Acquire" and "Release" -// semantics. A MemoryBarrier() has "Barrier" semantics, but does no memory -// access. -inline Atomic32 Acquire_CompareAndSwap(volatile Atomic32* ptr, - Atomic32 old_value, - Atomic32 new_value) { - Atomic32 res = NoBarrier_CompareAndSwap(ptr, old_value, new_value); - MemoryBarrier(); - return res; -} - -inline Atomic32 Release_CompareAndSwap(volatile Atomic32* ptr, - Atomic32 old_value, - Atomic32 new_value) { - MemoryBarrier(); - return NoBarrier_CompareAndSwap(ptr, old_value, new_value); -} - -inline void NoBarrier_Store(volatile Atomic32* ptr, Atomic32 value) { - *ptr = value; -} - -inline void MemoryBarrier() { - __asm__ __volatile__("sync" : : : "memory"); -} - -inline void Acquire_Store(volatile Atomic32* ptr, Atomic32 value) { - *ptr = value; - MemoryBarrier(); -} - -inline void Release_Store(volatile Atomic32* ptr, Atomic32 value) { - MemoryBarrier(); - *ptr = value; -} - -inline Atomic32 NoBarrier_Load(volatile const Atomic32* ptr) { - return *ptr; -} - -inline Atomic32 Acquire_Load(volatile const Atomic32* ptr) { - Atomic32 value = *ptr; - MemoryBarrier(); - return value; -} - -inline Atomic32 Release_Load(volatile const Atomic32* ptr) { - MemoryBarrier(); - return *ptr; -} - -} // namespace base::subtle -} // namespace base - -#endif // BASE_ATOMICOPS_INTERNALS_MIPS_GCC_H_ diff --git a/base/atomicops_internals_tsan.h b/base/atomicops_internals_tsan.h deleted file mode 100644 index 44d64009c7..0000000000 --- a/base/atomicops_internals_tsan.h +++ /dev/null @@ -1,378 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -// This file is an internal atomic implementation for compiler-based -// ThreadSanitizer. Use base/atomicops.h instead. - -#ifndef BASE_ATOMICOPS_INTERNALS_TSAN_H_ -#define BASE_ATOMICOPS_INTERNALS_TSAN_H_ - -#include "base/base_export.h" - -// This struct is not part of the public API of this module; clients may not -// use it. (However, it's exported via BASE_EXPORT because clients implicitly -// do use it at link time by inlining these functions.) -// Features of this x86. Values may not be correct before main() is run, -// but are set conservatively. -struct AtomicOps_x86CPUFeatureStruct { - bool has_amd_lock_mb_bug; // Processor has AMD memory-barrier bug; do lfence - // after acquire compare-and-swap. - bool has_sse2; // Processor has SSE2. -}; -BASE_EXPORT extern struct AtomicOps_x86CPUFeatureStruct - AtomicOps_Internalx86CPUFeatures; - -#define ATOMICOPS_COMPILER_BARRIER() __asm__ __volatile__("" : : : "memory") - -namespace base { -namespace subtle { - -#ifndef TSAN_INTERFACE_ATOMIC_H -#define TSAN_INTERFACE_ATOMIC_H - -#ifdef __cplusplus -extern "C" { -#endif - -typedef char __tsan_atomic8; -typedef short __tsan_atomic16; // NOLINT -typedef int __tsan_atomic32; -typedef long __tsan_atomic64; // NOLINT - -#if defined(__SIZEOF_INT128__) \ - || (__clang_major__ * 100 + __clang_minor__ >= 302) -typedef __int128 __tsan_atomic128; -#define __TSAN_HAS_INT128 1 -#else -typedef char __tsan_atomic128; -#define __TSAN_HAS_INT128 0 -#endif - -typedef enum { - __tsan_memory_order_relaxed, - __tsan_memory_order_consume, - __tsan_memory_order_acquire, - __tsan_memory_order_release, - __tsan_memory_order_acq_rel, - __tsan_memory_order_seq_cst, -} __tsan_memory_order; - -__tsan_atomic8 __tsan_atomic8_load(const volatile __tsan_atomic8 *a, - __tsan_memory_order mo); -__tsan_atomic16 __tsan_atomic16_load(const volatile __tsan_atomic16 *a, - __tsan_memory_order mo); -__tsan_atomic32 __tsan_atomic32_load(const volatile __tsan_atomic32 *a, - __tsan_memory_order mo); -__tsan_atomic64 __tsan_atomic64_load(const volatile __tsan_atomic64 *a, - __tsan_memory_order mo); -__tsan_atomic128 __tsan_atomic128_load(const volatile __tsan_atomic128 *a, - __tsan_memory_order mo); - -void __tsan_atomic8_store(volatile __tsan_atomic8 *a, __tsan_atomic8 v, - __tsan_memory_order mo); -void __tsan_atomic16_store(volatile __tsan_atomic16 *a, __tsan_atomic16 v, - __tsan_memory_order mo); -void __tsan_atomic32_store(volatile __tsan_atomic32 *a, __tsan_atomic32 v, - __tsan_memory_order mo); -void __tsan_atomic64_store(volatile __tsan_atomic64 *a, __tsan_atomic64 v, - __tsan_memory_order mo); -void __tsan_atomic128_store(volatile __tsan_atomic128 *a, __tsan_atomic128 v, - __tsan_memory_order mo); - -__tsan_atomic8 __tsan_atomic8_exchange(volatile __tsan_atomic8 *a, - __tsan_atomic8 v, __tsan_memory_order mo); -__tsan_atomic16 __tsan_atomic16_exchange(volatile __tsan_atomic16 *a, - __tsan_atomic16 v, __tsan_memory_order mo); -__tsan_atomic32 __tsan_atomic32_exchange(volatile __tsan_atomic32 *a, - __tsan_atomic32 v, __tsan_memory_order mo); -__tsan_atomic64 __tsan_atomic64_exchange(volatile __tsan_atomic64 *a, - __tsan_atomic64 v, __tsan_memory_order mo); -__tsan_atomic128 __tsan_atomic128_exchange(volatile __tsan_atomic128 *a, - __tsan_atomic128 v, __tsan_memory_order mo); - -__tsan_atomic8 __tsan_atomic8_fetch_add(volatile __tsan_atomic8 *a, - __tsan_atomic8 v, __tsan_memory_order mo); -__tsan_atomic16 __tsan_atomic16_fetch_add(volatile __tsan_atomic16 *a, - __tsan_atomic16 v, __tsan_memory_order mo); -__tsan_atomic32 __tsan_atomic32_fetch_add(volatile __tsan_atomic32 *a, - __tsan_atomic32 v, __tsan_memory_order mo); -__tsan_atomic64 __tsan_atomic64_fetch_add(volatile __tsan_atomic64 *a, - __tsan_atomic64 v, __tsan_memory_order mo); -__tsan_atomic128 __tsan_atomic128_fetch_add(volatile __tsan_atomic128 *a, - __tsan_atomic128 v, __tsan_memory_order mo); - -__tsan_atomic8 __tsan_atomic8_fetch_and(volatile __tsan_atomic8 *a, - __tsan_atomic8 v, __tsan_memory_order mo); -__tsan_atomic16 __tsan_atomic16_fetch_and(volatile __tsan_atomic16 *a, - __tsan_atomic16 v, __tsan_memory_order mo); -__tsan_atomic32 __tsan_atomic32_fetch_and(volatile __tsan_atomic32 *a, - __tsan_atomic32 v, __tsan_memory_order mo); -__tsan_atomic64 __tsan_atomic64_fetch_and(volatile __tsan_atomic64 *a, - __tsan_atomic64 v, __tsan_memory_order mo); -__tsan_atomic128 __tsan_atomic128_fetch_and(volatile __tsan_atomic128 *a, - __tsan_atomic128 v, __tsan_memory_order mo); - -__tsan_atomic8 __tsan_atomic8_fetch_or(volatile __tsan_atomic8 *a, - __tsan_atomic8 v, __tsan_memory_order mo); -__tsan_atomic16 __tsan_atomic16_fetch_or(volatile __tsan_atomic16 *a, - __tsan_atomic16 v, __tsan_memory_order mo); -__tsan_atomic32 __tsan_atomic32_fetch_or(volatile __tsan_atomic32 *a, - __tsan_atomic32 v, __tsan_memory_order mo); -__tsan_atomic64 __tsan_atomic64_fetch_or(volatile __tsan_atomic64 *a, - __tsan_atomic64 v, __tsan_memory_order mo); -__tsan_atomic128 __tsan_atomic128_fetch_or(volatile __tsan_atomic128 *a, - __tsan_atomic128 v, __tsan_memory_order mo); - -__tsan_atomic8 __tsan_atomic8_fetch_xor(volatile __tsan_atomic8 *a, - __tsan_atomic8 v, __tsan_memory_order mo); -__tsan_atomic16 __tsan_atomic16_fetch_xor(volatile __tsan_atomic16 *a, - __tsan_atomic16 v, __tsan_memory_order mo); -__tsan_atomic32 __tsan_atomic32_fetch_xor(volatile __tsan_atomic32 *a, - __tsan_atomic32 v, __tsan_memory_order mo); -__tsan_atomic64 __tsan_atomic64_fetch_xor(volatile __tsan_atomic64 *a, - __tsan_atomic64 v, __tsan_memory_order mo); -__tsan_atomic128 __tsan_atomic128_fetch_xor(volatile __tsan_atomic128 *a, - __tsan_atomic128 v, __tsan_memory_order mo); - -__tsan_atomic8 __tsan_atomic8_fetch_nand(volatile __tsan_atomic8 *a, - __tsan_atomic8 v, __tsan_memory_order mo); -__tsan_atomic16 __tsan_atomic16_fetch_nand(volatile __tsan_atomic16 *a, - __tsan_atomic16 v, __tsan_memory_order mo); -__tsan_atomic32 __tsan_atomic32_fetch_nand(volatile __tsan_atomic32 *a, - __tsan_atomic32 v, __tsan_memory_order mo); -__tsan_atomic64 __tsan_atomic64_fetch_nand(volatile __tsan_atomic64 *a, - __tsan_atomic64 v, __tsan_memory_order mo); -__tsan_atomic128 __tsan_atomic128_fetch_nand(volatile __tsan_atomic128 *a, - __tsan_atomic128 v, __tsan_memory_order mo); - -int __tsan_atomic8_compare_exchange_weak(volatile __tsan_atomic8 *a, - __tsan_atomic8 *c, __tsan_atomic8 v, __tsan_memory_order mo, - __tsan_memory_order fail_mo); -int __tsan_atomic16_compare_exchange_weak(volatile __tsan_atomic16 *a, - __tsan_atomic16 *c, __tsan_atomic16 v, __tsan_memory_order mo, - __tsan_memory_order fail_mo); -int __tsan_atomic32_compare_exchange_weak(volatile __tsan_atomic32 *a, - __tsan_atomic32 *c, __tsan_atomic32 v, __tsan_memory_order mo, - __tsan_memory_order fail_mo); -int __tsan_atomic64_compare_exchange_weak(volatile __tsan_atomic64 *a, - __tsan_atomic64 *c, __tsan_atomic64 v, __tsan_memory_order mo, - __tsan_memory_order fail_mo); -int __tsan_atomic128_compare_exchange_weak(volatile __tsan_atomic128 *a, - __tsan_atomic128 *c, __tsan_atomic128 v, __tsan_memory_order mo, - __tsan_memory_order fail_mo); - -int __tsan_atomic8_compare_exchange_strong(volatile __tsan_atomic8 *a, - __tsan_atomic8 *c, __tsan_atomic8 v, __tsan_memory_order mo, - __tsan_memory_order fail_mo); -int __tsan_atomic16_compare_exchange_strong(volatile __tsan_atomic16 *a, - __tsan_atomic16 *c, __tsan_atomic16 v, __tsan_memory_order mo, - __tsan_memory_order fail_mo); -int __tsan_atomic32_compare_exchange_strong(volatile __tsan_atomic32 *a, - __tsan_atomic32 *c, __tsan_atomic32 v, __tsan_memory_order mo, - __tsan_memory_order fail_mo); -int __tsan_atomic64_compare_exchange_strong(volatile __tsan_atomic64 *a, - __tsan_atomic64 *c, __tsan_atomic64 v, __tsan_memory_order mo, - __tsan_memory_order fail_mo); -int __tsan_atomic128_compare_exchange_strong(volatile __tsan_atomic128 *a, - __tsan_atomic128 *c, __tsan_atomic128 v, __tsan_memory_order mo, - __tsan_memory_order fail_mo); - -__tsan_atomic8 __tsan_atomic8_compare_exchange_val( - volatile __tsan_atomic8 *a, __tsan_atomic8 c, __tsan_atomic8 v, - __tsan_memory_order mo, __tsan_memory_order fail_mo); -__tsan_atomic16 __tsan_atomic16_compare_exchange_val( - volatile __tsan_atomic16 *a, __tsan_atomic16 c, __tsan_atomic16 v, - __tsan_memory_order mo, __tsan_memory_order fail_mo); -__tsan_atomic32 __tsan_atomic32_compare_exchange_val( - volatile __tsan_atomic32 *a, __tsan_atomic32 c, __tsan_atomic32 v, - __tsan_memory_order mo, __tsan_memory_order fail_mo); -__tsan_atomic64 __tsan_atomic64_compare_exchange_val( - volatile __tsan_atomic64 *a, __tsan_atomic64 c, __tsan_atomic64 v, - __tsan_memory_order mo, __tsan_memory_order fail_mo); -__tsan_atomic128 __tsan_atomic128_compare_exchange_val( - volatile __tsan_atomic128 *a, __tsan_atomic128 c, __tsan_atomic128 v, - __tsan_memory_order mo, __tsan_memory_order fail_mo); - -void __tsan_atomic_thread_fence(__tsan_memory_order mo); -void __tsan_atomic_signal_fence(__tsan_memory_order mo); - -#ifdef __cplusplus -} // extern "C" -#endif - -#endif // #ifndef TSAN_INTERFACE_ATOMIC_H - -inline Atomic32 NoBarrier_CompareAndSwap(volatile Atomic32 *ptr, - Atomic32 old_value, - Atomic32 new_value) { - Atomic32 cmp = old_value; - __tsan_atomic32_compare_exchange_strong(ptr, &cmp, new_value, - __tsan_memory_order_relaxed, __tsan_memory_order_relaxed); - return cmp; -} - -inline Atomic32 NoBarrier_AtomicExchange(volatile Atomic32 *ptr, - Atomic32 new_value) { - return __tsan_atomic32_exchange(ptr, new_value, - __tsan_memory_order_relaxed); -} - -inline Atomic32 Acquire_AtomicExchange(volatile Atomic32 *ptr, - Atomic32 new_value) { - return __tsan_atomic32_exchange(ptr, new_value, - __tsan_memory_order_acquire); -} - -inline Atomic32 Release_AtomicExchange(volatile Atomic32 *ptr, - Atomic32 new_value) { - return __tsan_atomic32_exchange(ptr, new_value, - __tsan_memory_order_release); -} - -inline Atomic32 NoBarrier_AtomicIncrement(volatile Atomic32 *ptr, - Atomic32 increment) { - return increment + __tsan_atomic32_fetch_add(ptr, increment, - __tsan_memory_order_relaxed); -} - -inline Atomic32 Barrier_AtomicIncrement(volatile Atomic32 *ptr, - Atomic32 increment) { - return increment + __tsan_atomic32_fetch_add(ptr, increment, - __tsan_memory_order_acq_rel); -} - -inline Atomic32 Acquire_CompareAndSwap(volatile Atomic32 *ptr, - Atomic32 old_value, - Atomic32 new_value) { - Atomic32 cmp = old_value; - __tsan_atomic32_compare_exchange_strong(ptr, &cmp, new_value, - __tsan_memory_order_acquire, __tsan_memory_order_acquire); - return cmp; -} - -inline Atomic32 Release_CompareAndSwap(volatile Atomic32 *ptr, - Atomic32 old_value, - Atomic32 new_value) { - Atomic32 cmp = old_value; - __tsan_atomic32_compare_exchange_strong(ptr, &cmp, new_value, - __tsan_memory_order_release, __tsan_memory_order_relaxed); - return cmp; -} - -inline void NoBarrier_Store(volatile Atomic32 *ptr, Atomic32 value) { - __tsan_atomic32_store(ptr, value, __tsan_memory_order_relaxed); -} - -inline void Acquire_Store(volatile Atomic32 *ptr, Atomic32 value) { - __tsan_atomic32_store(ptr, value, __tsan_memory_order_relaxed); - __tsan_atomic_thread_fence(__tsan_memory_order_seq_cst); -} - -inline void Release_Store(volatile Atomic32 *ptr, Atomic32 value) { - __tsan_atomic32_store(ptr, value, __tsan_memory_order_release); -} - -inline Atomic32 NoBarrier_Load(volatile const Atomic32 *ptr) { - return __tsan_atomic32_load(ptr, __tsan_memory_order_relaxed); -} - -inline Atomic32 Acquire_Load(volatile const Atomic32 *ptr) { - return __tsan_atomic32_load(ptr, __tsan_memory_order_acquire); -} - -inline Atomic32 Release_Load(volatile const Atomic32 *ptr) { - __tsan_atomic_thread_fence(__tsan_memory_order_seq_cst); - return __tsan_atomic32_load(ptr, __tsan_memory_order_relaxed); -} - -inline Atomic64 NoBarrier_CompareAndSwap(volatile Atomic64 *ptr, - Atomic64 old_value, - Atomic64 new_value) { - Atomic64 cmp = old_value; - __tsan_atomic64_compare_exchange_strong(ptr, &cmp, new_value, - __tsan_memory_order_relaxed, __tsan_memory_order_relaxed); - return cmp; -} - -inline Atomic64 NoBarrier_AtomicExchange(volatile Atomic64 *ptr, - Atomic64 new_value) { - return __tsan_atomic64_exchange(ptr, new_value, __tsan_memory_order_relaxed); -} - -inline Atomic64 Acquire_AtomicExchange(volatile Atomic64 *ptr, - Atomic64 new_value) { - return __tsan_atomic64_exchange(ptr, new_value, __tsan_memory_order_acquire); -} - -inline Atomic64 Release_AtomicExchange(volatile Atomic64 *ptr, - Atomic64 new_value) { - return __tsan_atomic64_exchange(ptr, new_value, __tsan_memory_order_release); -} - -inline Atomic64 NoBarrier_AtomicIncrement(volatile Atomic64 *ptr, - Atomic64 increment) { - return increment + __tsan_atomic64_fetch_add(ptr, increment, - __tsan_memory_order_relaxed); -} - -inline Atomic64 Barrier_AtomicIncrement(volatile Atomic64 *ptr, - Atomic64 increment) { - return increment + __tsan_atomic64_fetch_add(ptr, increment, - __tsan_memory_order_acq_rel); -} - -inline void NoBarrier_Store(volatile Atomic64 *ptr, Atomic64 value) { - __tsan_atomic64_store(ptr, value, __tsan_memory_order_relaxed); -} - -inline void Acquire_Store(volatile Atomic64 *ptr, Atomic64 value) { - __tsan_atomic64_store(ptr, value, __tsan_memory_order_relaxed); - __tsan_atomic_thread_fence(__tsan_memory_order_seq_cst); -} - -inline void Release_Store(volatile Atomic64 *ptr, Atomic64 value) { - __tsan_atomic64_store(ptr, value, __tsan_memory_order_release); -} - -inline Atomic64 NoBarrier_Load(volatile const Atomic64 *ptr) { - return __tsan_atomic64_load(ptr, __tsan_memory_order_relaxed); -} - -inline Atomic64 Acquire_Load(volatile const Atomic64 *ptr) { - return __tsan_atomic64_load(ptr, __tsan_memory_order_acquire); -} - -inline Atomic64 Release_Load(volatile const Atomic64 *ptr) { - __tsan_atomic_thread_fence(__tsan_memory_order_seq_cst); - return __tsan_atomic64_load(ptr, __tsan_memory_order_relaxed); -} - -inline Atomic64 Acquire_CompareAndSwap(volatile Atomic64 *ptr, - Atomic64 old_value, - Atomic64 new_value) { - Atomic64 cmp = old_value; - __tsan_atomic64_compare_exchange_strong(ptr, &cmp, new_value, - __tsan_memory_order_acquire, __tsan_memory_order_acquire); - return cmp; -} - -inline Atomic64 Release_CompareAndSwap(volatile Atomic64 *ptr, - Atomic64 old_value, - Atomic64 new_value) { - Atomic64 cmp = old_value; - __tsan_atomic64_compare_exchange_strong(ptr, &cmp, new_value, - __tsan_memory_order_release, __tsan_memory_order_relaxed); - return cmp; -} - -inline void MemoryBarrier() { - __tsan_atomic_thread_fence(__tsan_memory_order_seq_cst); -} - -} // namespace base::subtle -} // namespace base - -#undef ATOMICOPS_COMPILER_BARRIER - -#endif // BASE_ATOMICOPS_INTERNALS_TSAN_H_ diff --git a/base/atomicops_internals_x86_gcc.cc b/base/atomicops_internals_x86_gcc.cc deleted file mode 100644 index 933ca51896..0000000000 --- a/base/atomicops_internals_x86_gcc.cc +++ /dev/null @@ -1,104 +0,0 @@ -// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -// This module gets enough CPU information to optimize the -// atomicops module on x86. - -#include - -#include "base/atomicops.h" -#include "base/basictypes.h" - -// This file only makes sense with atomicops_internals_x86_gcc.h -- it -// depends on structs that are defined in that file. If atomicops.h -// doesn't sub-include that file, then we aren't needed, and shouldn't -// try to do anything. -#ifdef BASE_ATOMICOPS_INTERNALS_X86_GCC_H_ - -// Inline cpuid instruction. In PIC compilations, %ebx contains the address -// of the global offset table. To avoid breaking such executables, this code -// must preserve that register's value across cpuid instructions. -#if defined(__i386__) -#define cpuid(a, b, c, d, inp) \ - asm ("mov %%ebx, %%edi\n" \ - "cpuid\n" \ - "xchg %%edi, %%ebx\n" \ - : "=a" (a), "=D" (b), "=c" (c), "=d" (d) : "a" (inp)) -#elif defined (__x86_64__) -#define cpuid(a, b, c, d, inp) \ - asm ("mov %%rbx, %%rdi\n" \ - "cpuid\n" \ - "xchg %%rdi, %%rbx\n" \ - : "=a" (a), "=D" (b), "=c" (c), "=d" (d) : "a" (inp)) -#endif - -#if defined(cpuid) // initialize the struct only on x86 - -// Set the flags so that code will run correctly and conservatively, so even -// if we haven't been initialized yet, we're probably single threaded, and our -// default values should hopefully be pretty safe. -struct AtomicOps_x86CPUFeatureStruct AtomicOps_Internalx86CPUFeatures = { - false, // bug can't exist before process spawns multiple threads - false, // no SSE2 -}; - -// Initialize the AtomicOps_Internalx86CPUFeatures struct. -static void AtomicOps_Internalx86CPUFeaturesInit() { - uint32 eax; - uint32 ebx; - uint32 ecx; - uint32 edx; - - // Get vendor string (issue CPUID with eax = 0) - cpuid(eax, ebx, ecx, edx, 0); - char vendor[13]; - memcpy(vendor, &ebx, 4); - memcpy(vendor + 4, &edx, 4); - memcpy(vendor + 8, &ecx, 4); - vendor[12] = 0; - - // get feature flags in ecx/edx, and family/model in eax - cpuid(eax, ebx, ecx, edx, 1); - - int family = (eax >> 8) & 0xf; // family and model fields - int model = (eax >> 4) & 0xf; - if (family == 0xf) { // use extended family and model fields - family += (eax >> 20) & 0xff; - model += ((eax >> 16) & 0xf) << 4; - } - - // Opteron Rev E has a bug in which on very rare occasions a locked - // instruction doesn't act as a read-acquire barrier if followed by a - // non-locked read-modify-write instruction. Rev F has this bug in - // pre-release versions, but not in versions released to customers, - // so we test only for Rev E, which is family 15, model 32..63 inclusive. - if (strcmp(vendor, "AuthenticAMD") == 0 && // AMD - family == 15 && - 32 <= model && model <= 63) { - AtomicOps_Internalx86CPUFeatures.has_amd_lock_mb_bug = true; - } else { - AtomicOps_Internalx86CPUFeatures.has_amd_lock_mb_bug = false; - } - - // edx bit 26 is SSE2 which we use to tell use whether we can use mfence - AtomicOps_Internalx86CPUFeatures.has_sse2 = ((edx >> 26) & 1); -} - -namespace { - -class AtomicOpsx86Initializer { - public: - AtomicOpsx86Initializer() { - AtomicOps_Internalx86CPUFeaturesInit(); - } -}; - -// A global to get use initialized on startup via static initialization :/ -AtomicOpsx86Initializer g_initer; - -} // namespace - -#endif // if x86 - -#endif // ifdef BASE_ATOMICOPS_INTERNALS_X86_GCC_H_ diff --git a/base/atomicops_internals_x86_gcc.h b/base/atomicops_internals_x86_gcc.h deleted file mode 100644 index ac02b17f5d..0000000000 --- a/base/atomicops_internals_x86_gcc.h +++ /dev/null @@ -1,269 +0,0 @@ -// Copyright (c) 2011 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -// This file is an internal atomic implementation, use base/atomicops.h instead. - -#ifndef BASE_ATOMICOPS_INTERNALS_X86_GCC_H_ -#define BASE_ATOMICOPS_INTERNALS_X86_GCC_H_ - -#include "base/base_export.h" - -// This struct is not part of the public API of this module; clients may not -// use it. (However, it's exported via BASE_EXPORT because clients implicitly -// do use it at link time by inlining these functions.) -// Features of this x86. Values may not be correct before main() is run, -// but are set conservatively. -struct AtomicOps_x86CPUFeatureStruct { - bool has_amd_lock_mb_bug; // Processor has AMD memory-barrier bug; do lfence - // after acquire compare-and-swap. - bool has_sse2; // Processor has SSE2. -}; -BASE_EXPORT extern struct AtomicOps_x86CPUFeatureStruct - AtomicOps_Internalx86CPUFeatures; - -#define ATOMICOPS_COMPILER_BARRIER() __asm__ __volatile__("" : : : "memory") - -namespace base { -namespace subtle { - -// 32-bit low-level operations on any platform. - -inline Atomic32 NoBarrier_CompareAndSwap(volatile Atomic32* ptr, - Atomic32 old_value, - Atomic32 new_value) { - Atomic32 prev; - __asm__ __volatile__("lock; cmpxchgl %1,%2" - : "=a" (prev) - : "q" (new_value), "m" (*ptr), "0" (old_value) - : "memory"); - return prev; -} - -inline Atomic32 NoBarrier_AtomicExchange(volatile Atomic32* ptr, - Atomic32 new_value) { - __asm__ __volatile__("xchgl %1,%0" // The lock prefix is implicit for xchg. - : "=r" (new_value) - : "m" (*ptr), "0" (new_value) - : "memory"); - return new_value; // Now it's the previous value. -} - -inline Atomic32 NoBarrier_AtomicIncrement(volatile Atomic32* ptr, - Atomic32 increment) { - Atomic32 temp = increment; - __asm__ __volatile__("lock; xaddl %0,%1" - : "+r" (temp), "+m" (*ptr) - : : "memory"); - // temp now holds the old value of *ptr - return temp + increment; -} - -inline Atomic32 Barrier_AtomicIncrement(volatile Atomic32* ptr, - Atomic32 increment) { - Atomic32 temp = increment; - __asm__ __volatile__("lock; xaddl %0,%1" - : "+r" (temp), "+m" (*ptr) - : : "memory"); - // temp now holds the old value of *ptr - if (AtomicOps_Internalx86CPUFeatures.has_amd_lock_mb_bug) { - __asm__ __volatile__("lfence" : : : "memory"); - } - return temp + increment; -} - -inline Atomic32 Acquire_CompareAndSwap(volatile Atomic32* ptr, - Atomic32 old_value, - Atomic32 new_value) { - Atomic32 x = NoBarrier_CompareAndSwap(ptr, old_value, new_value); - if (AtomicOps_Internalx86CPUFeatures.has_amd_lock_mb_bug) { - __asm__ __volatile__("lfence" : : : "memory"); - } - return x; -} - -inline Atomic32 Release_CompareAndSwap(volatile Atomic32* ptr, - Atomic32 old_value, - Atomic32 new_value) { - return NoBarrier_CompareAndSwap(ptr, old_value, new_value); -} - -inline void NoBarrier_Store(volatile Atomic32* ptr, Atomic32 value) { - *ptr = value; -} - -#if defined(__x86_64__) - -// 64-bit implementations of memory barrier can be simpler, because it -// "mfence" is guaranteed to exist. -inline void MemoryBarrier() { - __asm__ __volatile__("mfence" : : : "memory"); -} - -inline void Acquire_Store(volatile Atomic32* ptr, Atomic32 value) { - *ptr = value; - MemoryBarrier(); -} - -#else - -inline void MemoryBarrier() { - if (AtomicOps_Internalx86CPUFeatures.has_sse2) { - __asm__ __volatile__("mfence" : : : "memory"); - } else { // mfence is faster but not present on PIII - Atomic32 x = 0; - NoBarrier_AtomicExchange(&x, 0); // acts as a barrier on PIII - } -} - -inline void Acquire_Store(volatile Atomic32* ptr, Atomic32 value) { - if (AtomicOps_Internalx86CPUFeatures.has_sse2) { - *ptr = value; - __asm__ __volatile__("mfence" : : : "memory"); - } else { - NoBarrier_AtomicExchange(ptr, value); - // acts as a barrier on PIII - } -} -#endif - -inline void Release_Store(volatile Atomic32* ptr, Atomic32 value) { - ATOMICOPS_COMPILER_BARRIER(); - *ptr = value; // An x86 store acts as a release barrier. - // See comments in Atomic64 version of Release_Store(), below. -} - -inline Atomic32 NoBarrier_Load(volatile const Atomic32* ptr) { - return *ptr; -} - -inline Atomic32 Acquire_Load(volatile const Atomic32* ptr) { - Atomic32 value = *ptr; // An x86 load acts as a acquire barrier. - // See comments in Atomic64 version of Release_Store(), below. - ATOMICOPS_COMPILER_BARRIER(); - return value; -} - -inline Atomic32 Release_Load(volatile const Atomic32* ptr) { - MemoryBarrier(); - return *ptr; -} - -#if defined(__x86_64__) - -// 64-bit low-level operations on 64-bit platform. - -inline Atomic64 NoBarrier_CompareAndSwap(volatile Atomic64* ptr, - Atomic64 old_value, - Atomic64 new_value) { - Atomic64 prev; - __asm__ __volatile__("lock; cmpxchgq %1,%2" - : "=a" (prev) - : "q" (new_value), "m" (*ptr), "0" (old_value) - : "memory"); - return prev; -} - -inline Atomic64 NoBarrier_AtomicExchange(volatile Atomic64* ptr, - Atomic64 new_value) { - __asm__ __volatile__("xchgq %1,%0" // The lock prefix is implicit for xchg. - : "=r" (new_value) - : "m" (*ptr), "0" (new_value) - : "memory"); - return new_value; // Now it's the previous value. -} - -inline Atomic64 NoBarrier_AtomicIncrement(volatile Atomic64* ptr, - Atomic64 increment) { - Atomic64 temp = increment; - __asm__ __volatile__("lock; xaddq %0,%1" - : "+r" (temp), "+m" (*ptr) - : : "memory"); - // temp now contains the previous value of *ptr - return temp + increment; -} - -inline Atomic64 Barrier_AtomicIncrement(volatile Atomic64* ptr, - Atomic64 increment) { - Atomic64 temp = increment; - __asm__ __volatile__("lock; xaddq %0,%1" - : "+r" (temp), "+m" (*ptr) - : : "memory"); - // temp now contains the previous value of *ptr - if (AtomicOps_Internalx86CPUFeatures.has_amd_lock_mb_bug) { - __asm__ __volatile__("lfence" : : : "memory"); - } - return temp + increment; -} - -inline void NoBarrier_Store(volatile Atomic64* ptr, Atomic64 value) { - *ptr = value; -} - -inline void Acquire_Store(volatile Atomic64* ptr, Atomic64 value) { - *ptr = value; - MemoryBarrier(); -} - -inline void Release_Store(volatile Atomic64* ptr, Atomic64 value) { - ATOMICOPS_COMPILER_BARRIER(); - - *ptr = value; // An x86 store acts as a release barrier - // for current AMD/Intel chips as of Jan 2008. - // See also Acquire_Load(), below. - - // When new chips come out, check: - // IA-32 Intel Architecture Software Developer's Manual, Volume 3: - // System Programming Guide, Chatper 7: Multiple-processor management, - // Section 7.2, Memory Ordering. - // Last seen at: - // http://developer.intel.com/design/pentium4/manuals/index_new.htm - // - // x86 stores/loads fail to act as barriers for a few instructions (clflush - // maskmovdqu maskmovq movntdq movnti movntpd movntps movntq) but these are - // not generated by the compiler, and are rare. Users of these instructions - // need to know about cache behaviour in any case since all of these involve - // either flushing cache lines or non-temporal cache hints. -} - -inline Atomic64 NoBarrier_Load(volatile const Atomic64* ptr) { - return *ptr; -} - -inline Atomic64 Acquire_Load(volatile const Atomic64* ptr) { - Atomic64 value = *ptr; // An x86 load acts as a acquire barrier, - // for current AMD/Intel chips as of Jan 2008. - // See also Release_Store(), above. - ATOMICOPS_COMPILER_BARRIER(); - return value; -} - -inline Atomic64 Release_Load(volatile const Atomic64* ptr) { - MemoryBarrier(); - return *ptr; -} - -inline Atomic64 Acquire_CompareAndSwap(volatile Atomic64* ptr, - Atomic64 old_value, - Atomic64 new_value) { - Atomic64 x = NoBarrier_CompareAndSwap(ptr, old_value, new_value); - if (AtomicOps_Internalx86CPUFeatures.has_amd_lock_mb_bug) { - __asm__ __volatile__("lfence" : : : "memory"); - } - return x; -} - -inline Atomic64 Release_CompareAndSwap(volatile Atomic64* ptr, - Atomic64 old_value, - Atomic64 new_value) { - return NoBarrier_CompareAndSwap(ptr, old_value, new_value); -} - -#endif // defined(__x86_64__) - -} // namespace base::subtle -} // namespace base - -#undef ATOMICOPS_COMPILER_BARRIER - -#endif // BASE_ATOMICOPS_INTERNALS_X86_GCC_H_ diff --git a/base/atomicops_internals_x86_msvc.h b/base/atomicops_internals_x86_msvc.h deleted file mode 100644 index 3a2c72ddb4..0000000000 --- a/base/atomicops_internals_x86_msvc.h +++ /dev/null @@ -1,194 +0,0 @@ -// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -// This file is an internal atomic implementation, use base/atomicops.h instead. - -#ifndef BASE_ATOMICOPS_INTERNALS_X86_MSVC_H_ -#define BASE_ATOMICOPS_INTERNALS_X86_MSVC_H_ - -#include - -#if defined(ARCH_CPU_64_BITS) -// windows.h #defines this (only on x64). This causes problems because the -// public API also uses MemoryBarrier at the public name for this fence. So, on -// X64, undef it, and call its documented -// (http://msdn.microsoft.com/en-us/library/windows/desktop/ms684208.aspx) -// implementation directly. -#undef MemoryBarrier -#endif - -namespace base { -namespace subtle { - -inline Atomic32 NoBarrier_CompareAndSwap(volatile Atomic32* ptr, - Atomic32 old_value, - Atomic32 new_value) { - LONG result = InterlockedCompareExchange( - reinterpret_cast(ptr), - static_cast(new_value), - static_cast(old_value)); - return static_cast(result); -} - -inline Atomic32 NoBarrier_AtomicExchange(volatile Atomic32* ptr, - Atomic32 new_value) { - LONG result = InterlockedExchange( - reinterpret_cast(ptr), - static_cast(new_value)); - return static_cast(result); -} - -inline Atomic32 Barrier_AtomicIncrement(volatile Atomic32* ptr, - Atomic32 increment) { - return InterlockedExchangeAdd( - reinterpret_cast(ptr), - static_cast(increment)) + increment; -} - -inline Atomic32 NoBarrier_AtomicIncrement(volatile Atomic32* ptr, - Atomic32 increment) { - return Barrier_AtomicIncrement(ptr, increment); -} - -#if !(defined(_MSC_VER) && _MSC_VER >= 1400) -#error "We require at least vs2005 for MemoryBarrier" -#endif -inline void MemoryBarrier() { -#if defined(ARCH_CPU_64_BITS) - // See #undef and note at the top of this file. - __faststorefence(); -#else - // We use MemoryBarrier from WinNT.h - ::MemoryBarrier(); -#endif -} - -inline Atomic32 Acquire_CompareAndSwap(volatile Atomic32* ptr, - Atomic32 old_value, - Atomic32 new_value) { - return NoBarrier_CompareAndSwap(ptr, old_value, new_value); -} - -inline Atomic32 Release_CompareAndSwap(volatile Atomic32* ptr, - Atomic32 old_value, - Atomic32 new_value) { - return NoBarrier_CompareAndSwap(ptr, old_value, new_value); -} - -inline void NoBarrier_Store(volatile Atomic32* ptr, Atomic32 value) { - *ptr = value; -} - -inline void Acquire_Store(volatile Atomic32* ptr, Atomic32 value) { - NoBarrier_AtomicExchange(ptr, value); - // acts as a barrier in this implementation -} - -inline void Release_Store(volatile Atomic32* ptr, Atomic32 value) { - *ptr = value; // works w/o barrier for current Intel chips as of June 2005 - // See comments in Atomic64 version of Release_Store() below. -} - -inline Atomic32 NoBarrier_Load(volatile const Atomic32* ptr) { - return *ptr; -} - -inline Atomic32 Acquire_Load(volatile const Atomic32* ptr) { - Atomic32 value = *ptr; - return value; -} - -inline Atomic32 Release_Load(volatile const Atomic32* ptr) { - MemoryBarrier(); - return *ptr; -} - -#if defined(_WIN64) - -// 64-bit low-level operations on 64-bit platform. - -COMPILE_ASSERT(sizeof(Atomic64) == sizeof(PVOID), atomic_word_is_atomic); - -inline Atomic64 NoBarrier_CompareAndSwap(volatile Atomic64* ptr, - Atomic64 old_value, - Atomic64 new_value) { - PVOID result = InterlockedCompareExchangePointer( - reinterpret_cast(ptr), - reinterpret_cast(new_value), reinterpret_cast(old_value)); - return reinterpret_cast(result); -} - -inline Atomic64 NoBarrier_AtomicExchange(volatile Atomic64* ptr, - Atomic64 new_value) { - PVOID result = InterlockedExchangePointer( - reinterpret_cast(ptr), - reinterpret_cast(new_value)); - return reinterpret_cast(result); -} - -inline Atomic64 Barrier_AtomicIncrement(volatile Atomic64* ptr, - Atomic64 increment) { - return InterlockedExchangeAdd64( - reinterpret_cast(ptr), - static_cast(increment)) + increment; -} - -inline Atomic64 NoBarrier_AtomicIncrement(volatile Atomic64* ptr, - Atomic64 increment) { - return Barrier_AtomicIncrement(ptr, increment); -} - -inline void NoBarrier_Store(volatile Atomic64* ptr, Atomic64 value) { - *ptr = value; -} - -inline void Acquire_Store(volatile Atomic64* ptr, Atomic64 value) { - NoBarrier_AtomicExchange(ptr, value); - // acts as a barrier in this implementation -} - -inline void Release_Store(volatile Atomic64* ptr, Atomic64 value) { - *ptr = value; // works w/o barrier for current Intel chips as of June 2005 - - // When new chips come out, check: - // IA-32 Intel Architecture Software Developer's Manual, Volume 3: - // System Programming Guide, Chatper 7: Multiple-processor management, - // Section 7.2, Memory Ordering. - // Last seen at: - // http://developer.intel.com/design/pentium4/manuals/index_new.htm -} - -inline Atomic64 NoBarrier_Load(volatile const Atomic64* ptr) { - return *ptr; -} - -inline Atomic64 Acquire_Load(volatile const Atomic64* ptr) { - Atomic64 value = *ptr; - return value; -} - -inline Atomic64 Release_Load(volatile const Atomic64* ptr) { - MemoryBarrier(); - return *ptr; -} - -inline Atomic64 Acquire_CompareAndSwap(volatile Atomic64* ptr, - Atomic64 old_value, - Atomic64 new_value) { - return NoBarrier_CompareAndSwap(ptr, old_value, new_value); -} - -inline Atomic64 Release_CompareAndSwap(volatile Atomic64* ptr, - Atomic64 old_value, - Atomic64 new_value) { - return NoBarrier_CompareAndSwap(ptr, old_value, new_value); -} - - -#endif // defined(_WIN64) - -} // namespace base::subtle -} // namespace base - -#endif // BASE_ATOMICOPS_INTERNALS_X86_MSVC_H_ diff --git a/base/atomicops_unittest.cc b/base/atomicops_unittest.cc deleted file mode 100644 index d73a098c48..0000000000 --- a/base/atomicops_unittest.cc +++ /dev/null @@ -1,241 +0,0 @@ -// Copyright (c) 2011 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "base/atomicops.h" - -#include - -#include "base/port.h" -#include "testing/gtest/include/gtest/gtest.h" - -template -static void TestAtomicIncrement() { - // For now, we just test single threaded execution - - // use a guard value to make sure the NoBarrier_AtomicIncrement doesn't go - // outside the expected address bounds. This is in particular to - // test that some future change to the asm code doesn't cause the - // 32-bit NoBarrier_AtomicIncrement doesn't do the wrong thing on 64-bit - // machines. - struct { - AtomicType prev_word; - AtomicType count; - AtomicType next_word; - } s; - - AtomicType prev_word_value, next_word_value; - memset(&prev_word_value, 0xFF, sizeof(AtomicType)); - memset(&next_word_value, 0xEE, sizeof(AtomicType)); - - s.prev_word = prev_word_value; - s.count = 0; - s.next_word = next_word_value; - - EXPECT_EQ(base::subtle::NoBarrier_AtomicIncrement(&s.count, 1), 1); - EXPECT_EQ(s.count, 1); - EXPECT_EQ(s.prev_word, prev_word_value); - EXPECT_EQ(s.next_word, next_word_value); - - EXPECT_EQ(base::subtle::NoBarrier_AtomicIncrement(&s.count, 2), 3); - EXPECT_EQ(s.count, 3); - EXPECT_EQ(s.prev_word, prev_word_value); - EXPECT_EQ(s.next_word, next_word_value); - - EXPECT_EQ(base::subtle::NoBarrier_AtomicIncrement(&s.count, 3), 6); - EXPECT_EQ(s.count, 6); - EXPECT_EQ(s.prev_word, prev_word_value); - EXPECT_EQ(s.next_word, next_word_value); - - EXPECT_EQ(base::subtle::NoBarrier_AtomicIncrement(&s.count, -3), 3); - EXPECT_EQ(s.count, 3); - EXPECT_EQ(s.prev_word, prev_word_value); - EXPECT_EQ(s.next_word, next_word_value); - - EXPECT_EQ(base::subtle::NoBarrier_AtomicIncrement(&s.count, -2), 1); - EXPECT_EQ(s.count, 1); - EXPECT_EQ(s.prev_word, prev_word_value); - EXPECT_EQ(s.next_word, next_word_value); - - EXPECT_EQ(base::subtle::NoBarrier_AtomicIncrement(&s.count, -1), 0); - EXPECT_EQ(s.count, 0); - EXPECT_EQ(s.prev_word, prev_word_value); - EXPECT_EQ(s.next_word, next_word_value); - - EXPECT_EQ(base::subtle::NoBarrier_AtomicIncrement(&s.count, -1), -1); - EXPECT_EQ(s.count, -1); - EXPECT_EQ(s.prev_word, prev_word_value); - EXPECT_EQ(s.next_word, next_word_value); - - EXPECT_EQ(base::subtle::NoBarrier_AtomicIncrement(&s.count, -4), -5); - EXPECT_EQ(s.count, -5); - EXPECT_EQ(s.prev_word, prev_word_value); - EXPECT_EQ(s.next_word, next_word_value); - - EXPECT_EQ(base::subtle::NoBarrier_AtomicIncrement(&s.count, 5), 0); - EXPECT_EQ(s.count, 0); - EXPECT_EQ(s.prev_word, prev_word_value); - EXPECT_EQ(s.next_word, next_word_value); -} - - -#define NUM_BITS(T) (sizeof(T) * 8) - - -template -static void TestCompareAndSwap() { - AtomicType value = 0; - AtomicType prev = base::subtle::NoBarrier_CompareAndSwap(&value, 0, 1); - EXPECT_EQ(1, value); - EXPECT_EQ(0, prev); - - // Use test value that has non-zero bits in both halves, more for testing - // 64-bit implementation on 32-bit platforms. - const AtomicType k_test_val = (GG_ULONGLONG(1) << - (NUM_BITS(AtomicType) - 2)) + 11; - value = k_test_val; - prev = base::subtle::NoBarrier_CompareAndSwap(&value, 0, 5); - EXPECT_EQ(k_test_val, value); - EXPECT_EQ(k_test_val, prev); - - value = k_test_val; - prev = base::subtle::NoBarrier_CompareAndSwap(&value, k_test_val, 5); - EXPECT_EQ(5, value); - EXPECT_EQ(k_test_val, prev); -} - - -template -static void TestAtomicExchange() { - AtomicType value = 0; - AtomicType new_value = base::subtle::NoBarrier_AtomicExchange(&value, 1); - EXPECT_EQ(1, value); - EXPECT_EQ(0, new_value); - - // Use test value that has non-zero bits in both halves, more for testing - // 64-bit implementation on 32-bit platforms. - const AtomicType k_test_val = (GG_ULONGLONG(1) << - (NUM_BITS(AtomicType) - 2)) + 11; - value = k_test_val; - new_value = base::subtle::NoBarrier_AtomicExchange(&value, k_test_val); - EXPECT_EQ(k_test_val, value); - EXPECT_EQ(k_test_val, new_value); - - value = k_test_val; - new_value = base::subtle::NoBarrier_AtomicExchange(&value, 5); - EXPECT_EQ(5, value); - EXPECT_EQ(k_test_val, new_value); -} - - -template -static void TestAtomicIncrementBounds() { - // Test at rollover boundary between int_max and int_min - AtomicType test_val = (GG_ULONGLONG(1) << - (NUM_BITS(AtomicType) - 1)); - AtomicType value = -1 ^ test_val; - AtomicType new_value = base::subtle::NoBarrier_AtomicIncrement(&value, 1); - EXPECT_EQ(test_val, value); - EXPECT_EQ(value, new_value); - - base::subtle::NoBarrier_AtomicIncrement(&value, -1); - EXPECT_EQ(-1 ^ test_val, value); - - // Test at 32-bit boundary for 64-bit atomic type. - test_val = GG_ULONGLONG(1) << (NUM_BITS(AtomicType) / 2); - value = test_val - 1; - new_value = base::subtle::NoBarrier_AtomicIncrement(&value, 1); - EXPECT_EQ(test_val, value); - EXPECT_EQ(value, new_value); - - base::subtle::NoBarrier_AtomicIncrement(&value, -1); - EXPECT_EQ(test_val - 1, value); -} - -// Return an AtomicType with the value 0xa5a5a5.. -template -static AtomicType TestFillValue() { - AtomicType val = 0; - memset(&val, 0xa5, sizeof(AtomicType)); - return val; -} - -// This is a simple sanity check that values are correct. Not testing -// atomicity -template -static void TestStore() { - const AtomicType kVal1 = TestFillValue(); - const AtomicType kVal2 = static_cast(-1); - - AtomicType value; - - base::subtle::NoBarrier_Store(&value, kVal1); - EXPECT_EQ(kVal1, value); - base::subtle::NoBarrier_Store(&value, kVal2); - EXPECT_EQ(kVal2, value); - - base::subtle::Acquire_Store(&value, kVal1); - EXPECT_EQ(kVal1, value); - base::subtle::Acquire_Store(&value, kVal2); - EXPECT_EQ(kVal2, value); - - base::subtle::Release_Store(&value, kVal1); - EXPECT_EQ(kVal1, value); - base::subtle::Release_Store(&value, kVal2); - EXPECT_EQ(kVal2, value); -} - -// This is a simple sanity check that values are correct. Not testing -// atomicity -template -static void TestLoad() { - const AtomicType kVal1 = TestFillValue(); - const AtomicType kVal2 = static_cast(-1); - - AtomicType value; - - value = kVal1; - EXPECT_EQ(kVal1, base::subtle::NoBarrier_Load(&value)); - value = kVal2; - EXPECT_EQ(kVal2, base::subtle::NoBarrier_Load(&value)); - - value = kVal1; - EXPECT_EQ(kVal1, base::subtle::Acquire_Load(&value)); - value = kVal2; - EXPECT_EQ(kVal2, base::subtle::Acquire_Load(&value)); - - value = kVal1; - EXPECT_EQ(kVal1, base::subtle::Release_Load(&value)); - value = kVal2; - EXPECT_EQ(kVal2, base::subtle::Release_Load(&value)); -} - -TEST(AtomicOpsTest, Inc) { - TestAtomicIncrement(); - TestAtomicIncrement(); -} - -TEST(AtomicOpsTest, CompareAndSwap) { - TestCompareAndSwap(); - TestCompareAndSwap(); -} - -TEST(AtomicOpsTest, Exchange) { - TestAtomicExchange(); - TestAtomicExchange(); -} - -TEST(AtomicOpsTest, IncrementBounds) { - TestAtomicIncrementBounds(); - TestAtomicIncrementBounds(); -} - -TEST(AtomicOpsTest, Store) { - TestStore(); - TestStore(); -} - -TEST(AtomicOpsTest, Load) { - TestLoad(); - TestLoad(); -} diff --git a/base/auto_reset.h b/base/auto_reset.h deleted file mode 100644 index 32f138e244..0000000000 --- a/base/auto_reset.h +++ /dev/null @@ -1,41 +0,0 @@ -// Copyright (c) 2011 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef BASE_AUTO_RESET_H_ -#define BASE_AUTO_RESET_H_ - -#include "base/basictypes.h" - -// base::AutoReset<> is useful for setting a variable to a new value only within -// a particular scope. An base::AutoReset<> object resets a variable to its -// original value upon destruction, making it an alternative to writing -// "var = false;" or "var = old_val;" at all of a block's exit points. -// -// This should be obvious, but note that an base::AutoReset<> instance should -// have a shorter lifetime than its scoped_variable, to prevent invalid memory -// writes when the base::AutoReset<> object is destroyed. - -namespace base { - -template -class AutoReset { - public: - AutoReset(T* scoped_variable, T new_value) - : scoped_variable_(scoped_variable), - original_value_(*scoped_variable) { - *scoped_variable_ = new_value; - } - - ~AutoReset() { *scoped_variable_ = original_value_; } - - private: - T* scoped_variable_; - T original_value_; - - DISALLOW_COPY_AND_ASSIGN(AutoReset); -}; - -} - -#endif // BASE_AUTO_RESET_H_ diff --git a/base/base.gyp b/base/base.gyp deleted file mode 100644 index e2af06bb6f..0000000000 --- a/base/base.gyp +++ /dev/null @@ -1,1315 +0,0 @@ -# Copyright (c) 2012 The Chromium Authors. All rights reserved. -# Use of this source code is governed by a BSD-style license that can be -# found in the LICENSE file. - -{ - 'variables': { - 'chromium_code': 1, - }, - 'includes': [ - '../build/win_precompile.gypi', - 'base.gypi', - ], - 'targets': [ - { - 'target_name': 'base', - 'type': '<(component)', - 'toolsets': ['host', 'target'], - 'variables': { - 'base_target': 1, - 'enable_wexit_time_destructors': 1, - 'optimize': 'max', - }, - 'dependencies': [ - 'base_static', - 'allocator/allocator.gyp:allocator_extension_thunks', - '../testing/gtest.gyp:gtest_prod', - '../third_party/modp_b64/modp_b64.gyp:modp_b64', - 'third_party/dynamic_annotations/dynamic_annotations.gyp:dynamic_annotations', - ], - # TODO(gregoryd): direct_dependent_settings should be shared with the - # 64-bit target, but it doesn't work due to a bug in gyp - 'direct_dependent_settings': { - 'include_dirs': [ - '..', - ], - }, - 'conditions': [ - ['use_glib==1', { - 'conditions': [ - ['chromeos==1', { - 'sources/': [ ['include', '_chromeos\\.cc$'] ] - }], - ['toolkit_uses_gtk==1', { - 'dependencies': [ - '../build/linux/system.gyp:gtk', - ], - 'export_dependent_settings': [ - '../build/linux/system.gyp:gtk', - ], - }], - ], - 'dependencies': [ - 'symbolize', - '../build/linux/system.gyp:glib', - 'xdg_mime', - ], - 'defines': [ - 'USE_SYMBOLIZE', - ], - 'cflags': [ - '-Wno-write-strings', - ], - 'export_dependent_settings': [ - '../build/linux/system.gyp:glib', - ], - }, { # use_glib!=1 - 'sources/': [ - ['exclude', '/xdg_user_dirs/'], - ['exclude', '_nss\\.cc$'], - ], - }], - ['use_x11==1', { - 'dependencies': [ - '../build/linux/system.gyp:x11', - ], - 'export_dependent_settings': [ - '../build/linux/system.gyp:x11', - ], - }], - ['OS == "android" and _toolset == "host"', { - # Always build base as a static_library for host toolset, even if - # we're doing a component build. Specifically, we only care about the - # target toolset using components since that's what developers are - # focusing on. In theory we should do this more generally for all - # targets when building for host, but getting the gyp magic - # per-toolset for the "component" variable is hard, and we really only - # need base on host. - 'type': 'static_library', - # Base for host support is the minimum required to run the - # ssl false start blacklist tool. It requires further changes - # to generically support host builds (and tests). - # Note: when building for host, gyp has OS == "android", - # hence the *_android.cc files are included but the actual code - # doesn't have OS_ANDROID / ANDROID defined. - 'conditions': [ - # Host build on linux depends on system.gyp::gtk as - # default linux build has TOOLKIT_GTK defined. - ['host_os == "linux"', { - 'sources/': [ - ['include', '^atomicops_internals_x86_gcc\\.cc$'], - ], - 'dependencies': [ - '../build/linux/system.gyp:gtk', - ], - 'export_dependent_settings': [ - '../build/linux/system.gyp:gtk', - ], - }], - ['host_os == "mac"', { - 'sources/': [ - ['exclude', '^native_library_linux\\.cc$'], - ['exclude', '^process_util_linux\\.cc$'], - ['exclude', '^sys_info_linux\\.cc$'], - ['exclude', '^sys_string_conversions_linux\\.cc$'], - ['exclude', '^worker_pool_linux\\.cc$'], - ], - }], - ], - }], - ['OS == "android" and _toolset == "target"', { - 'conditions': [ - ['target_arch == "ia32"', { - 'sources/': [ - ['include', '^atomicops_internals_x86_gcc\\.cc$'], - ], - }], - ['target_arch == "mipsel"', { - 'sources/': [ - ['include', '^atomicops_internals_mips_gcc\\.cc$'], - ], - }], - ], - 'dependencies': [ - 'base_jni_headers', - '../third_party/ashmem/ashmem.gyp:ashmem', - ], - 'include_dirs': [ - '<(SHARED_INTERMEDIATE_DIR)/base', - ], - 'link_settings': { - 'libraries': [ - '-llog', - ], - }, - 'sources!': [ - 'debug/stack_trace_posix.cc', - ], - 'includes': [ - '../build/android/cpufeatures.gypi', - ], - }], - ['OS == "android" and _toolset == "target" and android_webview_build == 0', { - 'dependencies': [ - 'base_java', - ], - }], - ['os_bsd==1', { - 'include_dirs': [ - '/usr/local/include', - ], - 'link_settings': { - 'libraries': [ - '-L/usr/local/lib -lexecinfo', - ], - }, - }], - ['OS == "linux"', { - 'link_settings': { - 'libraries': [ - # We need rt for clock_gettime(). - '-lrt', - # For 'native_library_linux.cc' - '-ldl', - ], - }, - 'conditions': [ - ['linux_use_tcmalloc==0', { - 'defines': [ - 'NO_TCMALLOC', - ], - 'direct_dependent_settings': { - 'defines': [ - 'NO_TCMALLOC', - ], - }, - }], - ], - }], - ['OS == "mac" or (OS == "ios" and _toolset == "host")', { - 'link_settings': { - 'libraries': [ - '$(SDKROOT)/System/Library/Frameworks/AppKit.framework', - '$(SDKROOT)/System/Library/Frameworks/ApplicationServices.framework', - '$(SDKROOT)/System/Library/Frameworks/Carbon.framework', - '$(SDKROOT)/System/Library/Frameworks/CoreFoundation.framework', - '$(SDKROOT)/System/Library/Frameworks/Foundation.framework', - '$(SDKROOT)/System/Library/Frameworks/IOKit.framework', - '$(SDKROOT)/System/Library/Frameworks/Security.framework', - ], - }, - 'dependencies': [ - '../third_party/mach_override/mach_override.gyp:mach_override', - ], - }], - ['OS == "ios" and _toolset != "host"', { - 'link_settings': { - 'libraries': [ - '$(SDKROOT)/System/Library/Frameworks/CoreFoundation.framework', - '$(SDKROOT)/System/Library/Frameworks/CoreGraphics.framework', - '$(SDKROOT)/System/Library/Frameworks/CoreText.framework', - '$(SDKROOT)/System/Library/Frameworks/Foundation.framework', - '$(SDKROOT)/System/Library/Frameworks/UIKit.framework', - ], - }, - }], - ['OS != "win" and OS != "ios"', { - 'dependencies': ['../third_party/libevent/libevent.gyp:libevent'], - },], - ['component=="shared_library"', { - 'conditions': [ - ['OS=="win"', { - 'sources!': [ - 'debug/debug_on_start_win.cc', - ], - }], - ], - }], - ['use_system_nspr==1', { - 'dependencies': [ - 'third_party/nspr/nspr.gyp:nspr', - ], - }], - ], - 'sources': [ - 'third_party/nspr/prcpucfg.h', - 'third_party/nspr/prcpucfg_win.h', - 'third_party/nspr/prtypes.h', - 'third_party/xdg_user_dirs/xdg_user_dir_lookup.cc', - 'third_party/xdg_user_dirs/xdg_user_dir_lookup.h', - 'auto_reset.h', - 'event_recorder.h', - 'event_recorder_stubs.cc', - 'event_recorder_win.cc', - 'linux_util.cc', - 'linux_util.h', - 'md5.cc', - 'md5.h', - 'message_loop/message_pump_android.cc', - 'message_loop/message_pump_android.h', - 'message_loop/message_pump_glib.cc', - 'message_loop/message_pump_glib.h', - 'message_loop/message_pump_gtk.cc', - 'message_loop/message_pump_gtk.h', - 'message_loop/message_pump_io_ios.cc', - 'message_loop/message_pump_io_ios.h', - 'message_loop/message_pump_observer.h', - 'message_loop/message_pump_aurax11.cc', - 'message_loop/message_pump_aurax11.h', - 'message_loop/message_pump_libevent.cc', - 'message_loop/message_pump_libevent.h', - 'message_loop/message_pump_mac.h', - 'message_loop/message_pump_mac.mm', - 'metrics/field_trial.cc', - 'metrics/field_trial.h', - 'posix/file_descriptor_shuffle.cc', - 'posix/file_descriptor_shuffle.h', - 'sync_socket.h', - 'sync_socket_win.cc', - 'sync_socket_posix.cc', - ], - }, - { - 'target_name': 'base_i18n', - 'type': '<(component)', - 'variables': { - 'enable_wexit_time_destructors': 1, - 'optimize': 'max', - }, - 'dependencies': [ - 'base', - 'third_party/dynamic_annotations/dynamic_annotations.gyp:dynamic_annotations', - '../third_party/icu/icu.gyp:icui18n', - '../third_party/icu/icu.gyp:icuuc', - ], - 'conditions': [ - ['toolkit_uses_gtk==1', { - 'dependencies': [ - # i18n/rtl.cc uses gtk - '../build/linux/system.gyp:gtk', - ], - }], - ['OS == "win"', { - # TODO(jschuh): crbug.com/167187 fix size_t to int truncations. - 'msvs_disabled_warnings': [ - 4267, - ], - }], - ], - 'export_dependent_settings': [ - 'base', - ], - 'defines': [ - 'BASE_I18N_IMPLEMENTATION', - ], - 'sources': [ - 'i18n/base_i18n_export.h', - 'i18n/bidi_line_iterator.cc', - 'i18n/bidi_line_iterator.h', - 'i18n/break_iterator.cc', - 'i18n/break_iterator.h', - 'i18n/char_iterator.cc', - 'i18n/char_iterator.h', - 'i18n/case_conversion.cc', - 'i18n/case_conversion.h', - 'i18n/file_util_icu.cc', - 'i18n/file_util_icu.h', - 'i18n/i18n_constants.cc', - 'i18n/i18n_constants.h', - 'i18n/icu_encoding_detection.cc', - 'i18n/icu_encoding_detection.h', - 'i18n/icu_string_conversions.cc', - 'i18n/icu_string_conversions.h', - 'i18n/icu_util.cc', - 'i18n/icu_util.h', - 'i18n/number_formatting.cc', - 'i18n/number_formatting.h', - 'i18n/rtl.cc', - 'i18n/rtl.h', - 'i18n/string_compare.cc', - 'i18n/string_compare.h', - 'i18n/string_search.cc', - 'i18n/string_search.h', - 'i18n/time_formatting.cc', - 'i18n/time_formatting.h', - ], - }, - { - 'target_name': 'base_prefs', - 'type': '<(component)', - 'variables': { - 'enable_wexit_time_destructors': 1, - 'optimize': 'max', - }, - 'dependencies': [ - 'base', - ], - 'export_dependent_settings': [ - 'base', - ], - 'defines': [ - 'BASE_PREFS_IMPLEMENTATION', - ], - 'sources': [ - 'prefs/base_prefs_export.h', - 'prefs/default_pref_store.cc', - 'prefs/default_pref_store.h', - 'prefs/json_pref_store.cc', - 'prefs/json_pref_store.h', - 'prefs/overlay_user_pref_store.cc', - 'prefs/overlay_user_pref_store.h', - 'prefs/persistent_pref_store.h', - 'prefs/pref_change_registrar.cc', - 'prefs/pref_change_registrar.h', - 'prefs/pref_member.cc', - 'prefs/pref_member.h', - 'prefs/pref_notifier.h', - 'prefs/pref_notifier_impl.cc', - 'prefs/pref_notifier_impl.h', - 'prefs/pref_observer.h', - 'prefs/pref_registry.cc', - 'prefs/pref_registry.h', - 'prefs/pref_registry_simple.cc', - 'prefs/pref_registry_simple.h', - 'prefs/pref_service.cc', - 'prefs/pref_service.h', - 'prefs/pref_service_builder.cc', - 'prefs/pref_service_builder.h', - 'prefs/pref_store.cc', - 'prefs/pref_store.h', - 'prefs/pref_value_map.cc', - 'prefs/pref_value_map.h', - 'prefs/pref_value_store.cc', - 'prefs/pref_value_store.h', - 'prefs/value_map_pref_store.cc', - 'prefs/value_map_pref_store.h', - ], - }, - { - 'target_name': 'base_prefs_test_support', - 'type': 'static_library', - 'dependencies': [ - 'base', - 'base_prefs', - '../testing/gmock.gyp:gmock', - ], - 'sources': [ - 'prefs/mock_pref_change_callback.cc', - 'prefs/pref_store_observer_mock.cc', - 'prefs/pref_store_observer_mock.h', - 'prefs/testing_pref_service.cc', - 'prefs/testing_pref_service.h', - 'prefs/testing_pref_store.cc', - 'prefs/testing_pref_store.h', - ], - }, - { - # This is the subset of files from base that should not be used with a - # dynamic library. Note that this library cannot depend on base because - # base depends on base_static. - 'target_name': 'base_static', - 'type': 'static_library', - 'variables': { - 'enable_wexit_time_destructors': 1, - 'optimize': 'max', - }, - 'toolsets': ['host', 'target'], - 'sources': [ - 'base_switches.cc', - 'base_switches.h', - 'win/pe_image.cc', - 'win/pe_image.h', - ], - 'include_dirs': [ - '..', - ], - }, - # Include this target for a main() function that simply instantiates - # and runs a base::TestSuite. - { - 'target_name': 'run_all_unittests', - 'type': 'static_library', - 'dependencies': [ - 'test_support_base', - ], - 'sources': [ - 'test/run_all_unittests.cc', - ], - }, - { - 'target_name': 'base_unittests', - 'type': '<(gtest_target_type)', - 'sources': [ - # Tests. - 'android/activity_status_unittest.cc', - 'android/jni_android_unittest.cc', - 'android/jni_array_unittest.cc', - 'android/jni_string_unittest.cc', - 'android/path_utils_unittest.cc', - 'android/scoped_java_ref_unittest.cc', - 'at_exit_unittest.cc', - 'atomicops_unittest.cc', - 'base64_unittest.cc', - 'bind_helpers_unittest.cc', - 'bind_unittest.cc', - 'bind_unittest.nc', - 'bits_unittest.cc', - 'build_time_unittest.cc', - 'callback_unittest.cc', - 'callback_unittest.nc', - 'cancelable_callback_unittest.cc', - 'command_line_unittest.cc', - 'containers/hash_tables_unittest.cc', - 'containers/linked_list_unittest.cc', - 'containers/mru_cache_unittest.cc', - 'containers/small_map_unittest.cc', - 'containers/stack_container_unittest.cc', - 'cpu_unittest.cc', - 'debug/crash_logging_unittest.cc', - 'debug/leak_tracker_unittest.cc', - 'debug/proc_maps_linux_unittest.cc', - 'debug/stack_trace_unittest.cc', - 'debug/trace_event_memory_unittest.cc', - 'debug/trace_event_unittest.cc', - 'debug/trace_event_unittest.h', - 'debug/trace_event_win_unittest.cc', - 'deferred_sequenced_task_runner_unittest.cc', - 'environment_unittest.cc', - 'file_util_unittest.cc', - 'file_version_info_unittest.cc', - 'files/dir_reader_posix_unittest.cc', - 'files/file_path_unittest.cc', - 'files/file_util_proxy_unittest.cc', - 'files/important_file_writer_unittest.cc', - 'files/scoped_temp_dir_unittest.cc', - 'gmock_unittest.cc', - 'guid_unittest.cc', - 'id_map_unittest.cc', - 'i18n/break_iterator_unittest.cc', - 'i18n/char_iterator_unittest.cc', - 'i18n/case_conversion_unittest.cc', - 'i18n/file_util_icu_unittest.cc', - 'i18n/icu_string_conversions_unittest.cc', - 'i18n/number_formatting_unittest.cc', - 'i18n/rtl_unittest.cc', - 'i18n/string_search_unittest.cc', - 'i18n/time_formatting_unittest.cc', - 'ini_parser_unittest.cc', - 'ios/device_util_unittest.mm', - 'json/json_parser_unittest.cc', - 'json/json_reader_unittest.cc', - 'json/json_value_converter_unittest.cc', - 'json/json_value_serializer_unittest.cc', - 'json/json_writer_unittest.cc', - 'json/string_escape_unittest.cc', - 'lazy_instance_unittest.cc', - 'logging_unittest.cc', - 'mac/bind_objc_block_unittest.mm', - 'mac/foundation_util_unittest.mm', - 'mac/libdispatch_task_runner_unittest.cc', - 'mac/mac_util_unittest.mm', - 'mac/objc_property_releaser_unittest.mm', - 'mac/scoped_nsobject_unittest.mm', - 'mac/scoped_sending_event_unittest.mm', - 'md5_unittest.cc', - 'memory/aligned_memory_unittest.cc', - 'memory/discardable_memory_unittest.cc', - 'memory/linked_ptr_unittest.cc', - 'memory/ref_counted_memory_unittest.cc', - 'memory/ref_counted_unittest.cc', - 'memory/scoped_ptr_unittest.cc', - 'memory/scoped_ptr_unittest.nc', - 'memory/scoped_vector_unittest.cc', - 'memory/shared_memory_unittest.cc', - 'memory/singleton_unittest.cc', - 'memory/weak_ptr_unittest.cc', - 'memory/weak_ptr_unittest.nc', - 'message_loop/message_loop_proxy_impl_unittest.cc', - 'message_loop/message_loop_proxy_unittest.cc', - 'message_loop/message_loop_unittest.cc', - 'message_loop/message_pump_glib_unittest.cc', - 'message_loop/message_pump_io_ios_unittest.cc', - 'message_loop/message_pump_libevent_unittest.cc', - 'metrics/sample_map_unittest.cc', - 'metrics/sample_vector_unittest.cc', - 'metrics/bucket_ranges_unittest.cc', - 'metrics/field_trial_unittest.cc', - 'metrics/histogram_base_unittest.cc', - 'metrics/histogram_unittest.cc', - 'metrics/sparse_histogram_unittest.cc', - 'metrics/stats_table_unittest.cc', - 'metrics/statistics_recorder_unittest.cc', - 'observer_list_unittest.cc', - 'os_compat_android_unittest.cc', - 'path_service_unittest.cc', - 'pickle_unittest.cc', - 'platform_file_unittest.cc', - 'posix/file_descriptor_shuffle_unittest.cc', - 'posix/unix_domain_socket_linux_unittest.cc', - 'power_monitor/power_monitor_unittest.cc', - 'prefs/default_pref_store_unittest.cc', - 'prefs/json_pref_store_unittest.cc', - 'prefs/mock_pref_change_callback.h', - 'prefs/overlay_user_pref_store_unittest.cc', - 'prefs/pref_change_registrar_unittest.cc', - 'prefs/pref_member_unittest.cc', - 'prefs/pref_notifier_impl_unittest.cc', - 'prefs/pref_service_unittest.cc', - 'prefs/pref_value_map_unittest.cc', - 'prefs/pref_value_store_unittest.cc', - 'process/memory_unittest.cc', - 'process/memory_unittest_mac.h', - 'process/memory_unittest_mac.mm', - 'process/process_util_unittest.cc', - 'process/process_util_unittest_ios.cc', - 'profiler/tracked_time_unittest.cc', - 'rand_util_unittest.cc', - 'safe_numerics_unittest.cc', - 'safe_numerics_unittest.nc', - 'scoped_clear_errno_unittest.cc', - 'scoped_native_library_unittest.cc', - 'scoped_observer.h', - 'security_unittest.cc', - 'sequence_checker_unittest.cc', - 'sha1_unittest.cc', - 'stl_util_unittest.cc', - 'strings/nullable_string16_unittest.cc', - 'strings/string16_unittest.cc', - 'strings/stringprintf_unittest.cc', - 'strings/string_number_conversions_unittest.cc', - 'strings/string_piece_unittest.cc', - 'strings/string_split_unittest.cc', - 'strings/string_tokenizer_unittest.cc', - 'strings/string_util_unittest.cc', - 'strings/stringize_macros_unittest.cc', - 'strings/sys_string_conversions_mac_unittest.mm', - 'strings/sys_string_conversions_unittest.cc', - 'strings/utf_offset_string_conversions_unittest.cc', - 'strings/utf_string_conversions_unittest.cc', - 'synchronization/cancellation_flag_unittest.cc', - 'synchronization/condition_variable_unittest.cc', - 'synchronization/lock_unittest.cc', - 'synchronization/waitable_event_unittest.cc', - 'synchronization/waitable_event_watcher_unittest.cc', - 'sys_info_unittest.cc', - 'system_monitor/system_monitor_unittest.cc', - 'task_runner_util_unittest.cc', - 'template_util_unittest.cc', - 'test/expectations/expectation_unittest.cc', - 'test/expectations/parser_unittest.cc', - 'test/trace_event_analyzer_unittest.cc', - 'threading/non_thread_safe_unittest.cc', - 'threading/platform_thread_unittest.cc', - 'threading/sequenced_worker_pool_unittest.cc', - 'threading/simple_thread_unittest.cc', - 'threading/thread_checker_unittest.cc', - 'threading/thread_collision_warner_unittest.cc', - 'threading/thread_id_name_manager_unittest.cc', - 'threading/thread_local_storage_unittest.cc', - 'threading/thread_local_unittest.cc', - 'threading/thread_unittest.cc', - 'threading/watchdog_unittest.cc', - 'threading/worker_pool_posix_unittest.cc', - 'threading/worker_pool_unittest.cc', - 'time/pr_time_unittest.cc', - 'time/time_unittest.cc', - 'time/time_win_unittest.cc', - 'timer/hi_res_timer_manager_unittest.cc', - 'timer/timer_unittest.cc', - 'tools_sanity_unittest.cc', - 'tracked_objects_unittest.cc', - 'tuple_unittest.cc', - 'values_unittest.cc', - 'version_unittest.cc', - 'vlog_unittest.cc', - 'win/dllmain.cc', - 'win/enum_variant_unittest.cc', - 'win/event_trace_consumer_unittest.cc', - 'win/event_trace_controller_unittest.cc', - 'win/event_trace_provider_unittest.cc', - 'win/i18n_unittest.cc', - 'win/iunknown_impl_unittest.cc', - 'win/message_window_unittest.cc', - 'win/object_watcher_unittest.cc', - 'win/pe_image_unittest.cc', - 'win/registry_unittest.cc', - 'win/sampling_profiler_unittest.cc', - 'win/scoped_bstr_unittest.cc', - 'win/scoped_comptr_unittest.cc', - 'win/scoped_handle_unittest.cc', - 'win/scoped_process_information_unittest.cc', - 'win/scoped_variant_unittest.cc', - 'win/shortcut_unittest.cc', - 'win/startup_information_unittest.cc', - 'win/win_util_unittest.cc', - 'win/wrapped_window_proc_unittest.cc', - ], - 'dependencies': [ - 'base', - 'base_i18n', - 'base_prefs', - 'base_prefs_test_support', - 'base_static', - 'run_all_unittests', - 'test_support_base', - 'third_party/dynamic_annotations/dynamic_annotations.gyp:dynamic_annotations', - '../testing/gmock.gyp:gmock', - '../testing/gtest.gyp:gtest', - '../third_party/icu/icu.gyp:icui18n', - '../third_party/icu/icu.gyp:icuuc', - ], - 'includes': ['../build/nocompile.gypi'], - 'variables': { - # TODO(ajwong): Is there a way to autodetect this? - 'module_dir': 'base' - }, - 'conditions': [ - ['use_glib==1', { - 'defines': [ - 'USE_SYMBOLIZE', - ], - }], - ['OS == "android"', { - 'dependencies': [ - 'android/jni_generator/jni_generator.gyp:jni_generator_tests', - ], - 'conditions': [ - ['gtest_target_type == "shared_library"', { - 'dependencies': [ - '../testing/android/native_test.gyp:native_test_native_code', - ], - }], - ], - }], - ['OS == "ios" and _toolset != "host"', { - 'sources/': [ - # Only test the iOS-meaningful portion of process_utils. - ['exclude', '^process/memory_unittest'], - ['exclude', '^process/process_util_unittest\\.cc$'], - ['include', '^process/process_util_unittest_ios\\.cc$'], - # Requires spawning processes. - ['exclude', '^metrics/stats_table_unittest\\.cc$'], - # iOS does not use message_pump_libevent. - ['exclude', '^message_loop/message_pump_libevent_unittest\\.cc$'], - ], - 'conditions': [ - ['coverage != 0', { - 'sources!': [ - # These sources can't be built with coverage due to a toolchain - # bug: http://openradar.appspot.com/radar?id=1499403 - 'json/json_reader_unittest.cc', - 'strings/string_piece_unittest.cc', - - # These tests crash when run with coverage turned on due to an - # issue with llvm_gcda_increment_indirect_counter: - # http://crbug.com/156058 - 'debug/trace_event_unittest.cc', - 'debug/trace_event_unittest.h', - 'logging_unittest.cc', - 'string_util_unittest.cc', - 'test/trace_event_analyzer_unittest.cc', - 'utf_offset_string_conversions_unittest.cc', - ], - }], - ], - 'actions': [ - { - 'action_name': 'copy_test_data', - 'variables': { - 'test_data_files': [ - 'test/data', - ], - 'test_data_prefix': 'base', - }, - 'includes': [ '../build/copy_test_data_ios.gypi' ], - }, - ], - }], - ['use_glib==1', { - 'sources!': [ - 'file_version_info_unittest.cc', - ], - 'conditions': [ - [ 'toolkit_uses_gtk==1', { - 'sources': [ - 'nix/xdg_util_unittest.cc', - ], - 'dependencies': [ - '../build/linux/system.gyp:gtk', - ] - }], - ], - 'dependencies': [ - '../build/linux/system.gyp:glib', - '../build/linux/system.gyp:ssl', - '../tools/xdisplaycheck/xdisplaycheck.gyp:xdisplaycheck', - ], - }, { # use_glib!=1 - 'sources!': [ - 'message_loop/message_pump_glib_unittest.cc', - ] - }], - ['use_ozone == 1', { - 'sources!': [ - 'message_loop/message_pump_glib_unittest.cc', - ] - }], - ['OS == "linux" and linux_use_tcmalloc==1', { - 'dependencies': [ - 'allocator/allocator.gyp:allocator', - ], - }, - ], - ['OS == "win"', { - # This is needed to trigger the dll copy step on windows. - # TODO(mark): This should not be necessary. - 'dependencies': [ - '../third_party/icu/icu.gyp:icudata', - ], - 'sources!': [ - 'file_descriptor_shuffle_unittest.cc', - 'files/dir_reader_posix_unittest.cc', - 'threading/worker_pool_posix_unittest.cc', - 'message_loop/message_pump_libevent_unittest.cc', - ], - # TODO(jschuh): crbug.com/167187 fix size_t to int truncations. - 'msvs_disabled_warnings': [ - 4267, - ], - # This is needed so base_unittests uses the allocator shim, as - # SecurityTest.MemoryAllocationRestriction* tests are dependent - # on tcmalloc. - # TODO(wfh): crbug.com/246278 Move tcmalloc specific tests into - # their own test suite. - 'conditions': [ - ['win_use_allocator_shim==1', { - 'dependencies': [ - 'allocator/allocator.gyp:allocator', - ], - }], - ], - }, { # OS != "win" - 'dependencies': [ - '../third_party/libevent/libevent.gyp:libevent' - ], - 'sources/': [ - ['exclude', '^win/'], - ], - 'sources!': [ - 'debug/trace_event_win_unittest.cc', - 'time/time_win_unittest.cc', - 'win/win_util_unittest.cc', - ], - }], - ['use_system_nspr==1', { - 'dependencies': [ - 'third_party/nspr/nspr.gyp:nspr', - ], - }], - ], # conditions - 'target_conditions': [ - ['OS == "ios" and _toolset != "host"', { - 'sources/': [ - # Pull in specific Mac files for iOS (which have been filtered out - # by file name rules). - ['include', '^mac/objc_property_releaser_unittest\\.mm$'], - ['include', '^mac/bind_objc_block_unittest\\.mm$'], - ['include', '^mac/scoped_nsobject_unittest\\.mm$'], - ['include', '^sys_string_conversions_mac_unittest\\.mm$'], - ], - }], - ['OS == "android"', { - 'sources/': [ - ['include', '^debug/proc_maps_linux_unittest\\.cc$'], - ], - }], - ], # target_conditions - }, - { - 'target_name': 'test_support_base', - 'type': 'static_library', - 'dependencies': [ - 'base', - 'base_static', - 'base_i18n', - '../testing/gmock.gyp:gmock', - '../testing/gtest.gyp:gtest', - 'third_party/dynamic_annotations/dynamic_annotations.gyp:dynamic_annotations', - ], - 'export_dependent_settings': [ - 'base', - ], - 'conditions': [ - ['toolkit_uses_gtk==1', { - 'dependencies': [ - # test_suite initializes GTK. - '../build/linux/system.gyp:gtk', - ], - }], - ['os_posix==0', { - 'sources!': [ - 'test/scoped_locale.cc', - 'test/scoped_locale.h', - ], - }], - ['os_bsd==1', { - 'sources!': [ - 'test/test_file_util_linux.cc', - ], - }], - ], - 'sources': [ - 'perftimer.cc', - 'test/expectations/expectation.cc', - 'test/expectations/expectation.h', - 'test/expectations/parser.cc', - 'test/expectations/parser.h', - 'test/mock_chrome_application_mac.h', - 'test/mock_chrome_application_mac.mm', - 'test/mock_devices_changed_observer.cc', - 'test/mock_devices_changed_observer.h', - 'test/mock_time_provider.cc', - 'test/mock_time_provider.h', - 'test/multiprocess_test.cc', - 'test/multiprocess_test.h', - 'test/multiprocess_test_android.cc', - 'test/null_task_runner.cc', - 'test/null_task_runner.h', - 'test/perf_test_suite.cc', - 'test/perf_test_suite.h', - 'test/power_monitor_test_base.cc', - 'test/power_monitor_test_base.h', - 'test/scoped_locale.cc', - 'test/scoped_locale.h', - 'test/scoped_path_override.cc', - 'test/scoped_path_override.h', - 'test/sequenced_task_runner_test_template.cc', - 'test/sequenced_task_runner_test_template.h', - 'test/sequenced_worker_pool_owner.cc', - 'test/sequenced_worker_pool_owner.h', - 'test/simple_test_clock.cc', - 'test/simple_test_clock.h', - 'test/simple_test_tick_clock.cc', - 'test/simple_test_tick_clock.h', - 'test/task_runner_test_template.cc', - 'test/task_runner_test_template.h', - 'test/test_file_util.cc', - 'test/test_file_util.h', - 'test/test_file_util_linux.cc', - 'test/test_file_util_mac.cc', - 'test/test_file_util_posix.cc', - 'test/test_file_util_win.cc', - 'test/test_launcher.cc', - 'test/test_launcher.h', - 'test/test_listener_ios.h', - 'test/test_listener_ios.mm', - 'test/test_pending_task.cc', - 'test/test_pending_task.h', - 'test/test_process_killer_win.cc', - 'test/test_process_killer_win.h', - 'test/test_reg_util_win.cc', - 'test/test_reg_util_win.h', - 'test/test_shortcut_win.cc', - 'test/test_shortcut_win.h', - 'test/test_simple_task_runner.cc', - 'test/test_simple_task_runner.h', - 'test/test_suite.cc', - 'test/test_suite.h', - 'test/test_support_android.cc', - 'test/test_support_android.h', - 'test/test_support_ios.h', - 'test/test_support_ios.mm', - 'test/test_switches.cc', - 'test/test_switches.h', - 'test/test_timeouts.cc', - 'test/test_timeouts.h', - 'test/thread_test_helper.cc', - 'test/thread_test_helper.h', - 'test/trace_event_analyzer.cc', - 'test/trace_event_analyzer.h', - 'test/values_test_util.cc', - 'test/values_test_util.h', - ], - 'target_conditions': [ - ['OS == "ios"', { - 'sources/': [ - # Pull in specific Mac files for iOS (which have been filtered out - # by file name rules). - ['include', '^test/test_file_util_mac\\.cc$'], - ], - }], - ], # target_conditions - }, - { - 'target_name': 'test_support_perf', - 'type': 'static_library', - 'dependencies': [ - 'base', - '../testing/gtest.gyp:gtest', - ], - 'sources': [ - 'perftimer.cc', - 'test/run_all_perftests.cc', - ], - 'direct_dependent_settings': { - 'defines': [ - 'PERF_TEST', - ], - }, - 'conditions': [ - ['toolkit_uses_gtk==1', { - 'dependencies': [ - # Needed to handle the #include chain: - # base/test/perf_test_suite.h - # base/test/test_suite.h - # gtk/gtk.h - '../build/linux/system.gyp:gtk', - ], - }], - ], - }, - ], - 'conditions': [ - ['OS!="ios"', { - 'targets': [ - { - 'target_name': 'check_example', - 'type': 'executable', - 'sources': [ - 'check_example.cc', - ], - 'dependencies': [ - 'base', - ], - }, - ], - }], - ['OS == "win" and target_arch=="ia32"', { - 'targets': [ - { - 'target_name': 'base_nacl_win64', - 'type': '<(component)', - 'variables': { - 'base_target': 1, - }, - 'dependencies': [ - 'base_static_win64', - 'allocator/allocator.gyp:allocator_extension_thunks_win64', - 'third_party/dynamic_annotations/dynamic_annotations.gyp:dynamic_annotations_win64', - ], - # TODO(gregoryd): direct_dependent_settings should be shared with the - # 32-bit target, but it doesn't work due to a bug in gyp - 'direct_dependent_settings': { - 'include_dirs': [ - '..', - ], - }, - 'defines': [ - '<@(nacl_win64_defines)', - ], - 'sources!': [ - # base64.cc depends on modp_b64. - 'base64.cc', - ], - 'configurations': { - 'Common_Base': { - 'msvs_target_platform': 'x64', - }, - }, - 'conditions': [ - ['component == "shared_library"', { - 'sources!': [ - 'debug/debug_on_start_win.cc', - ], - }], - ], - }, - { - 'target_name': 'base_i18n_nacl_win64', - 'type': '<(component)', - # TODO(gregoryd): direct_dependent_settings should be shared with the - # 32-bit target, but it doesn't work due to a bug in gyp - 'direct_dependent_settings': { - 'include_dirs': [ - '..', - ], - }, - 'defines': [ - '<@(nacl_win64_defines)', - 'BASE_I18N_IMPLEMENTATION', - ], - 'include_dirs': [ - '..', - ], - 'sources': [ - 'i18n/icu_util_nacl_win64.cc', - ], - 'configurations': { - 'Common_Base': { - 'msvs_target_platform': 'x64', - }, - }, - }, - { - # TODO(rvargas): Remove this when gyp finally supports a clean model. - # See bug 36232. - 'target_name': 'base_static_win64', - 'type': 'static_library', - 'sources': [ - 'base_switches.cc', - 'base_switches.h', - 'win/pe_image.cc', - 'win/pe_image.h', - ], - 'sources!': [ - # base64.cc depends on modp_b64. - 'base64.cc', - ], - 'include_dirs': [ - '..', - ], - 'configurations': { - 'Common_Base': { - 'msvs_target_platform': 'x64', - }, - }, - 'defines': [ - 'NACL_WIN64', - ], - # TODO(rvargas): Bug 78117. Remove this. - 'msvs_disabled_warnings': [ - 4244, - ], - }, - ], - }], - ['os_posix==1 and OS!="mac" and OS!="ios"', { - 'targets': [ - { - 'target_name': 'symbolize', - 'type': 'static_library', - 'toolsets': ['host', 'target'], - 'variables': { - 'chromium_code': 0, - }, - 'conditions': [ - ['OS == "solaris"', { - 'include_dirs': [ - '/usr/gnu/include', - '/usr/gnu/include/libelf', - ], - },], - ], - 'cflags': [ - '-Wno-sign-compare', - ], - 'cflags!': [ - '-Wextra', - ], - 'sources': [ - 'third_party/symbolize/config.h', - 'third_party/symbolize/demangle.cc', - 'third_party/symbolize/demangle.h', - 'third_party/symbolize/glog/logging.h', - 'third_party/symbolize/glog/raw_logging.h', - 'third_party/symbolize/symbolize.cc', - 'third_party/symbolize/symbolize.h', - 'third_party/symbolize/utilities.h', - ], - 'include_dirs': [ - '..', - ], - }, - { - 'target_name': 'xdg_mime', - 'type': 'static_library', - 'toolsets': ['host', 'target'], - 'variables': { - 'chromium_code': 0, - }, - 'cflags!': [ - '-Wextra', - ], - 'sources': [ - 'third_party/xdg_mime/xdgmime.c', - 'third_party/xdg_mime/xdgmime.h', - 'third_party/xdg_mime/xdgmimealias.c', - 'third_party/xdg_mime/xdgmimealias.h', - 'third_party/xdg_mime/xdgmimecache.c', - 'third_party/xdg_mime/xdgmimecache.h', - 'third_party/xdg_mime/xdgmimeglob.c', - 'third_party/xdg_mime/xdgmimeglob.h', - 'third_party/xdg_mime/xdgmimeicon.c', - 'third_party/xdg_mime/xdgmimeicon.h', - 'third_party/xdg_mime/xdgmimeint.c', - 'third_party/xdg_mime/xdgmimeint.h', - 'third_party/xdg_mime/xdgmimemagic.c', - 'third_party/xdg_mime/xdgmimemagic.h', - 'third_party/xdg_mime/xdgmimeparent.c', - 'third_party/xdg_mime/xdgmimeparent.h', - ], - }, - ], - }], - ['OS == "android"', { - 'targets': [ - { - 'target_name': 'base_jni_headers', - 'type': 'none', - 'sources': [ - 'android/java/src/org/chromium/base/ActivityStatus.java', - 'android/java/src/org/chromium/base/BuildInfo.java', - 'android/java/src/org/chromium/base/CpuFeatures.java', - 'android/java/src/org/chromium/base/ImportantFileWriterAndroid.java', - 'android/java/src/org/chromium/base/MemoryPressureListener.java', - 'android/java/src/org/chromium/base/JavaHandlerThread.java', - 'android/java/src/org/chromium/base/PathService.java', - 'android/java/src/org/chromium/base/PathUtils.java', - 'android/java/src/org/chromium/base/PowerMonitor.java', - 'android/java/src/org/chromium/base/SystemMessageHandler.java', - 'android/java/src/org/chromium/base/SysUtils.java', - 'android/java/src/org/chromium/base/ThreadUtils.java', - ], - 'conditions': [ - ['google_tv==1', { - 'sources': [ - 'android/java/src/org/chromium/base/ContextTypes.java', - ], - }], - ], - 'variables': { - 'jni_gen_package': 'base', - }, - 'includes': [ '../build/jni_generator.gypi' ], - }, - { - 'target_name': 'base_java', - 'type': 'none', - 'variables': { - 'java_in_dir': '../base/android/java', - }, - 'dependencies': [ - 'base_java_activity_state', - 'base_java_memory_pressure_level_list', - ], - 'includes': [ '../build/java.gypi' ], - 'conditions': [ - ['android_webview_build==0', { - 'dependencies': [ - '../third_party/jsr-305/jsr-305.gyp:jsr_305_javalib', - ], - }] - ], - }, - { - 'target_name': 'base_java_activity_state', - 'type': 'none', - # This target is used to auto-generate ActivityState.java - # from a template file. The source file contains a list of - # Java constant declarations matching the ones in - # android/activity_state_list.h. - 'sources': [ - 'android/java/src/org/chromium/base/ActivityState.template', - ], - 'variables': { - 'package_name': 'org/chromium/base', - 'template_deps': ['android/activity_state_list.h'], - }, - 'includes': [ '../build/android/java_cpp_template.gypi' ], - }, - { - 'target_name': 'base_java_memory_pressure_level_list', - 'type': 'none', - 'sources': [ - 'android/java/src/org/chromium/base/MemoryPressureLevelList.template', - ], - 'variables': { - 'package_name': 'org/chromium/base', - 'template_deps': ['memory/memory_pressure_level_list.h'], - }, - 'includes': [ '../build/android/java_cpp_template.gypi' ], - }, - { - 'target_name': 'base_java_test_support', - 'type': 'none', - 'dependencies': [ - 'base_java', - ], - 'variables': { - 'java_in_dir': '../base/test/android/javatests', - }, - 'includes': [ '../build/java.gypi' ], - }, - { - 'target_name': 'base_javatests', - 'type': 'none', - 'dependencies': [ - 'base_java', - 'base_java_test_support', - ], - 'variables': { - 'java_in_dir': '../base/android/javatests', - }, - 'includes': [ '../build/java.gypi' ], - }, - ], - }], - ['OS == "win"', { - 'targets': [ - { - 'target_name': 'debug_message', - 'type': 'executable', - 'sources': [ - 'debug_message.cc', - ], - 'msvs_settings': { - 'VCLinkerTool': { - 'SubSystem': '2', # Set /SUBSYSTEM:WINDOWS - }, - }, - }, - ], - }], - # Special target to wrap a gtest_target_type == shared_library - # base_unittests into an android apk for execution. - # TODO(jrg): lib.target comes from _InstallableTargetInstallPath() - # in the gyp make generator. What is the correct way to extract - # this path from gyp and into 'raw' for input to antfiles? - # Hard-coding in the gypfile seems a poor choice. - ['OS == "android" and gtest_target_type == "shared_library"', { - 'targets': [ - { - 'target_name': 'base_unittests_apk', - 'type': 'none', - 'dependencies': [ - 'base_java', - 'base_unittests', - ], - 'variables': { - 'test_suite_name': 'base_unittests', - 'input_shlib_path': '<(SHARED_LIB_DIR)/<(SHARED_LIB_PREFIX)base_unittests<(SHARED_LIB_SUFFIX)', - }, - 'includes': [ '../build/apk_test.gypi' ], - }, - ], - }], - ['test_isolation_mode != "noop"', { - 'targets': [ - { - 'target_name': 'base_unittests_run', - 'type': 'none', - 'dependencies': [ - 'base_unittests', - ], - 'includes': [ - '../build/isolate.gypi', - 'base_unittests.isolate', - ], - 'sources': [ - 'base_unittests.isolate', - ], - }, - ], - }], - ], -} diff --git a/base/base.gypi b/base/base.gypi deleted file mode 100644 index 6d82ee335b..0000000000 --- a/base/base.gypi +++ /dev/null @@ -1,894 +0,0 @@ -# Copyright (c) 2012 The Chromium Authors. All rights reserved. -# Use of this source code is governed by a BSD-style license that can be -# found in the LICENSE file. - -{ - 'target_defaults': { - 'variables': { - 'base_target': 0, - }, - 'target_conditions': [ - # This part is shared between the targets defined below. - ['base_target==1', { - 'sources': [ - '../build/build_config.h', - 'third_party/dmg_fp/dmg_fp.h', - 'third_party/dmg_fp/g_fmt.cc', - 'third_party/dmg_fp/dtoa_wrapper.cc', - 'third_party/icu/icu_utf.cc', - 'third_party/icu/icu_utf.h', - 'third_party/nspr/prcpucfg.h', - 'third_party/nspr/prcpucfg_freebsd.h', - 'third_party/nspr/prcpucfg_linux.h', - 'third_party/nspr/prcpucfg_mac.h', - 'third_party/nspr/prcpucfg_nacl.h', - 'third_party/nspr/prcpucfg_openbsd.h', - 'third_party/nspr/prcpucfg_solaris.h', - 'third_party/nspr/prcpucfg_win.h', - 'third_party/nspr/prtime.cc', - 'third_party/nspr/prtime.h', - 'third_party/nspr/prtypes.h', - 'third_party/xdg_mime/xdgmime.h', - 'allocator/allocator_extension.cc', - 'allocator/allocator_extension.h', - 'allocator/type_profiler_control.cc', - 'allocator/type_profiler_control.h', - 'android/activity_status.cc', - 'android/activity_status.h', - 'android/base_jni_registrar.cc', - 'android/base_jni_registrar.h', - 'android/build_info.cc', - 'android/build_info.h', - 'android/cpu_features.cc', - 'android/fifo_utils.cc', - 'android/fifo_utils.h', - 'android/important_file_writer_android.cc', - 'android/important_file_writer_android.h', - 'android/scoped_java_ref.cc', - 'android/scoped_java_ref.h', - 'android/jni_android.cc', - 'android/jni_android.h', - 'android/jni_array.cc', - 'android/jni_array.h', - 'android/jni_helper.cc', - 'android/jni_helper.h', - 'android/jni_registrar.cc', - 'android/jni_registrar.h', - 'android/jni_string.cc', - 'android/jni_string.h', - 'android/memory_pressure_listener_android.cc', - 'android/memory_pressure_listener_android.h', - 'android/java_handler_thread.cc', - 'android/java_handler_thread.h', - 'android/path_service_android.cc', - 'android/path_service_android.h', - 'android/path_utils.cc', - 'android/path_utils.h', - 'android/sys_utils.cc', - 'android/sys_utils.h', - 'android/thread_utils.h', - 'at_exit.cc', - 'at_exit.h', - 'atomic_ref_count.h', - 'atomic_sequence_num.h', - 'atomicops.h', - 'atomicops_internals_gcc.h', - 'atomicops_internals_mac.h', - 'atomicops_internals_tsan.h', - 'atomicops_internals_x86_gcc.cc', - 'atomicops_internals_x86_gcc.h', - 'atomicops_internals_x86_msvc.h', - 'base_export.h', - 'base_paths.cc', - 'base_paths.h', - 'base_paths_android.cc', - 'base_paths_android.h', - 'base_paths_mac.h', - 'base_paths_mac.mm', - 'base_paths_posix.cc', - 'base_paths_posix.h', - 'base_paths_win.cc', - 'base_paths_win.h', - 'base_switches.h', - 'base64.cc', - 'base64.h', - 'basictypes.h', - 'bind.h', - 'bind_helpers.cc', - 'bind_helpers.h', - 'bind_internal.h', - 'bind_internal_win.h', - 'bits.h', - 'build_time.cc', - 'build_time.h', - 'callback.h', - 'callback_helpers.h', - 'callback_internal.cc', - 'callback_internal.h', - 'cancelable_callback.h', - 'chromeos/chromeos_version.cc', - 'chromeos/chromeos_version.h', - 'command_line.cc', - 'command_line.h', - 'compiler_specific.h', - 'containers/hash_tables.h', - 'containers/linked_list.h', - 'containers/mru_cache.h', - 'containers/small_map.h', - 'containers/stack_container.h', - 'cpu.cc', - 'cpu.h', - 'critical_closure.h', - 'critical_closure_ios.mm', - 'debug/alias.cc', - 'debug/alias.h', - 'debug/crash_logging.cc', - 'debug/crash_logging.h', - 'debug/debug_on_start_win.cc', - 'debug/debug_on_start_win.h', - 'debug/debugger.cc', - 'debug/debugger.h', - 'debug/debugger_posix.cc', - 'debug/debugger_win.cc', - # This file depends on files from the 'allocator' target, - # but this target does not depend on 'allocator' (see - # allocator.gyp for details). - 'debug/leak_annotations.h', - 'debug/leak_tracker.h', - 'debug/proc_maps_linux.cc', - 'debug/proc_maps_linux.h', - 'debug/profiler.cc', - 'debug/profiler.h', - 'debug/stack_trace.cc', - 'debug/stack_trace.h', - 'debug/stack_trace_android.cc', - 'debug/stack_trace_ios.mm', - 'debug/stack_trace_posix.cc', - 'debug/stack_trace_win.cc', - 'debug/trace_event.h', - 'debug/trace_event_android.cc', - 'debug/trace_event_impl.cc', - 'debug/trace_event_impl.h', - 'debug/trace_event_impl_constants.cc', - 'debug/trace_event_memory.cc', - 'debug/trace_event_memory.h', - 'debug/trace_event_win.cc', - 'deferred_sequenced_task_runner.cc', - 'deferred_sequenced_task_runner.h', - 'environment.cc', - 'environment.h', - 'file_descriptor_posix.h', - 'file_util.cc', - 'file_util.h', - 'file_util_android.cc', - 'file_util_linux.cc', - 'file_util_mac.mm', - 'file_util_posix.cc', - 'file_util_win.cc', - 'file_version_info.h', - 'file_version_info_mac.h', - 'file_version_info_mac.mm', - 'file_version_info_win.cc', - 'file_version_info_win.h', - 'files/dir_reader_fallback.h', - 'files/dir_reader_linux.h', - 'files/dir_reader_posix.h', - 'files/file_enumerator.cc', - 'files/file_enumerator.h', - 'files/file_enumerator_posix.cc', - 'files/file_enumerator_win.cc', - 'files/file_path.cc', - 'files/file_path.h', - 'files/file_path_constants.cc', - 'files/file_path_watcher.cc', - 'files/file_path_watcher.h', - 'files/file_path_watcher_kqueue.cc', - 'files/file_path_watcher_linux.cc', - 'files/file_path_watcher_stub.cc', - 'files/file_path_watcher_win.cc', - 'files/file_util_proxy.cc', - 'files/file_util_proxy.h', - 'files/important_file_writer.h', - 'files/important_file_writer.cc', - 'files/memory_mapped_file.cc', - 'files/memory_mapped_file.h', - 'files/memory_mapped_file_posix.cc', - 'files/memory_mapped_file_win.cc', - 'files/scoped_platform_file_closer.cc', - 'files/scoped_platform_file_closer.h', - 'files/scoped_temp_dir.cc', - 'files/scoped_temp_dir.h', - 'float_util.h', - 'format_macros.h', - 'gtest_prod_util.h', - 'guid.cc', - 'guid.h', - 'guid_posix.cc', - 'guid_win.cc', - 'hash.cc', - 'hash.h', - 'id_map.h', - 'ini_parser.cc', - 'ini_parser.h', - 'ios/device_util.h', - 'ios/device_util.mm', - 'ios/ios_util.h', - 'ios/ios_util.mm', - 'ios/scoped_critical_action.h', - 'ios/scoped_critical_action.mm', - 'json/json_file_value_serializer.cc', - 'json/json_file_value_serializer.h', - 'json/json_parser.cc', - 'json/json_parser.h', - 'json/json_reader.cc', - 'json/json_reader.h', - 'json/json_string_value_serializer.cc', - 'json/json_string_value_serializer.h', - 'json/json_value_converter.h', - 'json/json_writer.cc', - 'json/json_writer.h', - 'json/string_escape.cc', - 'json/string_escape.h', - 'lazy_instance.cc', - 'lazy_instance.h', - 'location.cc', - 'location.h', - 'logging.cc', - 'logging.h', - 'logging_win.cc', - 'logging_win.h', - 'mac/authorization_util.h', - 'mac/authorization_util.mm', - 'mac/bind_objc_block.h', - 'mac/bundle_locations.h', - 'mac/bundle_locations.mm', - 'mac/cocoa_protocols.h', - 'mac/foundation_util.h', - 'mac/foundation_util.mm', - 'mac/launch_services_util.cc', - 'mac/launch_services_util.h', - 'mac/launchd.cc', - 'mac/launchd.h', - 'mac/libdispatch_task_runner.cc', - 'mac/libdispatch_task_runner.h', - 'mac/mac_logging.h', - 'mac/mac_logging.cc', - 'mac/mac_util.h', - 'mac/mac_util.mm', - 'mac/objc_property_releaser.h', - 'mac/objc_property_releaser.mm', - 'mac/os_crash_dumps.cc', - 'mac/os_crash_dumps.h', - 'mac/scoped_aedesc.h', - 'mac/scoped_authorizationref.h', - 'mac/scoped_block.h', - 'mac/scoped_cftyperef.h', - 'mac/scoped_ioobject.h', - 'mac/scoped_ioplugininterface.h', - 'mac/scoped_launch_data.h', - 'mac/scoped_mach_port.cc', - 'mac/scoped_mach_port.h', - 'mac/scoped_nsautorelease_pool.h', - 'mac/scoped_nsautorelease_pool.mm', - 'mac/scoped_nsexception_enabler.h', - 'mac/scoped_nsexception_enabler.mm', - 'mac/scoped_nsobject.h', - 'mac/scoped_sending_event.h', - 'mac/scoped_sending_event.mm', - 'mac/sdk_forward_declarations.h', - 'memory/aligned_memory.cc', - 'memory/aligned_memory.h', - 'memory/discardable_memory.cc', - 'memory/discardable_memory.h', - 'memory/discardable_memory_android.cc', - 'memory/discardable_memory_mac.cc', - 'memory/linked_ptr.h', - 'memory/manual_constructor.h', - 'memory/memory_pressure_listener.cc', - 'memory/memory_pressure_listener.h', - 'memory/raw_scoped_refptr_mismatch_checker.h', - 'memory/ref_counted.cc', - 'memory/ref_counted.h', - 'memory/ref_counted_delete_on_message_loop.h', - 'memory/ref_counted_memory.cc', - 'memory/ref_counted_memory.h', - 'memory/scoped_handle.h', - 'memory/scoped_open_process.h', - 'memory/scoped_policy.h', - 'memory/scoped_ptr.h', - 'memory/scoped_vector.h', - 'memory/shared_memory.h', - 'memory/shared_memory_android.cc', - 'memory/shared_memory_nacl.cc', - 'memory/shared_memory_posix.cc', - 'memory/shared_memory_win.cc', - 'memory/singleton.cc', - 'memory/singleton.h', - 'memory/weak_ptr.cc', - 'memory/weak_ptr.h', - 'message_loop/incoming_task_queue.cc', - 'message_loop/incoming_task_queue.h', - 'message_loop/message_loop.cc', - 'message_loop/message_loop.h', - 'message_loop/message_loop_proxy.cc', - 'message_loop/message_loop_proxy.h', - 'message_loop/message_loop_proxy_impl.cc', - 'message_loop/message_loop_proxy_impl.h', - 'message_loop/message_pump.cc', - 'message_loop/message_pump.h', - 'message_loop/message_pump_android.cc', - 'message_loop/message_pump_android.h', - 'message_loop/message_pump_default.cc', - 'message_loop/message_pump_default.h', - 'message_loop/message_pump_ozone.cc', - 'message_loop/message_pump_ozone.h', - 'message_loop/message_pump_win.cc', - 'message_loop/message_pump_win.h', - 'metrics/sample_map.cc', - 'metrics/sample_map.h', - 'metrics/sample_vector.cc', - 'metrics/sample_vector.h', - 'metrics/bucket_ranges.cc', - 'metrics/bucket_ranges.h', - 'metrics/histogram.cc', - 'metrics/histogram.h', - 'metrics/histogram_base.cc', - 'metrics/histogram_base.h', - 'metrics/histogram_flattener.h', - 'metrics/histogram_samples.cc', - 'metrics/histogram_samples.h', - 'metrics/histogram_snapshot_manager.cc', - 'metrics/histogram_snapshot_manager.h', - 'metrics/sparse_histogram.cc', - 'metrics/sparse_histogram.h', - 'metrics/statistics_recorder.cc', - 'metrics/statistics_recorder.h', - 'metrics/stats_counters.cc', - 'metrics/stats_counters.h', - 'metrics/stats_table.cc', - 'metrics/stats_table.h', - 'move.h', - 'native_library.h', - 'native_library_mac.mm', - 'native_library_posix.cc', - 'native_library_win.cc', - 'nix/mime_util_xdg.cc', - 'nix/mime_util_xdg.h', - 'nix/xdg_util.cc', - 'nix/xdg_util.h', - 'observer_list.h', - 'observer_list_threadsafe.h', - 'os_compat_android.cc', - 'os_compat_android.h', - 'os_compat_nacl.cc', - 'os_compat_nacl.h', - 'path_service.cc', - 'path_service.h', - 'pending_task.cc', - 'pending_task.h', - 'pickle.cc', - 'pickle.h', - 'platform_file.cc', - 'platform_file.h', - 'platform_file_posix.cc', - 'platform_file_win.cc', - 'port.h', - 'posix/eintr_wrapper.h', - 'posix/global_descriptors.cc', - 'posix/global_descriptors.h', - 'posix/unix_domain_socket_linux.cc', - 'posix/unix_domain_socket_linux.h', - 'power_monitor/power_monitor.cc', - 'power_monitor/power_monitor.h', - 'power_monitor/power_monitor_device_source_android.cc', - 'power_monitor/power_monitor_device_source_android.h', - 'power_monitor/power_monitor_device_source.cc', - 'power_monitor/power_monitor_device_source.h', - 'power_monitor/power_monitor_device_source_ios.mm', - 'power_monitor/power_monitor_device_source_mac.mm', - 'power_monitor/power_monitor_device_source_posix.cc', - 'power_monitor/power_monitor_device_source_win.cc', - 'power_monitor/power_monitor_source.cc', - 'power_monitor/power_monitor_source.h', - 'power_monitor/power_observer.h', - 'process/internal_linux.cc', - 'process/internal_linux.h', - 'process/kill.cc', - 'process/kill.h', - 'process/kill_mac.cc', - 'process/kill_posix.cc', - 'process/kill_win.cc', - 'process/launch.h', - 'process/launch_ios.cc', - 'process/launch_mac.cc', - 'process/launch_posix.cc', - 'process/launch_win.cc', - 'process/memory.h', - 'process/memory_linux.cc', - 'process/memory_mac.mm', - 'process/memory_win.cc', - 'process/process.h', - 'process/process_handle_freebsd.cc', - 'process/process_handle_linux.cc', - 'process/process_handle_mac.cc', - 'process/process_handle_openbsd.cc', - 'process/process_handle_posix.cc', - 'process/process_handle_win.cc', - 'process/process_info.h', - 'process/process_info_linux.cc', - 'process/process_info_mac.cc', - 'process/process_info_win.cc', - 'process/process_iterator.cc', - 'process/process_iterator.h', - 'process/process_iterator_freebsd.cc', - 'process/process_iterator_linux.cc', - 'process/process_iterator_mac.cc', - 'process/process_iterator_openbsd.cc', - 'process/process_iterator_win.cc', - 'process/process_linux.cc', - 'process/process_metrics.h', - 'process/process_metrics_freebsd.cc', - 'process/process_metrics_ios.cc', - 'process/process_metrics_linux.cc', - 'process/process_metrics_mac.cc', - 'process/process_metrics_openbsd.cc', - 'process/process_metrics_posix.cc', - 'process/process_metrics_win.cc', - 'process/process_posix.cc', - 'process/process_win.cc', - 'profiler/scoped_profile.cc', - 'profiler/scoped_profile.h', - 'profiler/alternate_timer.cc', - 'profiler/alternate_timer.h', - 'profiler/tracked_time.cc', - 'profiler/tracked_time.h', - 'rand_util.cc', - 'rand_util.h', - 'rand_util_nacl.cc', - 'rand_util_posix.cc', - 'rand_util_win.cc', - 'run_loop.cc', - 'run_loop.h', - 'safe_numerics.h', - 'safe_strerror_posix.cc', - 'safe_strerror_posix.h', - 'scoped_native_library.cc', - 'scoped_native_library.h', - 'sequence_checker.h', - 'sequence_checker_impl.cc', - 'sequence_checker_impl.h', - 'sequenced_task_runner.cc', - 'sequenced_task_runner.h', - 'sequenced_task_runner_helpers.h', - 'sha1.h', - 'sha1_portable.cc', - 'sha1_win.cc', - 'single_thread_task_runner.h', - 'stl_util.h', - 'strings/latin1_string_conversions.cc', - 'strings/latin1_string_conversions.h', - 'strings/nullable_string16.cc', - 'strings/nullable_string16.h', - 'strings/string16.cc', - 'strings/string16.h', - 'strings/string_number_conversions.cc', - 'strings/string_split.cc', - 'strings/string_split.h', - 'strings/string_number_conversions.h', - 'strings/string_piece.cc', - 'strings/string_piece.h', - 'strings/string_tokenizer.h', - 'strings/string_util.cc', - 'strings/string_util.h', - 'strings/string_util_constants.cc', - 'strings/string_util_posix.h', - 'strings/string_util_win.h', - 'strings/stringize_macros.h', - 'strings/stringprintf.cc', - 'strings/stringprintf.h', - 'strings/sys_string_conversions.h', - 'strings/sys_string_conversions_mac.mm', - 'strings/sys_string_conversions_posix.cc', - 'strings/sys_string_conversions_win.cc', - 'strings/utf_offset_string_conversions.cc', - 'strings/utf_offset_string_conversions.h', - 'strings/utf_string_conversion_utils.cc', - 'strings/utf_string_conversion_utils.h', - 'strings/utf_string_conversions.cc', - 'strings/utf_string_conversions.h', - 'supports_user_data.cc', - 'supports_user_data.h', - 'synchronization/cancellation_flag.cc', - 'synchronization/cancellation_flag.h', - 'synchronization/condition_variable.h', - 'synchronization/condition_variable_posix.cc', - 'synchronization/condition_variable_win.cc', - 'synchronization/lock.cc', - 'synchronization/lock.h', - 'synchronization/lock_impl.h', - 'synchronization/lock_impl_posix.cc', - 'synchronization/lock_impl_win.cc', - 'synchronization/spin_wait.h', - 'synchronization/waitable_event.h', - 'synchronization/waitable_event_posix.cc', - 'synchronization/waitable_event_watcher.h', - 'synchronization/waitable_event_watcher_posix.cc', - 'synchronization/waitable_event_watcher_win.cc', - 'synchronization/waitable_event_win.cc', - 'system_monitor/system_monitor.cc', - 'system_monitor/system_monitor.h', - 'sys_byteorder.h', - 'sys_info.cc', - 'sys_info.h', - 'sys_info_android.cc', - 'sys_info_chromeos.cc', - 'sys_info_freebsd.cc', - 'sys_info_ios.mm', - 'sys_info_linux.cc', - 'sys_info_mac.cc', - 'sys_info_openbsd.cc', - 'sys_info_posix.cc', - 'sys_info_win.cc', - 'task_runner.cc', - 'task_runner.h', - 'task_runner_util.h', - 'template_util.h', - 'thread_task_runner_handle.cc', - 'thread_task_runner_handle.h', - 'threading/non_thread_safe.h', - 'threading/non_thread_safe_impl.cc', - 'threading/non_thread_safe_impl.h', - 'threading/platform_thread.h', - 'threading/platform_thread_android.cc', - 'threading/platform_thread_linux.cc', - 'threading/platform_thread_mac.mm', - 'threading/platform_thread_posix.cc', - 'threading/platform_thread_win.cc', - 'threading/post_task_and_reply_impl.cc', - 'threading/post_task_and_reply_impl.h', - 'threading/sequenced_worker_pool.cc', - 'threading/sequenced_worker_pool.h', - 'threading/simple_thread.cc', - 'threading/simple_thread.h', - 'threading/thread.cc', - 'threading/thread.h', - 'threading/thread_checker.h', - 'threading/thread_checker_impl.cc', - 'threading/thread_checker_impl.h', - 'threading/thread_collision_warner.cc', - 'threading/thread_collision_warner.h', - 'threading/thread_id_name_manager.cc', - 'threading/thread_id_name_manager.h', - 'threading/thread_local.h', - 'threading/thread_local_posix.cc', - 'threading/thread_local_storage.h', - 'threading/thread_local_storage_posix.cc', - 'threading/thread_local_storage_win.cc', - 'threading/thread_local_win.cc', - 'threading/thread_restrictions.h', - 'threading/thread_restrictions.cc', - 'threading/watchdog.cc', - 'threading/watchdog.h', - 'threading/worker_pool.h', - 'threading/worker_pool.cc', - 'threading/worker_pool_posix.cc', - 'threading/worker_pool_posix.h', - 'threading/worker_pool_win.cc', - 'time/clock.cc', - 'time/clock.h', - 'time/default_clock.cc', - 'time/default_clock.h', - 'time/default_tick_clock.cc', - 'time/default_tick_clock.h', - 'time/tick_clock.cc', - 'time/tick_clock.h', - 'time/time.cc', - 'time/time.h', - 'time/time_mac.cc', - 'time/time_posix.cc', - 'time/time_win.cc', - 'timer/hi_res_timer_manager_posix.cc', - 'timer/hi_res_timer_manager_win.cc', - 'timer/hi_res_timer_manager.h', - 'timer/timer.cc', - 'timer/timer.h', - 'tracked_objects.cc', - 'tracked_objects.h', - 'tracking_info.cc', - 'tracking_info.h', - 'tuple.h', - 'values.cc', - 'values.h', - 'value_conversions.cc', - 'value_conversions.h', - 'version.cc', - 'version.h', - 'vlog.cc', - 'vlog.h', - 'win/enum_variant.cc', - 'win/enum_variant.h', - 'win/event_trace_consumer.h', - 'win/event_trace_controller.cc', - 'win/event_trace_controller.h', - 'win/event_trace_provider.cc', - 'win/event_trace_provider.h', - 'win/i18n.cc', - 'win/i18n.h', - 'win/iat_patch_function.cc', - 'win/iat_patch_function.h', - 'win/iunknown_impl.cc', - 'win/iunknown_impl.h', - 'win/message_window.cc', - 'win/message_window.h', - 'win/metro.cc', - 'win/metro.h', - 'win/object_watcher.cc', - 'win/object_watcher.h', - 'win/registry.cc', - 'win/registry.h', - 'win/resource_util.cc', - 'win/resource_util.h', - 'win/sampling_profiler.cc', - 'win/sampling_profiler.h', - 'win/scoped_bstr.cc', - 'win/scoped_bstr.h', - 'win/scoped_co_mem.h', - 'win/scoped_com_initializer.h', - 'win/scoped_comptr.h', - 'win/scoped_gdi_object.h', - 'win/scoped_handle.cc', - 'win/scoped_handle.h', - 'win/scoped_hdc.h', - 'win/scoped_hglobal.h', - 'win/scoped_process_information.cc', - 'win/scoped_process_information.h', - 'win/scoped_propvariant.h', - 'win/scoped_select_object.h', - 'win/scoped_variant.cc', - 'win/scoped_variant.h', - 'win/shortcut.cc', - 'win/shortcut.h', - 'win/startup_information.cc', - 'win/startup_information.h', - 'win/text_services_message_filter.cc', - 'win/text_services_message_filter.h', - 'win/win_util.cc', - 'win/win_util.h', - 'win/windows_version.cc', - 'win/windows_version.h', - 'win/wrapped_window_proc.cc', - 'win/wrapped_window_proc.h', - ], - 'conditions': [ - ['google_tv==1', { - 'sources': [ - 'android/context_types.cc', - 'android/context_types.h', - ], - }], - ], - 'defines': [ - 'BASE_IMPLEMENTATION', - ], - 'include_dirs': [ - '..', - ], - 'msvs_disabled_warnings': [ - 4018, - ], - 'target_conditions': [ - ['<(use_glib)==0 or >(nacl_untrusted_build)==1', { - 'sources/': [ - ['exclude', '^nix/'], - ], - 'sources!': [ - 'atomicops_internals_x86_gcc.cc', - 'message_loop/message_pump_glib.cc', - 'message_loop/message_pump_aurax11.cc', - ], - }], - ['<(toolkit_uses_gtk)==0 or >(nacl_untrusted_build)==1', { - 'sources!': ['message_loop/message_pump_gtk.cc'], - }], - ['(OS != "linux" and <(os_bsd) != 1 and OS != "android") or >(nacl_untrusted_build)==1', { - 'sources!': [ - # Not automatically excluded by the *linux.cc rules. - 'linux_util.cc', - ], - }, - ], - ['>(nacl_untrusted_build)==1', { - 'sources!': [ - 'allocator/type_profiler_control.cc', - 'allocator/type_profiler_control.h', - 'base_paths.cc', - 'cpu.cc', - 'debug/stack_trace_posix.cc', - 'file_util.cc', - 'file_util_posix.cc', - 'files/file_enumerator_posix.cc', - 'files/file_path_watcher_kqueue.cc', - 'files/file_util_proxy.cc', - 'memory/shared_memory_posix.cc', - 'native_library_posix.cc', - 'path_service.cc', - 'posix/unix_domain_socket_linux.cc', - 'process/kill_posix.cc', - 'process/launch_posix.cc', - 'process/process_metrics_posix.cc', - 'process/process_posix.cc', - 'rand_util_posix.cc', - 'scoped_native_library.cc', - 'files/scoped_temp_dir.cc', - 'sys_info_posix.cc', - 'third_party/dynamic_annotations/dynamic_annotations.c', - ], - 'sources/': [ - # Metrics won't work in the NaCl sandbox. - ['exclude', '^metrics/'], - ['include', '^threading/platform_thread_linux\\.cc$'], - ], - }], - ['OS == "android" and >(nacl_untrusted_build)==0', { - 'sources!': [ - 'base_paths_posix.cc', - 'files/file_path_watcher_kqueue.cc', - 'files/file_path_watcher_stub.cc', - 'power_monitor/power_monitor_device_source_posix.cc', - ], - 'sources/': [ - ['include', '^debug/proc_maps_linux\\.cc$'], - ['include', '^files/file_path_watcher_linux\\.cc$'], - ['include', '^process/memory_linux\\.cc$'], - ['include', '^process/internal_linux\\.cc$'], - ['include', '^process/process_handle_linux\\.cc$'], - ['include', '^process/process_iterator\\.cc$'], - ['include', '^process/process_iterator_linux\\.cc$'], - ['include', '^process/process_metrics_linux\\.cc$'], - ['include', '^posix/unix_domain_socket_linux\\.cc$'], - ['include', '^strings/sys_string_conversions_posix\\.cc$'], - ['include', '^sys_info_linux\\.cc$'], - ['include', '^worker_pool_linux\\.cc$'], - ], - }], - ['OS == "android" and _toolset == "host" and host_os == "linux"', { - 'sources/': [ - # Pull in specific files for host builds. - ['include', '^threading/platform_thread_linux\\.cc$'], - ], - }], - ['OS == "ios" and _toolset != "host"', { - 'sources/': [ - # Pull in specific Mac files for iOS (which have been filtered out - # by file name rules). - ['include', '^atomicops_internals_mac\\.'], - ['include', '^base_paths_mac\\.'], - ['include', '^file_util_mac\\.'], - ['include', '^file_version_info_mac\\.'], - ['include', '^mac/bundle_locations\\.'], - ['include', '^mac/foundation_util\\.'], - ['include', '^mac/mac_logging\\.'], - ['include', '^mac/objc_property_releaser\\.'], - ['include', '^mac/scoped_mach_port\\.'], - ['include', '^mac/scoped_nsautorelease_pool\\.'], - ['include', '^mac/scoped_nsobject\\.'], - ['include', '^memory/discardable_memory_mac\\.'], - ['include', '^message_loop/message_pump_mac\\.'], - ['include', '^strings/sys_string_conversions_mac\\.'], - ['include', '^threading/platform_thread_mac\\.'], - ['include', '^time/time_mac\\.'], - ['include', '^worker_pool_mac\\.'], - # Exclude all process/ except the minimal implementation - # needed on iOS (mostly for unit tests). - ['exclude', '^process/.*'], - ['include', '^process/.*_ios\.(cc|mm)$'], - ['include', '^process/memory_stubs\.cc$'], - ['include', '^process/process_handle_posix\.cc$'], - ], - 'sources': [ - 'process/memory_stubs.cc', - ], - 'sources!': [ - 'message_loop/message_pump_libevent.cc' - ], - }], - ['OS == "ios" and _toolset == "host"', { - 'sources/': [ - # Copied filename_rules to switch from iOS to Mac inclusions. - ['include', '_(cocoa|mac)(_unittest)?\\.(h|cc|mm?)$'], - ['include', '(^|/)(cocoa|mac)/'], - ['exclude', '_ios(_unittest)?\\.(h|cc|mm?)$'], - ['exclude', '(^|/)ios/'], - ] - }], - ['OS != "mac" or >(nacl_untrusted_build)==1', { - 'sources!': [ - 'mac/scoped_aedesc.h' - ], - }], - # For now, just test the *BSD platforms enough to exclude them. - # Subsequent changes will include them further. - ['OS != "freebsd" or >(nacl_untrusted_build)==1', { - 'sources/': [ ['exclude', '_freebsd\\.cc$'] ], - }, - ], - ['OS != "openbsd" or >(nacl_untrusted_build)==1', { - 'sources/': [ ['exclude', '_openbsd\\.cc$'] ], - }, - ], - ['OS != "win" or >(nacl_untrusted_build)==1', { - 'sources/': [ ['exclude', '^win/'] ], - }, - ], - ['OS != "android" or >(nacl_untrusted_build)==1', { - 'sources/': [ ['exclude', '^android/'] ], - }, - ], - ['OS == "win" and >(nacl_untrusted_build)==0', { - 'include_dirs': [ - '<(DEPTH)/third_party/wtl/include', - ], - 'sources!': [ - 'event_recorder_stubs.cc', - 'files/file_path_watcher_kqueue.cc', - 'files/file_path_watcher_stub.cc', - 'message_loop/message_pump_libevent.cc', - 'posix/file_descriptor_shuffle.cc', - # Not using sha1_win.cc because it may have caused a - # regression to page cycler moz. - 'sha1_win.cc', - 'strings/string16.cc', - ], - },], - ['<(use_ozone) == 1', { - 'sources!': [ - 'message_loop/message_pump_glib.cc', - 'message_loop/message_pump_aurax11.cc', - ] - }], - ['OS == "linux" and >(nacl_untrusted_build)==0', { - 'sources!': [ - 'files/file_path_watcher_kqueue.cc', - 'files/file_path_watcher_stub.cc', - ], - }], - ['(OS == "mac" or OS == "ios") and >(nacl_untrusted_build)==0', { - 'sources/': [ - ['exclude', '^files/file_path_watcher_stub\\.cc$'], - ['exclude', '^base_paths_posix\\.cc$'], - ['exclude', '^native_library_posix\\.cc$'], - ['exclude', '^strings/sys_string_conversions_posix\\.cc$'], - ], - }], - ['<(os_bsd)==1 and >(nacl_untrusted_build)==0', { - 'sources': [ - 'process/memory_stubs.cc', - ], - 'sources/': [ - ['exclude', '^files/file_path_watcher_linux\\.cc$'], - ['exclude', '^files/file_path_watcher_stub\\.cc$'], - ['exclude', '^file_util_linux\\.cc$'], - ['exclude', '^process/process_linux\\.cc$'], - ['exclude', '^sys_info_linux\\.cc$'], - ], - }], - ['<(chromeos)!=1 or >(nacl_untrusted_build)==1', { - 'sources/': [ - ['exclude', '^chromeos/'], - ], - }], - # Remove all unnecessary files for build_nexe.py to avoid exceeding - # command-line-string limitation when building NaCl on Windows. - ['OS == "win" and >(nacl_untrusted_build)==1', { - 'sources/': [ ['exclude', '\\.h$'] ], - }], - ['<(use_system_nspr)==1 and >(nacl_untrusted_build)==0', { - 'sources/': [ - ['exclude', '^third_party/nspr/'], - ], - }], - ], - }], - ], - }, -} diff --git a/base/base64.cc b/base/base64.cc deleted file mode 100644 index 9514b0a5c2..0000000000 --- a/base/base64.cc +++ /dev/null @@ -1,43 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "base/base64.h" - -#include "third_party/modp_b64/modp_b64.h" - -namespace base { - -bool Base64Encode(const StringPiece& input, std::string* output) { - std::string temp; - temp.resize(modp_b64_encode_len(input.size())); // makes room for null byte - - // null terminates result since result is base64 text! - int input_size = static_cast(input.size()); - - // modp_b64_encode_len() returns at least 1, so temp[0] is safe to use. - size_t output_size = modp_b64_encode(&(temp[0]), input.data(), input_size); - if (output_size == MODP_B64_ERROR) - return false; - - temp.resize(output_size); // strips off null byte - output->swap(temp); - return true; -} - -bool Base64Decode(const StringPiece& input, std::string* output) { - std::string temp; - temp.resize(modp_b64_decode_len(input.size())); - - // does not null terminate result since result is binary data! - size_t input_size = input.size(); - size_t output_size = modp_b64_decode(&(temp[0]), input.data(), input_size); - if (output_size == MODP_B64_ERROR) - return false; - - temp.resize(output_size); - output->swap(temp); - return true; -} - -} // namespace base diff --git a/base/base64.h b/base/base64.h deleted file mode 100644 index cc78edce5c..0000000000 --- a/base/base64.h +++ /dev/null @@ -1,25 +0,0 @@ -// Copyright (c) 2011 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef BASE_BASE64_H__ -#define BASE_BASE64_H__ - -#include - -#include "base/base_export.h" -#include "base/strings/string_piece.h" - -namespace base { - -// Encodes the input string in base64. Returns true if successful and false -// otherwise. The output string is only modified if successful. -BASE_EXPORT bool Base64Encode(const StringPiece& input, std::string* output); - -// Decodes the base64 input string. Returns true if successful and false -// otherwise. The output string is only modified if successful. -BASE_EXPORT bool Base64Decode(const StringPiece& input, std::string* output); - -} // namespace base - -#endif // BASE_BASE64_H__ diff --git a/base/base64_unittest.cc b/base/base64_unittest.cc deleted file mode 100644 index 9a5dd818e0..0000000000 --- a/base/base64_unittest.cc +++ /dev/null @@ -1,28 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "base/base64.h" - -#include "testing/gtest/include/gtest/gtest.h" - -namespace base { - -TEST(Base64Test, Basic) { - const std::string kText = "hello world"; - const std::string kBase64Text = "aGVsbG8gd29ybGQ="; - - std::string encoded; - std::string decoded; - bool ok; - - ok = Base64Encode(kText, &encoded); - EXPECT_TRUE(ok); - EXPECT_EQ(kBase64Text, encoded); - - ok = Base64Decode(encoded, &decoded); - EXPECT_TRUE(ok); - EXPECT_EQ(kText, decoded); -} - -} // namespace base diff --git a/base/base_export.h b/base/base_export.h deleted file mode 100644 index 723b38a60f..0000000000 --- a/base/base_export.h +++ /dev/null @@ -1,34 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef BASE_BASE_EXPORT_H_ -#define BASE_BASE_EXPORT_H_ - -#if defined(COMPONENT_BUILD) -#if defined(WIN32) - -#if defined(BASE_IMPLEMENTATION) -#define BASE_EXPORT __declspec(dllexport) -#define BASE_EXPORT_PRIVATE __declspec(dllexport) -#else -#define BASE_EXPORT __declspec(dllimport) -#define BASE_EXPORT_PRIVATE __declspec(dllimport) -#endif // defined(BASE_IMPLEMENTATION) - -#else // defined(WIN32) -#if defined(BASE_IMPLEMENTATION) -#define BASE_EXPORT __attribute__((visibility("default"))) -#define BASE_EXPORT_PRIVATE __attribute__((visibility("default"))) -#else -#define BASE_EXPORT -#define BASE_EXPORT_PRIVATE -#endif // defined(BASE_IMPLEMENTATION) -#endif - -#else // defined(COMPONENT_BUILD) -#define BASE_EXPORT -#define BASE_EXPORT_PRIVATE -#endif - -#endif // BASE_BASE_EXPORT_H_ diff --git a/base/base_paths.cc b/base/base_paths.cc deleted file mode 100644 index 9f2b250561..0000000000 --- a/base/base_paths.cc +++ /dev/null @@ -1,47 +0,0 @@ -// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "base/base_paths.h" - -#include "base/file_util.h" -#include "base/files/file_path.h" -#include "base/path_service.h" - -namespace base { - -bool PathProvider(int key, FilePath* result) { - // NOTE: DIR_CURRENT is a special case in PathService::Get - - FilePath cur; - switch (key) { - case DIR_EXE: - PathService::Get(FILE_EXE, &cur); - cur = cur.DirName(); - break; - case DIR_MODULE: - PathService::Get(FILE_MODULE, &cur); - cur = cur.DirName(); - break; - case DIR_TEMP: - if (!file_util::GetTempDir(&cur)) - return false; - break; - case DIR_TEST_DATA: - if (!PathService::Get(DIR_SOURCE_ROOT, &cur)) - return false; - cur = cur.Append(FILE_PATH_LITERAL("base")); - cur = cur.Append(FILE_PATH_LITERAL("test")); - cur = cur.Append(FILE_PATH_LITERAL("data")); - if (!base::PathExists(cur)) // We don't want to create this. - return false; - break; - default: - return false; - } - - *result = cur; - return true; -} - -} // namespace base diff --git a/base/base_paths.h b/base/base_paths.h deleted file mode 100644 index f9601a290a..0000000000 --- a/base/base_paths.h +++ /dev/null @@ -1,51 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef BASE_BASE_PATHS_H_ -#define BASE_BASE_PATHS_H_ - -// This file declares path keys for the base module. These can be used with -// the PathService to access various special directories and files. - -#include "build/build_config.h" - -#if defined(OS_WIN) -#include "base/base_paths_win.h" -#elif defined(OS_MACOSX) -#include "base/base_paths_mac.h" -#elif defined(OS_ANDROID) -#include "base/base_paths_android.h" -#endif - -#if defined(OS_POSIX) -#include "base/base_paths_posix.h" -#endif - -namespace base { - -enum BasePathKey { - PATH_START = 0, - - DIR_CURRENT, // Current directory. - DIR_EXE, // Directory containing FILE_EXE. - DIR_MODULE, // Directory containing FILE_MODULE. - DIR_TEMP, // Temporary directory. - FILE_EXE, // Path and filename of the current executable. - FILE_MODULE, // Path and filename of the module containing the code for - // the PathService (which could differ from FILE_EXE if the - // PathService were compiled into a shared object, for - // example). - DIR_SOURCE_ROOT, // Returns the root of the source tree. This key is useful - // for tests that need to locate various resources. It - // should not be used outside of test code. - DIR_USER_DESKTOP, // The current user's Desktop. - - DIR_TEST_DATA, // Used only for testing. - - PATH_END -}; - -} // namespace base - -#endif // BASE_BASE_PATHS_H_ diff --git a/base/base_paths_android.cc b/base/base_paths_android.cc deleted file mode 100644 index d0a709fc3a..0000000000 --- a/base/base_paths_android.cc +++ /dev/null @@ -1,63 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -// Defines base::PathProviderAndroid which replaces base::PathProviderPosix for -// Android in base/path_service.cc. - -#include - -#include "base/android/jni_android.h" -#include "base/android/path_utils.h" -#include "base/base_paths.h" -#include "base/file_util.h" -#include "base/files/file_path.h" -#include "base/logging.h" -#include "base/process/process_metrics.h" - -namespace base { - -bool PathProviderAndroid(int key, FilePath* result) { - switch (key) { - case base::FILE_EXE: { - char bin_dir[PATH_MAX + 1]; - int bin_dir_size = readlink(kProcSelfExe, bin_dir, PATH_MAX); - if (bin_dir_size < 0 || bin_dir_size > PATH_MAX) { - NOTREACHED() << "Unable to resolve " << kProcSelfExe << "."; - return false; - } - bin_dir[bin_dir_size] = 0; - *result = FilePath(bin_dir); - return true; - } - case base::FILE_MODULE: - // dladdr didn't work in Android as only the file name was returned. - NOTIMPLEMENTED(); - return false; - case base::DIR_MODULE: - return base::android::GetNativeLibraryDirectory(result); - case base::DIR_SOURCE_ROOT: - // This const is only used for tests. - return base::android::GetExternalStorageDirectory(result); - case base::DIR_USER_DESKTOP: - // Android doesn't support GetUserDesktop. - NOTIMPLEMENTED(); - return false; - case base::DIR_CACHE: - return base::android::GetCacheDirectory(result); - case base::DIR_ANDROID_APP_DATA: - return base::android::GetDataDirectory(result); - case base::DIR_HOME: - *result = file_util::GetHomeDir(); - return true; - case base::DIR_ANDROID_EXTERNAL_STORAGE: - return base::android::GetExternalStorageDirectory(result); - default: - // Note: the path system expects this function to override the default - // behavior. So no need to log an error if we don't support a given - // path. The system will just use the default. - return false; - } -} - -} // namespace base diff --git a/base/base_paths_android.h b/base/base_paths_android.h deleted file mode 100644 index 7a9ac4a674..0000000000 --- a/base/base_paths_android.h +++ /dev/null @@ -1,25 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef BASE_BASE_PATHS_ANDROID_H_ -#define BASE_BASE_PATHS_ANDROID_H_ - -// This file declares Android-specific path keys for the base module. -// These can be used with the PathService to access various special -// directories and files. - -namespace base { - -enum { - PATH_ANDROID_START = 300, - - DIR_ANDROID_APP_DATA, // Directory where to put Android app's data. - DIR_ANDROID_EXTERNAL_STORAGE, // Android external storage directory. - - PATH_ANDROID_END -}; - -} // namespace base - -#endif // BASE_BASE_PATHS_ANDROID_H_ diff --git a/base/base_paths_mac.h b/base/base_paths_mac.h deleted file mode 100644 index ac75402f3c..0000000000 --- a/base/base_paths_mac.h +++ /dev/null @@ -1,24 +0,0 @@ -// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef BASE_BASE_PATHS_MAC_H_ -#define BASE_BASE_PATHS_MAC_H_ - -// This file declares Mac-specific path keys for the base module. -// These can be used with the PathService to access various special -// directories and files. - -namespace base { - -enum { - PATH_MAC_START = 200, - - DIR_APP_DATA, // ~/Library/Application Support - - PATH_MAC_END -}; - -} // namespace base - -#endif // BASE_BASE_PATHS_MAC_H_ diff --git a/base/base_paths_mac.mm b/base/base_paths_mac.mm deleted file mode 100644 index 5d4461cb23..0000000000 --- a/base/base_paths_mac.mm +++ /dev/null @@ -1,117 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -// Defines base::PathProviderMac which replaces base::PathProviderPosix for Mac -// in base/path_service.cc. - -#include -#import -#include - -#include "base/base_paths.h" -#include "base/compiler_specific.h" -#include "base/file_util.h" -#include "base/files/file_path.h" -#include "base/logging.h" -#include "base/mac/foundation_util.h" -#include "base/path_service.h" -#include "base/strings/string_util.h" -#include "build/build_config.h" - -namespace { - -void GetNSExecutablePath(base::FilePath* path) { - DCHECK(path); - // Executable path can have relative references ("..") depending on - // how the app was launched. - uint32_t executable_length = 0; - _NSGetExecutablePath(NULL, &executable_length); - DCHECK_GT(executable_length, 1u); - std::string executable_path; - int rv = _NSGetExecutablePath(WriteInto(&executable_path, executable_length), - &executable_length); - DCHECK_EQ(rv, 0); - - // _NSGetExecutablePath may return paths containing ./ or ../ which makes - // FilePath::DirName() work incorrectly, convert it to absolute path so that - // paths such as DIR_SOURCE_ROOT can work, since we expect absolute paths to - // be returned here. - *path = base::MakeAbsoluteFilePath(base::FilePath(executable_path)); -} - -// Returns true if the module for |address| is found. |path| will contain -// the path to the module. Note that |path| may not be absolute. -bool GetModulePathForAddress(base::FilePath* path, - const void* address) WARN_UNUSED_RESULT; - -bool GetModulePathForAddress(base::FilePath* path, const void* address) { - Dl_info info; - if (dladdr(address, &info) == 0) - return false; - *path = base::FilePath(info.dli_fname); - return true; -} - -} // namespace - -namespace base { - -bool PathProviderMac(int key, base::FilePath* result) { - switch (key) { - case base::FILE_EXE: - GetNSExecutablePath(result); - return true; - case base::FILE_MODULE: - return GetModulePathForAddress(result, - reinterpret_cast(&base::PathProviderMac)); - case base::DIR_APP_DATA: { - bool success = base::mac::GetUserDirectory(NSApplicationSupportDirectory, - result); -#if defined(OS_IOS) - // On IOS, this directory does not exist unless it is created explicitly. - if (success && !base::PathExists(*result)) - success = file_util::CreateDirectory(*result); -#endif // defined(OS_IOS) - return success; - } - case base::DIR_SOURCE_ROOT: - // Go through PathService to catch overrides. - if (!PathService::Get(base::FILE_EXE, result)) - return false; - - // Start with the executable's directory. - *result = result->DirName(); - -#if !defined(OS_IOS) - if (base::mac::AmIBundled()) { - // The bundled app executables (Chromium, TestShell, etc) live five - // levels down, eg: - // src/xcodebuild/{Debug|Release}/Chromium.app/Contents/MacOS/Chromium - *result = result->DirName().DirName().DirName().DirName().DirName(); - } else { - // Unit tests execute two levels deep from the source root, eg: - // src/xcodebuild/{Debug|Release}/base_unittests - *result = result->DirName().DirName(); - } -#endif - return true; - case base::DIR_USER_DESKTOP: -#if defined(OS_IOS) - // iOS does not have desktop directories. - NOTIMPLEMENTED(); - return false; -#else - return base::mac::GetUserDirectory(NSDesktopDirectory, result); -#endif - case base::DIR_CACHE: - return base::mac::GetUserDirectory(NSCachesDirectory, result); - case base::DIR_HOME: - *result = base::mac::NSStringToFilePath(NSHomeDirectory()); - return true; - default: - return false; - } -} - -} // namespace base diff --git a/base/base_paths_posix.cc b/base/base_paths_posix.cc deleted file mode 100644 index 2d5fcbd26d..0000000000 --- a/base/base_paths_posix.cc +++ /dev/null @@ -1,119 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -// Defines base::PathProviderPosix, default path provider on POSIX OSes that -// don't have their own base_paths_OS.cc implementation (i.e. all but Mac and -// Android). - -#include -#include - -#include "base/base_paths.h" -#include "base/environment.h" -#include "base/file_util.h" -#include "base/files/file_path.h" -#include "base/logging.h" -#include "base/memory/scoped_ptr.h" -#include "base/nix/xdg_util.h" -#include "base/path_service.h" -#include "base/process/process_metrics.h" -#include "build/build_config.h" - -#if defined(OS_FREEBSD) -#include -#include -#elif defined(OS_SOLARIS) -#include -#endif - -namespace base { - -bool PathProviderPosix(int key, FilePath* result) { - FilePath path; - switch (key) { - case base::FILE_EXE: - case base::FILE_MODULE: { // TODO(evanm): is this correct? -#if defined(OS_LINUX) - FilePath bin_dir; - if (!file_util::ReadSymbolicLink(FilePath(kProcSelfExe), &bin_dir)) { - NOTREACHED() << "Unable to resolve " << kProcSelfExe << "."; - return false; - } - *result = bin_dir; - return true; -#elif defined(OS_FREEBSD) - int name[] = { CTL_KERN, KERN_PROC, KERN_PROC_PATHNAME, -1 }; - char bin_dir[PATH_MAX + 1]; - size_t length = sizeof(bin_dir); - // Upon return, |length| is the number of bytes written to |bin_dir| - // including the string terminator. - int error = sysctl(name, 4, bin_dir, &length, NULL, 0); - if (error < 0 || length <= 1) { - NOTREACHED() << "Unable to resolve path."; - return false; - } - *result = FilePath(FilePath::StringType(bin_dir, length - 1)); - return true; -#elif defined(OS_SOLARIS) - char bin_dir[PATH_MAX + 1]; - if (realpath(getexecname(), bin_dir) == NULL) { - NOTREACHED() << "Unable to resolve " << getexecname() << "."; - return false; - } - *result = FilePath(bin_dir); - return true; -#elif defined(OS_OPENBSD) - // There is currently no way to get the executable path on OpenBSD - char* cpath; - if ((cpath = getenv("CHROME_EXE_PATH")) != NULL) - *result = FilePath(cpath); - else - *result = FilePath("/usr/local/chrome/chrome"); - return true; -#endif - } - case base::DIR_SOURCE_ROOT: { - // Allow passing this in the environment, for more flexibility in build - // tree configurations (sub-project builds, gyp --output_dir, etc.) - scoped_ptr env(base::Environment::Create()); - std::string cr_source_root; - if (env->GetVar("CR_SOURCE_ROOT", &cr_source_root)) { - path = FilePath(cr_source_root); - if (base::PathExists(path)) { - *result = path; - return true; - } else { - DLOG(WARNING) << "CR_SOURCE_ROOT is set, but it appears to not " - << "point to a directory."; - } - } - // On POSIX, unit tests execute two levels deep from the source root. - // For example: out/{Debug|Release}/net_unittest - if (PathService::Get(base::DIR_EXE, &path)) { - *result = path.DirName().DirName(); - return true; - } - - DLOG(ERROR) << "Couldn't find your source root. " - << "Try running from your chromium/src directory."; - return false; - } - case base::DIR_USER_DESKTOP: - *result = base::nix::GetXDGUserDirectory("DESKTOP", "Desktop"); - return true; - case base::DIR_CACHE: { - scoped_ptr env(base::Environment::Create()); - FilePath cache_dir(base::nix::GetXDGDirectory(env.get(), "XDG_CACHE_HOME", - ".cache")); - *result = cache_dir; - return true; - } - case base::DIR_HOME: - *result = file_util::GetHomeDir(); - return true; - } - return false; -} - -} // namespace base diff --git a/base/base_paths_posix.h b/base/base_paths_posix.h deleted file mode 100644 index 811c8cb894..0000000000 --- a/base/base_paths_posix.h +++ /dev/null @@ -1,29 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef BASE_BASE_PATHS_POSIX_H_ -#define BASE_BASE_PATHS_POSIX_H_ - -// This file declares windows-specific path keys for the base module. -// These can be used with the PathService to access various special -// directories and files. - -namespace base { - -enum { - PATH_POSIX_START = 400, - - DIR_CACHE, // Directory where to put cache data. Note this is - // *not* where the browser cache lives, but the - // browser cache can be a subdirectory. - // This is $XDG_CACHE_HOME on Linux and - // ~/Library/Caches on Mac. - DIR_HOME, // $HOME on POSIX-like systems. - - PATH_POSIX_END -}; - -} // namespace base - -#endif // BASE_BASE_PATHS_POSIX_H_ diff --git a/base/base_paths_win.cc b/base/base_paths_win.cc deleted file mode 100644 index bc883358ad..0000000000 --- a/base/base_paths_win.cc +++ /dev/null @@ -1,208 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include -#include - -#include "base/base_paths.h" -#include "base/files/file_path.h" -#include "base/path_service.h" -#include "base/win/scoped_co_mem.h" -#include "base/win/windows_version.h" - -// http://blogs.msdn.com/oldnewthing/archive/2004/10/25/247180.aspx -extern "C" IMAGE_DOS_HEADER __ImageBase; - -using base::FilePath; - -namespace { - -bool GetQuickLaunchPath(bool default_user, FilePath* result) { - if (default_user) { - wchar_t system_buffer[MAX_PATH]; - system_buffer[0] = 0; - // As per MSDN, passing -1 for |hToken| indicates the Default user: - // http://msdn.microsoft.com/library/windows/desktop/bb762181.aspx - if (FAILED(SHGetFolderPath(NULL, CSIDL_APPDATA, - reinterpret_cast(-1), SHGFP_TYPE_CURRENT, - system_buffer))) { - return false; - } - *result = FilePath(system_buffer); - } else if (!PathService::Get(base::DIR_APP_DATA, result)) { - // For the current user, grab the APPDATA directory directly from the - // PathService cache. - return false; - } - // According to various sources, appending - // "Microsoft\Internet Explorer\Quick Launch" to %appdata% is the only - // reliable way to get the quick launch folder across all versions of Windows. - // http://stackoverflow.com/questions/76080/how-do-you-reliably-get-the-quick- - // http://www.microsoft.com/technet/scriptcenter/resources/qanda/sept05/hey0901.mspx - *result = result->AppendASCII("Microsoft"); - *result = result->AppendASCII("Internet Explorer"); - *result = result->AppendASCII("Quick Launch"); - return true; -} - -} // namespace - -namespace base { - -bool PathProviderWin(int key, FilePath* result) { - // We need to go compute the value. It would be nice to support paths with - // names longer than MAX_PATH, but the system functions don't seem to be - // designed for it either, with the exception of GetTempPath (but other - // things will surely break if the temp path is too long, so we don't bother - // handling it. - wchar_t system_buffer[MAX_PATH]; - system_buffer[0] = 0; - - FilePath cur; - switch (key) { - case base::FILE_EXE: - GetModuleFileName(NULL, system_buffer, MAX_PATH); - cur = FilePath(system_buffer); - break; - case base::FILE_MODULE: { - // the resource containing module is assumed to be the one that - // this code lives in, whether that's a dll or exe - HMODULE this_module = reinterpret_cast(&__ImageBase); - GetModuleFileName(this_module, system_buffer, MAX_PATH); - cur = FilePath(system_buffer); - break; - } - case base::DIR_WINDOWS: - GetWindowsDirectory(system_buffer, MAX_PATH); - cur = FilePath(system_buffer); - break; - case base::DIR_SYSTEM: - GetSystemDirectory(system_buffer, MAX_PATH); - cur = FilePath(system_buffer); - break; - case base::DIR_PROGRAM_FILESX86: - if (base::win::OSInfo::GetInstance()->architecture() != - base::win::OSInfo::X86_ARCHITECTURE) { - if (FAILED(SHGetFolderPath(NULL, CSIDL_PROGRAM_FILESX86, NULL, - SHGFP_TYPE_CURRENT, system_buffer))) - return false; - cur = FilePath(system_buffer); - break; - } - // Fall through to base::DIR_PROGRAM_FILES if we're on an X86 machine. - case base::DIR_PROGRAM_FILES: - if (FAILED(SHGetFolderPath(NULL, CSIDL_PROGRAM_FILES, NULL, - SHGFP_TYPE_CURRENT, system_buffer))) - return false; - cur = FilePath(system_buffer); - break; - case base::DIR_IE_INTERNET_CACHE: - if (FAILED(SHGetFolderPath(NULL, CSIDL_INTERNET_CACHE, NULL, - SHGFP_TYPE_CURRENT, system_buffer))) - return false; - cur = FilePath(system_buffer); - break; - case base::DIR_COMMON_START_MENU: - if (FAILED(SHGetFolderPath(NULL, CSIDL_COMMON_PROGRAMS, NULL, - SHGFP_TYPE_CURRENT, system_buffer))) - return false; - cur = FilePath(system_buffer); - break; - case base::DIR_START_MENU: - if (FAILED(SHGetFolderPath(NULL, CSIDL_PROGRAMS, NULL, - SHGFP_TYPE_CURRENT, system_buffer))) - return false; - cur = FilePath(system_buffer); - break; - case base::DIR_APP_DATA: - if (FAILED(SHGetFolderPath(NULL, CSIDL_APPDATA, NULL, SHGFP_TYPE_CURRENT, - system_buffer))) - return false; - cur = FilePath(system_buffer); - break; - case base::DIR_COMMON_APP_DATA: - if (FAILED(SHGetFolderPath(NULL, CSIDL_COMMON_APPDATA, NULL, - SHGFP_TYPE_CURRENT, system_buffer))) - return false; - cur = FilePath(system_buffer); - break; - case base::DIR_PROFILE: - if (FAILED(SHGetFolderPath(NULL, CSIDL_PROFILE, NULL, SHGFP_TYPE_CURRENT, - system_buffer))) - return false; - cur = FilePath(system_buffer); - break; - case base::DIR_LOCAL_APP_DATA_LOW: - if (win::GetVersion() < win::VERSION_VISTA) - return false; - - // TODO(nsylvain): We should use SHGetKnownFolderPath instead. Bug 1281128 - if (FAILED(SHGetFolderPath(NULL, CSIDL_APPDATA, NULL, SHGFP_TYPE_CURRENT, - system_buffer))) - return false; - cur = FilePath(system_buffer).DirName().AppendASCII("LocalLow"); - break; - case base::DIR_LOCAL_APP_DATA: - if (FAILED(SHGetFolderPath(NULL, CSIDL_LOCAL_APPDATA, NULL, - SHGFP_TYPE_CURRENT, system_buffer))) - return false; - cur = FilePath(system_buffer); - break; - case base::DIR_SOURCE_ROOT: { - FilePath executableDir; - // On Windows, unit tests execute two levels deep from the source root. - // For example: chrome/{Debug|Release}/ui_tests.exe - PathService::Get(base::DIR_EXE, &executableDir); - cur = executableDir.DirName().DirName(); - break; - } - case base::DIR_APP_SHORTCUTS: { - if (win::GetVersion() < win::VERSION_WIN8) - return false; - - base::win::ScopedCoMem path_buf; - if (FAILED(SHGetKnownFolderPath(FOLDERID_ApplicationShortcuts, 0, NULL, - &path_buf))) - return false; - - cur = FilePath(string16(path_buf)); - break; - } - case base::DIR_USER_DESKTOP: - if (FAILED(SHGetFolderPath(NULL, CSIDL_DESKTOPDIRECTORY, NULL, - SHGFP_TYPE_CURRENT, system_buffer))) { - return false; - } - cur = FilePath(system_buffer); - break; - case base::DIR_COMMON_DESKTOP: - if (FAILED(SHGetFolderPath(NULL, CSIDL_COMMON_DESKTOPDIRECTORY, NULL, - SHGFP_TYPE_CURRENT, system_buffer))) { - return false; - } - cur = FilePath(system_buffer); - break; - case base::DIR_USER_QUICK_LAUNCH: - if (!GetQuickLaunchPath(false, &cur)) - return false; - break; - case base::DIR_DEFAULT_USER_QUICK_LAUNCH: - if (!GetQuickLaunchPath(true, &cur)) - return false; - break; - case base::DIR_TASKBAR_PINS: - if (!PathService::Get(base::DIR_USER_QUICK_LAUNCH, &cur)) - return false; - cur = cur.AppendASCII("User Pinned"); - cur = cur.AppendASCII("TaskBar"); - break; - default: - return false; - } - - *result = cur; - return true; -} - -} // namespace base diff --git a/base/base_paths_win.h b/base/base_paths_win.h deleted file mode 100644 index 11bc111d66..0000000000 --- a/base/base_paths_win.h +++ /dev/null @@ -1,51 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef BASE_BASE_PATHS_WIN_H__ -#define BASE_BASE_PATHS_WIN_H__ - -// This file declares windows-specific path keys for the base module. -// These can be used with the PathService to access various special -// directories and files. - -namespace base { - -enum { - PATH_WIN_START = 100, - - DIR_WINDOWS, // Windows directory, usually "c:\windows" - DIR_SYSTEM, // Usually c:\windows\system32" - DIR_PROGRAM_FILES, // Usually c:\program files - DIR_PROGRAM_FILESX86, // Usually c:\program files or c:\program files (x86) - - DIR_IE_INTERNET_CACHE, // Temporary Internet Files directory. - DIR_COMMON_START_MENU, // Usually "C:\Documents and Settings\All Users\ - // Start Menu\Programs" - DIR_START_MENU, // Usually "C:\Documents and Settings\\ - // Start Menu\Programs" - DIR_APP_DATA, // Application Data directory under the user profile. - DIR_PROFILE, // Usually "C:\Documents and settings\. - DIR_LOCAL_APP_DATA_LOW, // Local AppData directory for low integrity level. - DIR_LOCAL_APP_DATA, // "Local Settings\Application Data" directory under - // the user profile. - DIR_COMMON_APP_DATA, // W2K, XP, W2K3: "C:\Documents and Settings\ - // All Users\Application Data". - // Vista, W2K8 and above: "C:\ProgramData". - DIR_APP_SHORTCUTS, // Where tiles on the start screen are stored, only - // for Windows 8. Maps to "Local\AppData\Microsoft\ - // Windows\Application Shortcuts\". - DIR_COMMON_DESKTOP, // Directory for the common desktop (visible - // on all user's Desktop). - DIR_USER_QUICK_LAUNCH, // Directory for the quick launch shortcuts. - DIR_DEFAULT_USER_QUICK_LAUNCH, // Directory for the quick launch shortcuts - // of the Default user. - DIR_TASKBAR_PINS, // Directory for the shortcuts pinned to taskbar via - // base::win::TaskbarPinShortcutLink(). - - PATH_WIN_END -}; - -} // namespace base - -#endif // BASE_BASE_PATHS_WIN_H__ diff --git a/base/base_switches.cc b/base/base_switches.cc deleted file mode 100644 index bdd7b62d47..0000000000 --- a/base/base_switches.cc +++ /dev/null @@ -1,60 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "base/base_switches.h" - -namespace switches { - -// If the program includes base/debug/debug_on_start_win.h, the process will -// (on Windows only) start the JIT system-registered debugger on itself and -// will wait for 60 seconds for the debugger to attach to itself. Then a break -// point will be hit. -const char kDebugOnStart[] = "debug-on-start"; - -// Disables the crash reporting. -const char kDisableBreakpad[] = "disable-breakpad"; - -// Enable DCHECKs in release mode. -const char kEnableDCHECK[] = "enable-dcheck"; - -// Generates full memory crash dump. -const char kFullMemoryCrashReport[] = "full-memory-crash-report"; - -// Suppresses all error dialogs when present. -const char kNoErrorDialogs[] = "noerrdialogs"; - -// When running certain tests that spawn child processes, this switch indicates -// to the test framework that the current process is a child process. -const char kTestChildProcess[] = "test-child-process"; - -// Gives the default maximal active V-logging level; 0 is the default. -// Normally positive values are used for V-logging levels. -const char kV[] = "v"; - -// Gives the per-module maximal V-logging levels to override the value -// given by --v. E.g. "my_module=2,foo*=3" would change the logging -// level for all code in source files "my_module.*" and "foo*.*" -// ("-inl" suffixes are also disregarded for this matching). -// -// Any pattern containing a forward or backward slash will be tested -// against the whole pathname and not just the module. E.g., -// "*/foo/bar/*=2" would change the logging level for all code in -// source files under a "foo/bar" directory. -const char kVModule[] = "vmodule"; - -// Will wait for 60 seconds for a debugger to come to attach to the process. -const char kWaitForDebugger[] = "wait-for-debugger"; - -// Sends a pretty-printed version of tracing info to the console. -const char kTraceToConsole[] = "trace-to-console"; - -#if defined(OS_POSIX) -// A flag, generated internally for renderer and other helper process command -// lines on Linux and Mac. It tells the helper process to enable crash dumping -// and reporting, because helpers cannot access the files needed to make this -// decision. -const char kEnableCrashReporter[] = "enable-crash-reporter"; -#endif - -} // namespace switches diff --git a/base/base_switches.h b/base/base_switches.h deleted file mode 100644 index 7686e76316..0000000000 --- a/base/base_switches.h +++ /dev/null @@ -1,31 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -// Defines all the "base" command-line switches. - -#ifndef BASE_BASE_SWITCHES_H_ -#define BASE_BASE_SWITCHES_H_ - -#include "build/build_config.h" - -namespace switches { - -extern const char kDebugOnStart[]; -extern const char kDisableBreakpad[]; -extern const char kEnableDCHECK[]; -extern const char kFullMemoryCrashReport[]; -extern const char kNoErrorDialogs[]; -extern const char kTestChildProcess[]; -extern const char kV[]; -extern const char kVModule[]; -extern const char kWaitForDebugger[]; -extern const char kTraceToConsole[]; - -#if defined(OS_POSIX) -extern const char kEnableCrashReporter[]; -#endif - -} // namespace switches - -#endif // BASE_BASE_SWITCHES_H_ diff --git a/base/base_unittests.isolate b/base/base_unittests.isolate deleted file mode 100644 index 852997b106..0000000000 --- a/base/base_unittests.isolate +++ /dev/null @@ -1,55 +0,0 @@ -# Copyright (c) 2012 The Chromium Authors. All rights reserved. -# Use of this source code is governed by a BSD-style license that can be -# found in the LICENSE file. -{ - 'conditions': [ - ['OS=="android" or OS=="linux" or OS=="mac" or OS=="win"', { - 'variables': { - 'isolate_dependency_untracked': [ - 'data/', - 'test/data/', - ], - }, - }], - ['OS=="linux"', { - 'variables': { - 'command': [ - '../testing/xvfb.py', - '<(PRODUCT_DIR)', - '../tools/swarm_client/googletest/run_test_cases.py', - '<(PRODUCT_DIR)/base_unittests<(EXECUTABLE_SUFFIX)', - ], - 'isolate_dependency_tracked': [ - '../testing/xvfb.py', - '<(PRODUCT_DIR)/xdisplaycheck<(EXECUTABLE_SUFFIX)', - ], - }, - }], - ['OS=="linux" or OS=="mac" or OS=="win"', { - 'variables': { - 'isolate_dependency_tracked': [ - '../testing/test_env.py', - '../tools/swarm_client/run_isolated.py', - '../tools/swarm_client/googletest/run_test_cases.py', - '<(PRODUCT_DIR)/base_unittests<(EXECUTABLE_SUFFIX)', - ], - }, - }], - ['OS=="mac" or OS=="win"', { - 'variables': { - 'command': [ - '../testing/test_env.py', - '../tools/swarm_client/googletest/run_test_cases.py', - '<(PRODUCT_DIR)/base_unittests<(EXECUTABLE_SUFFIX)', - ], - }, - }], - ['OS=="win"', { - 'variables': { - 'isolate_dependency_tracked': [ - '<(PRODUCT_DIR)/icudt.dll', - ], - }, - }], - ], -} diff --git a/base/base_untrusted.gyp b/base/base_untrusted.gyp deleted file mode 100644 index e4b005bc29..0000000000 --- a/base/base_untrusted.gyp +++ /dev/null @@ -1,41 +0,0 @@ -# Copyright (c) 2012 The Chromium Authors. All rights reserved. -# Use of this source code is governed by a BSD-style license that can be -# found in the LICENSE file. - -{ - 'variables': { - 'chromium_code': 1, - }, - 'includes': [ - '../build/common_untrusted.gypi', - 'base.gypi', - ], - 'conditions': [ - ['disable_nacl==0 and disable_nacl_untrusted==0', { - 'targets': [ - { - 'target_name': 'base_untrusted', - 'type': 'none', - 'variables': { - 'base_target': 1, - 'nacl_untrusted_build': 1, - 'nlib_target': 'libbase_untrusted.a', - 'build_glibc': 1, - 'build_newlib': 1, - 'build_irt': 1, - 'sources': [ - 'base_switches.cc', - 'base_switches.h', - 'strings/string16.cc', - 'sync_socket_nacl.cc', - 'time/time_posix.cc', - ], - }, - 'dependencies': [ - '<(DEPTH)/native_client/tools.gyp:prep_toolchain', - ], - }, - ], - }], - ], -} diff --git a/base/basictypes.h b/base/basictypes.h deleted file mode 100644 index 1bed65c6a5..0000000000 --- a/base/basictypes.h +++ /dev/null @@ -1,369 +0,0 @@ -// Copyright (c) 2011 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef BASE_BASICTYPES_H_ -#define BASE_BASICTYPES_H_ - -#include // So we can set the bounds of our types -#include // For size_t -#include // for memcpy - -#include "base/port.h" // Types that only need exist on certain systems - -#ifndef COMPILER_MSVC -// stdint.h is part of C99 but MSVC doesn't have it. -#include // For intptr_t. -#endif - -typedef signed char schar; -typedef signed char int8; -typedef short int16; -typedef int int32; - -// The NSPR system headers define 64-bit as |long| when possible, except on -// Mac OS X. In order to not have typedef mismatches, we do the same on LP64. -// -// On Mac OS X, |long long| is used for 64-bit types for compatibility with -// format macros even in the LP64 model. -#if defined(__LP64__) && !defined(OS_MACOSX) && !defined(OS_OPENBSD) -typedef long int64; -#else -typedef long long int64; -#endif - -// NOTE: It is DANGEROUS to compare signed with unsigned types in loop -// conditions and other conditional expressions, and it is DANGEROUS to -// compute object/allocation sizes, indices, and offsets with signed types. -// Integer overflow behavior for signed types is UNDEFINED in the C/C++ -// standards, but is defined for unsigned types. -// -// Use the unsigned types if your variable represents a bit pattern (e.g. a -// hash value), object or allocation size, object count, offset, -// array/vector index, etc. -// -// Do NOT use 'unsigned' to express "this value should always be positive"; -// use assertions for this. -// -// See the Chromium style guide for more information. -// https://sites.google.com/a/chromium.org/dev/developers/coding-style - -typedef unsigned char uint8; -typedef unsigned short uint16; -typedef unsigned int uint32; - -// See the comment above about NSPR and 64-bit. -#if defined(__LP64__) && !defined(OS_MACOSX) && !defined(OS_OPENBSD) -typedef unsigned long uint64; -#else -typedef unsigned long long uint64; -#endif - -// A type to represent a Unicode code-point value. As of Unicode 4.0, -// such values require up to 21 bits. -// (For type-checking on pointers, make this explicitly signed, -// and it should always be the signed version of whatever int32 is.) -typedef signed int char32; - -const uint8 kuint8max = (( uint8) 0xFF); -const uint16 kuint16max = ((uint16) 0xFFFF); -const uint32 kuint32max = ((uint32) 0xFFFFFFFF); -const uint64 kuint64max = ((uint64) GG_LONGLONG(0xFFFFFFFFFFFFFFFF)); -const int8 kint8min = (( int8) 0x80); -const int8 kint8max = (( int8) 0x7F); -const int16 kint16min = (( int16) 0x8000); -const int16 kint16max = (( int16) 0x7FFF); -const int32 kint32min = (( int32) 0x80000000); -const int32 kint32max = (( int32) 0x7FFFFFFF); -const int64 kint64min = (( int64) GG_LONGLONG(0x8000000000000000)); -const int64 kint64max = (( int64) GG_LONGLONG(0x7FFFFFFFFFFFFFFF)); - -// Put this in the private: declarations for a class to be uncopyable. -#define DISALLOW_COPY(TypeName) \ - TypeName(const TypeName&) - -// Put this in the private: declarations for a class to be unassignable. -#define DISALLOW_ASSIGN(TypeName) \ - void operator=(const TypeName&) - -// A macro to disallow the copy constructor and operator= functions -// This should be used in the private: declarations for a class -#define DISALLOW_COPY_AND_ASSIGN(TypeName) \ - TypeName(const TypeName&); \ - void operator=(const TypeName&) - -// An older, deprecated, politically incorrect name for the above. -// NOTE: The usage of this macro was banned from our code base, but some -// third_party libraries are yet using it. -// TODO(tfarina): Figure out how to fix the usage of this macro in the -// third_party libraries and get rid of it. -#define DISALLOW_EVIL_CONSTRUCTORS(TypeName) DISALLOW_COPY_AND_ASSIGN(TypeName) - -// A macro to disallow all the implicit constructors, namely the -// default constructor, copy constructor and operator= functions. -// -// This should be used in the private: declarations for a class -// that wants to prevent anyone from instantiating it. This is -// especially useful for classes containing only static methods. -#define DISALLOW_IMPLICIT_CONSTRUCTORS(TypeName) \ - TypeName(); \ - DISALLOW_COPY_AND_ASSIGN(TypeName) - -// The arraysize(arr) macro returns the # of elements in an array arr. -// The expression is a compile-time constant, and therefore can be -// used in defining new arrays, for example. If you use arraysize on -// a pointer by mistake, you will get a compile-time error. -// -// One caveat is that arraysize() doesn't accept any array of an -// anonymous type or a type defined inside a function. In these rare -// cases, you have to use the unsafe ARRAYSIZE_UNSAFE() macro below. This is -// due to a limitation in C++'s template system. The limitation might -// eventually be removed, but it hasn't happened yet. - -// This template function declaration is used in defining arraysize. -// Note that the function doesn't need an implementation, as we only -// use its type. -template -char (&ArraySizeHelper(T (&array)[N]))[N]; - -// That gcc wants both of these prototypes seems mysterious. VC, for -// its part, can't decide which to use (another mystery). Matching of -// template overloads: the final frontier. -#ifndef _MSC_VER -template -char (&ArraySizeHelper(const T (&array)[N]))[N]; -#endif - -#define arraysize(array) (sizeof(ArraySizeHelper(array))) - -// ARRAYSIZE_UNSAFE performs essentially the same calculation as arraysize, -// but can be used on anonymous types or types defined inside -// functions. It's less safe than arraysize as it accepts some -// (although not all) pointers. Therefore, you should use arraysize -// whenever possible. -// -// The expression ARRAYSIZE_UNSAFE(a) is a compile-time constant of type -// size_t. -// -// ARRAYSIZE_UNSAFE catches a few type errors. If you see a compiler error -// -// "warning: division by zero in ..." -// -// when using ARRAYSIZE_UNSAFE, you are (wrongfully) giving it a pointer. -// You should only use ARRAYSIZE_UNSAFE on statically allocated arrays. -// -// The following comments are on the implementation details, and can -// be ignored by the users. -// -// ARRAYSIZE_UNSAFE(arr) works by inspecting sizeof(arr) (the # of bytes in -// the array) and sizeof(*(arr)) (the # of bytes in one array -// element). If the former is divisible by the latter, perhaps arr is -// indeed an array, in which case the division result is the # of -// elements in the array. Otherwise, arr cannot possibly be an array, -// and we generate a compiler error to prevent the code from -// compiling. -// -// Since the size of bool is implementation-defined, we need to cast -// !(sizeof(a) & sizeof(*(a))) to size_t in order to ensure the final -// result has type size_t. -// -// This macro is not perfect as it wrongfully accepts certain -// pointers, namely where the pointer size is divisible by the pointee -// size. Since all our code has to go through a 32-bit compiler, -// where a pointer is 4 bytes, this means all pointers to a type whose -// size is 3 or greater than 4 will be (righteously) rejected. - -#define ARRAYSIZE_UNSAFE(a) \ - ((sizeof(a) / sizeof(*(a))) / \ - static_cast(!(sizeof(a) % sizeof(*(a))))) - - -// Use implicit_cast as a safe version of static_cast or const_cast -// for upcasting in the type hierarchy (i.e. casting a pointer to Foo -// to a pointer to SuperclassOfFoo or casting a pointer to Foo to -// a const pointer to Foo). -// When you use implicit_cast, the compiler checks that the cast is safe. -// Such explicit implicit_casts are necessary in surprisingly many -// situations where C++ demands an exact type match instead of an -// argument type convertible to a target type. -// -// The From type can be inferred, so the preferred syntax for using -// implicit_cast is the same as for static_cast etc.: -// -// implicit_cast(expr) -// -// implicit_cast would have been part of the C++ standard library, -// but the proposal was submitted too late. It will probably make -// its way into the language in the future. -template -inline To implicit_cast(From const &f) { - return f; -} - -// The COMPILE_ASSERT macro can be used to verify that a compile time -// expression is true. For example, you could use it to verify the -// size of a static array: -// -// COMPILE_ASSERT(ARRAYSIZE_UNSAFE(content_type_names) == CONTENT_NUM_TYPES, -// content_type_names_incorrect_size); -// -// or to make sure a struct is smaller than a certain size: -// -// COMPILE_ASSERT(sizeof(foo) < 128, foo_too_large); -// -// The second argument to the macro is the name of the variable. If -// the expression is false, most compilers will issue a warning/error -// containing the name of the variable. - -template -struct CompileAssert { -}; - -#undef COMPILE_ASSERT -#define COMPILE_ASSERT(expr, msg) \ - typedef CompileAssert<(bool(expr))> msg[bool(expr) ? 1 : -1] - -// Implementation details of COMPILE_ASSERT: -// -// - COMPILE_ASSERT works by defining an array type that has -1 -// elements (and thus is invalid) when the expression is false. -// -// - The simpler definition -// -// #define COMPILE_ASSERT(expr, msg) typedef char msg[(expr) ? 1 : -1] -// -// does not work, as gcc supports variable-length arrays whose sizes -// are determined at run-time (this is gcc's extension and not part -// of the C++ standard). As a result, gcc fails to reject the -// following code with the simple definition: -// -// int foo; -// COMPILE_ASSERT(foo, msg); // not supposed to compile as foo is -// // not a compile-time constant. -// -// - By using the type CompileAssert<(bool(expr))>, we ensures that -// expr is a compile-time constant. (Template arguments must be -// determined at compile-time.) -// -// - The outer parentheses in CompileAssert<(bool(expr))> are necessary -// to work around a bug in gcc 3.4.4 and 4.0.1. If we had written -// -// CompileAssert -// -// instead, these compilers will refuse to compile -// -// COMPILE_ASSERT(5 > 0, some_message); -// -// (They seem to think the ">" in "5 > 0" marks the end of the -// template argument list.) -// -// - The array size is (bool(expr) ? 1 : -1), instead of simply -// -// ((expr) ? 1 : -1). -// -// This is to avoid running into a bug in MS VC 7.1, which -// causes ((0.0) ? 1 : -1) to incorrectly evaluate to 1. - - -// bit_cast is a template function that implements the -// equivalent of "*reinterpret_cast(&source)". We need this in -// very low-level functions like the protobuf library and fast math -// support. -// -// float f = 3.14159265358979; -// int i = bit_cast(f); -// // i = 0x40490fdb -// -// The classical address-casting method is: -// -// // WRONG -// float f = 3.14159265358979; // WRONG -// int i = * reinterpret_cast(&f); // WRONG -// -// The address-casting method actually produces undefined behavior -// according to ISO C++ specification section 3.10 -15 -. Roughly, this -// section says: if an object in memory has one type, and a program -// accesses it with a different type, then the result is undefined -// behavior for most values of "different type". -// -// This is true for any cast syntax, either *(int*)&f or -// *reinterpret_cast(&f). And it is particularly true for -// conversions between integral lvalues and floating-point lvalues. -// -// The purpose of 3.10 -15- is to allow optimizing compilers to assume -// that expressions with different types refer to different memory. gcc -// 4.0.1 has an optimizer that takes advantage of this. So a -// non-conforming program quietly produces wildly incorrect output. -// -// The problem is not the use of reinterpret_cast. The problem is type -// punning: holding an object in memory of one type and reading its bits -// back using a different type. -// -// The C++ standard is more subtle and complex than this, but that -// is the basic idea. -// -// Anyways ... -// -// bit_cast<> calls memcpy() which is blessed by the standard, -// especially by the example in section 3.9 . Also, of course, -// bit_cast<> wraps up the nasty logic in one place. -// -// Fortunately memcpy() is very fast. In optimized mode, with a -// constant size, gcc 2.95.3, gcc 4.0.1, and msvc 7.1 produce inline -// code with the minimal amount of data movement. On a 32-bit system, -// memcpy(d,s,4) compiles to one load and one store, and memcpy(d,s,8) -// compiles to two loads and two stores. -// -// I tested this code with gcc 2.95.3, gcc 4.0.1, icc 8.1, and msvc 7.1. -// -// WARNING: if Dest or Source is a non-POD type, the result of the memcpy -// is likely to surprise you. - -template -inline Dest bit_cast(const Source& source) { - // Compile time assertion: sizeof(Dest) == sizeof(Source) - // A compile error here means your Dest and Source have different sizes. - typedef char VerifySizesAreEqual [sizeof(Dest) == sizeof(Source) ? 1 : -1]; - - Dest dest; - memcpy(&dest, &source, sizeof(dest)); - return dest; -} - -// Used to explicitly mark the return value of a function as unused. If you are -// really sure you don't want to do anything with the return value of a function -// that has been marked WARN_UNUSED_RESULT, wrap it with this. Example: -// -// scoped_ptr my_var = ...; -// if (TakeOwnership(my_var.get()) == SUCCESS) -// ignore_result(my_var.release()); -// -template -inline void ignore_result(const T&) { -} - -// The following enum should be used only as a constructor argument to indicate -// that the variable has static storage class, and that the constructor should -// do nothing to its state. It indicates to the reader that it is legal to -// declare a static instance of the class, provided the constructor is given -// the base::LINKER_INITIALIZED argument. Normally, it is unsafe to declare a -// static variable that has a constructor or a destructor because invocation -// order is undefined. However, IF the type can be initialized by filling with -// zeroes (which the loader does for static variables), AND the destructor also -// does nothing to the storage, AND there are no virtual methods, then a -// constructor declared as -// explicit MyClass(base::LinkerInitialized x) {} -// and invoked as -// static MyClass my_variable_name(base::LINKER_INITIALIZED); -namespace base { -enum LinkerInitialized { LINKER_INITIALIZED }; - -// Use these to declare and define a static local variable (static T;) so that -// it is leaked so that its destructors are not called at exit. If you need -// thread-safe initialization, use base/lazy_instance.h instead. -#define CR_DEFINE_STATIC_LOCAL(type, name, arguments) \ - static type& name = *new type arguments - -} // base - -#endif // BASE_BASICTYPES_H_ diff --git a/base/bind.h b/base/bind.h deleted file mode 100644 index 5cf124df32..0000000000 --- a/base/bind.h +++ /dev/null @@ -1,517 +0,0 @@ -// This file was GENERATED by command: -// pump.py bind.h.pump -// DO NOT EDIT BY HAND!!! - - -// Copyright (c) 2011 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef BASE_BIND_H_ -#define BASE_BIND_H_ - -#include "base/bind_internal.h" -#include "base/callback_internal.h" - -// ----------------------------------------------------------------------------- -// Usage documentation -// ----------------------------------------------------------------------------- -// -// See base/callback.h for documentation. -// -// -// ----------------------------------------------------------------------------- -// Implementation notes -// ----------------------------------------------------------------------------- -// -// If you're reading the implementation, before proceeding further, you should -// read the top comment of base/bind_internal.h for a definition of common -// terms and concepts. -// -// RETURN TYPES -// -// Though Bind()'s result is meant to be stored in a Callback<> type, it -// cannot actually return the exact type without requiring a large amount -// of extra template specializations. The problem is that in order to -// discern the correct specialization of Callback<>, Bind would need to -// unwrap the function signature to determine the signature's arity, and -// whether or not it is a method. -// -// Each unique combination of (arity, function_type, num_prebound) where -// function_type is one of {function, method, const_method} would require -// one specialization. We eventually have to do a similar number of -// specializations anyways in the implementation (see the Invoker<>, -// classes). However, it is avoidable in Bind if we return the result -// via an indirection like we do below. -// -// TODO(ajwong): We might be able to avoid this now, but need to test. -// -// It is possible to move most of the COMPILE_ASSERT asserts into BindState<>, -// but it feels a little nicer to have the asserts here so people do not -// need to crack open bind_internal.h. On the other hand, it makes Bind() -// harder to read. - -namespace base { - -template -base::Callback< - typename internal::BindState< - typename internal::FunctorTraits::RunnableType, - typename internal::FunctorTraits::RunType, - void()> - ::UnboundRunType> -Bind(Functor functor) { - // Typedefs for how to store and run the functor. - typedef typename internal::FunctorTraits::RunnableType RunnableType; - typedef typename internal::FunctorTraits::RunType RunType; - - // Use RunnableType::RunType instead of RunType above because our - // checks should below for bound references need to know what the actual - // functor is going to interpret the argument as. - typedef internal::FunctionTraits - BoundFunctorTraits; - - typedef internal::BindState BindState; - - - return Callback( - new BindState(internal::MakeRunnable(functor))); -} - -template -base::Callback< - typename internal::BindState< - typename internal::FunctorTraits::RunnableType, - typename internal::FunctorTraits::RunType, - void(typename internal::CallbackParamTraits::StorageType)> - ::UnboundRunType> -Bind(Functor functor, const P1& p1) { - // Typedefs for how to store and run the functor. - typedef typename internal::FunctorTraits::RunnableType RunnableType; - typedef typename internal::FunctorTraits::RunType RunType; - - // Use RunnableType::RunType instead of RunType above because our - // checks should below for bound references need to know what the actual - // functor is going to interpret the argument as. - typedef internal::FunctionTraits - BoundFunctorTraits; - - // Do not allow binding a non-const reference parameter. Non-const reference - // parameters are disallowed by the Google style guide. Also, binding a - // non-const reference parameter can make for subtle bugs because the - // invoked function will receive a reference to the stored copy of the - // argument and not the original. - COMPILE_ASSERT( - !(is_non_const_reference::value ), - do_not_bind_functions_with_nonconst_ref); - - // For methods, we need to be careful for parameter 1. We do not require - // a scoped_refptr because BindState<> itself takes care of AddRef() for - // methods. We also disallow binding of an array as the method's target - // object. - COMPILE_ASSERT( - internal::HasIsMethodTag::value || - !internal::NeedsScopedRefptrButGetsRawPtr::value, - p1_is_refcounted_type_and_needs_scoped_refptr); - COMPILE_ASSERT(!internal::HasIsMethodTag::value || - !is_array::value, - first_bound_argument_to_method_cannot_be_array); - typedef internal::BindState::StorageType)> BindState; - - - return Callback( - new BindState(internal::MakeRunnable(functor), p1)); -} - -template -base::Callback< - typename internal::BindState< - typename internal::FunctorTraits::RunnableType, - typename internal::FunctorTraits::RunType, - void(typename internal::CallbackParamTraits::StorageType, - typename internal::CallbackParamTraits::StorageType)> - ::UnboundRunType> -Bind(Functor functor, const P1& p1, const P2& p2) { - // Typedefs for how to store and run the functor. - typedef typename internal::FunctorTraits::RunnableType RunnableType; - typedef typename internal::FunctorTraits::RunType RunType; - - // Use RunnableType::RunType instead of RunType above because our - // checks should below for bound references need to know what the actual - // functor is going to interpret the argument as. - typedef internal::FunctionTraits - BoundFunctorTraits; - - // Do not allow binding a non-const reference parameter. Non-const reference - // parameters are disallowed by the Google style guide. Also, binding a - // non-const reference parameter can make for subtle bugs because the - // invoked function will receive a reference to the stored copy of the - // argument and not the original. - COMPILE_ASSERT( - !(is_non_const_reference::value || - is_non_const_reference::value ), - do_not_bind_functions_with_nonconst_ref); - - // For methods, we need to be careful for parameter 1. We do not require - // a scoped_refptr because BindState<> itself takes care of AddRef() for - // methods. We also disallow binding of an array as the method's target - // object. - COMPILE_ASSERT( - internal::HasIsMethodTag::value || - !internal::NeedsScopedRefptrButGetsRawPtr::value, - p1_is_refcounted_type_and_needs_scoped_refptr); - COMPILE_ASSERT(!internal::HasIsMethodTag::value || - !is_array::value, - first_bound_argument_to_method_cannot_be_array); - COMPILE_ASSERT(!internal::NeedsScopedRefptrButGetsRawPtr::value, - p2_is_refcounted_type_and_needs_scoped_refptr); - typedef internal::BindState::StorageType, - typename internal::CallbackParamTraits::StorageType)> BindState; - - - return Callback( - new BindState(internal::MakeRunnable(functor), p1, p2)); -} - -template -base::Callback< - typename internal::BindState< - typename internal::FunctorTraits::RunnableType, - typename internal::FunctorTraits::RunType, - void(typename internal::CallbackParamTraits::StorageType, - typename internal::CallbackParamTraits::StorageType, - typename internal::CallbackParamTraits::StorageType)> - ::UnboundRunType> -Bind(Functor functor, const P1& p1, const P2& p2, const P3& p3) { - // Typedefs for how to store and run the functor. - typedef typename internal::FunctorTraits::RunnableType RunnableType; - typedef typename internal::FunctorTraits::RunType RunType; - - // Use RunnableType::RunType instead of RunType above because our - // checks should below for bound references need to know what the actual - // functor is going to interpret the argument as. - typedef internal::FunctionTraits - BoundFunctorTraits; - - // Do not allow binding a non-const reference parameter. Non-const reference - // parameters are disallowed by the Google style guide. Also, binding a - // non-const reference parameter can make for subtle bugs because the - // invoked function will receive a reference to the stored copy of the - // argument and not the original. - COMPILE_ASSERT( - !(is_non_const_reference::value || - is_non_const_reference::value || - is_non_const_reference::value ), - do_not_bind_functions_with_nonconst_ref); - - // For methods, we need to be careful for parameter 1. We do not require - // a scoped_refptr because BindState<> itself takes care of AddRef() for - // methods. We also disallow binding of an array as the method's target - // object. - COMPILE_ASSERT( - internal::HasIsMethodTag::value || - !internal::NeedsScopedRefptrButGetsRawPtr::value, - p1_is_refcounted_type_and_needs_scoped_refptr); - COMPILE_ASSERT(!internal::HasIsMethodTag::value || - !is_array::value, - first_bound_argument_to_method_cannot_be_array); - COMPILE_ASSERT(!internal::NeedsScopedRefptrButGetsRawPtr::value, - p2_is_refcounted_type_and_needs_scoped_refptr); - COMPILE_ASSERT(!internal::NeedsScopedRefptrButGetsRawPtr::value, - p3_is_refcounted_type_and_needs_scoped_refptr); - typedef internal::BindState::StorageType, - typename internal::CallbackParamTraits::StorageType, - typename internal::CallbackParamTraits::StorageType)> BindState; - - - return Callback( - new BindState(internal::MakeRunnable(functor), p1, p2, p3)); -} - -template -base::Callback< - typename internal::BindState< - typename internal::FunctorTraits::RunnableType, - typename internal::FunctorTraits::RunType, - void(typename internal::CallbackParamTraits::StorageType, - typename internal::CallbackParamTraits::StorageType, - typename internal::CallbackParamTraits::StorageType, - typename internal::CallbackParamTraits::StorageType)> - ::UnboundRunType> -Bind(Functor functor, const P1& p1, const P2& p2, const P3& p3, const P4& p4) { - // Typedefs for how to store and run the functor. - typedef typename internal::FunctorTraits::RunnableType RunnableType; - typedef typename internal::FunctorTraits::RunType RunType; - - // Use RunnableType::RunType instead of RunType above because our - // checks should below for bound references need to know what the actual - // functor is going to interpret the argument as. - typedef internal::FunctionTraits - BoundFunctorTraits; - - // Do not allow binding a non-const reference parameter. Non-const reference - // parameters are disallowed by the Google style guide. Also, binding a - // non-const reference parameter can make for subtle bugs because the - // invoked function will receive a reference to the stored copy of the - // argument and not the original. - COMPILE_ASSERT( - !(is_non_const_reference::value || - is_non_const_reference::value || - is_non_const_reference::value || - is_non_const_reference::value ), - do_not_bind_functions_with_nonconst_ref); - - // For methods, we need to be careful for parameter 1. We do not require - // a scoped_refptr because BindState<> itself takes care of AddRef() for - // methods. We also disallow binding of an array as the method's target - // object. - COMPILE_ASSERT( - internal::HasIsMethodTag::value || - !internal::NeedsScopedRefptrButGetsRawPtr::value, - p1_is_refcounted_type_and_needs_scoped_refptr); - COMPILE_ASSERT(!internal::HasIsMethodTag::value || - !is_array::value, - first_bound_argument_to_method_cannot_be_array); - COMPILE_ASSERT(!internal::NeedsScopedRefptrButGetsRawPtr::value, - p2_is_refcounted_type_and_needs_scoped_refptr); - COMPILE_ASSERT(!internal::NeedsScopedRefptrButGetsRawPtr::value, - p3_is_refcounted_type_and_needs_scoped_refptr); - COMPILE_ASSERT(!internal::NeedsScopedRefptrButGetsRawPtr::value, - p4_is_refcounted_type_and_needs_scoped_refptr); - typedef internal::BindState::StorageType, - typename internal::CallbackParamTraits::StorageType, - typename internal::CallbackParamTraits::StorageType, - typename internal::CallbackParamTraits::StorageType)> BindState; - - - return Callback( - new BindState(internal::MakeRunnable(functor), p1, p2, p3, p4)); -} - -template -base::Callback< - typename internal::BindState< - typename internal::FunctorTraits::RunnableType, - typename internal::FunctorTraits::RunType, - void(typename internal::CallbackParamTraits::StorageType, - typename internal::CallbackParamTraits::StorageType, - typename internal::CallbackParamTraits::StorageType, - typename internal::CallbackParamTraits::StorageType, - typename internal::CallbackParamTraits::StorageType)> - ::UnboundRunType> -Bind(Functor functor, const P1& p1, const P2& p2, const P3& p3, const P4& p4, - const P5& p5) { - // Typedefs for how to store and run the functor. - typedef typename internal::FunctorTraits::RunnableType RunnableType; - typedef typename internal::FunctorTraits::RunType RunType; - - // Use RunnableType::RunType instead of RunType above because our - // checks should below for bound references need to know what the actual - // functor is going to interpret the argument as. - typedef internal::FunctionTraits - BoundFunctorTraits; - - // Do not allow binding a non-const reference parameter. Non-const reference - // parameters are disallowed by the Google style guide. Also, binding a - // non-const reference parameter can make for subtle bugs because the - // invoked function will receive a reference to the stored copy of the - // argument and not the original. - COMPILE_ASSERT( - !(is_non_const_reference::value || - is_non_const_reference::value || - is_non_const_reference::value || - is_non_const_reference::value || - is_non_const_reference::value ), - do_not_bind_functions_with_nonconst_ref); - - // For methods, we need to be careful for parameter 1. We do not require - // a scoped_refptr because BindState<> itself takes care of AddRef() for - // methods. We also disallow binding of an array as the method's target - // object. - COMPILE_ASSERT( - internal::HasIsMethodTag::value || - !internal::NeedsScopedRefptrButGetsRawPtr::value, - p1_is_refcounted_type_and_needs_scoped_refptr); - COMPILE_ASSERT(!internal::HasIsMethodTag::value || - !is_array::value, - first_bound_argument_to_method_cannot_be_array); - COMPILE_ASSERT(!internal::NeedsScopedRefptrButGetsRawPtr::value, - p2_is_refcounted_type_and_needs_scoped_refptr); - COMPILE_ASSERT(!internal::NeedsScopedRefptrButGetsRawPtr::value, - p3_is_refcounted_type_and_needs_scoped_refptr); - COMPILE_ASSERT(!internal::NeedsScopedRefptrButGetsRawPtr::value, - p4_is_refcounted_type_and_needs_scoped_refptr); - COMPILE_ASSERT(!internal::NeedsScopedRefptrButGetsRawPtr::value, - p5_is_refcounted_type_and_needs_scoped_refptr); - typedef internal::BindState::StorageType, - typename internal::CallbackParamTraits::StorageType, - typename internal::CallbackParamTraits::StorageType, - typename internal::CallbackParamTraits::StorageType, - typename internal::CallbackParamTraits::StorageType)> BindState; - - - return Callback( - new BindState(internal::MakeRunnable(functor), p1, p2, p3, p4, p5)); -} - -template -base::Callback< - typename internal::BindState< - typename internal::FunctorTraits::RunnableType, - typename internal::FunctorTraits::RunType, - void(typename internal::CallbackParamTraits::StorageType, - typename internal::CallbackParamTraits::StorageType, - typename internal::CallbackParamTraits::StorageType, - typename internal::CallbackParamTraits::StorageType, - typename internal::CallbackParamTraits::StorageType, - typename internal::CallbackParamTraits::StorageType)> - ::UnboundRunType> -Bind(Functor functor, const P1& p1, const P2& p2, const P3& p3, const P4& p4, - const P5& p5, const P6& p6) { - // Typedefs for how to store and run the functor. - typedef typename internal::FunctorTraits::RunnableType RunnableType; - typedef typename internal::FunctorTraits::RunType RunType; - - // Use RunnableType::RunType instead of RunType above because our - // checks should below for bound references need to know what the actual - // functor is going to interpret the argument as. - typedef internal::FunctionTraits - BoundFunctorTraits; - - // Do not allow binding a non-const reference parameter. Non-const reference - // parameters are disallowed by the Google style guide. Also, binding a - // non-const reference parameter can make for subtle bugs because the - // invoked function will receive a reference to the stored copy of the - // argument and not the original. - COMPILE_ASSERT( - !(is_non_const_reference::value || - is_non_const_reference::value || - is_non_const_reference::value || - is_non_const_reference::value || - is_non_const_reference::value || - is_non_const_reference::value ), - do_not_bind_functions_with_nonconst_ref); - - // For methods, we need to be careful for parameter 1. We do not require - // a scoped_refptr because BindState<> itself takes care of AddRef() for - // methods. We also disallow binding of an array as the method's target - // object. - COMPILE_ASSERT( - internal::HasIsMethodTag::value || - !internal::NeedsScopedRefptrButGetsRawPtr::value, - p1_is_refcounted_type_and_needs_scoped_refptr); - COMPILE_ASSERT(!internal::HasIsMethodTag::value || - !is_array::value, - first_bound_argument_to_method_cannot_be_array); - COMPILE_ASSERT(!internal::NeedsScopedRefptrButGetsRawPtr::value, - p2_is_refcounted_type_and_needs_scoped_refptr); - COMPILE_ASSERT(!internal::NeedsScopedRefptrButGetsRawPtr::value, - p3_is_refcounted_type_and_needs_scoped_refptr); - COMPILE_ASSERT(!internal::NeedsScopedRefptrButGetsRawPtr::value, - p4_is_refcounted_type_and_needs_scoped_refptr); - COMPILE_ASSERT(!internal::NeedsScopedRefptrButGetsRawPtr::value, - p5_is_refcounted_type_and_needs_scoped_refptr); - COMPILE_ASSERT(!internal::NeedsScopedRefptrButGetsRawPtr::value, - p6_is_refcounted_type_and_needs_scoped_refptr); - typedef internal::BindState::StorageType, - typename internal::CallbackParamTraits::StorageType, - typename internal::CallbackParamTraits::StorageType, - typename internal::CallbackParamTraits::StorageType, - typename internal::CallbackParamTraits::StorageType, - typename internal::CallbackParamTraits::StorageType)> BindState; - - - return Callback( - new BindState(internal::MakeRunnable(functor), p1, p2, p3, p4, p5, p6)); -} - -template -base::Callback< - typename internal::BindState< - typename internal::FunctorTraits::RunnableType, - typename internal::FunctorTraits::RunType, - void(typename internal::CallbackParamTraits::StorageType, - typename internal::CallbackParamTraits::StorageType, - typename internal::CallbackParamTraits::StorageType, - typename internal::CallbackParamTraits::StorageType, - typename internal::CallbackParamTraits::StorageType, - typename internal::CallbackParamTraits::StorageType, - typename internal::CallbackParamTraits::StorageType)> - ::UnboundRunType> -Bind(Functor functor, const P1& p1, const P2& p2, const P3& p3, const P4& p4, - const P5& p5, const P6& p6, const P7& p7) { - // Typedefs for how to store and run the functor. - typedef typename internal::FunctorTraits::RunnableType RunnableType; - typedef typename internal::FunctorTraits::RunType RunType; - - // Use RunnableType::RunType instead of RunType above because our - // checks should below for bound references need to know what the actual - // functor is going to interpret the argument as. - typedef internal::FunctionTraits - BoundFunctorTraits; - - // Do not allow binding a non-const reference parameter. Non-const reference - // parameters are disallowed by the Google style guide. Also, binding a - // non-const reference parameter can make for subtle bugs because the - // invoked function will receive a reference to the stored copy of the - // argument and not the original. - COMPILE_ASSERT( - !(is_non_const_reference::value || - is_non_const_reference::value || - is_non_const_reference::value || - is_non_const_reference::value || - is_non_const_reference::value || - is_non_const_reference::value || - is_non_const_reference::value ), - do_not_bind_functions_with_nonconst_ref); - - // For methods, we need to be careful for parameter 1. We do not require - // a scoped_refptr because BindState<> itself takes care of AddRef() for - // methods. We also disallow binding of an array as the method's target - // object. - COMPILE_ASSERT( - internal::HasIsMethodTag::value || - !internal::NeedsScopedRefptrButGetsRawPtr::value, - p1_is_refcounted_type_and_needs_scoped_refptr); - COMPILE_ASSERT(!internal::HasIsMethodTag::value || - !is_array::value, - first_bound_argument_to_method_cannot_be_array); - COMPILE_ASSERT(!internal::NeedsScopedRefptrButGetsRawPtr::value, - p2_is_refcounted_type_and_needs_scoped_refptr); - COMPILE_ASSERT(!internal::NeedsScopedRefptrButGetsRawPtr::value, - p3_is_refcounted_type_and_needs_scoped_refptr); - COMPILE_ASSERT(!internal::NeedsScopedRefptrButGetsRawPtr::value, - p4_is_refcounted_type_and_needs_scoped_refptr); - COMPILE_ASSERT(!internal::NeedsScopedRefptrButGetsRawPtr::value, - p5_is_refcounted_type_and_needs_scoped_refptr); - COMPILE_ASSERT(!internal::NeedsScopedRefptrButGetsRawPtr::value, - p6_is_refcounted_type_and_needs_scoped_refptr); - COMPILE_ASSERT(!internal::NeedsScopedRefptrButGetsRawPtr::value, - p7_is_refcounted_type_and_needs_scoped_refptr); - typedef internal::BindState::StorageType, - typename internal::CallbackParamTraits::StorageType, - typename internal::CallbackParamTraits::StorageType, - typename internal::CallbackParamTraits::StorageType, - typename internal::CallbackParamTraits::StorageType, - typename internal::CallbackParamTraits::StorageType, - typename internal::CallbackParamTraits::StorageType)> BindState; - - - return Callback( - new BindState(internal::MakeRunnable(functor), p1, p2, p3, p4, p5, p6, - p7)); -} - -} // namespace base - -#endif // BASE_BIND_H_ diff --git a/base/bind.h.pump b/base/bind.h.pump deleted file mode 100644 index b321649aea..0000000000 --- a/base/bind.h.pump +++ /dev/null @@ -1,153 +0,0 @@ -$$ This is a pump file for generating file templates. Pump is a python -$$ script that is part of the Google Test suite of utilities. Description -$$ can be found here: -$$ -$$ http://code.google.com/p/googletest/wiki/PumpManual -$$ - -$$ -$$ MAX_ARITY controls the number of arguments that Bind() supports. -$$ The amount of code, and more importantly, the number of template types -$$ generated by pump grows at O(MAX_ARITY^2). -$$ -$$ We tried going to 11 and found it imposed an extra 10 penalty on windows -$$ cycle times compared to our original baseline of 6. -$$ -$$ Currently 7 is chosen as a compromise between supporting a convenient -$$ number of arguments and keeping compile times low. At 7, we have 115 -$$ templates being generated by pump. -$$ -$$ Be careful when adjusting this number. If people find a need to bind -$$ a larger number of arguments, consider refactoring the function to use -$$ a param struct instead of raising the MAX_ARITY. -$$ -$$ See http://crbug.com/98542 for more context. -$$ -$var MAX_ARITY = 7 - -// Copyright (c) 2011 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef BASE_BIND_H_ -#define BASE_BIND_H_ - -#include "base/bind_internal.h" -#include "base/callback_internal.h" - -// ----------------------------------------------------------------------------- -// Usage documentation -// ----------------------------------------------------------------------------- -// -// See base/callback.h for documentation. -// -// -// ----------------------------------------------------------------------------- -// Implementation notes -// ----------------------------------------------------------------------------- -// -// If you're reading the implementation, before proceeding further, you should -// read the top comment of base/bind_internal.h for a definition of common -// terms and concepts. -// -// RETURN TYPES -// -// Though Bind()'s result is meant to be stored in a Callback<> type, it -// cannot actually return the exact type without requiring a large amount -// of extra template specializations. The problem is that in order to -// discern the correct specialization of Callback<>, Bind would need to -// unwrap the function signature to determine the signature's arity, and -// whether or not it is a method. -// -// Each unique combination of (arity, function_type, num_prebound) where -// function_type is one of {function, method, const_method} would require -// one specialization. We eventually have to do a similar number of -// specializations anyways in the implementation (see the Invoker<>, -// classes). However, it is avoidable in Bind if we return the result -// via an indirection like we do below. -// -// TODO(ajwong): We might be able to avoid this now, but need to test. -// -// It is possible to move most of the COMPILE_ASSERT asserts into BindState<>, -// but it feels a little nicer to have the asserts here so people do not -// need to crack open bind_internal.h. On the other hand, it makes Bind() -// harder to read. - -namespace base { - -$range ARITY 0..MAX_ARITY -$for ARITY [[ -$range ARG 1..ARITY - -template 0 [[, ]] $for ARG , [[typename P$(ARG)]]> -base::Callback< - typename internal::BindState< - typename internal::FunctorTraits::RunnableType, - typename internal::FunctorTraits::RunType, - void($for ARG , [[typename internal::CallbackParamTraits::StorageType]])> - ::UnboundRunType> -Bind(Functor functor -$if ARITY > 0 [[, ]] $for ARG , [[const P$(ARG)& p$(ARG)]]) { - // Typedefs for how to store and run the functor. - typedef typename internal::FunctorTraits::RunnableType RunnableType; - typedef typename internal::FunctorTraits::RunType RunType; - - // Use RunnableType::RunType instead of RunType above because our - // checks should below for bound references need to know what the actual - // functor is going to interpret the argument as. - typedef internal::FunctionTraits - BoundFunctorTraits; - -$if ARITY > 0 [[ - - // Do not allow binding a non-const reference parameter. Non-const reference - // parameters are disallowed by the Google style guide. Also, binding a - // non-const reference parameter can make for subtle bugs because the - // invoked function will receive a reference to the stored copy of the - // argument and not the original. - COMPILE_ASSERT( - !($for ARG || [[ -is_non_const_reference::value ]]), - do_not_bind_functions_with_nonconst_ref); - -]] - - -$for ARG [[ - - -$if ARG == 1 [[ - // For methods, we need to be careful for parameter 1. We do not require - // a scoped_refptr because BindState<> itself takes care of AddRef() for - // methods. We also disallow binding of an array as the method's target - // object. - COMPILE_ASSERT( - internal::HasIsMethodTag::value || - !internal::NeedsScopedRefptrButGetsRawPtr::value, - p$(ARG)_is_refcounted_type_and_needs_scoped_refptr); - COMPILE_ASSERT(!internal::HasIsMethodTag::value || - !is_array::value, - first_bound_argument_to_method_cannot_be_array); -]] $else [[ - COMPILE_ASSERT(!internal::NeedsScopedRefptrButGetsRawPtr::value, - p$(ARG)_is_refcounted_type_and_needs_scoped_refptr); -]] $$ $if ARG - -]] $$ $for ARG - - typedef internal::BindState::StorageType]])> [[]] -BindState; - - - return Callback( - new BindState(internal::MakeRunnable(functor)[[]] -$if ARITY > 0 [[, ]] $for ARG , [[p$(ARG)]])); -} - -]] $$ for ARITY - -} // namespace base - -#endif // BASE_BIND_H_ diff --git a/base/bind_helpers.cc b/base/bind_helpers.cc deleted file mode 100644 index f2fc3bb0da..0000000000 --- a/base/bind_helpers.cc +++ /dev/null @@ -1,29 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "base/bind_helpers.h" - -#include "base/callback.h" - -namespace base { - -void DoNothing() { -} - -ScopedClosureRunner::ScopedClosureRunner(const Closure& closure) - : closure_(closure) { -} - -ScopedClosureRunner::~ScopedClosureRunner() { - if (!closure_.is_null()) - closure_.Run(); -} - -Closure ScopedClosureRunner::Release() { - Closure result = closure_; - closure_.Reset(); - return result; -} - -} // namespace base diff --git a/base/bind_helpers.h b/base/bind_helpers.h deleted file mode 100644 index 0cfaab7ece..0000000000 --- a/base/bind_helpers.h +++ /dev/null @@ -1,563 +0,0 @@ -// Copyright (c) 2011 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -// This defines a set of argument wrappers and related factory methods that -// can be used specify the refcounting and reference semantics of arguments -// that are bound by the Bind() function in base/bind.h. -// -// It also defines a set of simple functions and utilities that people want -// when using Callback<> and Bind(). -// -// -// ARGUMENT BINDING WRAPPERS -// -// The wrapper functions are base::Unretained(), base::Owned(), bass::Passed(), -// base::ConstRef(), and base::IgnoreResult(). -// -// Unretained() allows Bind() to bind a non-refcounted class, and to disable -// refcounting on arguments that are refcounted objects. -// -// Owned() transfers ownership of an object to the Callback resulting from -// bind; the object will be deleted when the Callback is deleted. -// -// Passed() is for transferring movable-but-not-copyable types (eg. scoped_ptr) -// through a Callback. Logically, this signifies a destructive transfer of -// the state of the argument into the target function. Invoking -// Callback::Run() twice on a Callback that was created with a Passed() -// argument will CHECK() because the first invocation would have already -// transferred ownership to the target function. -// -// ConstRef() allows binding a constant reference to an argument rather -// than a copy. -// -// IgnoreResult() is used to adapt a function or Callback with a return type to -// one with a void return. This is most useful if you have a function with, -// say, a pesky ignorable bool return that you want to use with PostTask or -// something else that expect a Callback with a void return. -// -// EXAMPLE OF Unretained(): -// -// class Foo { -// public: -// void func() { cout << "Foo:f" << endl; } -// }; -// -// // In some function somewhere. -// Foo foo; -// Closure foo_callback = -// Bind(&Foo::func, Unretained(&foo)); -// foo_callback.Run(); // Prints "Foo:f". -// -// Without the Unretained() wrapper on |&foo|, the above call would fail -// to compile because Foo does not support the AddRef() and Release() methods. -// -// -// EXAMPLE OF Owned(): -// -// void foo(int* arg) { cout << *arg << endl } -// -// int* pn = new int(1); -// Closure foo_callback = Bind(&foo, Owned(pn)); -// -// foo_callback.Run(); // Prints "1" -// foo_callback.Run(); // Prints "1" -// *n = 2; -// foo_callback.Run(); // Prints "2" -// -// foo_callback.Reset(); // |pn| is deleted. Also will happen when -// // |foo_callback| goes out of scope. -// -// Without Owned(), someone would have to know to delete |pn| when the last -// reference to the Callback is deleted. -// -// -// EXAMPLE OF ConstRef(): -// -// void foo(int arg) { cout << arg << endl } -// -// int n = 1; -// Closure no_ref = Bind(&foo, n); -// Closure has_ref = Bind(&foo, ConstRef(n)); -// -// no_ref.Run(); // Prints "1" -// has_ref.Run(); // Prints "1" -// -// n = 2; -// no_ref.Run(); // Prints "1" -// has_ref.Run(); // Prints "2" -// -// Note that because ConstRef() takes a reference on |n|, |n| must outlive all -// its bound callbacks. -// -// -// EXAMPLE OF IgnoreResult(): -// -// int DoSomething(int arg) { cout << arg << endl; } -// -// // Assign to a Callback with a void return type. -// Callback cb = Bind(IgnoreResult(&DoSomething)); -// cb->Run(1); // Prints "1". -// -// // Prints "1" on |ml|. -// ml->PostTask(FROM_HERE, Bind(IgnoreResult(&DoSomething), 1); -// -// -// EXAMPLE OF Passed(): -// -// void TakesOwnership(scoped_ptr arg) { } -// scoped_ptr CreateFoo() { return scoped_ptr(new Foo()); } -// -// scoped_ptr f(new Foo()); -// -// // |cb| is given ownership of Foo(). |f| is now NULL. -// // You can use f.Pass() in place of &f, but it's more verbose. -// Closure cb = Bind(&TakesOwnership, Passed(&f)); -// -// // Run was never called so |cb| still owns Foo() and deletes -// // it on Reset(). -// cb.Reset(); -// -// // |cb| is given a new Foo created by CreateFoo(). -// cb = Bind(&TakesOwnership, Passed(CreateFoo())); -// -// // |arg| in TakesOwnership() is given ownership of Foo(). |cb| -// // no longer owns Foo() and, if reset, would not delete Foo(). -// cb.Run(); // Foo() is now transferred to |arg| and deleted. -// cb.Run(); // This CHECK()s since Foo() already been used once. -// -// Passed() is particularly useful with PostTask() when you are transferring -// ownership of an argument into a task, but don't necessarily know if the -// task will always be executed. This can happen if the task is cancellable -// or if it is posted to a MessageLoopProxy. -// -// -// SIMPLE FUNCTIONS AND UTILITIES. -// -// DoNothing() - Useful for creating a Closure that does nothing when called. -// DeletePointer() - Useful for creating a Closure that will delete a -// pointer when invoked. Only use this when necessary. -// In most cases MessageLoop::DeleteSoon() is a better -// fit. -// ScopedClosureRunner - Scoper object that runs the wrapped closure when it -// goes out of scope. It's conceptually similar to -// scoped_ptr<> but calls Run() instead of deleting -// the pointer. - -#ifndef BASE_BIND_HELPERS_H_ -#define BASE_BIND_HELPERS_H_ - -#include "base/basictypes.h" -#include "base/callback.h" -#include "base/memory/weak_ptr.h" -#include "base/template_util.h" - -namespace base { -namespace internal { - -// Use the Substitution Failure Is Not An Error (SFINAE) trick to inspect T -// for the existence of AddRef() and Release() functions of the correct -// signature. -// -// http://en.wikipedia.org/wiki/Substitution_failure_is_not_an_error -// http://stackoverflow.com/questions/257288/is-it-possible-to-write-a-c-template-to-check-for-a-functions-existence -// http://stackoverflow.com/questions/4358584/sfinae-approach-comparison -// http://stackoverflow.com/questions/1966362/sfinae-to-check-for-inherited-member-functions -// -// The last link in particular show the method used below. -// -// For SFINAE to work with inherited methods, we need to pull some extra tricks -// with multiple inheritance. In the more standard formulation, the overloads -// of Check would be: -// -// template -// Yes NotTheCheckWeWant(Helper<&C::TargetFunc>*); -// -// template -// No NotTheCheckWeWant(...); -// -// static const bool value = sizeof(NotTheCheckWeWant(0)) == sizeof(Yes); -// -// The problem here is that template resolution will not match -// C::TargetFunc if TargetFunc does not exist directly in C. That is, if -// TargetFunc in inherited from an ancestor, &C::TargetFunc will not match, -// |value| will be false. This formulation only checks for whether or -// not TargetFunc exist directly in the class being introspected. -// -// To get around this, we play a dirty trick with multiple inheritance. -// First, We create a class BaseMixin that declares each function that we -// want to probe for. Then we create a class Base that inherits from both T -// (the class we wish to probe) and BaseMixin. Note that the function -// signature in BaseMixin does not need to match the signature of the function -// we are probing for; thus it's easiest to just use void(void). -// -// Now, if TargetFunc exists somewhere in T, then &Base::TargetFunc has an -// ambiguous resolution between BaseMixin and T. This lets us write the -// following: -// -// template -// No GoodCheck(Helper<&C::TargetFunc>*); -// -// template -// Yes GoodCheck(...); -// -// static const bool value = sizeof(GoodCheck(0)) == sizeof(Yes); -// -// Notice here that the variadic version of GoodCheck() returns Yes here -// instead of No like the previous one. Also notice that we calculate |value| -// by specializing GoodCheck() on Base instead of T. -// -// We've reversed the roles of the variadic, and Helper overloads. -// GoodCheck(Helper<&C::TargetFunc>*), when C = Base, fails to be a valid -// substitution if T::TargetFunc exists. Thus GoodCheck(0) will resolve -// to the variadic version if T has TargetFunc. If T::TargetFunc does not -// exist, then &C::TargetFunc is not ambiguous, and the overload resolution -// will prefer GoodCheck(Helper<&C::TargetFunc>*). -// -// This method of SFINAE will correctly probe for inherited names, but it cannot -// typecheck those names. It's still a good enough sanity check though. -// -// Works on gcc-4.2, gcc-4.4, and Visual Studio 2008. -// -// TODO(ajwong): Move to ref_counted.h or template_util.h when we've vetted -// this works well. -// -// TODO(ajwong): Make this check for Release() as well. -// See http://crbug.com/82038. -template -class SupportsAddRefAndRelease { - typedef char Yes[1]; - typedef char No[2]; - - struct BaseMixin { - void AddRef(); - }; - -// MSVC warns when you try to use Base if T has a private destructor, the -// common pattern for refcounted types. It does this even though no attempt to -// instantiate Base is made. We disable the warning for this definition. -#if defined(OS_WIN) -#pragma warning(push) -#pragma warning(disable:4624) -#endif - struct Base : public T, public BaseMixin { - }; -#if defined(OS_WIN) -#pragma warning(pop) -#endif - - template struct Helper {}; - - template - static No& Check(Helper<&C::AddRef>*); - - template - static Yes& Check(...); - - public: - static const bool value = sizeof(Check(0)) == sizeof(Yes); -}; - -// Helpers to assert that arguments of a recounted type are bound with a -// scoped_refptr. -template -struct UnsafeBindtoRefCountedArgHelper : false_type { -}; - -template -struct UnsafeBindtoRefCountedArgHelper - : integral_constant::value> { -}; - -template -struct UnsafeBindtoRefCountedArg : false_type { -}; - -template -struct UnsafeBindtoRefCountedArg - : UnsafeBindtoRefCountedArgHelper::value, T> { -}; - -template -class HasIsMethodTag { - typedef char Yes[1]; - typedef char No[2]; - - template - static Yes& Check(typename U::IsMethod*); - - template - static No& Check(...); - - public: - static const bool value = sizeof(Check(0)) == sizeof(Yes); -}; - -template -class UnretainedWrapper { - public: - explicit UnretainedWrapper(T* o) : ptr_(o) {} - T* get() const { return ptr_; } - private: - T* ptr_; -}; - -template -class ConstRefWrapper { - public: - explicit ConstRefWrapper(const T& o) : ptr_(&o) {} - const T& get() const { return *ptr_; } - private: - const T* ptr_; -}; - -template -struct IgnoreResultHelper { - explicit IgnoreResultHelper(T functor) : functor_(functor) {} - - T functor_; -}; - -template -struct IgnoreResultHelper > { - explicit IgnoreResultHelper(const Callback& functor) : functor_(functor) {} - - const Callback& functor_; -}; - -// An alternate implementation is to avoid the destructive copy, and instead -// specialize ParamTraits<> for OwnedWrapper<> to change the StorageType to -// a class that is essentially a scoped_ptr<>. -// -// The current implementation has the benefit though of leaving ParamTraits<> -// fully in callback_internal.h as well as avoiding type conversions during -// storage. -template -class OwnedWrapper { - public: - explicit OwnedWrapper(T* o) : ptr_(o) {} - ~OwnedWrapper() { delete ptr_; } - T* get() const { return ptr_; } - OwnedWrapper(const OwnedWrapper& other) { - ptr_ = other.ptr_; - other.ptr_ = NULL; - } - - private: - mutable T* ptr_; -}; - -// PassedWrapper is a copyable adapter for a scoper that ignores const. -// -// It is needed to get around the fact that Bind() takes a const reference to -// all its arguments. Because Bind() takes a const reference to avoid -// unnecessary copies, it is incompatible with movable-but-not-copyable -// types; doing a destructive "move" of the type into Bind() would violate -// the const correctness. -// -// This conundrum cannot be solved without either C++11 rvalue references or -// a O(2^n) blowup of Bind() templates to handle each combination of regular -// types and movable-but-not-copyable types. Thus we introduce a wrapper type -// that is copyable to transmit the correct type information down into -// BindState<>. Ignoring const in this type makes sense because it is only -// created when we are explicitly trying to do a destructive move. -// -// Two notes: -// 1) PassedWrapper supports any type that has a "Pass()" function. -// This is intentional. The whitelisting of which specific types we -// support is maintained by CallbackParamTraits<>. -// 2) is_valid_ is distinct from NULL because it is valid to bind a "NULL" -// scoper to a Callback and allow the Callback to execute once. -template -class PassedWrapper { - public: - explicit PassedWrapper(T scoper) : is_valid_(true), scoper_(scoper.Pass()) {} - PassedWrapper(const PassedWrapper& other) - : is_valid_(other.is_valid_), scoper_(other.scoper_.Pass()) { - } - T Pass() const { - CHECK(is_valid_); - is_valid_ = false; - return scoper_.Pass(); - } - - private: - mutable bool is_valid_; - mutable T scoper_; -}; - -// Unwrap the stored parameters for the wrappers above. -template -struct UnwrapTraits { - typedef const T& ForwardType; - static ForwardType Unwrap(const T& o) { return o; } -}; - -template -struct UnwrapTraits > { - typedef T* ForwardType; - static ForwardType Unwrap(UnretainedWrapper unretained) { - return unretained.get(); - } -}; - -template -struct UnwrapTraits > { - typedef const T& ForwardType; - static ForwardType Unwrap(ConstRefWrapper const_ref) { - return const_ref.get(); - } -}; - -template -struct UnwrapTraits > { - typedef T* ForwardType; - static ForwardType Unwrap(const scoped_refptr& o) { return o.get(); } -}; - -template -struct UnwrapTraits > { - typedef const WeakPtr& ForwardType; - static ForwardType Unwrap(const WeakPtr& o) { return o; } -}; - -template -struct UnwrapTraits > { - typedef T* ForwardType; - static ForwardType Unwrap(const OwnedWrapper& o) { - return o.get(); - } -}; - -template -struct UnwrapTraits > { - typedef T ForwardType; - static T Unwrap(PassedWrapper& o) { - return o.Pass(); - } -}; - -// Utility for handling different refcounting semantics in the Bind() -// function. -template -struct MaybeRefcount; - -template -struct MaybeRefcount { - static void AddRef(const T&) {} - static void Release(const T&) {} -}; - -template -struct MaybeRefcount { - static void AddRef(const T*) {} - static void Release(const T*) {} -}; - -template -struct MaybeRefcount { - static void AddRef(const T&) {} - static void Release(const T&) {} -}; - -template -struct MaybeRefcount { - static void AddRef(T* o) { o->AddRef(); } - static void Release(T* o) { o->Release(); } -}; - -// No need to additionally AddRef() and Release() since we are storing a -// scoped_refptr<> inside the storage object already. -template -struct MaybeRefcount > { - static void AddRef(const scoped_refptr& o) {} - static void Release(const scoped_refptr& o) {} -}; - -template -struct MaybeRefcount { - static void AddRef(const T* o) { o->AddRef(); } - static void Release(const T* o) { o->Release(); } -}; - -// IsWeakMethod is a helper that determine if we are binding a WeakPtr<> to a -// method. It is used internally by Bind() to select the correct -// InvokeHelper that will no-op itself in the event the WeakPtr<> for -// the target object is invalidated. -// -// P1 should be the type of the object that will be received of the method. -template -struct IsWeakMethod : public false_type {}; - -template -struct IsWeakMethod > : public true_type {}; - -template -struct IsWeakMethod > > : public true_type {}; - -} // namespace internal - -template -static inline internal::UnretainedWrapper Unretained(T* o) { - return internal::UnretainedWrapper(o); -} - -template -static inline internal::ConstRefWrapper ConstRef(const T& o) { - return internal::ConstRefWrapper(o); -} - -template -static inline internal::OwnedWrapper Owned(T* o) { - return internal::OwnedWrapper(o); -} - -// We offer 2 syntaxes for calling Passed(). The first takes a temporary and -// is best suited for use with the return value of a function. The second -// takes a pointer to the scoper and is just syntactic sugar to avoid having -// to write Passed(scoper.Pass()). -template -static inline internal::PassedWrapper Passed(T scoper) { - return internal::PassedWrapper(scoper.Pass()); -} -template -static inline internal::PassedWrapper Passed(T* scoper) { - return internal::PassedWrapper(scoper->Pass()); -} - -template -static inline internal::IgnoreResultHelper IgnoreResult(T data) { - return internal::IgnoreResultHelper(data); -} - -template -static inline internal::IgnoreResultHelper > -IgnoreResult(const Callback& data) { - return internal::IgnoreResultHelper >(data); -} - -BASE_EXPORT void DoNothing(); - -template -void DeletePointer(T* obj) { - delete obj; -} - -// ScopedClosureRunner is akin to scoped_ptr for Closures. It ensures that the -// Closure is executed and deleted no matter how the current scope exits. -class BASE_EXPORT ScopedClosureRunner { - public: - explicit ScopedClosureRunner(const Closure& closure); - ~ScopedClosureRunner(); - - Closure Release(); - - private: - Closure closure_; - - DISALLOW_IMPLICIT_CONSTRUCTORS(ScopedClosureRunner); -}; - -} // namespace base - -#endif // BASE_BIND_HELPERS_H_ diff --git a/base/bind_helpers_unittest.cc b/base/bind_helpers_unittest.cc deleted file mode 100644 index 3ef2d75435..0000000000 --- a/base/bind_helpers_unittest.cc +++ /dev/null @@ -1,39 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "base/bind_helpers.h" - -#include "base/callback.h" -#include "base/bind.h" -#include "testing/gtest/include/gtest/gtest.h" - -namespace { - -void Increment(int* value) { - (*value)++; -} - -TEST(BindHelpersTest, TestScopedClosureRunnerExitScope) { - int run_count = 0; - { - base::ScopedClosureRunner runner(base::Bind(&Increment, &run_count)); - EXPECT_EQ(0, run_count); - } - EXPECT_EQ(1, run_count); -} - -TEST(BindHelpersTest, TestScopedClosureRunnerRelease) { - int run_count = 0; - base::Closure c; - { - base::ScopedClosureRunner runner(base::Bind(&Increment, &run_count)); - c = runner.Release(); - EXPECT_EQ(0, run_count); - } - EXPECT_EQ(0, run_count); - c.Run(); - EXPECT_EQ(1, run_count); -} - -} // namespace diff --git a/base/bind_internal.h b/base/bind_internal.h deleted file mode 100644 index ae17ebf86c..0000000000 --- a/base/bind_internal.h +++ /dev/null @@ -1,2789 +0,0 @@ -// This file was GENERATED by command: -// pump.py bind_internal.h.pump -// DO NOT EDIT BY HAND!!! - - -// Copyright (c) 2011 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef BASE_BIND_INTERNAL_H_ -#define BASE_BIND_INTERNAL_H_ - -#include "base/bind_helpers.h" -#include "base/callback_internal.h" -#include "base/memory/raw_scoped_refptr_mismatch_checker.h" -#include "base/memory/weak_ptr.h" -#include "base/template_util.h" -#include "build/build_config.h" - -#if defined(OS_WIN) -#include "base/bind_internal_win.h" -#endif - -namespace base { -namespace internal { - -// See base/callback.h for user documentation. -// -// -// CONCEPTS: -// Runnable -- A type (really a type class) that has a single Run() method -// and a RunType typedef that corresponds to the type of Run(). -// A Runnable can declare that it should treated like a method -// call by including a typedef named IsMethod. The value of -// this typedef is NOT inspected, only the existence. When a -// Runnable declares itself a method, Bind() will enforce special -// refcounting + WeakPtr handling semantics for the first -// parameter which is expected to be an object. -// Functor -- A copyable type representing something that should be called. -// All function pointers, Callback<>, and Runnables are functors -// even if the invocation syntax differs. -// RunType -- A function type (as opposed to function _pointer_ type) for -// a Run() function. Usually just a convenience typedef. -// (Bound)ArgsType -- A function type that is being (ab)used to store the -// types of set of arguments. The "return" type is always -// void here. We use this hack so that we do not need -// a new type name for each arity of type. (eg., -// BindState1, BindState2). This makes forward -// declarations and friending much much easier. -// -// Types: -// RunnableAdapter<> -- Wraps the various "function" pointer types into an -// object that adheres to the Runnable interface. -// There are |3*ARITY| RunnableAdapter types. -// FunctionTraits<> -- Type traits that unwrap a function signature into a -// a set of easier to use typedefs. Used mainly for -// compile time asserts. -// There are |ARITY| FunctionTraits types. -// ForceVoidReturn<> -- Helper class for translating function signatures to -// equivalent forms with a "void" return type. -// There are |ARITY| ForceVoidReturn types. -// FunctorTraits<> -- Type traits used determine the correct RunType and -// RunnableType for a Functor. This is where function -// signature adapters are applied. -// There are |ARITY| ForceVoidReturn types. -// MakeRunnable<> -- Takes a Functor and returns an object in the Runnable -// type class that represents the underlying Functor. -// There are |O(1)| MakeRunnable types. -// InvokeHelper<> -- Take a Runnable + arguments and actully invokes it. -// Handle the differing syntaxes needed for WeakPtr<> support, -// and for ignoring return values. This is separate from -// Invoker to avoid creating multiple version of Invoker<> -// which grows at O(n^2) with the arity. -// There are |k*ARITY| InvokeHelper types. -// Invoker<> -- Unwraps the curried parameters and executes the Runnable. -// There are |(ARITY^2 + ARITY)/2| Invoketypes. -// BindState<> -- Stores the curried parameters, and is the main entry point -// into the Bind() system, doing most of the type resolution. -// There are ARITY BindState types. - -// RunnableAdapter<> -// -// The RunnableAdapter<> templates provide a uniform interface for invoking -// a function pointer, method pointer, or const method pointer. The adapter -// exposes a Run() method with an appropriate signature. Using this wrapper -// allows for writing code that supports all three pointer types without -// undue repetition. Without it, a lot of code would need to be repeated 3 -// times. -// -// For method pointers and const method pointers the first argument to Run() -// is considered to be the received of the method. This is similar to STL's -// mem_fun(). -// -// This class also exposes a RunType typedef that is the function type of the -// Run() function. -// -// If and only if the wrapper contains a method or const method pointer, an -// IsMethod typedef is exposed. The existence of this typedef (NOT the value) -// marks that the wrapper should be considered a method wrapper. - -template -class RunnableAdapter; - -// Function: Arity 0. -template -class RunnableAdapter { - public: - typedef R (RunType)(); - - explicit RunnableAdapter(R(*function)()) - : function_(function) { - } - - R Run() { - return function_(); - } - - private: - R (*function_)(); -}; - -// Method: Arity 0. -template -class RunnableAdapter { - public: - typedef R (RunType)(T*); - typedef true_type IsMethod; - - explicit RunnableAdapter(R(T::*method)()) - : method_(method) { - } - - R Run(T* object) { - return (object->*method_)(); - } - - private: - R (T::*method_)(); -}; - -// Const Method: Arity 0. -template -class RunnableAdapter { - public: - typedef R (RunType)(const T*); - typedef true_type IsMethod; - - explicit RunnableAdapter(R(T::*method)() const) - : method_(method) { - } - - R Run(const T* object) { - return (object->*method_)(); - } - - private: - R (T::*method_)() const; -}; - -// Function: Arity 1. -template -class RunnableAdapter { - public: - typedef R (RunType)(A1); - - explicit RunnableAdapter(R(*function)(A1)) - : function_(function) { - } - - R Run(typename CallbackParamTraits::ForwardType a1) { - return function_(CallbackForward(a1)); - } - - private: - R (*function_)(A1); -}; - -// Method: Arity 1. -template -class RunnableAdapter { - public: - typedef R (RunType)(T*, A1); - typedef true_type IsMethod; - - explicit RunnableAdapter(R(T::*method)(A1)) - : method_(method) { - } - - R Run(T* object, typename CallbackParamTraits::ForwardType a1) { - return (object->*method_)(CallbackForward(a1)); - } - - private: - R (T::*method_)(A1); -}; - -// Const Method: Arity 1. -template -class RunnableAdapter { - public: - typedef R (RunType)(const T*, A1); - typedef true_type IsMethod; - - explicit RunnableAdapter(R(T::*method)(A1) const) - : method_(method) { - } - - R Run(const T* object, typename CallbackParamTraits::ForwardType a1) { - return (object->*method_)(CallbackForward(a1)); - } - - private: - R (T::*method_)(A1) const; -}; - -// Function: Arity 2. -template -class RunnableAdapter { - public: - typedef R (RunType)(A1, A2); - - explicit RunnableAdapter(R(*function)(A1, A2)) - : function_(function) { - } - - R Run(typename CallbackParamTraits::ForwardType a1, - typename CallbackParamTraits::ForwardType a2) { - return function_(CallbackForward(a1), CallbackForward(a2)); - } - - private: - R (*function_)(A1, A2); -}; - -// Method: Arity 2. -template -class RunnableAdapter { - public: - typedef R (RunType)(T*, A1, A2); - typedef true_type IsMethod; - - explicit RunnableAdapter(R(T::*method)(A1, A2)) - : method_(method) { - } - - R Run(T* object, typename CallbackParamTraits::ForwardType a1, - typename CallbackParamTraits::ForwardType a2) { - return (object->*method_)(CallbackForward(a1), CallbackForward(a2)); - } - - private: - R (T::*method_)(A1, A2); -}; - -// Const Method: Arity 2. -template -class RunnableAdapter { - public: - typedef R (RunType)(const T*, A1, A2); - typedef true_type IsMethod; - - explicit RunnableAdapter(R(T::*method)(A1, A2) const) - : method_(method) { - } - - R Run(const T* object, typename CallbackParamTraits::ForwardType a1, - typename CallbackParamTraits::ForwardType a2) { - return (object->*method_)(CallbackForward(a1), CallbackForward(a2)); - } - - private: - R (T::*method_)(A1, A2) const; -}; - -// Function: Arity 3. -template -class RunnableAdapter { - public: - typedef R (RunType)(A1, A2, A3); - - explicit RunnableAdapter(R(*function)(A1, A2, A3)) - : function_(function) { - } - - R Run(typename CallbackParamTraits::ForwardType a1, - typename CallbackParamTraits::ForwardType a2, - typename CallbackParamTraits::ForwardType a3) { - return function_(CallbackForward(a1), CallbackForward(a2), - CallbackForward(a3)); - } - - private: - R (*function_)(A1, A2, A3); -}; - -// Method: Arity 3. -template -class RunnableAdapter { - public: - typedef R (RunType)(T*, A1, A2, A3); - typedef true_type IsMethod; - - explicit RunnableAdapter(R(T::*method)(A1, A2, A3)) - : method_(method) { - } - - R Run(T* object, typename CallbackParamTraits::ForwardType a1, - typename CallbackParamTraits::ForwardType a2, - typename CallbackParamTraits::ForwardType a3) { - return (object->*method_)(CallbackForward(a1), CallbackForward(a2), - CallbackForward(a3)); - } - - private: - R (T::*method_)(A1, A2, A3); -}; - -// Const Method: Arity 3. -template -class RunnableAdapter { - public: - typedef R (RunType)(const T*, A1, A2, A3); - typedef true_type IsMethod; - - explicit RunnableAdapter(R(T::*method)(A1, A2, A3) const) - : method_(method) { - } - - R Run(const T* object, typename CallbackParamTraits::ForwardType a1, - typename CallbackParamTraits::ForwardType a2, - typename CallbackParamTraits::ForwardType a3) { - return (object->*method_)(CallbackForward(a1), CallbackForward(a2), - CallbackForward(a3)); - } - - private: - R (T::*method_)(A1, A2, A3) const; -}; - -// Function: Arity 4. -template -class RunnableAdapter { - public: - typedef R (RunType)(A1, A2, A3, A4); - - explicit RunnableAdapter(R(*function)(A1, A2, A3, A4)) - : function_(function) { - } - - R Run(typename CallbackParamTraits::ForwardType a1, - typename CallbackParamTraits::ForwardType a2, - typename CallbackParamTraits::ForwardType a3, - typename CallbackParamTraits::ForwardType a4) { - return function_(CallbackForward(a1), CallbackForward(a2), - CallbackForward(a3), CallbackForward(a4)); - } - - private: - R (*function_)(A1, A2, A3, A4); -}; - -// Method: Arity 4. -template -class RunnableAdapter { - public: - typedef R (RunType)(T*, A1, A2, A3, A4); - typedef true_type IsMethod; - - explicit RunnableAdapter(R(T::*method)(A1, A2, A3, A4)) - : method_(method) { - } - - R Run(T* object, typename CallbackParamTraits::ForwardType a1, - typename CallbackParamTraits::ForwardType a2, - typename CallbackParamTraits::ForwardType a3, - typename CallbackParamTraits::ForwardType a4) { - return (object->*method_)(CallbackForward(a1), CallbackForward(a2), - CallbackForward(a3), CallbackForward(a4)); - } - - private: - R (T::*method_)(A1, A2, A3, A4); -}; - -// Const Method: Arity 4. -template -class RunnableAdapter { - public: - typedef R (RunType)(const T*, A1, A2, A3, A4); - typedef true_type IsMethod; - - explicit RunnableAdapter(R(T::*method)(A1, A2, A3, A4) const) - : method_(method) { - } - - R Run(const T* object, typename CallbackParamTraits::ForwardType a1, - typename CallbackParamTraits::ForwardType a2, - typename CallbackParamTraits::ForwardType a3, - typename CallbackParamTraits::ForwardType a4) { - return (object->*method_)(CallbackForward(a1), CallbackForward(a2), - CallbackForward(a3), CallbackForward(a4)); - } - - private: - R (T::*method_)(A1, A2, A3, A4) const; -}; - -// Function: Arity 5. -template -class RunnableAdapter { - public: - typedef R (RunType)(A1, A2, A3, A4, A5); - - explicit RunnableAdapter(R(*function)(A1, A2, A3, A4, A5)) - : function_(function) { - } - - R Run(typename CallbackParamTraits::ForwardType a1, - typename CallbackParamTraits::ForwardType a2, - typename CallbackParamTraits::ForwardType a3, - typename CallbackParamTraits::ForwardType a4, - typename CallbackParamTraits::ForwardType a5) { - return function_(CallbackForward(a1), CallbackForward(a2), - CallbackForward(a3), CallbackForward(a4), CallbackForward(a5)); - } - - private: - R (*function_)(A1, A2, A3, A4, A5); -}; - -// Method: Arity 5. -template -class RunnableAdapter { - public: - typedef R (RunType)(T*, A1, A2, A3, A4, A5); - typedef true_type IsMethod; - - explicit RunnableAdapter(R(T::*method)(A1, A2, A3, A4, A5)) - : method_(method) { - } - - R Run(T* object, typename CallbackParamTraits::ForwardType a1, - typename CallbackParamTraits::ForwardType a2, - typename CallbackParamTraits::ForwardType a3, - typename CallbackParamTraits::ForwardType a4, - typename CallbackParamTraits::ForwardType a5) { - return (object->*method_)(CallbackForward(a1), CallbackForward(a2), - CallbackForward(a3), CallbackForward(a4), CallbackForward(a5)); - } - - private: - R (T::*method_)(A1, A2, A3, A4, A5); -}; - -// Const Method: Arity 5. -template -class RunnableAdapter { - public: - typedef R (RunType)(const T*, A1, A2, A3, A4, A5); - typedef true_type IsMethod; - - explicit RunnableAdapter(R(T::*method)(A1, A2, A3, A4, A5) const) - : method_(method) { - } - - R Run(const T* object, typename CallbackParamTraits::ForwardType a1, - typename CallbackParamTraits::ForwardType a2, - typename CallbackParamTraits::ForwardType a3, - typename CallbackParamTraits::ForwardType a4, - typename CallbackParamTraits::ForwardType a5) { - return (object->*method_)(CallbackForward(a1), CallbackForward(a2), - CallbackForward(a3), CallbackForward(a4), CallbackForward(a5)); - } - - private: - R (T::*method_)(A1, A2, A3, A4, A5) const; -}; - -// Function: Arity 6. -template -class RunnableAdapter { - public: - typedef R (RunType)(A1, A2, A3, A4, A5, A6); - - explicit RunnableAdapter(R(*function)(A1, A2, A3, A4, A5, A6)) - : function_(function) { - } - - R Run(typename CallbackParamTraits::ForwardType a1, - typename CallbackParamTraits::ForwardType a2, - typename CallbackParamTraits::ForwardType a3, - typename CallbackParamTraits::ForwardType a4, - typename CallbackParamTraits::ForwardType a5, - typename CallbackParamTraits::ForwardType a6) { - return function_(CallbackForward(a1), CallbackForward(a2), - CallbackForward(a3), CallbackForward(a4), CallbackForward(a5), - CallbackForward(a6)); - } - - private: - R (*function_)(A1, A2, A3, A4, A5, A6); -}; - -// Method: Arity 6. -template -class RunnableAdapter { - public: - typedef R (RunType)(T*, A1, A2, A3, A4, A5, A6); - typedef true_type IsMethod; - - explicit RunnableAdapter(R(T::*method)(A1, A2, A3, A4, A5, A6)) - : method_(method) { - } - - R Run(T* object, typename CallbackParamTraits::ForwardType a1, - typename CallbackParamTraits::ForwardType a2, - typename CallbackParamTraits::ForwardType a3, - typename CallbackParamTraits::ForwardType a4, - typename CallbackParamTraits::ForwardType a5, - typename CallbackParamTraits::ForwardType a6) { - return (object->*method_)(CallbackForward(a1), CallbackForward(a2), - CallbackForward(a3), CallbackForward(a4), CallbackForward(a5), - CallbackForward(a6)); - } - - private: - R (T::*method_)(A1, A2, A3, A4, A5, A6); -}; - -// Const Method: Arity 6. -template -class RunnableAdapter { - public: - typedef R (RunType)(const T*, A1, A2, A3, A4, A5, A6); - typedef true_type IsMethod; - - explicit RunnableAdapter(R(T::*method)(A1, A2, A3, A4, A5, A6) const) - : method_(method) { - } - - R Run(const T* object, typename CallbackParamTraits::ForwardType a1, - typename CallbackParamTraits::ForwardType a2, - typename CallbackParamTraits::ForwardType a3, - typename CallbackParamTraits::ForwardType a4, - typename CallbackParamTraits::ForwardType a5, - typename CallbackParamTraits::ForwardType a6) { - return (object->*method_)(CallbackForward(a1), CallbackForward(a2), - CallbackForward(a3), CallbackForward(a4), CallbackForward(a5), - CallbackForward(a6)); - } - - private: - R (T::*method_)(A1, A2, A3, A4, A5, A6) const; -}; - -// Function: Arity 7. -template -class RunnableAdapter { - public: - typedef R (RunType)(A1, A2, A3, A4, A5, A6, A7); - - explicit RunnableAdapter(R(*function)(A1, A2, A3, A4, A5, A6, A7)) - : function_(function) { - } - - R Run(typename CallbackParamTraits::ForwardType a1, - typename CallbackParamTraits::ForwardType a2, - typename CallbackParamTraits::ForwardType a3, - typename CallbackParamTraits::ForwardType a4, - typename CallbackParamTraits::ForwardType a5, - typename CallbackParamTraits::ForwardType a6, - typename CallbackParamTraits::ForwardType a7) { - return function_(CallbackForward(a1), CallbackForward(a2), - CallbackForward(a3), CallbackForward(a4), CallbackForward(a5), - CallbackForward(a6), CallbackForward(a7)); - } - - private: - R (*function_)(A1, A2, A3, A4, A5, A6, A7); -}; - -// Method: Arity 7. -template -class RunnableAdapter { - public: - typedef R (RunType)(T*, A1, A2, A3, A4, A5, A6, A7); - typedef true_type IsMethod; - - explicit RunnableAdapter(R(T::*method)(A1, A2, A3, A4, A5, A6, A7)) - : method_(method) { - } - - R Run(T* object, typename CallbackParamTraits::ForwardType a1, - typename CallbackParamTraits::ForwardType a2, - typename CallbackParamTraits::ForwardType a3, - typename CallbackParamTraits::ForwardType a4, - typename CallbackParamTraits::ForwardType a5, - typename CallbackParamTraits::ForwardType a6, - typename CallbackParamTraits::ForwardType a7) { - return (object->*method_)(CallbackForward(a1), CallbackForward(a2), - CallbackForward(a3), CallbackForward(a4), CallbackForward(a5), - CallbackForward(a6), CallbackForward(a7)); - } - - private: - R (T::*method_)(A1, A2, A3, A4, A5, A6, A7); -}; - -// Const Method: Arity 7. -template -class RunnableAdapter { - public: - typedef R (RunType)(const T*, A1, A2, A3, A4, A5, A6, A7); - typedef true_type IsMethod; - - explicit RunnableAdapter(R(T::*method)(A1, A2, A3, A4, A5, A6, A7) const) - : method_(method) { - } - - R Run(const T* object, typename CallbackParamTraits::ForwardType a1, - typename CallbackParamTraits::ForwardType a2, - typename CallbackParamTraits::ForwardType a3, - typename CallbackParamTraits::ForwardType a4, - typename CallbackParamTraits::ForwardType a5, - typename CallbackParamTraits::ForwardType a6, - typename CallbackParamTraits::ForwardType a7) { - return (object->*method_)(CallbackForward(a1), CallbackForward(a2), - CallbackForward(a3), CallbackForward(a4), CallbackForward(a5), - CallbackForward(a6), CallbackForward(a7)); - } - - private: - R (T::*method_)(A1, A2, A3, A4, A5, A6, A7) const; -}; - - -// FunctionTraits<> -// -// Breaks a function signature apart into typedefs for easier introspection. -template -struct FunctionTraits; - -template -struct FunctionTraits { - typedef R ReturnType; -}; - -template -struct FunctionTraits { - typedef R ReturnType; - typedef A1 A1Type; -}; - -template -struct FunctionTraits { - typedef R ReturnType; - typedef A1 A1Type; - typedef A2 A2Type; -}; - -template -struct FunctionTraits { - typedef R ReturnType; - typedef A1 A1Type; - typedef A2 A2Type; - typedef A3 A3Type; -}; - -template -struct FunctionTraits { - typedef R ReturnType; - typedef A1 A1Type; - typedef A2 A2Type; - typedef A3 A3Type; - typedef A4 A4Type; -}; - -template -struct FunctionTraits { - typedef R ReturnType; - typedef A1 A1Type; - typedef A2 A2Type; - typedef A3 A3Type; - typedef A4 A4Type; - typedef A5 A5Type; -}; - -template -struct FunctionTraits { - typedef R ReturnType; - typedef A1 A1Type; - typedef A2 A2Type; - typedef A3 A3Type; - typedef A4 A4Type; - typedef A5 A5Type; - typedef A6 A6Type; -}; - -template -struct FunctionTraits { - typedef R ReturnType; - typedef A1 A1Type; - typedef A2 A2Type; - typedef A3 A3Type; - typedef A4 A4Type; - typedef A5 A5Type; - typedef A6 A6Type; - typedef A7 A7Type; -}; - - -// ForceVoidReturn<> -// -// Set of templates that support forcing the function return type to void. -template -struct ForceVoidReturn; - -template -struct ForceVoidReturn { - typedef void(RunType)(); -}; - -template -struct ForceVoidReturn { - typedef void(RunType)(A1); -}; - -template -struct ForceVoidReturn { - typedef void(RunType)(A1, A2); -}; - -template -struct ForceVoidReturn { - typedef void(RunType)(A1, A2, A3); -}; - -template -struct ForceVoidReturn { - typedef void(RunType)(A1, A2, A3, A4); -}; - -template -struct ForceVoidReturn { - typedef void(RunType)(A1, A2, A3, A4, A5); -}; - -template -struct ForceVoidReturn { - typedef void(RunType)(A1, A2, A3, A4, A5, A6); -}; - -template -struct ForceVoidReturn { - typedef void(RunType)(A1, A2, A3, A4, A5, A6, A7); -}; - - -// FunctorTraits<> -// -// See description at top of file. -template -struct FunctorTraits { - typedef RunnableAdapter RunnableType; - typedef typename RunnableType::RunType RunType; -}; - -template -struct FunctorTraits > { - typedef typename FunctorTraits::RunnableType RunnableType; - typedef typename ForceVoidReturn< - typename RunnableType::RunType>::RunType RunType; -}; - -template -struct FunctorTraits > { - typedef Callback RunnableType; - typedef typename Callback::RunType RunType; -}; - - -// MakeRunnable<> -// -// Converts a passed in functor to a RunnableType using type inference. - -template -typename FunctorTraits::RunnableType MakeRunnable(const T& t) { - return RunnableAdapter(t); -} - -template -typename FunctorTraits::RunnableType -MakeRunnable(const IgnoreResultHelper& t) { - return MakeRunnable(t.functor_); -} - -template -const typename FunctorTraits >::RunnableType& -MakeRunnable(const Callback& t) { - DCHECK(!t.is_null()); - return t; -} - - -// InvokeHelper<> -// -// There are 3 logical InvokeHelper<> specializations: normal, void-return, -// WeakCalls. -// -// The normal type just calls the underlying runnable. -// -// We need a InvokeHelper to handle void return types in order to support -// IgnoreResult(). Normally, if the Runnable's RunType had a void return, -// the template system would just accept "return functor.Run()" ignoring -// the fact that a void function is being used with return. This piece of -// sugar breaks though when the Runnable's RunType is not void. Thus, we -// need a partial specialization to change the syntax to drop the "return" -// from the invocation call. -// -// WeakCalls similarly need special syntax that is applied to the first -// argument to check if they should no-op themselves. -template -struct InvokeHelper; - -template -struct InvokeHelper { - static ReturnType MakeItSo(Runnable runnable) { - return runnable.Run(); - } -}; - -template -struct InvokeHelper { - static void MakeItSo(Runnable runnable) { - runnable.Run(); - } -}; - -template -struct InvokeHelper { - static ReturnType MakeItSo(Runnable runnable, A1 a1) { - return runnable.Run(CallbackForward(a1)); - } -}; - -template -struct InvokeHelper { - static void MakeItSo(Runnable runnable, A1 a1) { - runnable.Run(CallbackForward(a1)); - } -}; - -template -struct InvokeHelper { - static void MakeItSo(Runnable runnable, BoundWeakPtr weak_ptr) { - if (!weak_ptr.get()) { - return; - } - runnable.Run(weak_ptr.get()); - } -}; - -template -struct InvokeHelper { - static ReturnType MakeItSo(Runnable runnable, A1 a1, A2 a2) { - return runnable.Run(CallbackForward(a1), CallbackForward(a2)); - } -}; - -template -struct InvokeHelper { - static void MakeItSo(Runnable runnable, A1 a1, A2 a2) { - runnable.Run(CallbackForward(a1), CallbackForward(a2)); - } -}; - -template -struct InvokeHelper { - static void MakeItSo(Runnable runnable, BoundWeakPtr weak_ptr, A2 a2) { - if (!weak_ptr.get()) { - return; - } - runnable.Run(weak_ptr.get(), CallbackForward(a2)); - } -}; - -template -struct InvokeHelper { - static ReturnType MakeItSo(Runnable runnable, A1 a1, A2 a2, A3 a3) { - return runnable.Run(CallbackForward(a1), CallbackForward(a2), - CallbackForward(a3)); - } -}; - -template -struct InvokeHelper { - static void MakeItSo(Runnable runnable, A1 a1, A2 a2, A3 a3) { - runnable.Run(CallbackForward(a1), CallbackForward(a2), CallbackForward(a3)); - } -}; - -template -struct InvokeHelper { - static void MakeItSo(Runnable runnable, BoundWeakPtr weak_ptr, A2 a2, A3 a3) { - if (!weak_ptr.get()) { - return; - } - runnable.Run(weak_ptr.get(), CallbackForward(a2), CallbackForward(a3)); - } -}; - -template -struct InvokeHelper { - static ReturnType MakeItSo(Runnable runnable, A1 a1, A2 a2, A3 a3, A4 a4) { - return runnable.Run(CallbackForward(a1), CallbackForward(a2), - CallbackForward(a3), CallbackForward(a4)); - } -}; - -template -struct InvokeHelper { - static void MakeItSo(Runnable runnable, A1 a1, A2 a2, A3 a3, A4 a4) { - runnable.Run(CallbackForward(a1), CallbackForward(a2), CallbackForward(a3), - CallbackForward(a4)); - } -}; - -template -struct InvokeHelper { - static void MakeItSo(Runnable runnable, BoundWeakPtr weak_ptr, A2 a2, A3 a3, - A4 a4) { - if (!weak_ptr.get()) { - return; - } - runnable.Run(weak_ptr.get(), CallbackForward(a2), CallbackForward(a3), - CallbackForward(a4)); - } -}; - -template -struct InvokeHelper { - static ReturnType MakeItSo(Runnable runnable, A1 a1, A2 a2, A3 a3, A4 a4, - A5 a5) { - return runnable.Run(CallbackForward(a1), CallbackForward(a2), - CallbackForward(a3), CallbackForward(a4), CallbackForward(a5)); - } -}; - -template -struct InvokeHelper { - static void MakeItSo(Runnable runnable, A1 a1, A2 a2, A3 a3, A4 a4, A5 a5) { - runnable.Run(CallbackForward(a1), CallbackForward(a2), CallbackForward(a3), - CallbackForward(a4), CallbackForward(a5)); - } -}; - -template -struct InvokeHelper { - static void MakeItSo(Runnable runnable, BoundWeakPtr weak_ptr, A2 a2, A3 a3, - A4 a4, A5 a5) { - if (!weak_ptr.get()) { - return; - } - runnable.Run(weak_ptr.get(), CallbackForward(a2), CallbackForward(a3), - CallbackForward(a4), CallbackForward(a5)); - } -}; - -template -struct InvokeHelper { - static ReturnType MakeItSo(Runnable runnable, A1 a1, A2 a2, A3 a3, A4 a4, - A5 a5, A6 a6) { - return runnable.Run(CallbackForward(a1), CallbackForward(a2), - CallbackForward(a3), CallbackForward(a4), CallbackForward(a5), - CallbackForward(a6)); - } -}; - -template -struct InvokeHelper { - static void MakeItSo(Runnable runnable, A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, - A6 a6) { - runnable.Run(CallbackForward(a1), CallbackForward(a2), CallbackForward(a3), - CallbackForward(a4), CallbackForward(a5), CallbackForward(a6)); - } -}; - -template -struct InvokeHelper { - static void MakeItSo(Runnable runnable, BoundWeakPtr weak_ptr, A2 a2, A3 a3, - A4 a4, A5 a5, A6 a6) { - if (!weak_ptr.get()) { - return; - } - runnable.Run(weak_ptr.get(), CallbackForward(a2), CallbackForward(a3), - CallbackForward(a4), CallbackForward(a5), CallbackForward(a6)); - } -}; - -template -struct InvokeHelper { - static ReturnType MakeItSo(Runnable runnable, A1 a1, A2 a2, A3 a3, A4 a4, - A5 a5, A6 a6, A7 a7) { - return runnable.Run(CallbackForward(a1), CallbackForward(a2), - CallbackForward(a3), CallbackForward(a4), CallbackForward(a5), - CallbackForward(a6), CallbackForward(a7)); - } -}; - -template -struct InvokeHelper { - static void MakeItSo(Runnable runnable, A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, - A6 a6, A7 a7) { - runnable.Run(CallbackForward(a1), CallbackForward(a2), CallbackForward(a3), - CallbackForward(a4), CallbackForward(a5), CallbackForward(a6), - CallbackForward(a7)); - } -}; - -template -struct InvokeHelper { - static void MakeItSo(Runnable runnable, BoundWeakPtr weak_ptr, A2 a2, A3 a3, - A4 a4, A5 a5, A6 a6, A7 a7) { - if (!weak_ptr.get()) { - return; - } - runnable.Run(weak_ptr.get(), CallbackForward(a2), CallbackForward(a3), - CallbackForward(a4), CallbackForward(a5), CallbackForward(a6), - CallbackForward(a7)); - } -}; - -#if !defined(_MSC_VER) - -template -struct InvokeHelper { - // WeakCalls are only supported for functions with a void return type. - // Otherwise, the function result would be undefined if the the WeakPtr<> - // is invalidated. - COMPILE_ASSERT(is_void::value, - weak_ptrs_can_only_bind_to_methods_without_return_values); -}; - -#endif - -// Invoker<> -// -// See description at the top of the file. -template -struct Invoker; - -// Arity 0 -> 0. -template -struct Invoker<0, StorageType, R()> { - typedef R(RunType)(BindStateBase*); - - typedef R(UnboundRunType)(); - - static R Run(BindStateBase* base) { - StorageType* storage = static_cast(base); - - // Local references to make debugger stepping easier. If in a debugger, - // you really want to warp ahead and step through the - // InvokeHelper<>::MakeItSo() call below. - - return InvokeHelper - ::MakeItSo(storage->runnable_); - } -}; - -// Arity 1 -> 1. -template -struct Invoker<0, StorageType, R(X1)> { - typedef R(RunType)(BindStateBase*, - typename CallbackParamTraits::ForwardType); - - typedef R(UnboundRunType)(X1); - - static R Run(BindStateBase* base, - typename CallbackParamTraits::ForwardType x1) { - StorageType* storage = static_cast(base); - - // Local references to make debugger stepping easier. If in a debugger, - // you really want to warp ahead and step through the - // InvokeHelper<>::MakeItSo() call below. - - return InvokeHelper::ForwardType x1)> - ::MakeItSo(storage->runnable_, CallbackForward(x1)); - } -}; - -// Arity 1 -> 0. -template -struct Invoker<1, StorageType, R(X1)> { - typedef R(RunType)(BindStateBase*); - - typedef R(UnboundRunType)(); - - static R Run(BindStateBase* base) { - StorageType* storage = static_cast(base); - - // Local references to make debugger stepping easier. If in a debugger, - // you really want to warp ahead and step through the - // InvokeHelper<>::MakeItSo() call below. - typedef typename StorageType::Bound1UnwrapTraits Bound1UnwrapTraits; - - typename Bound1UnwrapTraits::ForwardType x1 = - Bound1UnwrapTraits::Unwrap(storage->p1_); - return InvokeHelper - ::MakeItSo(storage->runnable_, CallbackForward(x1)); - } -}; - -// Arity 2 -> 2. -template -struct Invoker<0, StorageType, R(X1, X2)> { - typedef R(RunType)(BindStateBase*, - typename CallbackParamTraits::ForwardType, - typename CallbackParamTraits::ForwardType); - - typedef R(UnboundRunType)(X1, X2); - - static R Run(BindStateBase* base, - typename CallbackParamTraits::ForwardType x1, - typename CallbackParamTraits::ForwardType x2) { - StorageType* storage = static_cast(base); - - // Local references to make debugger stepping easier. If in a debugger, - // you really want to warp ahead and step through the - // InvokeHelper<>::MakeItSo() call below. - - return InvokeHelper::ForwardType x1, - typename CallbackParamTraits::ForwardType x2)> - ::MakeItSo(storage->runnable_, CallbackForward(x1), - CallbackForward(x2)); - } -}; - -// Arity 2 -> 1. -template -struct Invoker<1, StorageType, R(X1, X2)> { - typedef R(RunType)(BindStateBase*, - typename CallbackParamTraits::ForwardType); - - typedef R(UnboundRunType)(X2); - - static R Run(BindStateBase* base, - typename CallbackParamTraits::ForwardType x2) { - StorageType* storage = static_cast(base); - - // Local references to make debugger stepping easier. If in a debugger, - // you really want to warp ahead and step through the - // InvokeHelper<>::MakeItSo() call below. - typedef typename StorageType::Bound1UnwrapTraits Bound1UnwrapTraits; - - typename Bound1UnwrapTraits::ForwardType x1 = - Bound1UnwrapTraits::Unwrap(storage->p1_); - return InvokeHelper::ForwardType x2)> - ::MakeItSo(storage->runnable_, CallbackForward(x1), - CallbackForward(x2)); - } -}; - -// Arity 2 -> 0. -template -struct Invoker<2, StorageType, R(X1, X2)> { - typedef R(RunType)(BindStateBase*); - - typedef R(UnboundRunType)(); - - static R Run(BindStateBase* base) { - StorageType* storage = static_cast(base); - - // Local references to make debugger stepping easier. If in a debugger, - // you really want to warp ahead and step through the - // InvokeHelper<>::MakeItSo() call below. - typedef typename StorageType::Bound1UnwrapTraits Bound1UnwrapTraits; - typedef typename StorageType::Bound2UnwrapTraits Bound2UnwrapTraits; - - typename Bound1UnwrapTraits::ForwardType x1 = - Bound1UnwrapTraits::Unwrap(storage->p1_); - typename Bound2UnwrapTraits::ForwardType x2 = - Bound2UnwrapTraits::Unwrap(storage->p2_); - return InvokeHelper - ::MakeItSo(storage->runnable_, CallbackForward(x1), - CallbackForward(x2)); - } -}; - -// Arity 3 -> 3. -template -struct Invoker<0, StorageType, R(X1, X2, X3)> { - typedef R(RunType)(BindStateBase*, - typename CallbackParamTraits::ForwardType, - typename CallbackParamTraits::ForwardType, - typename CallbackParamTraits::ForwardType); - - typedef R(UnboundRunType)(X1, X2, X3); - - static R Run(BindStateBase* base, - typename CallbackParamTraits::ForwardType x1, - typename CallbackParamTraits::ForwardType x2, - typename CallbackParamTraits::ForwardType x3) { - StorageType* storage = static_cast(base); - - // Local references to make debugger stepping easier. If in a debugger, - // you really want to warp ahead and step through the - // InvokeHelper<>::MakeItSo() call below. - - return InvokeHelper::ForwardType x1, - typename CallbackParamTraits::ForwardType x2, - typename CallbackParamTraits::ForwardType x3)> - ::MakeItSo(storage->runnable_, CallbackForward(x1), - CallbackForward(x2), CallbackForward(x3)); - } -}; - -// Arity 3 -> 2. -template -struct Invoker<1, StorageType, R(X1, X2, X3)> { - typedef R(RunType)(BindStateBase*, - typename CallbackParamTraits::ForwardType, - typename CallbackParamTraits::ForwardType); - - typedef R(UnboundRunType)(X2, X3); - - static R Run(BindStateBase* base, - typename CallbackParamTraits::ForwardType x2, - typename CallbackParamTraits::ForwardType x3) { - StorageType* storage = static_cast(base); - - // Local references to make debugger stepping easier. If in a debugger, - // you really want to warp ahead and step through the - // InvokeHelper<>::MakeItSo() call below. - typedef typename StorageType::Bound1UnwrapTraits Bound1UnwrapTraits; - - typename Bound1UnwrapTraits::ForwardType x1 = - Bound1UnwrapTraits::Unwrap(storage->p1_); - return InvokeHelper::ForwardType x2, - typename CallbackParamTraits::ForwardType x3)> - ::MakeItSo(storage->runnable_, CallbackForward(x1), - CallbackForward(x2), CallbackForward(x3)); - } -}; - -// Arity 3 -> 1. -template -struct Invoker<2, StorageType, R(X1, X2, X3)> { - typedef R(RunType)(BindStateBase*, - typename CallbackParamTraits::ForwardType); - - typedef R(UnboundRunType)(X3); - - static R Run(BindStateBase* base, - typename CallbackParamTraits::ForwardType x3) { - StorageType* storage = static_cast(base); - - // Local references to make debugger stepping easier. If in a debugger, - // you really want to warp ahead and step through the - // InvokeHelper<>::MakeItSo() call below. - typedef typename StorageType::Bound1UnwrapTraits Bound1UnwrapTraits; - typedef typename StorageType::Bound2UnwrapTraits Bound2UnwrapTraits; - - typename Bound1UnwrapTraits::ForwardType x1 = - Bound1UnwrapTraits::Unwrap(storage->p1_); - typename Bound2UnwrapTraits::ForwardType x2 = - Bound2UnwrapTraits::Unwrap(storage->p2_); - return InvokeHelper::ForwardType x3)> - ::MakeItSo(storage->runnable_, CallbackForward(x1), - CallbackForward(x2), CallbackForward(x3)); - } -}; - -// Arity 3 -> 0. -template -struct Invoker<3, StorageType, R(X1, X2, X3)> { - typedef R(RunType)(BindStateBase*); - - typedef R(UnboundRunType)(); - - static R Run(BindStateBase* base) { - StorageType* storage = static_cast(base); - - // Local references to make debugger stepping easier. If in a debugger, - // you really want to warp ahead and step through the - // InvokeHelper<>::MakeItSo() call below. - typedef typename StorageType::Bound1UnwrapTraits Bound1UnwrapTraits; - typedef typename StorageType::Bound2UnwrapTraits Bound2UnwrapTraits; - typedef typename StorageType::Bound3UnwrapTraits Bound3UnwrapTraits; - - typename Bound1UnwrapTraits::ForwardType x1 = - Bound1UnwrapTraits::Unwrap(storage->p1_); - typename Bound2UnwrapTraits::ForwardType x2 = - Bound2UnwrapTraits::Unwrap(storage->p2_); - typename Bound3UnwrapTraits::ForwardType x3 = - Bound3UnwrapTraits::Unwrap(storage->p3_); - return InvokeHelper - ::MakeItSo(storage->runnable_, CallbackForward(x1), - CallbackForward(x2), CallbackForward(x3)); - } -}; - -// Arity 4 -> 4. -template -struct Invoker<0, StorageType, R(X1, X2, X3, X4)> { - typedef R(RunType)(BindStateBase*, - typename CallbackParamTraits::ForwardType, - typename CallbackParamTraits::ForwardType, - typename CallbackParamTraits::ForwardType, - typename CallbackParamTraits::ForwardType); - - typedef R(UnboundRunType)(X1, X2, X3, X4); - - static R Run(BindStateBase* base, - typename CallbackParamTraits::ForwardType x1, - typename CallbackParamTraits::ForwardType x2, - typename CallbackParamTraits::ForwardType x3, - typename CallbackParamTraits::ForwardType x4) { - StorageType* storage = static_cast(base); - - // Local references to make debugger stepping easier. If in a debugger, - // you really want to warp ahead and step through the - // InvokeHelper<>::MakeItSo() call below. - - return InvokeHelper::ForwardType x1, - typename CallbackParamTraits::ForwardType x2, - typename CallbackParamTraits::ForwardType x3, - typename CallbackParamTraits::ForwardType x4)> - ::MakeItSo(storage->runnable_, CallbackForward(x1), - CallbackForward(x2), CallbackForward(x3), - CallbackForward(x4)); - } -}; - -// Arity 4 -> 3. -template -struct Invoker<1, StorageType, R(X1, X2, X3, X4)> { - typedef R(RunType)(BindStateBase*, - typename CallbackParamTraits::ForwardType, - typename CallbackParamTraits::ForwardType, - typename CallbackParamTraits::ForwardType); - - typedef R(UnboundRunType)(X2, X3, X4); - - static R Run(BindStateBase* base, - typename CallbackParamTraits::ForwardType x2, - typename CallbackParamTraits::ForwardType x3, - typename CallbackParamTraits::ForwardType x4) { - StorageType* storage = static_cast(base); - - // Local references to make debugger stepping easier. If in a debugger, - // you really want to warp ahead and step through the - // InvokeHelper<>::MakeItSo() call below. - typedef typename StorageType::Bound1UnwrapTraits Bound1UnwrapTraits; - - typename Bound1UnwrapTraits::ForwardType x1 = - Bound1UnwrapTraits::Unwrap(storage->p1_); - return InvokeHelper::ForwardType x2, - typename CallbackParamTraits::ForwardType x3, - typename CallbackParamTraits::ForwardType x4)> - ::MakeItSo(storage->runnable_, CallbackForward(x1), - CallbackForward(x2), CallbackForward(x3), - CallbackForward(x4)); - } -}; - -// Arity 4 -> 2. -template -struct Invoker<2, StorageType, R(X1, X2, X3, X4)> { - typedef R(RunType)(BindStateBase*, - typename CallbackParamTraits::ForwardType, - typename CallbackParamTraits::ForwardType); - - typedef R(UnboundRunType)(X3, X4); - - static R Run(BindStateBase* base, - typename CallbackParamTraits::ForwardType x3, - typename CallbackParamTraits::ForwardType x4) { - StorageType* storage = static_cast(base); - - // Local references to make debugger stepping easier. If in a debugger, - // you really want to warp ahead and step through the - // InvokeHelper<>::MakeItSo() call below. - typedef typename StorageType::Bound1UnwrapTraits Bound1UnwrapTraits; - typedef typename StorageType::Bound2UnwrapTraits Bound2UnwrapTraits; - - typename Bound1UnwrapTraits::ForwardType x1 = - Bound1UnwrapTraits::Unwrap(storage->p1_); - typename Bound2UnwrapTraits::ForwardType x2 = - Bound2UnwrapTraits::Unwrap(storage->p2_); - return InvokeHelper::ForwardType x3, - typename CallbackParamTraits::ForwardType x4)> - ::MakeItSo(storage->runnable_, CallbackForward(x1), - CallbackForward(x2), CallbackForward(x3), - CallbackForward(x4)); - } -}; - -// Arity 4 -> 1. -template -struct Invoker<3, StorageType, R(X1, X2, X3, X4)> { - typedef R(RunType)(BindStateBase*, - typename CallbackParamTraits::ForwardType); - - typedef R(UnboundRunType)(X4); - - static R Run(BindStateBase* base, - typename CallbackParamTraits::ForwardType x4) { - StorageType* storage = static_cast(base); - - // Local references to make debugger stepping easier. If in a debugger, - // you really want to warp ahead and step through the - // InvokeHelper<>::MakeItSo() call below. - typedef typename StorageType::Bound1UnwrapTraits Bound1UnwrapTraits; - typedef typename StorageType::Bound2UnwrapTraits Bound2UnwrapTraits; - typedef typename StorageType::Bound3UnwrapTraits Bound3UnwrapTraits; - - typename Bound1UnwrapTraits::ForwardType x1 = - Bound1UnwrapTraits::Unwrap(storage->p1_); - typename Bound2UnwrapTraits::ForwardType x2 = - Bound2UnwrapTraits::Unwrap(storage->p2_); - typename Bound3UnwrapTraits::ForwardType x3 = - Bound3UnwrapTraits::Unwrap(storage->p3_); - return InvokeHelper::ForwardType x4)> - ::MakeItSo(storage->runnable_, CallbackForward(x1), - CallbackForward(x2), CallbackForward(x3), - CallbackForward(x4)); - } -}; - -// Arity 4 -> 0. -template -struct Invoker<4, StorageType, R(X1, X2, X3, X4)> { - typedef R(RunType)(BindStateBase*); - - typedef R(UnboundRunType)(); - - static R Run(BindStateBase* base) { - StorageType* storage = static_cast(base); - - // Local references to make debugger stepping easier. If in a debugger, - // you really want to warp ahead and step through the - // InvokeHelper<>::MakeItSo() call below. - typedef typename StorageType::Bound1UnwrapTraits Bound1UnwrapTraits; - typedef typename StorageType::Bound2UnwrapTraits Bound2UnwrapTraits; - typedef typename StorageType::Bound3UnwrapTraits Bound3UnwrapTraits; - typedef typename StorageType::Bound4UnwrapTraits Bound4UnwrapTraits; - - typename Bound1UnwrapTraits::ForwardType x1 = - Bound1UnwrapTraits::Unwrap(storage->p1_); - typename Bound2UnwrapTraits::ForwardType x2 = - Bound2UnwrapTraits::Unwrap(storage->p2_); - typename Bound3UnwrapTraits::ForwardType x3 = - Bound3UnwrapTraits::Unwrap(storage->p3_); - typename Bound4UnwrapTraits::ForwardType x4 = - Bound4UnwrapTraits::Unwrap(storage->p4_); - return InvokeHelper - ::MakeItSo(storage->runnable_, CallbackForward(x1), - CallbackForward(x2), CallbackForward(x3), - CallbackForward(x4)); - } -}; - -// Arity 5 -> 5. -template -struct Invoker<0, StorageType, R(X1, X2, X3, X4, X5)> { - typedef R(RunType)(BindStateBase*, - typename CallbackParamTraits::ForwardType, - typename CallbackParamTraits::ForwardType, - typename CallbackParamTraits::ForwardType, - typename CallbackParamTraits::ForwardType, - typename CallbackParamTraits::ForwardType); - - typedef R(UnboundRunType)(X1, X2, X3, X4, X5); - - static R Run(BindStateBase* base, - typename CallbackParamTraits::ForwardType x1, - typename CallbackParamTraits::ForwardType x2, - typename CallbackParamTraits::ForwardType x3, - typename CallbackParamTraits::ForwardType x4, - typename CallbackParamTraits::ForwardType x5) { - StorageType* storage = static_cast(base); - - // Local references to make debugger stepping easier. If in a debugger, - // you really want to warp ahead and step through the - // InvokeHelper<>::MakeItSo() call below. - - return InvokeHelper::ForwardType x1, - typename CallbackParamTraits::ForwardType x2, - typename CallbackParamTraits::ForwardType x3, - typename CallbackParamTraits::ForwardType x4, - typename CallbackParamTraits::ForwardType x5)> - ::MakeItSo(storage->runnable_, CallbackForward(x1), - CallbackForward(x2), CallbackForward(x3), - CallbackForward(x4), CallbackForward(x5)); - } -}; - -// Arity 5 -> 4. -template -struct Invoker<1, StorageType, R(X1, X2, X3, X4, X5)> { - typedef R(RunType)(BindStateBase*, - typename CallbackParamTraits::ForwardType, - typename CallbackParamTraits::ForwardType, - typename CallbackParamTraits::ForwardType, - typename CallbackParamTraits::ForwardType); - - typedef R(UnboundRunType)(X2, X3, X4, X5); - - static R Run(BindStateBase* base, - typename CallbackParamTraits::ForwardType x2, - typename CallbackParamTraits::ForwardType x3, - typename CallbackParamTraits::ForwardType x4, - typename CallbackParamTraits::ForwardType x5) { - StorageType* storage = static_cast(base); - - // Local references to make debugger stepping easier. If in a debugger, - // you really want to warp ahead and step through the - // InvokeHelper<>::MakeItSo() call below. - typedef typename StorageType::Bound1UnwrapTraits Bound1UnwrapTraits; - - typename Bound1UnwrapTraits::ForwardType x1 = - Bound1UnwrapTraits::Unwrap(storage->p1_); - return InvokeHelper::ForwardType x2, - typename CallbackParamTraits::ForwardType x3, - typename CallbackParamTraits::ForwardType x4, - typename CallbackParamTraits::ForwardType x5)> - ::MakeItSo(storage->runnable_, CallbackForward(x1), - CallbackForward(x2), CallbackForward(x3), - CallbackForward(x4), CallbackForward(x5)); - } -}; - -// Arity 5 -> 3. -template -struct Invoker<2, StorageType, R(X1, X2, X3, X4, X5)> { - typedef R(RunType)(BindStateBase*, - typename CallbackParamTraits::ForwardType, - typename CallbackParamTraits::ForwardType, - typename CallbackParamTraits::ForwardType); - - typedef R(UnboundRunType)(X3, X4, X5); - - static R Run(BindStateBase* base, - typename CallbackParamTraits::ForwardType x3, - typename CallbackParamTraits::ForwardType x4, - typename CallbackParamTraits::ForwardType x5) { - StorageType* storage = static_cast(base); - - // Local references to make debugger stepping easier. If in a debugger, - // you really want to warp ahead and step through the - // InvokeHelper<>::MakeItSo() call below. - typedef typename StorageType::Bound1UnwrapTraits Bound1UnwrapTraits; - typedef typename StorageType::Bound2UnwrapTraits Bound2UnwrapTraits; - - typename Bound1UnwrapTraits::ForwardType x1 = - Bound1UnwrapTraits::Unwrap(storage->p1_); - typename Bound2UnwrapTraits::ForwardType x2 = - Bound2UnwrapTraits::Unwrap(storage->p2_); - return InvokeHelper::ForwardType x3, - typename CallbackParamTraits::ForwardType x4, - typename CallbackParamTraits::ForwardType x5)> - ::MakeItSo(storage->runnable_, CallbackForward(x1), - CallbackForward(x2), CallbackForward(x3), - CallbackForward(x4), CallbackForward(x5)); - } -}; - -// Arity 5 -> 2. -template -struct Invoker<3, StorageType, R(X1, X2, X3, X4, X5)> { - typedef R(RunType)(BindStateBase*, - typename CallbackParamTraits::ForwardType, - typename CallbackParamTraits::ForwardType); - - typedef R(UnboundRunType)(X4, X5); - - static R Run(BindStateBase* base, - typename CallbackParamTraits::ForwardType x4, - typename CallbackParamTraits::ForwardType x5) { - StorageType* storage = static_cast(base); - - // Local references to make debugger stepping easier. If in a debugger, - // you really want to warp ahead and step through the - // InvokeHelper<>::MakeItSo() call below. - typedef typename StorageType::Bound1UnwrapTraits Bound1UnwrapTraits; - typedef typename StorageType::Bound2UnwrapTraits Bound2UnwrapTraits; - typedef typename StorageType::Bound3UnwrapTraits Bound3UnwrapTraits; - - typename Bound1UnwrapTraits::ForwardType x1 = - Bound1UnwrapTraits::Unwrap(storage->p1_); - typename Bound2UnwrapTraits::ForwardType x2 = - Bound2UnwrapTraits::Unwrap(storage->p2_); - typename Bound3UnwrapTraits::ForwardType x3 = - Bound3UnwrapTraits::Unwrap(storage->p3_); - return InvokeHelper::ForwardType x4, - typename CallbackParamTraits::ForwardType x5)> - ::MakeItSo(storage->runnable_, CallbackForward(x1), - CallbackForward(x2), CallbackForward(x3), - CallbackForward(x4), CallbackForward(x5)); - } -}; - -// Arity 5 -> 1. -template -struct Invoker<4, StorageType, R(X1, X2, X3, X4, X5)> { - typedef R(RunType)(BindStateBase*, - typename CallbackParamTraits::ForwardType); - - typedef R(UnboundRunType)(X5); - - static R Run(BindStateBase* base, - typename CallbackParamTraits::ForwardType x5) { - StorageType* storage = static_cast(base); - - // Local references to make debugger stepping easier. If in a debugger, - // you really want to warp ahead and step through the - // InvokeHelper<>::MakeItSo() call below. - typedef typename StorageType::Bound1UnwrapTraits Bound1UnwrapTraits; - typedef typename StorageType::Bound2UnwrapTraits Bound2UnwrapTraits; - typedef typename StorageType::Bound3UnwrapTraits Bound3UnwrapTraits; - typedef typename StorageType::Bound4UnwrapTraits Bound4UnwrapTraits; - - typename Bound1UnwrapTraits::ForwardType x1 = - Bound1UnwrapTraits::Unwrap(storage->p1_); - typename Bound2UnwrapTraits::ForwardType x2 = - Bound2UnwrapTraits::Unwrap(storage->p2_); - typename Bound3UnwrapTraits::ForwardType x3 = - Bound3UnwrapTraits::Unwrap(storage->p3_); - typename Bound4UnwrapTraits::ForwardType x4 = - Bound4UnwrapTraits::Unwrap(storage->p4_); - return InvokeHelper::ForwardType x5)> - ::MakeItSo(storage->runnable_, CallbackForward(x1), - CallbackForward(x2), CallbackForward(x3), - CallbackForward(x4), CallbackForward(x5)); - } -}; - -// Arity 5 -> 0. -template -struct Invoker<5, StorageType, R(X1, X2, X3, X4, X5)> { - typedef R(RunType)(BindStateBase*); - - typedef R(UnboundRunType)(); - - static R Run(BindStateBase* base) { - StorageType* storage = static_cast(base); - - // Local references to make debugger stepping easier. If in a debugger, - // you really want to warp ahead and step through the - // InvokeHelper<>::MakeItSo() call below. - typedef typename StorageType::Bound1UnwrapTraits Bound1UnwrapTraits; - typedef typename StorageType::Bound2UnwrapTraits Bound2UnwrapTraits; - typedef typename StorageType::Bound3UnwrapTraits Bound3UnwrapTraits; - typedef typename StorageType::Bound4UnwrapTraits Bound4UnwrapTraits; - typedef typename StorageType::Bound5UnwrapTraits Bound5UnwrapTraits; - - typename Bound1UnwrapTraits::ForwardType x1 = - Bound1UnwrapTraits::Unwrap(storage->p1_); - typename Bound2UnwrapTraits::ForwardType x2 = - Bound2UnwrapTraits::Unwrap(storage->p2_); - typename Bound3UnwrapTraits::ForwardType x3 = - Bound3UnwrapTraits::Unwrap(storage->p3_); - typename Bound4UnwrapTraits::ForwardType x4 = - Bound4UnwrapTraits::Unwrap(storage->p4_); - typename Bound5UnwrapTraits::ForwardType x5 = - Bound5UnwrapTraits::Unwrap(storage->p5_); - return InvokeHelper - ::MakeItSo(storage->runnable_, CallbackForward(x1), - CallbackForward(x2), CallbackForward(x3), - CallbackForward(x4), CallbackForward(x5)); - } -}; - -// Arity 6 -> 6. -template -struct Invoker<0, StorageType, R(X1, X2, X3, X4, X5, X6)> { - typedef R(RunType)(BindStateBase*, - typename CallbackParamTraits::ForwardType, - typename CallbackParamTraits::ForwardType, - typename CallbackParamTraits::ForwardType, - typename CallbackParamTraits::ForwardType, - typename CallbackParamTraits::ForwardType, - typename CallbackParamTraits::ForwardType); - - typedef R(UnboundRunType)(X1, X2, X3, X4, X5, X6); - - static R Run(BindStateBase* base, - typename CallbackParamTraits::ForwardType x1, - typename CallbackParamTraits::ForwardType x2, - typename CallbackParamTraits::ForwardType x3, - typename CallbackParamTraits::ForwardType x4, - typename CallbackParamTraits::ForwardType x5, - typename CallbackParamTraits::ForwardType x6) { - StorageType* storage = static_cast(base); - - // Local references to make debugger stepping easier. If in a debugger, - // you really want to warp ahead and step through the - // InvokeHelper<>::MakeItSo() call below. - - return InvokeHelper::ForwardType x1, - typename CallbackParamTraits::ForwardType x2, - typename CallbackParamTraits::ForwardType x3, - typename CallbackParamTraits::ForwardType x4, - typename CallbackParamTraits::ForwardType x5, - typename CallbackParamTraits::ForwardType x6)> - ::MakeItSo(storage->runnable_, CallbackForward(x1), - CallbackForward(x2), CallbackForward(x3), - CallbackForward(x4), CallbackForward(x5), - CallbackForward(x6)); - } -}; - -// Arity 6 -> 5. -template -struct Invoker<1, StorageType, R(X1, X2, X3, X4, X5, X6)> { - typedef R(RunType)(BindStateBase*, - typename CallbackParamTraits::ForwardType, - typename CallbackParamTraits::ForwardType, - typename CallbackParamTraits::ForwardType, - typename CallbackParamTraits::ForwardType, - typename CallbackParamTraits::ForwardType); - - typedef R(UnboundRunType)(X2, X3, X4, X5, X6); - - static R Run(BindStateBase* base, - typename CallbackParamTraits::ForwardType x2, - typename CallbackParamTraits::ForwardType x3, - typename CallbackParamTraits::ForwardType x4, - typename CallbackParamTraits::ForwardType x5, - typename CallbackParamTraits::ForwardType x6) { - StorageType* storage = static_cast(base); - - // Local references to make debugger stepping easier. If in a debugger, - // you really want to warp ahead and step through the - // InvokeHelper<>::MakeItSo() call below. - typedef typename StorageType::Bound1UnwrapTraits Bound1UnwrapTraits; - - typename Bound1UnwrapTraits::ForwardType x1 = - Bound1UnwrapTraits::Unwrap(storage->p1_); - return InvokeHelper::ForwardType x2, - typename CallbackParamTraits::ForwardType x3, - typename CallbackParamTraits::ForwardType x4, - typename CallbackParamTraits::ForwardType x5, - typename CallbackParamTraits::ForwardType x6)> - ::MakeItSo(storage->runnable_, CallbackForward(x1), - CallbackForward(x2), CallbackForward(x3), - CallbackForward(x4), CallbackForward(x5), - CallbackForward(x6)); - } -}; - -// Arity 6 -> 4. -template -struct Invoker<2, StorageType, R(X1, X2, X3, X4, X5, X6)> { - typedef R(RunType)(BindStateBase*, - typename CallbackParamTraits::ForwardType, - typename CallbackParamTraits::ForwardType, - typename CallbackParamTraits::ForwardType, - typename CallbackParamTraits::ForwardType); - - typedef R(UnboundRunType)(X3, X4, X5, X6); - - static R Run(BindStateBase* base, - typename CallbackParamTraits::ForwardType x3, - typename CallbackParamTraits::ForwardType x4, - typename CallbackParamTraits::ForwardType x5, - typename CallbackParamTraits::ForwardType x6) { - StorageType* storage = static_cast(base); - - // Local references to make debugger stepping easier. If in a debugger, - // you really want to warp ahead and step through the - // InvokeHelper<>::MakeItSo() call below. - typedef typename StorageType::Bound1UnwrapTraits Bound1UnwrapTraits; - typedef typename StorageType::Bound2UnwrapTraits Bound2UnwrapTraits; - - typename Bound1UnwrapTraits::ForwardType x1 = - Bound1UnwrapTraits::Unwrap(storage->p1_); - typename Bound2UnwrapTraits::ForwardType x2 = - Bound2UnwrapTraits::Unwrap(storage->p2_); - return InvokeHelper::ForwardType x3, - typename CallbackParamTraits::ForwardType x4, - typename CallbackParamTraits::ForwardType x5, - typename CallbackParamTraits::ForwardType x6)> - ::MakeItSo(storage->runnable_, CallbackForward(x1), - CallbackForward(x2), CallbackForward(x3), - CallbackForward(x4), CallbackForward(x5), - CallbackForward(x6)); - } -}; - -// Arity 6 -> 3. -template -struct Invoker<3, StorageType, R(X1, X2, X3, X4, X5, X6)> { - typedef R(RunType)(BindStateBase*, - typename CallbackParamTraits::ForwardType, - typename CallbackParamTraits::ForwardType, - typename CallbackParamTraits::ForwardType); - - typedef R(UnboundRunType)(X4, X5, X6); - - static R Run(BindStateBase* base, - typename CallbackParamTraits::ForwardType x4, - typename CallbackParamTraits::ForwardType x5, - typename CallbackParamTraits::ForwardType x6) { - StorageType* storage = static_cast(base); - - // Local references to make debugger stepping easier. If in a debugger, - // you really want to warp ahead and step through the - // InvokeHelper<>::MakeItSo() call below. - typedef typename StorageType::Bound1UnwrapTraits Bound1UnwrapTraits; - typedef typename StorageType::Bound2UnwrapTraits Bound2UnwrapTraits; - typedef typename StorageType::Bound3UnwrapTraits Bound3UnwrapTraits; - - typename Bound1UnwrapTraits::ForwardType x1 = - Bound1UnwrapTraits::Unwrap(storage->p1_); - typename Bound2UnwrapTraits::ForwardType x2 = - Bound2UnwrapTraits::Unwrap(storage->p2_); - typename Bound3UnwrapTraits::ForwardType x3 = - Bound3UnwrapTraits::Unwrap(storage->p3_); - return InvokeHelper::ForwardType x4, - typename CallbackParamTraits::ForwardType x5, - typename CallbackParamTraits::ForwardType x6)> - ::MakeItSo(storage->runnable_, CallbackForward(x1), - CallbackForward(x2), CallbackForward(x3), - CallbackForward(x4), CallbackForward(x5), - CallbackForward(x6)); - } -}; - -// Arity 6 -> 2. -template -struct Invoker<4, StorageType, R(X1, X2, X3, X4, X5, X6)> { - typedef R(RunType)(BindStateBase*, - typename CallbackParamTraits::ForwardType, - typename CallbackParamTraits::ForwardType); - - typedef R(UnboundRunType)(X5, X6); - - static R Run(BindStateBase* base, - typename CallbackParamTraits::ForwardType x5, - typename CallbackParamTraits::ForwardType x6) { - StorageType* storage = static_cast(base); - - // Local references to make debugger stepping easier. If in a debugger, - // you really want to warp ahead and step through the - // InvokeHelper<>::MakeItSo() call below. - typedef typename StorageType::Bound1UnwrapTraits Bound1UnwrapTraits; - typedef typename StorageType::Bound2UnwrapTraits Bound2UnwrapTraits; - typedef typename StorageType::Bound3UnwrapTraits Bound3UnwrapTraits; - typedef typename StorageType::Bound4UnwrapTraits Bound4UnwrapTraits; - - typename Bound1UnwrapTraits::ForwardType x1 = - Bound1UnwrapTraits::Unwrap(storage->p1_); - typename Bound2UnwrapTraits::ForwardType x2 = - Bound2UnwrapTraits::Unwrap(storage->p2_); - typename Bound3UnwrapTraits::ForwardType x3 = - Bound3UnwrapTraits::Unwrap(storage->p3_); - typename Bound4UnwrapTraits::ForwardType x4 = - Bound4UnwrapTraits::Unwrap(storage->p4_); - return InvokeHelper::ForwardType x5, - typename CallbackParamTraits::ForwardType x6)> - ::MakeItSo(storage->runnable_, CallbackForward(x1), - CallbackForward(x2), CallbackForward(x3), - CallbackForward(x4), CallbackForward(x5), - CallbackForward(x6)); - } -}; - -// Arity 6 -> 1. -template -struct Invoker<5, StorageType, R(X1, X2, X3, X4, X5, X6)> { - typedef R(RunType)(BindStateBase*, - typename CallbackParamTraits::ForwardType); - - typedef R(UnboundRunType)(X6); - - static R Run(BindStateBase* base, - typename CallbackParamTraits::ForwardType x6) { - StorageType* storage = static_cast(base); - - // Local references to make debugger stepping easier. If in a debugger, - // you really want to warp ahead and step through the - // InvokeHelper<>::MakeItSo() call below. - typedef typename StorageType::Bound1UnwrapTraits Bound1UnwrapTraits; - typedef typename StorageType::Bound2UnwrapTraits Bound2UnwrapTraits; - typedef typename StorageType::Bound3UnwrapTraits Bound3UnwrapTraits; - typedef typename StorageType::Bound4UnwrapTraits Bound4UnwrapTraits; - typedef typename StorageType::Bound5UnwrapTraits Bound5UnwrapTraits; - - typename Bound1UnwrapTraits::ForwardType x1 = - Bound1UnwrapTraits::Unwrap(storage->p1_); - typename Bound2UnwrapTraits::ForwardType x2 = - Bound2UnwrapTraits::Unwrap(storage->p2_); - typename Bound3UnwrapTraits::ForwardType x3 = - Bound3UnwrapTraits::Unwrap(storage->p3_); - typename Bound4UnwrapTraits::ForwardType x4 = - Bound4UnwrapTraits::Unwrap(storage->p4_); - typename Bound5UnwrapTraits::ForwardType x5 = - Bound5UnwrapTraits::Unwrap(storage->p5_); - return InvokeHelper::ForwardType x6)> - ::MakeItSo(storage->runnable_, CallbackForward(x1), - CallbackForward(x2), CallbackForward(x3), - CallbackForward(x4), CallbackForward(x5), - CallbackForward(x6)); - } -}; - -// Arity 6 -> 0. -template -struct Invoker<6, StorageType, R(X1, X2, X3, X4, X5, X6)> { - typedef R(RunType)(BindStateBase*); - - typedef R(UnboundRunType)(); - - static R Run(BindStateBase* base) { - StorageType* storage = static_cast(base); - - // Local references to make debugger stepping easier. If in a debugger, - // you really want to warp ahead and step through the - // InvokeHelper<>::MakeItSo() call below. - typedef typename StorageType::Bound1UnwrapTraits Bound1UnwrapTraits; - typedef typename StorageType::Bound2UnwrapTraits Bound2UnwrapTraits; - typedef typename StorageType::Bound3UnwrapTraits Bound3UnwrapTraits; - typedef typename StorageType::Bound4UnwrapTraits Bound4UnwrapTraits; - typedef typename StorageType::Bound5UnwrapTraits Bound5UnwrapTraits; - typedef typename StorageType::Bound6UnwrapTraits Bound6UnwrapTraits; - - typename Bound1UnwrapTraits::ForwardType x1 = - Bound1UnwrapTraits::Unwrap(storage->p1_); - typename Bound2UnwrapTraits::ForwardType x2 = - Bound2UnwrapTraits::Unwrap(storage->p2_); - typename Bound3UnwrapTraits::ForwardType x3 = - Bound3UnwrapTraits::Unwrap(storage->p3_); - typename Bound4UnwrapTraits::ForwardType x4 = - Bound4UnwrapTraits::Unwrap(storage->p4_); - typename Bound5UnwrapTraits::ForwardType x5 = - Bound5UnwrapTraits::Unwrap(storage->p5_); - typename Bound6UnwrapTraits::ForwardType x6 = - Bound6UnwrapTraits::Unwrap(storage->p6_); - return InvokeHelper - ::MakeItSo(storage->runnable_, CallbackForward(x1), - CallbackForward(x2), CallbackForward(x3), - CallbackForward(x4), CallbackForward(x5), - CallbackForward(x6)); - } -}; - -// Arity 7 -> 7. -template -struct Invoker<0, StorageType, R(X1, X2, X3, X4, X5, X6, X7)> { - typedef R(RunType)(BindStateBase*, - typename CallbackParamTraits::ForwardType, - typename CallbackParamTraits::ForwardType, - typename CallbackParamTraits::ForwardType, - typename CallbackParamTraits::ForwardType, - typename CallbackParamTraits::ForwardType, - typename CallbackParamTraits::ForwardType, - typename CallbackParamTraits::ForwardType); - - typedef R(UnboundRunType)(X1, X2, X3, X4, X5, X6, X7); - - static R Run(BindStateBase* base, - typename CallbackParamTraits::ForwardType x1, - typename CallbackParamTraits::ForwardType x2, - typename CallbackParamTraits::ForwardType x3, - typename CallbackParamTraits::ForwardType x4, - typename CallbackParamTraits::ForwardType x5, - typename CallbackParamTraits::ForwardType x6, - typename CallbackParamTraits::ForwardType x7) { - StorageType* storage = static_cast(base); - - // Local references to make debugger stepping easier. If in a debugger, - // you really want to warp ahead and step through the - // InvokeHelper<>::MakeItSo() call below. - - return InvokeHelper::ForwardType x1, - typename CallbackParamTraits::ForwardType x2, - typename CallbackParamTraits::ForwardType x3, - typename CallbackParamTraits::ForwardType x4, - typename CallbackParamTraits::ForwardType x5, - typename CallbackParamTraits::ForwardType x6, - typename CallbackParamTraits::ForwardType x7)> - ::MakeItSo(storage->runnable_, CallbackForward(x1), - CallbackForward(x2), CallbackForward(x3), - CallbackForward(x4), CallbackForward(x5), - CallbackForward(x6), CallbackForward(x7)); - } -}; - -// Arity 7 -> 6. -template -struct Invoker<1, StorageType, R(X1, X2, X3, X4, X5, X6, X7)> { - typedef R(RunType)(BindStateBase*, - typename CallbackParamTraits::ForwardType, - typename CallbackParamTraits::ForwardType, - typename CallbackParamTraits::ForwardType, - typename CallbackParamTraits::ForwardType, - typename CallbackParamTraits::ForwardType, - typename CallbackParamTraits::ForwardType); - - typedef R(UnboundRunType)(X2, X3, X4, X5, X6, X7); - - static R Run(BindStateBase* base, - typename CallbackParamTraits::ForwardType x2, - typename CallbackParamTraits::ForwardType x3, - typename CallbackParamTraits::ForwardType x4, - typename CallbackParamTraits::ForwardType x5, - typename CallbackParamTraits::ForwardType x6, - typename CallbackParamTraits::ForwardType x7) { - StorageType* storage = static_cast(base); - - // Local references to make debugger stepping easier. If in a debugger, - // you really want to warp ahead and step through the - // InvokeHelper<>::MakeItSo() call below. - typedef typename StorageType::Bound1UnwrapTraits Bound1UnwrapTraits; - - typename Bound1UnwrapTraits::ForwardType x1 = - Bound1UnwrapTraits::Unwrap(storage->p1_); - return InvokeHelper::ForwardType x2, - typename CallbackParamTraits::ForwardType x3, - typename CallbackParamTraits::ForwardType x4, - typename CallbackParamTraits::ForwardType x5, - typename CallbackParamTraits::ForwardType x6, - typename CallbackParamTraits::ForwardType x7)> - ::MakeItSo(storage->runnable_, CallbackForward(x1), - CallbackForward(x2), CallbackForward(x3), - CallbackForward(x4), CallbackForward(x5), - CallbackForward(x6), CallbackForward(x7)); - } -}; - -// Arity 7 -> 5. -template -struct Invoker<2, StorageType, R(X1, X2, X3, X4, X5, X6, X7)> { - typedef R(RunType)(BindStateBase*, - typename CallbackParamTraits::ForwardType, - typename CallbackParamTraits::ForwardType, - typename CallbackParamTraits::ForwardType, - typename CallbackParamTraits::ForwardType, - typename CallbackParamTraits::ForwardType); - - typedef R(UnboundRunType)(X3, X4, X5, X6, X7); - - static R Run(BindStateBase* base, - typename CallbackParamTraits::ForwardType x3, - typename CallbackParamTraits::ForwardType x4, - typename CallbackParamTraits::ForwardType x5, - typename CallbackParamTraits::ForwardType x6, - typename CallbackParamTraits::ForwardType x7) { - StorageType* storage = static_cast(base); - - // Local references to make debugger stepping easier. If in a debugger, - // you really want to warp ahead and step through the - // InvokeHelper<>::MakeItSo() call below. - typedef typename StorageType::Bound1UnwrapTraits Bound1UnwrapTraits; - typedef typename StorageType::Bound2UnwrapTraits Bound2UnwrapTraits; - - typename Bound1UnwrapTraits::ForwardType x1 = - Bound1UnwrapTraits::Unwrap(storage->p1_); - typename Bound2UnwrapTraits::ForwardType x2 = - Bound2UnwrapTraits::Unwrap(storage->p2_); - return InvokeHelper::ForwardType x3, - typename CallbackParamTraits::ForwardType x4, - typename CallbackParamTraits::ForwardType x5, - typename CallbackParamTraits::ForwardType x6, - typename CallbackParamTraits::ForwardType x7)> - ::MakeItSo(storage->runnable_, CallbackForward(x1), - CallbackForward(x2), CallbackForward(x3), - CallbackForward(x4), CallbackForward(x5), - CallbackForward(x6), CallbackForward(x7)); - } -}; - -// Arity 7 -> 4. -template -struct Invoker<3, StorageType, R(X1, X2, X3, X4, X5, X6, X7)> { - typedef R(RunType)(BindStateBase*, - typename CallbackParamTraits::ForwardType, - typename CallbackParamTraits::ForwardType, - typename CallbackParamTraits::ForwardType, - typename CallbackParamTraits::ForwardType); - - typedef R(UnboundRunType)(X4, X5, X6, X7); - - static R Run(BindStateBase* base, - typename CallbackParamTraits::ForwardType x4, - typename CallbackParamTraits::ForwardType x5, - typename CallbackParamTraits::ForwardType x6, - typename CallbackParamTraits::ForwardType x7) { - StorageType* storage = static_cast(base); - - // Local references to make debugger stepping easier. If in a debugger, - // you really want to warp ahead and step through the - // InvokeHelper<>::MakeItSo() call below. - typedef typename StorageType::Bound1UnwrapTraits Bound1UnwrapTraits; - typedef typename StorageType::Bound2UnwrapTraits Bound2UnwrapTraits; - typedef typename StorageType::Bound3UnwrapTraits Bound3UnwrapTraits; - - typename Bound1UnwrapTraits::ForwardType x1 = - Bound1UnwrapTraits::Unwrap(storage->p1_); - typename Bound2UnwrapTraits::ForwardType x2 = - Bound2UnwrapTraits::Unwrap(storage->p2_); - typename Bound3UnwrapTraits::ForwardType x3 = - Bound3UnwrapTraits::Unwrap(storage->p3_); - return InvokeHelper::ForwardType x4, - typename CallbackParamTraits::ForwardType x5, - typename CallbackParamTraits::ForwardType x6, - typename CallbackParamTraits::ForwardType x7)> - ::MakeItSo(storage->runnable_, CallbackForward(x1), - CallbackForward(x2), CallbackForward(x3), - CallbackForward(x4), CallbackForward(x5), - CallbackForward(x6), CallbackForward(x7)); - } -}; - -// Arity 7 -> 3. -template -struct Invoker<4, StorageType, R(X1, X2, X3, X4, X5, X6, X7)> { - typedef R(RunType)(BindStateBase*, - typename CallbackParamTraits::ForwardType, - typename CallbackParamTraits::ForwardType, - typename CallbackParamTraits::ForwardType); - - typedef R(UnboundRunType)(X5, X6, X7); - - static R Run(BindStateBase* base, - typename CallbackParamTraits::ForwardType x5, - typename CallbackParamTraits::ForwardType x6, - typename CallbackParamTraits::ForwardType x7) { - StorageType* storage = static_cast(base); - - // Local references to make debugger stepping easier. If in a debugger, - // you really want to warp ahead and step through the - // InvokeHelper<>::MakeItSo() call below. - typedef typename StorageType::Bound1UnwrapTraits Bound1UnwrapTraits; - typedef typename StorageType::Bound2UnwrapTraits Bound2UnwrapTraits; - typedef typename StorageType::Bound3UnwrapTraits Bound3UnwrapTraits; - typedef typename StorageType::Bound4UnwrapTraits Bound4UnwrapTraits; - - typename Bound1UnwrapTraits::ForwardType x1 = - Bound1UnwrapTraits::Unwrap(storage->p1_); - typename Bound2UnwrapTraits::ForwardType x2 = - Bound2UnwrapTraits::Unwrap(storage->p2_); - typename Bound3UnwrapTraits::ForwardType x3 = - Bound3UnwrapTraits::Unwrap(storage->p3_); - typename Bound4UnwrapTraits::ForwardType x4 = - Bound4UnwrapTraits::Unwrap(storage->p4_); - return InvokeHelper::ForwardType x5, - typename CallbackParamTraits::ForwardType x6, - typename CallbackParamTraits::ForwardType x7)> - ::MakeItSo(storage->runnable_, CallbackForward(x1), - CallbackForward(x2), CallbackForward(x3), - CallbackForward(x4), CallbackForward(x5), - CallbackForward(x6), CallbackForward(x7)); - } -}; - -// Arity 7 -> 2. -template -struct Invoker<5, StorageType, R(X1, X2, X3, X4, X5, X6, X7)> { - typedef R(RunType)(BindStateBase*, - typename CallbackParamTraits::ForwardType, - typename CallbackParamTraits::ForwardType); - - typedef R(UnboundRunType)(X6, X7); - - static R Run(BindStateBase* base, - typename CallbackParamTraits::ForwardType x6, - typename CallbackParamTraits::ForwardType x7) { - StorageType* storage = static_cast(base); - - // Local references to make debugger stepping easier. If in a debugger, - // you really want to warp ahead and step through the - // InvokeHelper<>::MakeItSo() call below. - typedef typename StorageType::Bound1UnwrapTraits Bound1UnwrapTraits; - typedef typename StorageType::Bound2UnwrapTraits Bound2UnwrapTraits; - typedef typename StorageType::Bound3UnwrapTraits Bound3UnwrapTraits; - typedef typename StorageType::Bound4UnwrapTraits Bound4UnwrapTraits; - typedef typename StorageType::Bound5UnwrapTraits Bound5UnwrapTraits; - - typename Bound1UnwrapTraits::ForwardType x1 = - Bound1UnwrapTraits::Unwrap(storage->p1_); - typename Bound2UnwrapTraits::ForwardType x2 = - Bound2UnwrapTraits::Unwrap(storage->p2_); - typename Bound3UnwrapTraits::ForwardType x3 = - Bound3UnwrapTraits::Unwrap(storage->p3_); - typename Bound4UnwrapTraits::ForwardType x4 = - Bound4UnwrapTraits::Unwrap(storage->p4_); - typename Bound5UnwrapTraits::ForwardType x5 = - Bound5UnwrapTraits::Unwrap(storage->p5_); - return InvokeHelper::ForwardType x6, - typename CallbackParamTraits::ForwardType x7)> - ::MakeItSo(storage->runnable_, CallbackForward(x1), - CallbackForward(x2), CallbackForward(x3), - CallbackForward(x4), CallbackForward(x5), - CallbackForward(x6), CallbackForward(x7)); - } -}; - -// Arity 7 -> 1. -template -struct Invoker<6, StorageType, R(X1, X2, X3, X4, X5, X6, X7)> { - typedef R(RunType)(BindStateBase*, - typename CallbackParamTraits::ForwardType); - - typedef R(UnboundRunType)(X7); - - static R Run(BindStateBase* base, - typename CallbackParamTraits::ForwardType x7) { - StorageType* storage = static_cast(base); - - // Local references to make debugger stepping easier. If in a debugger, - // you really want to warp ahead and step through the - // InvokeHelper<>::MakeItSo() call below. - typedef typename StorageType::Bound1UnwrapTraits Bound1UnwrapTraits; - typedef typename StorageType::Bound2UnwrapTraits Bound2UnwrapTraits; - typedef typename StorageType::Bound3UnwrapTraits Bound3UnwrapTraits; - typedef typename StorageType::Bound4UnwrapTraits Bound4UnwrapTraits; - typedef typename StorageType::Bound5UnwrapTraits Bound5UnwrapTraits; - typedef typename StorageType::Bound6UnwrapTraits Bound6UnwrapTraits; - - typename Bound1UnwrapTraits::ForwardType x1 = - Bound1UnwrapTraits::Unwrap(storage->p1_); - typename Bound2UnwrapTraits::ForwardType x2 = - Bound2UnwrapTraits::Unwrap(storage->p2_); - typename Bound3UnwrapTraits::ForwardType x3 = - Bound3UnwrapTraits::Unwrap(storage->p3_); - typename Bound4UnwrapTraits::ForwardType x4 = - Bound4UnwrapTraits::Unwrap(storage->p4_); - typename Bound5UnwrapTraits::ForwardType x5 = - Bound5UnwrapTraits::Unwrap(storage->p5_); - typename Bound6UnwrapTraits::ForwardType x6 = - Bound6UnwrapTraits::Unwrap(storage->p6_); - return InvokeHelper::ForwardType x7)> - ::MakeItSo(storage->runnable_, CallbackForward(x1), - CallbackForward(x2), CallbackForward(x3), - CallbackForward(x4), CallbackForward(x5), - CallbackForward(x6), CallbackForward(x7)); - } -}; - -// Arity 7 -> 0. -template -struct Invoker<7, StorageType, R(X1, X2, X3, X4, X5, X6, X7)> { - typedef R(RunType)(BindStateBase*); - - typedef R(UnboundRunType)(); - - static R Run(BindStateBase* base) { - StorageType* storage = static_cast(base); - - // Local references to make debugger stepping easier. If in a debugger, - // you really want to warp ahead and step through the - // InvokeHelper<>::MakeItSo() call below. - typedef typename StorageType::Bound1UnwrapTraits Bound1UnwrapTraits; - typedef typename StorageType::Bound2UnwrapTraits Bound2UnwrapTraits; - typedef typename StorageType::Bound3UnwrapTraits Bound3UnwrapTraits; - typedef typename StorageType::Bound4UnwrapTraits Bound4UnwrapTraits; - typedef typename StorageType::Bound5UnwrapTraits Bound5UnwrapTraits; - typedef typename StorageType::Bound6UnwrapTraits Bound6UnwrapTraits; - typedef typename StorageType::Bound7UnwrapTraits Bound7UnwrapTraits; - - typename Bound1UnwrapTraits::ForwardType x1 = - Bound1UnwrapTraits::Unwrap(storage->p1_); - typename Bound2UnwrapTraits::ForwardType x2 = - Bound2UnwrapTraits::Unwrap(storage->p2_); - typename Bound3UnwrapTraits::ForwardType x3 = - Bound3UnwrapTraits::Unwrap(storage->p3_); - typename Bound4UnwrapTraits::ForwardType x4 = - Bound4UnwrapTraits::Unwrap(storage->p4_); - typename Bound5UnwrapTraits::ForwardType x5 = - Bound5UnwrapTraits::Unwrap(storage->p5_); - typename Bound6UnwrapTraits::ForwardType x6 = - Bound6UnwrapTraits::Unwrap(storage->p6_); - typename Bound7UnwrapTraits::ForwardType x7 = - Bound7UnwrapTraits::Unwrap(storage->p7_); - return InvokeHelper - ::MakeItSo(storage->runnable_, CallbackForward(x1), - CallbackForward(x2), CallbackForward(x3), - CallbackForward(x4), CallbackForward(x5), - CallbackForward(x6), CallbackForward(x7)); - } -}; - - -// BindState<> -// -// This stores all the state passed into Bind() and is also where most -// of the template resolution magic occurs. -// -// Runnable is the functor we are binding arguments to. -// RunType is type of the Run() function that the Invoker<> should use. -// Normally, this is the same as the RunType of the Runnable, but it can -// be different if an adapter like IgnoreResult() has been used. -// -// BoundArgsType contains the storage type for all the bound arguments by -// (ab)using a function type. -template -struct BindState; - -template -struct BindState : public BindStateBase { - typedef Runnable RunnableType; - typedef false_type IsWeakCall; - typedef Invoker<0, BindState, RunType> InvokerType; - typedef typename InvokerType::UnboundRunType UnboundRunType; - explicit BindState(const Runnable& runnable) - : runnable_(runnable) { - } - - virtual ~BindState() { } - - RunnableType runnable_; -}; - -template -struct BindState : public BindStateBase { - typedef Runnable RunnableType; - typedef IsWeakMethod::value, P1> IsWeakCall; - typedef Invoker<1, BindState, RunType> InvokerType; - typedef typename InvokerType::UnboundRunType UnboundRunType; - - // Convenience typedefs for bound argument types. - typedef UnwrapTraits Bound1UnwrapTraits; - - BindState(const Runnable& runnable, const P1& p1) - : runnable_(runnable), - p1_(p1) { - MaybeRefcount::value, P1>::AddRef(p1_); - } - - virtual ~BindState() { MaybeRefcount::value, - P1>::Release(p1_); } - - RunnableType runnable_; - P1 p1_; -}; - -template -struct BindState : public BindStateBase { - typedef Runnable RunnableType; - typedef IsWeakMethod::value, P1> IsWeakCall; - typedef Invoker<2, BindState, RunType> InvokerType; - typedef typename InvokerType::UnboundRunType UnboundRunType; - - // Convenience typedefs for bound argument types. - typedef UnwrapTraits Bound1UnwrapTraits; - typedef UnwrapTraits Bound2UnwrapTraits; - - BindState(const Runnable& runnable, const P1& p1, const P2& p2) - : runnable_(runnable), - p1_(p1), - p2_(p2) { - MaybeRefcount::value, P1>::AddRef(p1_); - } - - virtual ~BindState() { MaybeRefcount::value, - P1>::Release(p1_); } - - RunnableType runnable_; - P1 p1_; - P2 p2_; -}; - -template -struct BindState : public BindStateBase { - typedef Runnable RunnableType; - typedef IsWeakMethod::value, P1> IsWeakCall; - typedef Invoker<3, BindState, RunType> InvokerType; - typedef typename InvokerType::UnboundRunType UnboundRunType; - - // Convenience typedefs for bound argument types. - typedef UnwrapTraits Bound1UnwrapTraits; - typedef UnwrapTraits Bound2UnwrapTraits; - typedef UnwrapTraits Bound3UnwrapTraits; - - BindState(const Runnable& runnable, const P1& p1, const P2& p2, const P3& p3) - : runnable_(runnable), - p1_(p1), - p2_(p2), - p3_(p3) { - MaybeRefcount::value, P1>::AddRef(p1_); - } - - virtual ~BindState() { MaybeRefcount::value, - P1>::Release(p1_); } - - RunnableType runnable_; - P1 p1_; - P2 p2_; - P3 p3_; -}; - -template -struct BindState : public BindStateBase { - typedef Runnable RunnableType; - typedef IsWeakMethod::value, P1> IsWeakCall; - typedef Invoker<4, BindState, RunType> InvokerType; - typedef typename InvokerType::UnboundRunType UnboundRunType; - - // Convenience typedefs for bound argument types. - typedef UnwrapTraits Bound1UnwrapTraits; - typedef UnwrapTraits Bound2UnwrapTraits; - typedef UnwrapTraits Bound3UnwrapTraits; - typedef UnwrapTraits Bound4UnwrapTraits; - - BindState(const Runnable& runnable, const P1& p1, const P2& p2, const P3& p3, - const P4& p4) - : runnable_(runnable), - p1_(p1), - p2_(p2), - p3_(p3), - p4_(p4) { - MaybeRefcount::value, P1>::AddRef(p1_); - } - - virtual ~BindState() { MaybeRefcount::value, - P1>::Release(p1_); } - - RunnableType runnable_; - P1 p1_; - P2 p2_; - P3 p3_; - P4 p4_; -}; - -template -struct BindState : public BindStateBase { - typedef Runnable RunnableType; - typedef IsWeakMethod::value, P1> IsWeakCall; - typedef Invoker<5, BindState, RunType> InvokerType; - typedef typename InvokerType::UnboundRunType UnboundRunType; - - // Convenience typedefs for bound argument types. - typedef UnwrapTraits Bound1UnwrapTraits; - typedef UnwrapTraits Bound2UnwrapTraits; - typedef UnwrapTraits Bound3UnwrapTraits; - typedef UnwrapTraits Bound4UnwrapTraits; - typedef UnwrapTraits Bound5UnwrapTraits; - - BindState(const Runnable& runnable, const P1& p1, const P2& p2, const P3& p3, - const P4& p4, const P5& p5) - : runnable_(runnable), - p1_(p1), - p2_(p2), - p3_(p3), - p4_(p4), - p5_(p5) { - MaybeRefcount::value, P1>::AddRef(p1_); - } - - virtual ~BindState() { MaybeRefcount::value, - P1>::Release(p1_); } - - RunnableType runnable_; - P1 p1_; - P2 p2_; - P3 p3_; - P4 p4_; - P5 p5_; -}; - -template -struct BindState : public BindStateBase { - typedef Runnable RunnableType; - typedef IsWeakMethod::value, P1> IsWeakCall; - typedef Invoker<6, BindState, RunType> InvokerType; - typedef typename InvokerType::UnboundRunType UnboundRunType; - - // Convenience typedefs for bound argument types. - typedef UnwrapTraits Bound1UnwrapTraits; - typedef UnwrapTraits Bound2UnwrapTraits; - typedef UnwrapTraits Bound3UnwrapTraits; - typedef UnwrapTraits Bound4UnwrapTraits; - typedef UnwrapTraits Bound5UnwrapTraits; - typedef UnwrapTraits Bound6UnwrapTraits; - - BindState(const Runnable& runnable, const P1& p1, const P2& p2, const P3& p3, - const P4& p4, const P5& p5, const P6& p6) - : runnable_(runnable), - p1_(p1), - p2_(p2), - p3_(p3), - p4_(p4), - p5_(p5), - p6_(p6) { - MaybeRefcount::value, P1>::AddRef(p1_); - } - - virtual ~BindState() { MaybeRefcount::value, - P1>::Release(p1_); } - - RunnableType runnable_; - P1 p1_; - P2 p2_; - P3 p3_; - P4 p4_; - P5 p5_; - P6 p6_; -}; - -template -struct BindState : public BindStateBase { - typedef Runnable RunnableType; - typedef IsWeakMethod::value, P1> IsWeakCall; - typedef Invoker<7, BindState, RunType> InvokerType; - typedef typename InvokerType::UnboundRunType UnboundRunType; - - // Convenience typedefs for bound argument types. - typedef UnwrapTraits Bound1UnwrapTraits; - typedef UnwrapTraits Bound2UnwrapTraits; - typedef UnwrapTraits Bound3UnwrapTraits; - typedef UnwrapTraits Bound4UnwrapTraits; - typedef UnwrapTraits Bound5UnwrapTraits; - typedef UnwrapTraits Bound6UnwrapTraits; - typedef UnwrapTraits Bound7UnwrapTraits; - - BindState(const Runnable& runnable, const P1& p1, const P2& p2, const P3& p3, - const P4& p4, const P5& p5, const P6& p6, const P7& p7) - : runnable_(runnable), - p1_(p1), - p2_(p2), - p3_(p3), - p4_(p4), - p5_(p5), - p6_(p6), - p7_(p7) { - MaybeRefcount::value, P1>::AddRef(p1_); - } - - virtual ~BindState() { MaybeRefcount::value, - P1>::Release(p1_); } - - RunnableType runnable_; - P1 p1_; - P2 p2_; - P3 p3_; - P4 p4_; - P5 p5_; - P6 p6_; - P7 p7_; -}; - -} // namespace internal -} // namespace base - -#endif // BASE_BIND_INTERNAL_H_ diff --git a/base/bind_internal.h.pump b/base/bind_internal.h.pump deleted file mode 100644 index f632b99e55..0000000000 --- a/base/bind_internal.h.pump +++ /dev/null @@ -1,500 +0,0 @@ -$$ This is a pump file for generating file templates. Pump is a python -$$ script that is part of the Google Test suite of utilities. Description -$$ can be found here: -$$ -$$ http://code.google.com/p/googletest/wiki/PumpManual -$$ - -$$ See comment for MAX_ARITY in base/bind.h.pump. -$var MAX_ARITY = 7 -$range ARITY 0..MAX_ARITY - -// Copyright (c) 2011 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef BASE_BIND_INTERNAL_H_ -#define BASE_BIND_INTERNAL_H_ - -#include "base/bind_helpers.h" -#include "base/callback_internal.h" -#include "base/memory/raw_scoped_refptr_mismatch_checker.h" -#include "base/memory/weak_ptr.h" -#include "base/template_util.h" -#include "build/build_config.h" - -#if defined(OS_WIN) -#include "base/bind_internal_win.h" -#endif - -namespace base { -namespace internal { - -// See base/callback.h for user documentation. -// -// -// CONCEPTS: -// Runnable -- A type (really a type class) that has a single Run() method -// and a RunType typedef that corresponds to the type of Run(). -// A Runnable can declare that it should treated like a method -// call by including a typedef named IsMethod. The value of -// this typedef is NOT inspected, only the existence. When a -// Runnable declares itself a method, Bind() will enforce special -// refcounting + WeakPtr handling semantics for the first -// parameter which is expected to be an object. -// Functor -- A copyable type representing something that should be called. -// All function pointers, Callback<>, and Runnables are functors -// even if the invocation syntax differs. -// RunType -- A function type (as opposed to function _pointer_ type) for -// a Run() function. Usually just a convenience typedef. -// (Bound)ArgsType -- A function type that is being (ab)used to store the -// types of set of arguments. The "return" type is always -// void here. We use this hack so that we do not need -// a new type name for each arity of type. (eg., -// BindState1, BindState2). This makes forward -// declarations and friending much much easier. -// -// Types: -// RunnableAdapter<> -- Wraps the various "function" pointer types into an -// object that adheres to the Runnable interface. -// There are |3*ARITY| RunnableAdapter types. -// FunctionTraits<> -- Type traits that unwrap a function signature into a -// a set of easier to use typedefs. Used mainly for -// compile time asserts. -// There are |ARITY| FunctionTraits types. -// ForceVoidReturn<> -- Helper class for translating function signatures to -// equivalent forms with a "void" return type. -// There are |ARITY| ForceVoidReturn types. -// FunctorTraits<> -- Type traits used determine the correct RunType and -// RunnableType for a Functor. This is where function -// signature adapters are applied. -// There are |ARITY| ForceVoidReturn types. -// MakeRunnable<> -- Takes a Functor and returns an object in the Runnable -// type class that represents the underlying Functor. -// There are |O(1)| MakeRunnable types. -// InvokeHelper<> -- Take a Runnable + arguments and actully invokes it. -// Handle the differing syntaxes needed for WeakPtr<> support, -// and for ignoring return values. This is separate from -// Invoker to avoid creating multiple version of Invoker<> -// which grows at O(n^2) with the arity. -// There are |k*ARITY| InvokeHelper types. -// Invoker<> -- Unwraps the curried parameters and executes the Runnable. -// There are |(ARITY^2 + ARITY)/2| Invoketypes. -// BindState<> -- Stores the curried parameters, and is the main entry point -// into the Bind() system, doing most of the type resolution. -// There are ARITY BindState types. - -// RunnableAdapter<> -// -// The RunnableAdapter<> templates provide a uniform interface for invoking -// a function pointer, method pointer, or const method pointer. The adapter -// exposes a Run() method with an appropriate signature. Using this wrapper -// allows for writing code that supports all three pointer types without -// undue repetition. Without it, a lot of code would need to be repeated 3 -// times. -// -// For method pointers and const method pointers the first argument to Run() -// is considered to be the received of the method. This is similar to STL's -// mem_fun(). -// -// This class also exposes a RunType typedef that is the function type of the -// Run() function. -// -// If and only if the wrapper contains a method or const method pointer, an -// IsMethod typedef is exposed. The existence of this typedef (NOT the value) -// marks that the wrapper should be considered a method wrapper. - -template -class RunnableAdapter; - -$for ARITY [[ -$range ARG 1..ARITY - -// Function: Arity $(ARITY). -template 0[[, ]] $for ARG , [[typename A$(ARG)]]> -class RunnableAdapter { - public: - typedef R (RunType)($for ARG , [[A$(ARG)]]); - - explicit RunnableAdapter(R(*function)($for ARG , [[A$(ARG)]])) - : function_(function) { - } - - R Run($for ARG , [[typename CallbackParamTraits::ForwardType a$(ARG)]]) { - return function_($for ARG , [[CallbackForward(a$(ARG))]]); - } - - private: - R (*function_)($for ARG , [[A$(ARG)]]); -}; - -// Method: Arity $(ARITY). -template 0[[, ]] $for ARG , [[typename A$(ARG)]]> -class RunnableAdapter { - public: - typedef R (RunType)(T*[[]] -$if ARITY > 0[[, ]] $for ARG , [[A$(ARG)]]); - typedef true_type IsMethod; - - explicit RunnableAdapter(R(T::*method)($for ARG , [[A$(ARG)]])) - : method_(method) { - } - - R Run(T* object[[]] -$if ARITY > 0[[, ]] $for ARG, [[typename CallbackParamTraits::ForwardType a$(ARG)]]) { - return (object->*method_)($for ARG , [[CallbackForward(a$(ARG))]]); - } - - private: - R (T::*method_)($for ARG , [[A$(ARG)]]); -}; - -// Const Method: Arity $(ARITY). -template 0[[, ]] $for ARG , [[typename A$(ARG)]]> -class RunnableAdapter { - public: - typedef R (RunType)(const T*[[]] -$if ARITY > 0[[, ]] $for ARG , [[A$(ARG)]]); - typedef true_type IsMethod; - - explicit RunnableAdapter(R(T::*method)($for ARG , [[A$(ARG)]]) const) - : method_(method) { - } - - R Run(const T* object[[]] -$if ARITY > 0[[, ]] $for ARG, [[typename CallbackParamTraits::ForwardType a$(ARG)]]) { - return (object->*method_)($for ARG , [[CallbackForward(a$(ARG))]]); - } - - private: - R (T::*method_)($for ARG , [[A$(ARG)]]) const; -}; - -]] $$ for ARITY - - -// FunctionTraits<> -// -// Breaks a function signature apart into typedefs for easier introspection. -template -struct FunctionTraits; - -$for ARITY [[ -$range ARG 1..ARITY - -template 0[[, ]] $for ARG , [[typename A$(ARG)]]> -struct FunctionTraits { - typedef R ReturnType; -$for ARG [[ - - typedef A$(ARG) A$(ARG)Type; -]] - -}; - -]] - - -// ForceVoidReturn<> -// -// Set of templates that support forcing the function return type to void. -template -struct ForceVoidReturn; - -$for ARITY [[ -$range ARG 1..ARITY - -template 0[[, ]] $for ARG , [[typename A$(ARG)]]> -struct ForceVoidReturn { - typedef void(RunType)($for ARG , [[A$(ARG)]]); -}; - -]] $$ for ARITY - - -// FunctorTraits<> -// -// See description at top of file. -template -struct FunctorTraits { - typedef RunnableAdapter RunnableType; - typedef typename RunnableType::RunType RunType; -}; - -template -struct FunctorTraits > { - typedef typename FunctorTraits::RunnableType RunnableType; - typedef typename ForceVoidReturn< - typename RunnableType::RunType>::RunType RunType; -}; - -template -struct FunctorTraits > { - typedef Callback RunnableType; - typedef typename Callback::RunType RunType; -}; - - -// MakeRunnable<> -// -// Converts a passed in functor to a RunnableType using type inference. - -template -typename FunctorTraits::RunnableType MakeRunnable(const T& t) { - return RunnableAdapter(t); -} - -template -typename FunctorTraits::RunnableType -MakeRunnable(const IgnoreResultHelper& t) { - return MakeRunnable(t.functor_); -} - -template -const typename FunctorTraits >::RunnableType& -MakeRunnable(const Callback& t) { - DCHECK(!t.is_null()); - return t; -} - - -// InvokeHelper<> -// -// There are 3 logical InvokeHelper<> specializations: normal, void-return, -// WeakCalls. -// -// The normal type just calls the underlying runnable. -// -// We need a InvokeHelper to handle void return types in order to support -// IgnoreResult(). Normally, if the Runnable's RunType had a void return, -// the template system would just accept "return functor.Run()" ignoring -// the fact that a void function is being used with return. This piece of -// sugar breaks though when the Runnable's RunType is not void. Thus, we -// need a partial specialization to change the syntax to drop the "return" -// from the invocation call. -// -// WeakCalls similarly need special syntax that is applied to the first -// argument to check if they should no-op themselves. -template -struct InvokeHelper; - -$for ARITY [[ -$range ARG 1..ARITY -$range WEAKCALL_ARG 2..ARITY - -template 0 [[,]] $for ARG , [[typename A$(ARG)]]> -struct InvokeHelper { - static ReturnType MakeItSo(Runnable runnable[[]] -$if ARITY > 0[[, ]] $for ARG , [[A$(ARG) a$(ARG)]]) { - return runnable.Run($for ARG , [[CallbackForward(a$(ARG))]]); - } -}; - -template 0 [[,]] $for ARG , [[typename A$(ARG)]]> -struct InvokeHelper { - static void MakeItSo(Runnable runnable[[]] -$if ARITY > 0[[, ]] $for ARG , [[A$(ARG) a$(ARG)]]) { - runnable.Run($for ARG , [[CallbackForward(a$(ARG))]]); - } -}; - -$if ARITY > 0 [[ - -template 1[[, ]] $for WEAKCALL_ARG , [[typename A$(WEAKCALL_ARG)]]> -struct InvokeHelper 1[[, ]] $for WEAKCALL_ARG , [[A$(WEAKCALL_ARG)]])> { - static void MakeItSo(Runnable runnable, BoundWeakPtr weak_ptr -$if ARITY > 1[[, ]] $for WEAKCALL_ARG , [[A$(WEAKCALL_ARG) a$(WEAKCALL_ARG)]]) { - if (!weak_ptr.get()) { - return; - } - runnable.Run(weak_ptr.get() -$if ARITY > 1[[, ]] $for WEAKCALL_ARG , [[CallbackForward(a$(WEAKCALL_ARG))]]); - } -}; - -]] - -]] $$ for ARITY - -#if !defined(_MSC_VER) - -template -struct InvokeHelper { - // WeakCalls are only supported for functions with a void return type. - // Otherwise, the function result would be undefined if the the WeakPtr<> - // is invalidated. - COMPILE_ASSERT(is_void::value, - weak_ptrs_can_only_bind_to_methods_without_return_values); -}; - -#endif - -// Invoker<> -// -// See description at the top of the file. -template -struct Invoker; - -$for ARITY [[ - -$$ Number of bound arguments. -$range BOUND 0..ARITY -$for BOUND [[ - -$var UNBOUND = ARITY - BOUND -$range ARG 1..ARITY -$range BOUND_ARG 1..BOUND -$range UNBOUND_ARG (ARITY - UNBOUND + 1)..ARITY - -// Arity $(ARITY) -> $(UNBOUND). -template 0 [[,]][[]] -$for ARG , [[typename X$(ARG)]]> -struct Invoker<$(BOUND), StorageType, R($for ARG , [[X$(ARG)]])> { - typedef R(RunType)(BindStateBase*[[]] -$if UNBOUND != 0 [[, ]] -$for UNBOUND_ARG , [[typename CallbackParamTraits::ForwardType]]); - - typedef R(UnboundRunType)($for UNBOUND_ARG , [[X$(UNBOUND_ARG)]]); - - static R Run(BindStateBase* base[[]] -$if UNBOUND != 0 [[, ]][[]] -$for UNBOUND_ARG , [[ -typename CallbackParamTraits::ForwardType x$(UNBOUND_ARG) -]][[]] -) { - StorageType* storage = static_cast(base); - - // Local references to make debugger stepping easier. If in a debugger, - // you really want to warp ahead and step through the - // InvokeHelper<>::MakeItSo() call below. -$for BOUND_ARG -[[ - - typedef typename StorageType::Bound$(BOUND_ARG)UnwrapTraits Bound$(BOUND_ARG)UnwrapTraits; -]] - - -$for BOUND_ARG -[[ - - typename Bound$(BOUND_ARG)UnwrapTraits::ForwardType x$(BOUND_ARG) = - Bound$(BOUND_ARG)UnwrapTraits::Unwrap(storage->p$(BOUND_ARG)_); -]] - - return InvokeHelper 0 [[$if BOUND > 0 [[, ]]]][[]] - -$for UNBOUND_ARG , [[ -typename CallbackParamTraits::ForwardType x$(UNBOUND_ARG) -]] -)> - ::MakeItSo(storage->runnable_ -$if ARITY > 0[[, ]] $for ARG , [[CallbackForward(x$(ARG))]]); - } -}; - -]] $$ for BOUND -]] $$ for ARITY - - -// BindState<> -// -// This stores all the state passed into Bind() and is also where most -// of the template resolution magic occurs. -// -// Runnable is the functor we are binding arguments to. -// RunType is type of the Run() function that the Invoker<> should use. -// Normally, this is the same as the RunType of the Runnable, but it can -// be different if an adapter like IgnoreResult() has been used. -// -// BoundArgsType contains the storage type for all the bound arguments by -// (ab)using a function type. -template -struct BindState; - -$for ARITY [[ -$range ARG 1..ARITY - -template 0[[, ]] $for ARG , [[typename P$(ARG)]]> -struct BindState : public BindStateBase { - typedef Runnable RunnableType; - -$if ARITY > 0 [[ - typedef IsWeakMethod::value, P1> IsWeakCall; -]] $else [[ - typedef false_type IsWeakCall; -]] - - typedef Invoker<$(ARITY), BindState, RunType> InvokerType; - typedef typename InvokerType::UnboundRunType UnboundRunType; - -$if ARITY > 0 [[ - - // Convenience typedefs for bound argument types. - -$for ARG [[ - typedef UnwrapTraits Bound$(ARG)UnwrapTraits; - -]] $$ for ARG - - -]] $$ if ARITY > 0 - -$$ The extra [[ ]] is needed to massage spacing. Silly pump.py. -[[ ]]$if ARITY == 0 [[explicit ]]BindState(const Runnable& runnable -$if ARITY > 0 [[, ]] $for ARG , [[const P$(ARG)& p$(ARG)]]) - : runnable_(runnable)[[]] -$if ARITY == 0 [[ - { - -]] $else [[ -, $for ARG , [[ - - p$(ARG)_(p$(ARG)) -]] { - MaybeRefcount::value, P1>::AddRef(p1_); - -]] - } - - virtual ~BindState() { -$if ARITY > 0 [[ - MaybeRefcount::value, P1>::Release(p1_); -]] - } - - RunnableType runnable_; - -$for ARG [[ - P$(ARG) p$(ARG)_; - -]] -}; - -]] $$ for ARITY - -} // namespace internal -} // namespace base - -#endif // BASE_BIND_INTERNAL_H_ diff --git a/base/bind_internal_win.h b/base/bind_internal_win.h deleted file mode 100644 index 7a8486a309..0000000000 --- a/base/bind_internal_win.h +++ /dev/null @@ -1,368 +0,0 @@ -// This file was GENERATED by command: -// pump.py bind_internal_win.h.pump -// DO NOT EDIT BY HAND!!! - - -// Copyright (c) 2011 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -// Specializations of RunnableAdapter<> for Windows specific calling -// conventions. Please see base/bind_internal.h for more info. - -#ifndef BASE_BIND_INTERNAL_WIN_H_ -#define BASE_BIND_INTERNAL_WIN_H_ - -// In the x64 architecture in Windows, __fastcall, __stdcall, etc, are all -// the same as __cdecl which would turn the following specializations into -// multiple definitions. -#if !defined(ARCH_CPU_X86_64) - -namespace base { -namespace internal { - -template -class RunnableAdapter; - -// __stdcall Function: Arity 0. -template -class RunnableAdapter { - public: - typedef R (RunType)(); - - explicit RunnableAdapter(R(__stdcall *function)()) - : function_(function) { - } - - R Run() { - return function_(); - } - - private: - R (__stdcall *function_)(); -}; - -// __fastcall Function: Arity 0. -template -class RunnableAdapter { - public: - typedef R (RunType)(); - - explicit RunnableAdapter(R(__fastcall *function)()) - : function_(function) { - } - - R Run() { - return function_(); - } - - private: - R (__fastcall *function_)(); -}; - -// __stdcall Function: Arity 1. -template -class RunnableAdapter { - public: - typedef R (RunType)(A1); - - explicit RunnableAdapter(R(__stdcall *function)(A1)) - : function_(function) { - } - - R Run(typename CallbackParamTraits::ForwardType a1) { - return function_(a1); - } - - private: - R (__stdcall *function_)(A1); -}; - -// __fastcall Function: Arity 1. -template -class RunnableAdapter { - public: - typedef R (RunType)(A1); - - explicit RunnableAdapter(R(__fastcall *function)(A1)) - : function_(function) { - } - - R Run(typename CallbackParamTraits::ForwardType a1) { - return function_(a1); - } - - private: - R (__fastcall *function_)(A1); -}; - -// __stdcall Function: Arity 2. -template -class RunnableAdapter { - public: - typedef R (RunType)(A1, A2); - - explicit RunnableAdapter(R(__stdcall *function)(A1, A2)) - : function_(function) { - } - - R Run(typename CallbackParamTraits::ForwardType a1, - typename CallbackParamTraits::ForwardType a2) { - return function_(a1, a2); - } - - private: - R (__stdcall *function_)(A1, A2); -}; - -// __fastcall Function: Arity 2. -template -class RunnableAdapter { - public: - typedef R (RunType)(A1, A2); - - explicit RunnableAdapter(R(__fastcall *function)(A1, A2)) - : function_(function) { - } - - R Run(typename CallbackParamTraits::ForwardType a1, - typename CallbackParamTraits::ForwardType a2) { - return function_(a1, a2); - } - - private: - R (__fastcall *function_)(A1, A2); -}; - -// __stdcall Function: Arity 3. -template -class RunnableAdapter { - public: - typedef R (RunType)(A1, A2, A3); - - explicit RunnableAdapter(R(__stdcall *function)(A1, A2, A3)) - : function_(function) { - } - - R Run(typename CallbackParamTraits::ForwardType a1, - typename CallbackParamTraits::ForwardType a2, - typename CallbackParamTraits::ForwardType a3) { - return function_(a1, a2, a3); - } - - private: - R (__stdcall *function_)(A1, A2, A3); -}; - -// __fastcall Function: Arity 3. -template -class RunnableAdapter { - public: - typedef R (RunType)(A1, A2, A3); - - explicit RunnableAdapter(R(__fastcall *function)(A1, A2, A3)) - : function_(function) { - } - - R Run(typename CallbackParamTraits::ForwardType a1, - typename CallbackParamTraits::ForwardType a2, - typename CallbackParamTraits::ForwardType a3) { - return function_(a1, a2, a3); - } - - private: - R (__fastcall *function_)(A1, A2, A3); -}; - -// __stdcall Function: Arity 4. -template -class RunnableAdapter { - public: - typedef R (RunType)(A1, A2, A3, A4); - - explicit RunnableAdapter(R(__stdcall *function)(A1, A2, A3, A4)) - : function_(function) { - } - - R Run(typename CallbackParamTraits::ForwardType a1, - typename CallbackParamTraits::ForwardType a2, - typename CallbackParamTraits::ForwardType a3, - typename CallbackParamTraits::ForwardType a4) { - return function_(a1, a2, a3, a4); - } - - private: - R (__stdcall *function_)(A1, A2, A3, A4); -}; - -// __fastcall Function: Arity 4. -template -class RunnableAdapter { - public: - typedef R (RunType)(A1, A2, A3, A4); - - explicit RunnableAdapter(R(__fastcall *function)(A1, A2, A3, A4)) - : function_(function) { - } - - R Run(typename CallbackParamTraits::ForwardType a1, - typename CallbackParamTraits::ForwardType a2, - typename CallbackParamTraits::ForwardType a3, - typename CallbackParamTraits::ForwardType a4) { - return function_(a1, a2, a3, a4); - } - - private: - R (__fastcall *function_)(A1, A2, A3, A4); -}; - -// __stdcall Function: Arity 5. -template -class RunnableAdapter { - public: - typedef R (RunType)(A1, A2, A3, A4, A5); - - explicit RunnableAdapter(R(__stdcall *function)(A1, A2, A3, A4, A5)) - : function_(function) { - } - - R Run(typename CallbackParamTraits::ForwardType a1, - typename CallbackParamTraits::ForwardType a2, - typename CallbackParamTraits::ForwardType a3, - typename CallbackParamTraits::ForwardType a4, - typename CallbackParamTraits::ForwardType a5) { - return function_(a1, a2, a3, a4, a5); - } - - private: - R (__stdcall *function_)(A1, A2, A3, A4, A5); -}; - -// __fastcall Function: Arity 5. -template -class RunnableAdapter { - public: - typedef R (RunType)(A1, A2, A3, A4, A5); - - explicit RunnableAdapter(R(__fastcall *function)(A1, A2, A3, A4, A5)) - : function_(function) { - } - - R Run(typename CallbackParamTraits::ForwardType a1, - typename CallbackParamTraits::ForwardType a2, - typename CallbackParamTraits::ForwardType a3, - typename CallbackParamTraits::ForwardType a4, - typename CallbackParamTraits::ForwardType a5) { - return function_(a1, a2, a3, a4, a5); - } - - private: - R (__fastcall *function_)(A1, A2, A3, A4, A5); -}; - -// __stdcall Function: Arity 6. -template -class RunnableAdapter { - public: - typedef R (RunType)(A1, A2, A3, A4, A5, A6); - - explicit RunnableAdapter(R(__stdcall *function)(A1, A2, A3, A4, A5, A6)) - : function_(function) { - } - - R Run(typename CallbackParamTraits::ForwardType a1, - typename CallbackParamTraits::ForwardType a2, - typename CallbackParamTraits::ForwardType a3, - typename CallbackParamTraits::ForwardType a4, - typename CallbackParamTraits::ForwardType a5, - typename CallbackParamTraits::ForwardType a6) { - return function_(a1, a2, a3, a4, a5, a6); - } - - private: - R (__stdcall *function_)(A1, A2, A3, A4, A5, A6); -}; - -// __fastcall Function: Arity 6. -template -class RunnableAdapter { - public: - typedef R (RunType)(A1, A2, A3, A4, A5, A6); - - explicit RunnableAdapter(R(__fastcall *function)(A1, A2, A3, A4, A5, A6)) - : function_(function) { - } - - R Run(typename CallbackParamTraits::ForwardType a1, - typename CallbackParamTraits::ForwardType a2, - typename CallbackParamTraits::ForwardType a3, - typename CallbackParamTraits::ForwardType a4, - typename CallbackParamTraits::ForwardType a5, - typename CallbackParamTraits::ForwardType a6) { - return function_(a1, a2, a3, a4, a5, a6); - } - - private: - R (__fastcall *function_)(A1, A2, A3, A4, A5, A6); -}; - -// __stdcall Function: Arity 7. -template -class RunnableAdapter { - public: - typedef R (RunType)(A1, A2, A3, A4, A5, A6, A7); - - explicit RunnableAdapter(R(__stdcall *function)(A1, A2, A3, A4, A5, A6, A7)) - : function_(function) { - } - - R Run(typename CallbackParamTraits::ForwardType a1, - typename CallbackParamTraits::ForwardType a2, - typename CallbackParamTraits::ForwardType a3, - typename CallbackParamTraits::ForwardType a4, - typename CallbackParamTraits::ForwardType a5, - typename CallbackParamTraits::ForwardType a6, - typename CallbackParamTraits::ForwardType a7) { - return function_(a1, a2, a3, a4, a5, a6, a7); - } - - private: - R (__stdcall *function_)(A1, A2, A3, A4, A5, A6, A7); -}; - -// __fastcall Function: Arity 7. -template -class RunnableAdapter { - public: - typedef R (RunType)(A1, A2, A3, A4, A5, A6, A7); - - explicit RunnableAdapter(R(__fastcall *function)(A1, A2, A3, A4, A5, A6, A7)) - : function_(function) { - } - - R Run(typename CallbackParamTraits::ForwardType a1, - typename CallbackParamTraits::ForwardType a2, - typename CallbackParamTraits::ForwardType a3, - typename CallbackParamTraits::ForwardType a4, - typename CallbackParamTraits::ForwardType a5, - typename CallbackParamTraits::ForwardType a6, - typename CallbackParamTraits::ForwardType a7) { - return function_(a1, a2, a3, a4, a5, a6, a7); - } - - private: - R (__fastcall *function_)(A1, A2, A3, A4, A5, A6, A7); -}; - -} // namespace internal -} // namespace base - -#endif // !defined(ARCH_CPU_X86_64) - -#endif // BASE_BIND_INTERNAL_WIN_H_ diff --git a/base/bind_internal_win.h.pump b/base/bind_internal_win.h.pump deleted file mode 100644 index cd108b6abe..0000000000 --- a/base/bind_internal_win.h.pump +++ /dev/null @@ -1,81 +0,0 @@ -$$ This is a pump file for generating file templates. Pump is a python -$$ script that is part of the Google Test suite of utilities. Description -$$ can be found here: -$$ -$$ http://code.google.com/p/googletest/wiki/PumpManual -$$ - -$$ See comment for MAX_ARITY in base/bind.h.pump. -$var MAX_ARITY = 7 - -// Copyright (c) 2011 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -// Specializations of RunnableAdapter<> for Windows specific calling -// conventions. Please see base/bind_internal.h for more info. - -#ifndef BASE_BIND_INTERNAL_WIN_H_ -#define BASE_BIND_INTERNAL_WIN_H_ - -// In the x64 architecture in Windows, __fastcall, __stdcall, etc, are all -// the same as __cdecl which would turn the following specializations into -// multiple definitions. -#if !defined(ARCH_CPU_X86_64) - -namespace base { -namespace internal { - -template -class RunnableAdapter; - -$range ARITY 0..MAX_ARITY -$for ARITY [[ -$range ARG 1..ARITY - -// __stdcall Function: Arity $(ARITY). -template 0[[, ]] $for ARG , [[typename A$(ARG)]]> -class RunnableAdapter { - public: - typedef R (RunType)($for ARG , [[A$(ARG)]]); - - explicit RunnableAdapter(R(__stdcall *function)($for ARG , [[A$(ARG)]])) - : function_(function) { - } - - R Run($for ARG , [[typename CallbackParamTraits::ForwardType a$(ARG)]]) { - return function_($for ARG , [[a$(ARG)]]); - } - - private: - R (__stdcall *function_)($for ARG , [[A$(ARG)]]); -}; - -// __fastcall Function: Arity $(ARITY). -template 0[[, ]] $for ARG , [[typename A$(ARG)]]> -class RunnableAdapter { - public: - typedef R (RunType)($for ARG , [[A$(ARG)]]); - - explicit RunnableAdapter(R(__fastcall *function)($for ARG , [[A$(ARG)]])) - : function_(function) { - } - - R Run($for ARG , [[typename CallbackParamTraits::ForwardType a$(ARG)]]) { - return function_($for ARG , [[a$(ARG)]]); - } - - private: - R (__fastcall *function_)($for ARG , [[A$(ARG)]]); -}; - -]] $$for ARITY - -} // namespace internal -} // namespace base - -#endif // !defined(ARCH_CPU_X86_64) - -#endif // BASE_BIND_INTERNAL_WIN_H_ diff --git a/base/bind_unittest.cc b/base/bind_unittest.cc deleted file mode 100644 index 2c93d53ee4..0000000000 --- a/base/bind_unittest.cc +++ /dev/null @@ -1,833 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "base/bind.h" - -#include "base/callback.h" -#include "base/memory/ref_counted.h" -#include "base/memory/scoped_ptr.h" -#include "base/memory/weak_ptr.h" -#include "testing/gmock/include/gmock/gmock.h" -#include "testing/gtest/include/gtest/gtest.h" - -using ::testing::Mock; -using ::testing::Return; -using ::testing::StrictMock; - -namespace base { -namespace { - -class IncompleteType; - -class NoRef { - public: - NoRef() {} - - MOCK_METHOD0(VoidMethod0, void(void)); - MOCK_CONST_METHOD0(VoidConstMethod0, void(void)); - - MOCK_METHOD0(IntMethod0, int(void)); - MOCK_CONST_METHOD0(IntConstMethod0, int(void)); - - private: - // Particularly important in this test to ensure no copies are made. - DISALLOW_COPY_AND_ASSIGN(NoRef); -}; - -class HasRef : public NoRef { - public: - HasRef() {} - - MOCK_CONST_METHOD0(AddRef, void(void)); - MOCK_CONST_METHOD0(Release, bool(void)); - - private: - // Particularly important in this test to ensure no copies are made. - DISALLOW_COPY_AND_ASSIGN(HasRef); -}; - -class HasRefPrivateDtor : public HasRef { - private: - ~HasRefPrivateDtor() {} -}; - -static const int kParentValue = 1; -static const int kChildValue = 2; - -class Parent { - public: - void AddRef(void) const {} - void Release(void) const {} - virtual void VirtualSet() { value = kParentValue; } - void NonVirtualSet() { value = kParentValue; } - int value; -}; - -class Child : public Parent { - public: - virtual void VirtualSet() OVERRIDE { value = kChildValue; } - void NonVirtualSet() { value = kChildValue; } -}; - -class NoRefParent { - public: - virtual void VirtualSet() { value = kParentValue; } - void NonVirtualSet() { value = kParentValue; } - int value; -}; - -class NoRefChild : public NoRefParent { - virtual void VirtualSet() OVERRIDE { value = kChildValue; } - void NonVirtualSet() { value = kChildValue; } -}; - -// Used for probing the number of copies that occur if a type must be coerced -// during argument forwarding in the Run() methods. -struct DerivedCopyCounter { - DerivedCopyCounter(int* copies, int* assigns) - : copies_(copies), assigns_(assigns) { - } - int* copies_; - int* assigns_; -}; - -// Used for probing the number of copies in an argument. -class CopyCounter { - public: - CopyCounter(int* copies, int* assigns) - : copies_(copies), assigns_(assigns) { - } - - CopyCounter(const CopyCounter& other) - : copies_(other.copies_), - assigns_(other.assigns_) { - (*copies_)++; - } - - // Probing for copies from coercion. - explicit CopyCounter(const DerivedCopyCounter& other) - : copies_(other.copies_), - assigns_(other.assigns_) { - (*copies_)++; - } - - const CopyCounter& operator=(const CopyCounter& rhs) { - copies_ = rhs.copies_; - assigns_ = rhs.assigns_; - - if (assigns_) { - (*assigns_)++; - } - - return *this; - } - - int copies() const { - return *copies_; - } - - int assigns() const { - return *assigns_; - } - - private: - int* copies_; - int* assigns_; -}; - -class DeleteCounter { - public: - explicit DeleteCounter(int* deletes) - : deletes_(deletes) { - } - - ~DeleteCounter() { - (*deletes_)++; - } - - void VoidMethod0() {} - - private: - int* deletes_; -}; - -template -T PassThru(T scoper) { - return scoper.Pass(); -} - -// Some test functions that we can Bind to. -template -T PolymorphicIdentity(T t) { - return t; -} - -template -void VoidPolymorphic1(T t) { -} - -int Identity(int n) { - return n; -} - -int ArrayGet(const int array[], int n) { - return array[n]; -} - -int Sum(int a, int b, int c, int d, int e, int f) { - return a + b + c + d + e + f; -} - -const char* CStringIdentity(const char* s) { - return s; -} - -int GetCopies(const CopyCounter& counter) { - return counter.copies(); -} - -int UnwrapNoRefParent(NoRefParent p) { - return p.value; -} - -int UnwrapNoRefParentPtr(NoRefParent* p) { - return p->value; -} - -int UnwrapNoRefParentConstRef(const NoRefParent& p) { - return p.value; -} - -void RefArgSet(int &n) { - n = 2; -} - -void PtrArgSet(int *n) { - *n = 2; -} - -int FunctionWithWeakFirstParam(WeakPtr o, int n) { - return n; -} - -int FunctionWithScopedRefptrFirstParam(const scoped_refptr& o, int n) { - return n; -} - -void TakesACallback(const Closure& callback) { - callback.Run(); -} - -class BindTest : public ::testing::Test { - public: - BindTest() { - const_has_ref_ptr_ = &has_ref_; - const_no_ref_ptr_ = &no_ref_; - static_func_mock_ptr = &static_func_mock_; - } - - virtual ~BindTest() { - } - - static void VoidFunc0(void) { - static_func_mock_ptr->VoidMethod0(); - } - - static int IntFunc0(void) { return static_func_mock_ptr->IntMethod0(); } - - protected: - StrictMock no_ref_; - StrictMock has_ref_; - const HasRef* const_has_ref_ptr_; - const NoRef* const_no_ref_ptr_; - StrictMock static_func_mock_; - - // Used by the static functions to perform expectations. - static StrictMock* static_func_mock_ptr; - - private: - DISALLOW_COPY_AND_ASSIGN(BindTest); -}; - -StrictMock* BindTest::static_func_mock_ptr; - -// Sanity check that we can instantiate a callback for each arity. -TEST_F(BindTest, ArityTest) { - Callback c0 = Bind(&Sum, 32, 16, 8, 4, 2, 1); - EXPECT_EQ(63, c0.Run()); - - Callback c1 = Bind(&Sum, 32, 16, 8, 4, 2); - EXPECT_EQ(75, c1.Run(13)); - - Callback c2 = Bind(&Sum, 32, 16, 8, 4); - EXPECT_EQ(85, c2.Run(13, 12)); - - Callback c3 = Bind(&Sum, 32, 16, 8); - EXPECT_EQ(92, c3.Run(13, 12, 11)); - - Callback c4 = Bind(&Sum, 32, 16); - EXPECT_EQ(94, c4.Run(13, 12, 11, 10)); - - Callback c5 = Bind(&Sum, 32); - EXPECT_EQ(87, c5.Run(13, 12, 11, 10, 9)); - - Callback c6 = Bind(&Sum); - EXPECT_EQ(69, c6.Run(13, 12, 11, 10, 9, 14)); -} - -// Test the Currying ability of the Callback system. -TEST_F(BindTest, CurryingTest) { - Callback c6 = Bind(&Sum); - EXPECT_EQ(69, c6.Run(13, 12, 11, 10, 9, 14)); - - Callback c5 = Bind(c6, 32); - EXPECT_EQ(87, c5.Run(13, 12, 11, 10, 9)); - - Callback c4 = Bind(c5, 16); - EXPECT_EQ(94, c4.Run(13, 12, 11, 10)); - - Callback c3 = Bind(c4, 8); - EXPECT_EQ(92, c3.Run(13, 12, 11)); - - Callback c2 = Bind(c3, 4); - EXPECT_EQ(85, c2.Run(13, 12)); - - Callback c1 = Bind(c2, 2); - EXPECT_EQ(75, c1.Run(13)); - - Callback c0 = Bind(c1, 1); - EXPECT_EQ(63, c0.Run()); -} - -// Test that currying the rvalue result of another Bind() works correctly. -// - rvalue should be usable as argument to Bind(). -// - multiple runs of resulting Callback remain valid. -TEST_F(BindTest, CurryingRvalueResultOfBind) { - int n = 0; - Closure cb = base::Bind(&TakesACallback, base::Bind(&PtrArgSet, &n)); - - // If we implement Bind() such that the return value has auto_ptr-like - // semantics, the second call here will fail because ownership of - // the internal BindState<> would have been transfered to a *temporary* - // constructon of a Callback object on the first call. - cb.Run(); - EXPECT_EQ(2, n); - - n = 0; - cb.Run(); - EXPECT_EQ(2, n); -} - -// Function type support. -// - Normal function. -// - Normal function bound with non-refcounted first argument. -// - Method bound to non-const object. -// - Method bound to scoped_refptr. -// - Const method bound to non-const object. -// - Const method bound to const object. -// - Derived classes can be used with pointers to non-virtual base functions. -// - Derived classes can be used with pointers to virtual base functions (and -// preserve virtual dispatch). -TEST_F(BindTest, FunctionTypeSupport) { - EXPECT_CALL(static_func_mock_, VoidMethod0()); - EXPECT_CALL(has_ref_, AddRef()).Times(5); - EXPECT_CALL(has_ref_, Release()).Times(5); - EXPECT_CALL(has_ref_, VoidMethod0()).Times(2); - EXPECT_CALL(has_ref_, VoidConstMethod0()).Times(2); - - Closure normal_cb = Bind(&VoidFunc0); - Callback normal_non_refcounted_cb = - Bind(&PolymorphicIdentity, &no_ref_); - normal_cb.Run(); - EXPECT_EQ(&no_ref_, normal_non_refcounted_cb.Run()); - - Closure method_cb = Bind(&HasRef::VoidMethod0, &has_ref_); - Closure method_refptr_cb = Bind(&HasRef::VoidMethod0, - make_scoped_refptr(&has_ref_)); - Closure const_method_nonconst_obj_cb = Bind(&HasRef::VoidConstMethod0, - &has_ref_); - Closure const_method_const_obj_cb = Bind(&HasRef::VoidConstMethod0, - const_has_ref_ptr_); - method_cb.Run(); - method_refptr_cb.Run(); - const_method_nonconst_obj_cb.Run(); - const_method_const_obj_cb.Run(); - - Child child; - child.value = 0; - Closure virtual_set_cb = Bind(&Parent::VirtualSet, &child); - virtual_set_cb.Run(); - EXPECT_EQ(kChildValue, child.value); - - child.value = 0; - Closure non_virtual_set_cb = Bind(&Parent::NonVirtualSet, &child); - non_virtual_set_cb.Run(); - EXPECT_EQ(kParentValue, child.value); -} - -// Return value support. -// - Function with return value. -// - Method with return value. -// - Const method with return value. -TEST_F(BindTest, ReturnValues) { - EXPECT_CALL(static_func_mock_, IntMethod0()).WillOnce(Return(1337)); - EXPECT_CALL(has_ref_, AddRef()).Times(3); - EXPECT_CALL(has_ref_, Release()).Times(3); - EXPECT_CALL(has_ref_, IntMethod0()).WillOnce(Return(31337)); - EXPECT_CALL(has_ref_, IntConstMethod0()) - .WillOnce(Return(41337)) - .WillOnce(Return(51337)); - - Callback normal_cb = Bind(&IntFunc0); - Callback method_cb = Bind(&HasRef::IntMethod0, &has_ref_); - Callback const_method_nonconst_obj_cb = - Bind(&HasRef::IntConstMethod0, &has_ref_); - Callback const_method_const_obj_cb = - Bind(&HasRef::IntConstMethod0, const_has_ref_ptr_); - EXPECT_EQ(1337, normal_cb.Run()); - EXPECT_EQ(31337, method_cb.Run()); - EXPECT_EQ(41337, const_method_nonconst_obj_cb.Run()); - EXPECT_EQ(51337, const_method_const_obj_cb.Run()); -} - -// IgnoreResult adapter test. -// - Function with return value. -// - Method with return value. -// - Const Method with return. -// - Method with return value bound to WeakPtr<>. -// - Const Method with return bound to WeakPtr<>. -TEST_F(BindTest, IgnoreResult) { - EXPECT_CALL(static_func_mock_, IntMethod0()).WillOnce(Return(1337)); - EXPECT_CALL(has_ref_, AddRef()).Times(2); - EXPECT_CALL(has_ref_, Release()).Times(2); - EXPECT_CALL(has_ref_, IntMethod0()).WillOnce(Return(10)); - EXPECT_CALL(has_ref_, IntConstMethod0()).WillOnce(Return(11)); - EXPECT_CALL(no_ref_, IntMethod0()).WillOnce(Return(12)); - EXPECT_CALL(no_ref_, IntConstMethod0()).WillOnce(Return(13)); - - Closure normal_func_cb = Bind(IgnoreResult(&IntFunc0)); - normal_func_cb.Run(); - - Closure non_void_method_cb = - Bind(IgnoreResult(&HasRef::IntMethod0), &has_ref_); - non_void_method_cb.Run(); - - Closure non_void_const_method_cb = - Bind(IgnoreResult(&HasRef::IntConstMethod0), &has_ref_); - non_void_const_method_cb.Run(); - - WeakPtrFactory weak_factory(&no_ref_); - WeakPtrFactory const_weak_factory(const_no_ref_ptr_); - - Closure non_void_weak_method_cb = - Bind(IgnoreResult(&NoRef::IntMethod0), weak_factory.GetWeakPtr()); - non_void_weak_method_cb.Run(); - - Closure non_void_weak_const_method_cb = - Bind(IgnoreResult(&NoRef::IntConstMethod0), weak_factory.GetWeakPtr()); - non_void_weak_const_method_cb.Run(); - - weak_factory.InvalidateWeakPtrs(); - non_void_weak_const_method_cb.Run(); - non_void_weak_method_cb.Run(); -} - -// Argument binding tests. -// - Argument binding to primitive. -// - Argument binding to primitive pointer. -// - Argument binding to a literal integer. -// - Argument binding to a literal string. -// - Argument binding with template function. -// - Argument binding to an object. -// - Argument binding to pointer to incomplete type. -// - Argument gets type converted. -// - Pointer argument gets converted. -// - Const Reference forces conversion. -TEST_F(BindTest, ArgumentBinding) { - int n = 2; - - Callback bind_primitive_cb = Bind(&Identity, n); - EXPECT_EQ(n, bind_primitive_cb.Run()); - - Callback bind_primitive_pointer_cb = - Bind(&PolymorphicIdentity, &n); - EXPECT_EQ(&n, bind_primitive_pointer_cb.Run()); - - Callback bind_int_literal_cb = Bind(&Identity, 3); - EXPECT_EQ(3, bind_int_literal_cb.Run()); - - Callback bind_string_literal_cb = - Bind(&CStringIdentity, "hi"); - EXPECT_STREQ("hi", bind_string_literal_cb.Run()); - - Callback bind_template_function_cb = - Bind(&PolymorphicIdentity, 4); - EXPECT_EQ(4, bind_template_function_cb.Run()); - - NoRefParent p; - p.value = 5; - Callback bind_object_cb = Bind(&UnwrapNoRefParent, p); - EXPECT_EQ(5, bind_object_cb.Run()); - - IncompleteType* incomplete_ptr = reinterpret_cast(123); - Callback bind_incomplete_ptr_cb = - Bind(&PolymorphicIdentity, incomplete_ptr); - EXPECT_EQ(incomplete_ptr, bind_incomplete_ptr_cb.Run()); - - NoRefChild c; - c.value = 6; - Callback bind_promotes_cb = Bind(&UnwrapNoRefParent, c); - EXPECT_EQ(6, bind_promotes_cb.Run()); - - c.value = 7; - Callback bind_pointer_promotes_cb = - Bind(&UnwrapNoRefParentPtr, &c); - EXPECT_EQ(7, bind_pointer_promotes_cb.Run()); - - c.value = 8; - Callback bind_const_reference_promotes_cb = - Bind(&UnwrapNoRefParentConstRef, c); - EXPECT_EQ(8, bind_const_reference_promotes_cb.Run()); -} - -// Unbound argument type support tests. -// - Unbound value. -// - Unbound pointer. -// - Unbound reference. -// - Unbound const reference. -// - Unbound unsized array. -// - Unbound sized array. -// - Unbound array-of-arrays. -TEST_F(BindTest, UnboundArgumentTypeSupport) { - Callback unbound_value_cb = Bind(&VoidPolymorphic1); - Callback unbound_pointer_cb = Bind(&VoidPolymorphic1); - Callback unbound_ref_cb = Bind(&VoidPolymorphic1); - Callback unbound_const_ref_cb = - Bind(&VoidPolymorphic1); - Callback unbound_unsized_array_cb = - Bind(&VoidPolymorphic1); - Callback unbound_sized_array_cb = - Bind(&VoidPolymorphic1); - Callback unbound_array_of_arrays_cb = - Bind(&VoidPolymorphic1); -} - -// Function with unbound reference parameter. -// - Original parameter is modified by callback. -TEST_F(BindTest, UnboundReferenceSupport) { - int n = 0; - Callback unbound_ref_cb = Bind(&RefArgSet); - unbound_ref_cb.Run(n); - EXPECT_EQ(2, n); -} - -// Functions that take reference parameters. -// - Forced reference parameter type still stores a copy. -// - Forced const reference parameter type still stores a copy. -TEST_F(BindTest, ReferenceArgumentBinding) { - int n = 1; - int& ref_n = n; - const int& const_ref_n = n; - - Callback ref_copies_cb = Bind(&Identity, ref_n); - EXPECT_EQ(n, ref_copies_cb.Run()); - n++; - EXPECT_EQ(n - 1, ref_copies_cb.Run()); - - Callback const_ref_copies_cb = Bind(&Identity, const_ref_n); - EXPECT_EQ(n, const_ref_copies_cb.Run()); - n++; - EXPECT_EQ(n - 1, const_ref_copies_cb.Run()); -} - -// Check that we can pass in arrays and have them be stored as a pointer. -// - Array of values stores a pointer. -// - Array of const values stores a pointer. -TEST_F(BindTest, ArrayArgumentBinding) { - int array[4] = {1, 1, 1, 1}; - const int (*const_array_ptr)[4] = &array; - - Callback array_cb = Bind(&ArrayGet, array, 1); - EXPECT_EQ(1, array_cb.Run()); - - Callback const_array_cb = Bind(&ArrayGet, *const_array_ptr, 1); - EXPECT_EQ(1, const_array_cb.Run()); - - array[1] = 3; - EXPECT_EQ(3, array_cb.Run()); - EXPECT_EQ(3, const_array_cb.Run()); -} - -// Verify SupportsAddRefAndRelease correctly introspects the class type for -// AddRef() and Release(). -// - Class with AddRef() and Release() -// - Class without AddRef() and Release() -// - Derived Class with AddRef() and Release() -// - Derived Class without AddRef() and Release() -// - Derived Class with AddRef() and Release() and a private destructor. -TEST_F(BindTest, SupportsAddRefAndRelease) { - EXPECT_TRUE(internal::SupportsAddRefAndRelease::value); - EXPECT_FALSE(internal::SupportsAddRefAndRelease::value); - - // StrictMock is a derived class of T. So, we use StrictMock and - // StrictMock to test that SupportsAddRefAndRelease works over - // inheritance. - EXPECT_TRUE(internal::SupportsAddRefAndRelease >::value); - EXPECT_FALSE(internal::SupportsAddRefAndRelease >::value); - - // This matters because the implementation creates a dummy class that - // inherits from the template type. - EXPECT_TRUE(internal::SupportsAddRefAndRelease::value); -} - -// Unretained() wrapper support. -// - Method bound to Unretained() non-const object. -// - Const method bound to Unretained() non-const object. -// - Const method bound to Unretained() const object. -TEST_F(BindTest, Unretained) { - EXPECT_CALL(no_ref_, VoidMethod0()); - EXPECT_CALL(no_ref_, VoidConstMethod0()).Times(2); - - Callback method_cb = - Bind(&NoRef::VoidMethod0, Unretained(&no_ref_)); - method_cb.Run(); - - Callback const_method_cb = - Bind(&NoRef::VoidConstMethod0, Unretained(&no_ref_)); - const_method_cb.Run(); - - Callback const_method_const_ptr_cb = - Bind(&NoRef::VoidConstMethod0, Unretained(const_no_ref_ptr_)); - const_method_const_ptr_cb.Run(); -} - -// WeakPtr() support. -// - Method bound to WeakPtr<> to non-const object. -// - Const method bound to WeakPtr<> to non-const object. -// - Const method bound to WeakPtr<> to const object. -// - Normal Function with WeakPtr<> as P1 can have return type and is -// not canceled. -TEST_F(BindTest, WeakPtr) { - EXPECT_CALL(no_ref_, VoidMethod0()); - EXPECT_CALL(no_ref_, VoidConstMethod0()).Times(2); - - WeakPtrFactory weak_factory(&no_ref_); - WeakPtrFactory const_weak_factory(const_no_ref_ptr_); - - Closure method_cb = - Bind(&NoRef::VoidMethod0, weak_factory.GetWeakPtr()); - method_cb.Run(); - - Closure const_method_cb = - Bind(&NoRef::VoidConstMethod0, const_weak_factory.GetWeakPtr()); - const_method_cb.Run(); - - Closure const_method_const_ptr_cb = - Bind(&NoRef::VoidConstMethod0, const_weak_factory.GetWeakPtr()); - const_method_const_ptr_cb.Run(); - - Callback normal_func_cb = - Bind(&FunctionWithWeakFirstParam, weak_factory.GetWeakPtr()); - EXPECT_EQ(1, normal_func_cb.Run(1)); - - weak_factory.InvalidateWeakPtrs(); - const_weak_factory.InvalidateWeakPtrs(); - - method_cb.Run(); - const_method_cb.Run(); - const_method_const_ptr_cb.Run(); - - // Still runs even after the pointers are invalidated. - EXPECT_EQ(2, normal_func_cb.Run(2)); -} - -// ConstRef() wrapper support. -// - Binding w/o ConstRef takes a copy. -// - Binding a ConstRef takes a reference. -// - Binding ConstRef to a function ConstRef does not copy on invoke. -TEST_F(BindTest, ConstRef) { - int n = 1; - - Callback copy_cb = Bind(&Identity, n); - Callback const_ref_cb = Bind(&Identity, ConstRef(n)); - EXPECT_EQ(n, copy_cb.Run()); - EXPECT_EQ(n, const_ref_cb.Run()); - n++; - EXPECT_EQ(n - 1, copy_cb.Run()); - EXPECT_EQ(n, const_ref_cb.Run()); - - int copies = 0; - int assigns = 0; - CopyCounter counter(&copies, &assigns); - Callback all_const_ref_cb = - Bind(&GetCopies, ConstRef(counter)); - EXPECT_EQ(0, all_const_ref_cb.Run()); - EXPECT_EQ(0, copies); - EXPECT_EQ(0, assigns); -} - -TEST_F(BindTest, ScopedRefptr) { - // BUG: The scoped_refptr should cause the only AddRef()/Release() pair. But - // due to a bug in base::Bind(), there's an extra call when invoking the - // callback. - // https://code.google.com/p/chromium/issues/detail?id=251937 - EXPECT_CALL(has_ref_, AddRef()).Times(2); - EXPECT_CALL(has_ref_, Release()).Times(2); - - const scoped_refptr > refptr(&has_ref_); - - Callback scoped_refptr_const_ref_cb = - Bind(&FunctionWithScopedRefptrFirstParam, base::ConstRef(refptr), 1); - EXPECT_EQ(1, scoped_refptr_const_ref_cb.Run()); -} - -// Test Owned() support. -TEST_F(BindTest, Owned) { - int deletes = 0; - DeleteCounter* counter = new DeleteCounter(&deletes); - - // If we don't capture, delete happens on Callback destruction/reset. - // return the same value. - Callback no_capture_cb = - Bind(&PolymorphicIdentity, Owned(counter)); - ASSERT_EQ(counter, no_capture_cb.Run()); - ASSERT_EQ(counter, no_capture_cb.Run()); - EXPECT_EQ(0, deletes); - no_capture_cb.Reset(); // This should trigger a delete. - EXPECT_EQ(1, deletes); - - deletes = 0; - counter = new DeleteCounter(&deletes); - base::Closure own_object_cb = - Bind(&DeleteCounter::VoidMethod0, Owned(counter)); - own_object_cb.Run(); - EXPECT_EQ(0, deletes); - own_object_cb.Reset(); - EXPECT_EQ(1, deletes); -} - -// Passed() wrapper support. -// - Passed() can be constructed from a pointer to scoper. -// - Passed() can be constructed from a scoper rvalue. -// - Using Passed() gives Callback Ownership. -// - Ownership is transferred from Callback to callee on the first Run(). -// - Callback supports unbound arguments. -TEST_F(BindTest, ScopedPtr) { - int deletes = 0; - - // Tests the Passed() function's support for pointers. - scoped_ptr ptr(new DeleteCounter(&deletes)); - Callback(void)> unused_callback = - Bind(&PassThru >, Passed(&ptr)); - EXPECT_FALSE(ptr.get()); - EXPECT_EQ(0, deletes); - - // If we never invoke the Callback, it retains ownership and deletes. - unused_callback.Reset(); - EXPECT_EQ(1, deletes); - - // Tests the Passed() function's support for rvalues. - deletes = 0; - DeleteCounter* counter = new DeleteCounter(&deletes); - Callback(void)> callback = - Bind(&PassThru >, - Passed(scoped_ptr(counter))); - EXPECT_FALSE(ptr.get()); - EXPECT_EQ(0, deletes); - - // Check that ownership can be transferred back out. - scoped_ptr result = callback.Run(); - ASSERT_EQ(counter, result.get()); - EXPECT_EQ(0, deletes); - - // Resetting does not delete since ownership was transferred. - callback.Reset(); - EXPECT_EQ(0, deletes); - - // Ensure that we actually did get ownership. - result.reset(); - EXPECT_EQ(1, deletes); - - // Test unbound argument forwarding. - Callback(scoped_ptr)> cb_unbound = - Bind(&PassThru >); - ptr.reset(new DeleteCounter(&deletes)); - cb_unbound.Run(ptr.Pass()); -} - -// Argument Copy-constructor usage for non-reference parameters. -// - Bound arguments are only copied once. -// - Forwarded arguments are only copied once. -// - Forwarded arguments with coercions are only copied twice (once for the -// coercion, and one for the final dispatch). -TEST_F(BindTest, ArgumentCopies) { - int copies = 0; - int assigns = 0; - - CopyCounter counter(&copies, &assigns); - - Callback copy_cb = - Bind(&VoidPolymorphic1, counter); - EXPECT_GE(1, copies); - EXPECT_EQ(0, assigns); - - copies = 0; - assigns = 0; - Callback forward_cb = - Bind(&VoidPolymorphic1); - forward_cb.Run(counter); - EXPECT_GE(1, copies); - EXPECT_EQ(0, assigns); - - copies = 0; - assigns = 0; - DerivedCopyCounter dervied(&copies, &assigns); - Callback coerce_cb = - Bind(&VoidPolymorphic1); - coerce_cb.Run(CopyCounter(dervied)); - EXPECT_GE(2, copies); - EXPECT_EQ(0, assigns); -} - -// Callback construction and assignment tests. -// - Construction from an InvokerStorageHolder should not cause ref/deref. -// - Assignment from other callback should only cause one ref -// -// TODO(ajwong): Is there actually a way to test this? - -#if defined(OS_WIN) -int __fastcall FastCallFunc(int n) { - return n; -} - -int __stdcall StdCallFunc(int n) { - return n; -} - -// Windows specific calling convention support. -// - Can bind a __fastcall function. -// - Can bind a __stdcall function. -TEST_F(BindTest, WindowsCallingConventions) { - Callback fastcall_cb = Bind(&FastCallFunc, 1); - EXPECT_EQ(1, fastcall_cb.Run()); - - Callback stdcall_cb = Bind(&StdCallFunc, 2); - EXPECT_EQ(2, stdcall_cb.Run()); -} -#endif - -#if (!defined(NDEBUG) || defined(DCHECK_ALWAYS_ON)) && GTEST_HAS_DEATH_TEST - -// Test null callbacks cause a DCHECK. -TEST(BindDeathTest, NullCallback) { - base::Callback null_cb; - ASSERT_TRUE(null_cb.is_null()); - EXPECT_DEATH(base::Bind(null_cb, 42), ""); -} - -#endif // (!defined(NDEBUG) || defined(DCHECK_ALWAYS_ON)) && - // GTEST_HAS_DEATH_TEST - -} // namespace -} // namespace base diff --git a/base/bind_unittest.nc b/base/bind_unittest.nc deleted file mode 100644 index 033acfaa05..0000000000 --- a/base/bind_unittest.nc +++ /dev/null @@ -1,203 +0,0 @@ -// Copyright (c) 2011 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "base/callback.h" -#include "base/bind.h" -#include "base/memory/ref_counted.h" - -namespace base { - -// Do not put everything inside an anonymous namespace. If you do, many of the -// helper function declarations will generate unused definition warnings unless -// unused definition warnings. - -static const int kParentValue = 1; -static const int kChildValue = 2; - -class NoRef { - public: - void VoidMethod0() {} - void VoidConstMethod0() const {} - int IntMethod0() { return 1; } -}; - -class HasRef : public NoRef, public base::RefCounted { -}; - -class Parent { - public: - void AddRef(void) const {} - void Release(void) const {} - virtual void VirtualSet() { value = kParentValue; } - void NonVirtualSet() { value = kParentValue; } - int value; -}; - -class Child : public Parent { - public: - virtual void VirtualSet() { value = kChildValue; } - void NonVirtualSet() { value = kChildValue; } -}; - -class NoRefParent { - public: - virtual void VirtualSet() { value = kParentValue; } - void NonVirtualSet() { value = kParentValue; } - int value; -}; - -class NoRefChild : public NoRefParent { - virtual void VirtualSet() { value = kChildValue; } - void NonVirtualSet() { value = kChildValue; } -}; - -template -T PolymorphicIdentity(T t) { - return t; -} - -int UnwrapParentRef(Parent& p) { - return p.value; -} - -template -void VoidPolymorphic1(T t) { -} - -#if defined(NCTEST_METHOD_ON_CONST_OBJECT) // [r"invalid conversion from 'const base::NoRef\*' to 'base::NoRef\*'"] - -// Method bound to const-object. -// -// Only const methods should be allowed to work with const objects. -void WontCompile() { - HasRef has_ref; - const HasRef* const_has_ref_ptr_ = &has_ref; - Callback method_to_const_cb = - Bind(&HasRef::VoidMethod0, const_has_ref_ptr_); - method_to_const_cb.Run(); -} - -#elif defined(NCTEST_METHOD_BIND_NEEDS_REFCOUNTED_OBJECT) // [r"has no member named 'AddRef'"] - -// Method bound to non-refcounted object. -// -// We require refcounts unless you have Unretained(). -void WontCompile() { - NoRef no_ref; - Callback no_ref_cb = - Bind(&NoRef::VoidMethod0, &no_ref); - no_ref_cb.Run(); -} - -#elif defined(NCTEST_CONST_METHOD_NEEDS_REFCOUNTED_OBJECT) // [r"has no member named 'AddRef'"] - -// Const Method bound to non-refcounted object. -// -// We require refcounts unless you have Unretained(). -void WontCompile() { - NoRef no_ref; - Callback no_ref_const_cb = - Bind(&NoRef::VoidConstMethod0, &no_ref); - no_ref_const_cb.Run(); -} - -#elif defined(NCTEST_CONST_POINTER) // [r"invalid conversion from 'const base::NoRef\*' to 'base::NoRef\*'"] - -// Const argument used with non-const pointer parameter of same type. -// -// This is just a const-correctness check. -void WontCompile() { - const NoRef* const_no_ref_ptr; - Callback pointer_same_cb = - Bind(&PolymorphicIdentity, const_no_ref_ptr); - pointer_same_cb.Run(); -} - -#elif defined(NCTEST_CONST_POINTER_SUBTYPE) // [r"'const base::NoRefParent\*' to 'base::NoRefParent\*'"] - -// Const argument used with non-const pointer parameter of super type. -// -// This is just a const-correctness check. -void WontCompile() { - const NoRefChild* const_child_ptr; - Callback pointer_super_cb = - Bind(&PolymorphicIdentity, const_child_ptr); - pointer_super_cb.Run(); -} - -#elif defined(DISABLED_NCTEST_DISALLOW_NON_CONST_REF_PARAM) // [r"badstring"] -// I think there's a type safety promotion issue here where we can pass a const -// ref to a non const-ref function, or vice versa accidentally. Or we make a -// copy accidentally. Check. - -// Functions with reference parameters, unsupported. -// -// First, non-const reference parameters are disallowed by the Google -// style guide. Second, since we are doing argument forwarding it becomes -// very tricky to avoid copies, maintain const correctness, and not -// accidentally have the function be modifying a temporary, or a copy. -void WontCompile() { - Parent p; - Callback ref_arg_cb = Bind(&UnwrapParentRef); - ref_arg_cb.Run(p); -} - -#elif defined(NCTEST_DISALLOW_BIND_TO_NON_CONST_REF_PARAM) // [r"size of array is negative"] - -// Binding functions with reference parameters, unsupported. -// -// See comment in NCTEST_DISALLOW_NON_CONST_REF_PARAM -void WontCompile() { - Parent p; - Callback ref_cb = Bind(&UnwrapParentRef, p); - ref_cb.Run(); -} - -#elif defined(NCTEST_NO_IMPLICIT_ARRAY_PTR_CONVERSION) // [r"size of array is negative"] - -// A method should not be bindable with an array of objects. -// -// This is likely not wanted behavior. We specifically check for it though -// because it is possible, depending on how you implement prebinding, to -// implicitly convert an array type to a pointer type. -void WontCompile() { - HasRef p[10]; - Callback method_bound_to_array_cb = - Bind(&HasRef::VoidMethod0, p); - method_bound_to_array_cb.Run(); -} - -#elif defined(NCTEST_NO_RAW_PTR_FOR_REFCOUNTED_TYPES) // [r"size of array is negative"] - -// Refcounted types should not be bound as a raw pointer. -void WontCompile() { - HasRef for_raw_ptr; - int a; - Callback ref_count_as_raw_ptr_a = - Bind(&VoidPolymorphic1, &a); - Callback ref_count_as_raw_ptr = - Bind(&VoidPolymorphic1, &for_raw_ptr); -} - -#elif defined(NCTEST_WEAKPTR_BIND_MUST_RETURN_VOID) // [r"size of array is negative"] - -// WeakPtrs cannot be bound to methods with return types. -void WontCompile() { - NoRef no_ref; - WeakPtrFactory weak_factory(&no_ref); - Callback weak_ptr_with_non_void_return_type = - Bind(&NoRef::IntMethod0, weak_factory.GetWeakPtr()); - weak_ptr_with_non_void_return_type.Run(); -} - -#elif defined(NCTEST_DISALLOW_ASSIGN_DIFFERENT_TYPES) // [r"conversion from 'base::Callback' to non-scalar type"] - -// Bind result cannot be assigned to Callbacks with a mismatching type. -void WontCompile() { - Closure callback_mismatches_bind_type = Bind(&VoidPolymorphic1); -} - -#endif - -} // namespace base diff --git a/base/bits.h b/base/bits.h deleted file mode 100644 index b2209e8ed7..0000000000 --- a/base/bits.h +++ /dev/null @@ -1,47 +0,0 @@ -// Copyright (c) 2009 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -// This file defines some bit utilities. - -#ifndef BASE_BITS_H_ -#define BASE_BITS_H_ - -#include "base/basictypes.h" -#include "base/logging.h" - -namespace base { -namespace bits { - -// Returns the integer i such as 2^i <= n < 2^(i+1) -inline int Log2Floor(uint32 n) { - if (n == 0) - return -1; - int log = 0; - uint32 value = n; - for (int i = 4; i >= 0; --i) { - int shift = (1 << i); - uint32 x = value >> shift; - if (x != 0) { - value = x; - log += shift; - } - } - DCHECK_EQ(value, 1u); - return log; -} - -// Returns the integer i such as 2^(i-1) < n <= 2^i -inline int Log2Ceiling(uint32 n) { - if (n == 0) { - return -1; - } else { - // Log2Floor returns -1 for 0, so the following works correctly for n=1. - return 1 + Log2Floor(n - 1); - } -} - -} // namespace bits -} // namespace base - -#endif // BASE_BITS_H_ diff --git a/base/bits_unittest.cc b/base/bits_unittest.cc deleted file mode 100644 index e913d6ae59..0000000000 --- a/base/bits_unittest.cc +++ /dev/null @@ -1,48 +0,0 @@ -// Copyright (c) 2009 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -// This file contains the unit tests for the bit utilities. - -#include "base/bits.h" -#include "testing/gtest/include/gtest/gtest.h" - -namespace base { -namespace bits { - -TEST(BitsTest, Log2Floor) { - EXPECT_EQ(-1, Log2Floor(0)); - EXPECT_EQ(0, Log2Floor(1)); - EXPECT_EQ(1, Log2Floor(2)); - EXPECT_EQ(1, Log2Floor(3)); - EXPECT_EQ(2, Log2Floor(4)); - for (int i = 3; i < 31; ++i) { - unsigned int value = 1U << i; - EXPECT_EQ(i, Log2Floor(value)); - EXPECT_EQ(i, Log2Floor(value + 1)); - EXPECT_EQ(i, Log2Floor(value + 2)); - EXPECT_EQ(i - 1, Log2Floor(value - 1)); - EXPECT_EQ(i - 1, Log2Floor(value - 2)); - } - EXPECT_EQ(31, Log2Floor(0xffffffffU)); -} - -TEST(BitsTest, Log2Ceiling) { - EXPECT_EQ(-1, Log2Ceiling(0)); - EXPECT_EQ(0, Log2Ceiling(1)); - EXPECT_EQ(1, Log2Ceiling(2)); - EXPECT_EQ(2, Log2Ceiling(3)); - EXPECT_EQ(2, Log2Ceiling(4)); - for (int i = 3; i < 31; ++i) { - unsigned int value = 1U << i; - EXPECT_EQ(i, Log2Ceiling(value)); - EXPECT_EQ(i + 1, Log2Ceiling(value + 1)); - EXPECT_EQ(i + 1, Log2Ceiling(value + 2)); - EXPECT_EQ(i, Log2Ceiling(value - 1)); - EXPECT_EQ(i, Log2Ceiling(value - 2)); - } - EXPECT_EQ(32, Log2Ceiling(0xffffffffU)); -} - -} // namespace bits -} // namespace base diff --git a/base/build_time.cc b/base/build_time.cc deleted file mode 100644 index 760269a3ff..0000000000 --- a/base/build_time.cc +++ /dev/null @@ -1,25 +0,0 @@ -// Copyright (c) 2011 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "base/build_time.h" - -#include "base/logging.h" -#include "base/time/time.h" - -namespace base { - -Time GetBuildTime() { - Time integral_build_time; - // The format of __DATE__ and __TIME__ is specified by the ANSI C Standard, - // section 6.8.8. - // - // __DATE__ is exactly "Mmm DD YYYY". - // __TIME__ is exactly "hh:mm:ss". - const char kDateTime[] = __DATE__ " " __TIME__ " PST"; - bool result = Time::FromString(kDateTime, &integral_build_time); - DCHECK(result); - return integral_build_time; -} - -} // namespace base diff --git a/base/build_time.h b/base/build_time.h deleted file mode 100644 index 73c01b052b..0000000000 --- a/base/build_time.h +++ /dev/null @@ -1,25 +0,0 @@ -// Copyright (c) 2011 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef BASE_BUILD_TIME_ -#define BASE_BUILD_TIME_ - -#include "base/base_export.h" -#include "base/time/time.h" - -namespace base { - -// GetBuildTime returns the time at which the current binary was built. -// -// This uses the __DATE__ and __TIME__ macros, which don't trigger a rebuild -// when they change. However, official builds will always be rebuilt from -// scratch. -// -// Also, since __TIME__ doesn't include a timezone, this value should only be -// considered accurate to a day. -Time BASE_EXPORT GetBuildTime(); - -} // namespace base - -#endif // BASE_BUILD_TIME_ diff --git a/base/build_time_unittest.cc b/base/build_time_unittest.cc deleted file mode 100644 index 399a53f953..0000000000 --- a/base/build_time_unittest.cc +++ /dev/null @@ -1,30 +0,0 @@ -// Copyright (c) 2011 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "base/build_time.h" - -#include "testing/gtest/include/gtest/gtest.h" - -TEST(BuildTime, DateLooksValid) { - char build_date[] = __DATE__; - - EXPECT_EQ(11u, strlen(build_date)); - EXPECT_EQ(' ', build_date[3]); - EXPECT_EQ(' ', build_date[6]); -} - -TEST(BuildTime, TimeLooksValid) { - char build_time[] = __TIME__; - - EXPECT_EQ(8u, strlen(build_time)); - EXPECT_EQ(':', build_time[2]); - EXPECT_EQ(':', build_time[5]); -} - -TEST(BuildTime, DoesntCrash) { - // Since __DATE__ isn't updated unless one does a clobber build, we can't - // really test the value returned by it, except to check that it doesn't - // crash. - base::GetBuildTime(); -} diff --git a/base/callback.h b/base/callback.h deleted file mode 100644 index ade3f8c1fc..0000000000 --- a/base/callback.h +++ /dev/null @@ -1,765 +0,0 @@ -// This file was GENERATED by command: -// pump.py callback.h.pump -// DO NOT EDIT BY HAND!!! - - -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef BASE_CALLBACK_H_ -#define BASE_CALLBACK_H_ - -#include "base/callback_forward.h" -#include "base/callback_internal.h" -#include "base/template_util.h" - -// NOTE: Header files that do not require the full definition of Callback or -// Closure should #include "base/callback_forward.h" instead of this file. - -// ----------------------------------------------------------------------------- -// Introduction -// ----------------------------------------------------------------------------- -// -// The templated Callback class is a generalized function object. Together -// with the Bind() function in bind.h, they provide a type-safe method for -// performing partial application of functions. -// -// Partial application (or "currying") is the process of binding a subset of -// a function's arguments to produce another function that takes fewer -// arguments. This can be used to pass around a unit of delayed execution, -// much like lexical closures are used in other languages. For example, it -// is used in Chromium code to schedule tasks on different MessageLoops. -// -// A callback with no unbound input parameters (base::Callback) -// is called a base::Closure. Note that this is NOT the same as what other -// languages refer to as a closure -- it does not retain a reference to its -// enclosing environment. -// -// MEMORY MANAGEMENT AND PASSING -// -// The Callback objects themselves should be passed by const-reference, and -// stored by copy. They internally store their state via a refcounted class -// and thus do not need to be deleted. -// -// The reason to pass via a const-reference is to avoid unnecessary -// AddRef/Release pairs to the internal state. -// -// -// ----------------------------------------------------------------------------- -// Quick reference for basic stuff -// ----------------------------------------------------------------------------- -// -// BINDING A BARE FUNCTION -// -// int Return5() { return 5; } -// base::Callback func_cb = base::Bind(&Return5); -// LOG(INFO) << func_cb.Run(); // Prints 5. -// -// BINDING A CLASS METHOD -// -// The first argument to bind is the member function to call, the second is -// the object on which to call it. -// -// class Ref : public base::RefCountedThreadSafe { -// public: -// int Foo() { return 3; } -// void PrintBye() { LOG(INFO) << "bye."; } -// }; -// scoped_refptr ref = new Ref(); -// base::Callback ref_cb = base::Bind(&Ref::Foo, ref); -// LOG(INFO) << ref_cb.Run(); // Prints out 3. -// -// By default the object must support RefCounted or you will get a compiler -// error. If you're passing between threads, be sure it's -// RefCountedThreadSafe! See "Advanced binding of member functions" below if -// you don't want to use reference counting. -// -// RUNNING A CALLBACK -// -// Callbacks can be run with their "Run" method, which has the same -// signature as the template argument to the callback. -// -// void DoSomething(const base::Callback& callback) { -// callback.Run(5, "hello"); -// } -// -// Callbacks can be run more than once (they don't get deleted or marked when -// run). However, this precludes using base::Passed (see below). -// -// void DoSomething(const base::Callback& callback) { -// double myresult = callback.Run(3.14159); -// myresult += callback.Run(2.71828); -// } -// -// PASSING UNBOUND INPUT PARAMETERS -// -// Unbound parameters are specified at the time a callback is Run(). They are -// specified in the Callback template type: -// -// void MyFunc(int i, const std::string& str) {} -// base::Callback cb = base::Bind(&MyFunc); -// cb.Run(23, "hello, world"); -// -// PASSING BOUND INPUT PARAMETERS -// -// Bound parameters are specified when you create thee callback as arguments -// to Bind(). They will be passed to the function and the Run()ner of the -// callback doesn't see those values or even know that the function it's -// calling. -// -// void MyFunc(int i, const std::string& str) {} -// base::Callback cb = base::Bind(&MyFunc, 23, "hello world"); -// cb.Run(); -// -// A callback with no unbound input parameters (base::Callback) -// is called a base::Closure. So we could have also written: -// -// base::Closure cb = base::Bind(&MyFunc, 23, "hello world"); -// -// When calling member functions, bound parameters just go after the object -// pointer. -// -// base::Closure cb = base::Bind(&MyClass::MyFunc, this, 23, "hello world"); -// -// PARTIAL BINDING OF PARAMETERS -// -// You can specify some parameters when you create the callback, and specify -// the rest when you execute the callback. -// -// void MyFunc(int i, const std::string& str) {} -// base::Callback cb = base::Bind(&MyFunc, 23); -// cb.Run("hello world"); -// -// When calling a function bound parameters are first, followed by unbound -// parameters. -// -// -// ----------------------------------------------------------------------------- -// Quick reference for advanced binding -// ----------------------------------------------------------------------------- -// -// BINDING A CLASS METHOD WITH WEAK POINTERS -// -// base::Bind(&MyClass::Foo, GetWeakPtr()); -// -// The callback will not be issued if the object is destroyed at the time -// it's issued. DANGER: weak pointers are not threadsafe, so don't use this -// when passing between threads! -// -// BINDING A CLASS METHOD WITH MANUAL LIFETIME MANAGEMENT -// -// base::Bind(&MyClass::Foo, base::Unretained(this)); -// -// This disables all lifetime management on the object. You're responsible -// for making sure the object is alive at the time of the call. You break it, -// you own it! -// -// BINDING A CLASS METHOD AND HAVING THE CALLBACK OWN THE CLASS -// -// MyClass* myclass = new MyClass; -// base::Bind(&MyClass::Foo, base::Owned(myclass)); -// -// The object will be deleted when the callback is destroyed, even if it's -// not run (like if you post a task during shutdown). Potentially useful for -// "fire and forget" cases. -// -// IGNORING RETURN VALUES -// -// Sometimes you want to call a function that returns a value in a callback -// that doesn't expect a return value. -// -// int DoSomething(int arg) { cout << arg << endl; } -// base::Callback) cb = -// base::Bind(base::IgnoreResult(&DoSomething)); -// -// -// ----------------------------------------------------------------------------- -// Quick reference for binding parameters to Bind() -// ----------------------------------------------------------------------------- -// -// Bound parameters are specified as arguments to Bind() and are passed to the -// function. A callback with no parameters or no unbound parameters is called a -// Closure (base::Callback and base::Closure are the same thing). -// -// PASSING PARAMETERS OWNED BY THE CALLBACK -// -// void Foo(int* arg) { cout << *arg << endl; } -// int* pn = new int(1); -// base::Closure foo_callback = base::Bind(&foo, base::Owned(pn)); -// -// The parameter will be deleted when the callback is destroyed, even if it's -// not run (like if you post a task during shutdown). -// -// PASSING PARAMETERS AS A scoped_ptr -// -// void TakesOwnership(scoped_ptr arg) {} -// scoped_ptr f(new Foo); -// // f becomes null during the following call. -// base::Closure cb = base::Bind(&TakesOwnership, base::Passed(&f)); -// -// Ownership of the parameter will be with the callback until the it is run, -// when ownership is passed to the callback function. This means the callback -// can only be run once. If the callback is never run, it will delete the -// object when it's destroyed. -// -// PASSING PARAMETERS AS A scoped_refptr -// -// void TakesOneRef(scoped_refptr arg) {} -// scoped_refptr f(new Foo) -// base::Closure cb = base::Bind(&TakesOneRef, f); -// -// This should "just work." The closure will take a reference as long as it -// is alive, and another reference will be taken for the called function. -// -// PASSING PARAMETERS BY REFERENCE -// -// void foo(int arg) { cout << arg << endl } -// int n = 1; -// base::Closure has_ref = base::Bind(&foo, base::ConstRef(n)); -// n = 2; -// has_ref.Run(); // Prints "2" -// -// Normally parameters are copied in the closure. DANGER: ConstRef stores a -// const reference instead, referencing the original parameter. This means -// that you must ensure the object outlives the callback! -// -// -// ----------------------------------------------------------------------------- -// Implementation notes -// ----------------------------------------------------------------------------- -// -// WHERE IS THIS DESIGN FROM: -// -// The design Callback and Bind is heavily influenced by C++'s -// tr1::function/tr1::bind, and by the "Google Callback" system used inside -// Google. -// -// -// HOW THE IMPLEMENTATION WORKS: -// -// There are three main components to the system: -// 1) The Callback classes. -// 2) The Bind() functions. -// 3) The arguments wrappers (e.g., Unretained() and ConstRef()). -// -// The Callback classes represent a generic function pointer. Internally, -// it stores a refcounted piece of state that represents the target function -// and all its bound parameters. Each Callback specialization has a templated -// constructor that takes an BindState<>*. In the context of the constructor, -// the static type of this BindState<> pointer uniquely identifies the -// function it is representing, all its bound parameters, and a Run() method -// that is capable of invoking the target. -// -// Callback's constructor takes the BindState<>* that has the full static type -// and erases the target function type as well as the types of the bound -// parameters. It does this by storing a pointer to the specific Run() -// function, and upcasting the state of BindState<>* to a -// BindStateBase*. This is safe as long as this BindStateBase pointer -// is only used with the stored Run() pointer. -// -// To BindState<> objects are created inside the Bind() functions. -// These functions, along with a set of internal templates, are responsible for -// -// - Unwrapping the function signature into return type, and parameters -// - Determining the number of parameters that are bound -// - Creating the BindState storing the bound parameters -// - Performing compile-time asserts to avoid error-prone behavior -// - Returning an Callback<> with an arity matching the number of unbound -// parameters and that knows the correct refcounting semantics for the -// target object if we are binding a method. -// -// The Bind functions do the above using type-inference, and template -// specializations. -// -// By default Bind() will store copies of all bound parameters, and attempt -// to refcount a target object if the function being bound is a class method. -// These copies are created even if the function takes parameters as const -// references. (Binding to non-const references is forbidden, see bind.h.) -// -// To change this behavior, we introduce a set of argument wrappers -// (e.g., Unretained(), and ConstRef()). These are simple container templates -// that are passed by value, and wrap a pointer to argument. See the -// file-level comment in base/bind_helpers.h for more info. -// -// These types are passed to the Unwrap() functions, and the MaybeRefcount() -// functions respectively to modify the behavior of Bind(). The Unwrap() -// and MaybeRefcount() functions change behavior by doing partial -// specialization based on whether or not a parameter is a wrapper type. -// -// ConstRef() is similar to tr1::cref. Unretained() is specific to Chromium. -// -// -// WHY NOT TR1 FUNCTION/BIND? -// -// Direct use of tr1::function and tr1::bind was considered, but ultimately -// rejected because of the number of copy constructors invocations involved -// in the binding of arguments during construction, and the forwarding of -// arguments during invocation. These copies will no longer be an issue in -// C++0x because C++0x will support rvalue reference allowing for the compiler -// to avoid these copies. However, waiting for C++0x is not an option. -// -// Measured with valgrind on gcc version 4.4.3 (Ubuntu 4.4.3-4ubuntu5), the -// tr1::bind call itself will invoke a non-trivial copy constructor three times -// for each bound parameter. Also, each when passing a tr1::function, each -// bound argument will be copied again. -// -// In addition to the copies taken at binding and invocation, copying a -// tr1::function causes a copy to be made of all the bound parameters and -// state. -// -// Furthermore, in Chromium, it is desirable for the Callback to take a -// reference on a target object when representing a class method call. This -// is not supported by tr1. -// -// Lastly, tr1::function and tr1::bind has a more general and flexible API. -// This includes things like argument reordering by use of -// tr1::bind::placeholder, support for non-const reference parameters, and some -// limited amount of subtyping of the tr1::function object (e.g., -// tr1::function is convertible to tr1::function). -// -// These are not features that are required in Chromium. Some of them, such as -// allowing for reference parameters, and subtyping of functions, may actually -// become a source of errors. Removing support for these features actually -// allows for a simpler implementation, and a terser Currying API. -// -// -// WHY NOT GOOGLE CALLBACKS? -// -// The Google callback system also does not support refcounting. Furthermore, -// its implementation has a number of strange edge cases with respect to type -// conversion of its arguments. In particular, the argument's constness must -// at times match exactly the function signature, or the type-inference might -// break. Given the above, writing a custom solution was easier. -// -// -// MISSING FUNCTIONALITY -// - Invoking the return of Bind. Bind(&foo).Run() does not work; -// - Binding arrays to functions that take a non-const pointer. -// Example: -// void Foo(const char* ptr); -// void Bar(char* ptr); -// Bind(&Foo, "test"); -// Bind(&Bar, "test"); // This fails because ptr is not const. - -namespace base { - -// First, we forward declare the Callback class template. This informs the -// compiler that the template only has 1 type parameter which is the function -// signature that the Callback is representing. -// -// After this, create template specializations for 0-7 parameters. Note that -// even though the template typelist grows, the specialization still -// only has one type: the function signature. -// -// If you are thinking of forward declaring Callback in your own header file, -// please include "base/callback_forward.h" instead. -template -class Callback; - -namespace internal { -template -struct BindState; -} // namespace internal - -template -class Callback : public internal::CallbackBase { - public: - typedef R(RunType)(); - - Callback() : CallbackBase(NULL) { } - - // Note that this constructor CANNOT be explicit, and that Bind() CANNOT - // return the exact Callback<> type. See base/bind.h for details. - template - Callback(internal::BindState* bind_state) - : CallbackBase(bind_state) { - - // Force the assignment to a local variable of PolymorphicInvoke - // so the compiler will typecheck that the passed in Run() method has - // the correct type. - PolymorphicInvoke invoke_func = - &internal::BindState - ::InvokerType::Run; - polymorphic_invoke_ = reinterpret_cast(invoke_func); - } - - bool Equals(const Callback& other) const { - return CallbackBase::Equals(other); - } - - R Run() const { - PolymorphicInvoke f = - reinterpret_cast(polymorphic_invoke_); - - return f(bind_state_.get()); - } - - private: - typedef R(*PolymorphicInvoke)( - internal::BindStateBase*); - -}; - -template -class Callback : public internal::CallbackBase { - public: - typedef R(RunType)(A1); - - Callback() : CallbackBase(NULL) { } - - // Note that this constructor CANNOT be explicit, and that Bind() CANNOT - // return the exact Callback<> type. See base/bind.h for details. - template - Callback(internal::BindState* bind_state) - : CallbackBase(bind_state) { - - // Force the assignment to a local variable of PolymorphicInvoke - // so the compiler will typecheck that the passed in Run() method has - // the correct type. - PolymorphicInvoke invoke_func = - &internal::BindState - ::InvokerType::Run; - polymorphic_invoke_ = reinterpret_cast(invoke_func); - } - - bool Equals(const Callback& other) const { - return CallbackBase::Equals(other); - } - - R Run(typename internal::CallbackParamTraits::ForwardType a1) const { - PolymorphicInvoke f = - reinterpret_cast(polymorphic_invoke_); - - return f(bind_state_.get(), internal::CallbackForward(a1)); - } - - private: - typedef R(*PolymorphicInvoke)( - internal::BindStateBase*, - typename internal::CallbackParamTraits::ForwardType); - -}; - -template -class Callback : public internal::CallbackBase { - public: - typedef R(RunType)(A1, A2); - - Callback() : CallbackBase(NULL) { } - - // Note that this constructor CANNOT be explicit, and that Bind() CANNOT - // return the exact Callback<> type. See base/bind.h for details. - template - Callback(internal::BindState* bind_state) - : CallbackBase(bind_state) { - - // Force the assignment to a local variable of PolymorphicInvoke - // so the compiler will typecheck that the passed in Run() method has - // the correct type. - PolymorphicInvoke invoke_func = - &internal::BindState - ::InvokerType::Run; - polymorphic_invoke_ = reinterpret_cast(invoke_func); - } - - bool Equals(const Callback& other) const { - return CallbackBase::Equals(other); - } - - R Run(typename internal::CallbackParamTraits::ForwardType a1, - typename internal::CallbackParamTraits::ForwardType a2) const { - PolymorphicInvoke f = - reinterpret_cast(polymorphic_invoke_); - - return f(bind_state_.get(), internal::CallbackForward(a1), - internal::CallbackForward(a2)); - } - - private: - typedef R(*PolymorphicInvoke)( - internal::BindStateBase*, - typename internal::CallbackParamTraits::ForwardType, - typename internal::CallbackParamTraits::ForwardType); - -}; - -template -class Callback : public internal::CallbackBase { - public: - typedef R(RunType)(A1, A2, A3); - - Callback() : CallbackBase(NULL) { } - - // Note that this constructor CANNOT be explicit, and that Bind() CANNOT - // return the exact Callback<> type. See base/bind.h for details. - template - Callback(internal::BindState* bind_state) - : CallbackBase(bind_state) { - - // Force the assignment to a local variable of PolymorphicInvoke - // so the compiler will typecheck that the passed in Run() method has - // the correct type. - PolymorphicInvoke invoke_func = - &internal::BindState - ::InvokerType::Run; - polymorphic_invoke_ = reinterpret_cast(invoke_func); - } - - bool Equals(const Callback& other) const { - return CallbackBase::Equals(other); - } - - R Run(typename internal::CallbackParamTraits::ForwardType a1, - typename internal::CallbackParamTraits::ForwardType a2, - typename internal::CallbackParamTraits::ForwardType a3) const { - PolymorphicInvoke f = - reinterpret_cast(polymorphic_invoke_); - - return f(bind_state_.get(), internal::CallbackForward(a1), - internal::CallbackForward(a2), - internal::CallbackForward(a3)); - } - - private: - typedef R(*PolymorphicInvoke)( - internal::BindStateBase*, - typename internal::CallbackParamTraits::ForwardType, - typename internal::CallbackParamTraits::ForwardType, - typename internal::CallbackParamTraits::ForwardType); - -}; - -template -class Callback : public internal::CallbackBase { - public: - typedef R(RunType)(A1, A2, A3, A4); - - Callback() : CallbackBase(NULL) { } - - // Note that this constructor CANNOT be explicit, and that Bind() CANNOT - // return the exact Callback<> type. See base/bind.h for details. - template - Callback(internal::BindState* bind_state) - : CallbackBase(bind_state) { - - // Force the assignment to a local variable of PolymorphicInvoke - // so the compiler will typecheck that the passed in Run() method has - // the correct type. - PolymorphicInvoke invoke_func = - &internal::BindState - ::InvokerType::Run; - polymorphic_invoke_ = reinterpret_cast(invoke_func); - } - - bool Equals(const Callback& other) const { - return CallbackBase::Equals(other); - } - - R Run(typename internal::CallbackParamTraits::ForwardType a1, - typename internal::CallbackParamTraits::ForwardType a2, - typename internal::CallbackParamTraits::ForwardType a3, - typename internal::CallbackParamTraits::ForwardType a4) const { - PolymorphicInvoke f = - reinterpret_cast(polymorphic_invoke_); - - return f(bind_state_.get(), internal::CallbackForward(a1), - internal::CallbackForward(a2), - internal::CallbackForward(a3), - internal::CallbackForward(a4)); - } - - private: - typedef R(*PolymorphicInvoke)( - internal::BindStateBase*, - typename internal::CallbackParamTraits::ForwardType, - typename internal::CallbackParamTraits::ForwardType, - typename internal::CallbackParamTraits::ForwardType, - typename internal::CallbackParamTraits::ForwardType); - -}; - -template -class Callback : public internal::CallbackBase { - public: - typedef R(RunType)(A1, A2, A3, A4, A5); - - Callback() : CallbackBase(NULL) { } - - // Note that this constructor CANNOT be explicit, and that Bind() CANNOT - // return the exact Callback<> type. See base/bind.h for details. - template - Callback(internal::BindState* bind_state) - : CallbackBase(bind_state) { - - // Force the assignment to a local variable of PolymorphicInvoke - // so the compiler will typecheck that the passed in Run() method has - // the correct type. - PolymorphicInvoke invoke_func = - &internal::BindState - ::InvokerType::Run; - polymorphic_invoke_ = reinterpret_cast(invoke_func); - } - - bool Equals(const Callback& other) const { - return CallbackBase::Equals(other); - } - - R Run(typename internal::CallbackParamTraits::ForwardType a1, - typename internal::CallbackParamTraits::ForwardType a2, - typename internal::CallbackParamTraits::ForwardType a3, - typename internal::CallbackParamTraits::ForwardType a4, - typename internal::CallbackParamTraits::ForwardType a5) const { - PolymorphicInvoke f = - reinterpret_cast(polymorphic_invoke_); - - return f(bind_state_.get(), internal::CallbackForward(a1), - internal::CallbackForward(a2), - internal::CallbackForward(a3), - internal::CallbackForward(a4), - internal::CallbackForward(a5)); - } - - private: - typedef R(*PolymorphicInvoke)( - internal::BindStateBase*, - typename internal::CallbackParamTraits::ForwardType, - typename internal::CallbackParamTraits::ForwardType, - typename internal::CallbackParamTraits::ForwardType, - typename internal::CallbackParamTraits::ForwardType, - typename internal::CallbackParamTraits::ForwardType); - -}; - -template -class Callback : public internal::CallbackBase { - public: - typedef R(RunType)(A1, A2, A3, A4, A5, A6); - - Callback() : CallbackBase(NULL) { } - - // Note that this constructor CANNOT be explicit, and that Bind() CANNOT - // return the exact Callback<> type. See base/bind.h for details. - template - Callback(internal::BindState* bind_state) - : CallbackBase(bind_state) { - - // Force the assignment to a local variable of PolymorphicInvoke - // so the compiler will typecheck that the passed in Run() method has - // the correct type. - PolymorphicInvoke invoke_func = - &internal::BindState - ::InvokerType::Run; - polymorphic_invoke_ = reinterpret_cast(invoke_func); - } - - bool Equals(const Callback& other) const { - return CallbackBase::Equals(other); - } - - R Run(typename internal::CallbackParamTraits::ForwardType a1, - typename internal::CallbackParamTraits::ForwardType a2, - typename internal::CallbackParamTraits::ForwardType a3, - typename internal::CallbackParamTraits::ForwardType a4, - typename internal::CallbackParamTraits::ForwardType a5, - typename internal::CallbackParamTraits::ForwardType a6) const { - PolymorphicInvoke f = - reinterpret_cast(polymorphic_invoke_); - - return f(bind_state_.get(), internal::CallbackForward(a1), - internal::CallbackForward(a2), - internal::CallbackForward(a3), - internal::CallbackForward(a4), - internal::CallbackForward(a5), - internal::CallbackForward(a6)); - } - - private: - typedef R(*PolymorphicInvoke)( - internal::BindStateBase*, - typename internal::CallbackParamTraits::ForwardType, - typename internal::CallbackParamTraits::ForwardType, - typename internal::CallbackParamTraits::ForwardType, - typename internal::CallbackParamTraits::ForwardType, - typename internal::CallbackParamTraits::ForwardType, - typename internal::CallbackParamTraits::ForwardType); - -}; - -template -class Callback : public internal::CallbackBase { - public: - typedef R(RunType)(A1, A2, A3, A4, A5, A6, A7); - - Callback() : CallbackBase(NULL) { } - - // Note that this constructor CANNOT be explicit, and that Bind() CANNOT - // return the exact Callback<> type. See base/bind.h for details. - template - Callback(internal::BindState* bind_state) - : CallbackBase(bind_state) { - - // Force the assignment to a local variable of PolymorphicInvoke - // so the compiler will typecheck that the passed in Run() method has - // the correct type. - PolymorphicInvoke invoke_func = - &internal::BindState - ::InvokerType::Run; - polymorphic_invoke_ = reinterpret_cast(invoke_func); - } - - bool Equals(const Callback& other) const { - return CallbackBase::Equals(other); - } - - R Run(typename internal::CallbackParamTraits::ForwardType a1, - typename internal::CallbackParamTraits::ForwardType a2, - typename internal::CallbackParamTraits::ForwardType a3, - typename internal::CallbackParamTraits::ForwardType a4, - typename internal::CallbackParamTraits::ForwardType a5, - typename internal::CallbackParamTraits::ForwardType a6, - typename internal::CallbackParamTraits::ForwardType a7) const { - PolymorphicInvoke f = - reinterpret_cast(polymorphic_invoke_); - - return f(bind_state_.get(), internal::CallbackForward(a1), - internal::CallbackForward(a2), - internal::CallbackForward(a3), - internal::CallbackForward(a4), - internal::CallbackForward(a5), - internal::CallbackForward(a6), - internal::CallbackForward(a7)); - } - - private: - typedef R(*PolymorphicInvoke)( - internal::BindStateBase*, - typename internal::CallbackParamTraits::ForwardType, - typename internal::CallbackParamTraits::ForwardType, - typename internal::CallbackParamTraits::ForwardType, - typename internal::CallbackParamTraits::ForwardType, - typename internal::CallbackParamTraits::ForwardType, - typename internal::CallbackParamTraits::ForwardType, - typename internal::CallbackParamTraits::ForwardType); - -}; - - -// Syntactic sugar to make Callbacks easier to declare since it -// will be used in a lot of APIs with delayed execution. -typedef Callback Closure; - -} // namespace base - -#endif // BASE_CALLBACK_H diff --git a/base/callback.h.pump b/base/callback.h.pump deleted file mode 100644 index 41d2ee9aec..0000000000 --- a/base/callback.h.pump +++ /dev/null @@ -1,436 +0,0 @@ -$$ This is a pump file for generating file templates. Pump is a python -$$ script that is part of the Google Test suite of utilities. Description -$$ can be found here: -$$ -$$ http://code.google.com/p/googletest/wiki/PumpManual -$$ - -$$ See comment for MAX_ARITY in base/bind.h.pump. -$var MAX_ARITY = 7 - -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef BASE_CALLBACK_H_ -#define BASE_CALLBACK_H_ - -#include "base/callback_forward.h" -#include "base/callback_internal.h" -#include "base/template_util.h" - -// NOTE: Header files that do not require the full definition of Callback or -// Closure should #include "base/callback_forward.h" instead of this file. - -// ----------------------------------------------------------------------------- -// Introduction -// ----------------------------------------------------------------------------- -// -// The templated Callback class is a generalized function object. Together -// with the Bind() function in bind.h, they provide a type-safe method for -// performing partial application of functions. -// -// Partial application (or "currying") is the process of binding a subset of -// a function's arguments to produce another function that takes fewer -// arguments. This can be used to pass around a unit of delayed execution, -// much like lexical closures are used in other languages. For example, it -// is used in Chromium code to schedule tasks on different MessageLoops. -// -// A callback with no unbound input parameters (base::Callback) -// is called a base::Closure. Note that this is NOT the same as what other -// languages refer to as a closure -- it does not retain a reference to its -// enclosing environment. -// -// MEMORY MANAGEMENT AND PASSING -// -// The Callback objects themselves should be passed by const-reference, and -// stored by copy. They internally store their state via a refcounted class -// and thus do not need to be deleted. -// -// The reason to pass via a const-reference is to avoid unnecessary -// AddRef/Release pairs to the internal state. -// -// -// ----------------------------------------------------------------------------- -// Quick reference for basic stuff -// ----------------------------------------------------------------------------- -// -// BINDING A BARE FUNCTION -// -// int Return5() { return 5; } -// base::Callback func_cb = base::Bind(&Return5); -// LOG(INFO) << func_cb.Run(); // Prints 5. -// -// BINDING A CLASS METHOD -// -// The first argument to bind is the member function to call, the second is -// the object on which to call it. -// -// class Ref : public base::RefCountedThreadSafe { -// public: -// int Foo() { return 3; } -// void PrintBye() { LOG(INFO) << "bye."; } -// }; -// scoped_refptr ref = new Ref(); -// base::Callback ref_cb = base::Bind(&Ref::Foo, ref); -// LOG(INFO) << ref_cb.Run(); // Prints out 3. -// -// By default the object must support RefCounted or you will get a compiler -// error. If you're passing between threads, be sure it's -// RefCountedThreadSafe! See "Advanced binding of member functions" below if -// you don't want to use reference counting. -// -// RUNNING A CALLBACK -// -// Callbacks can be run with their "Run" method, which has the same -// signature as the template argument to the callback. -// -// void DoSomething(const base::Callback& callback) { -// callback.Run(5, "hello"); -// } -// -// Callbacks can be run more than once (they don't get deleted or marked when -// run). However, this precludes using base::Passed (see below). -// -// void DoSomething(const base::Callback& callback) { -// double myresult = callback.Run(3.14159); -// myresult += callback.Run(2.71828); -// } -// -// PASSING UNBOUND INPUT PARAMETERS -// -// Unbound parameters are specified at the time a callback is Run(). They are -// specified in the Callback template type: -// -// void MyFunc(int i, const std::string& str) {} -// base::Callback cb = base::Bind(&MyFunc); -// cb.Run(23, "hello, world"); -// -// PASSING BOUND INPUT PARAMETERS -// -// Bound parameters are specified when you create thee callback as arguments -// to Bind(). They will be passed to the function and the Run()ner of the -// callback doesn't see those values or even know that the function it's -// calling. -// -// void MyFunc(int i, const std::string& str) {} -// base::Callback cb = base::Bind(&MyFunc, 23, "hello world"); -// cb.Run(); -// -// A callback with no unbound input parameters (base::Callback) -// is called a base::Closure. So we could have also written: -// -// base::Closure cb = base::Bind(&MyFunc, 23, "hello world"); -// -// When calling member functions, bound parameters just go after the object -// pointer. -// -// base::Closure cb = base::Bind(&MyClass::MyFunc, this, 23, "hello world"); -// -// PARTIAL BINDING OF PARAMETERS -// -// You can specify some parameters when you create the callback, and specify -// the rest when you execute the callback. -// -// void MyFunc(int i, const std::string& str) {} -// base::Callback cb = base::Bind(&MyFunc, 23); -// cb.Run("hello world"); -// -// When calling a function bound parameters are first, followed by unbound -// parameters. -// -// -// ----------------------------------------------------------------------------- -// Quick reference for advanced binding -// ----------------------------------------------------------------------------- -// -// BINDING A CLASS METHOD WITH WEAK POINTERS -// -// base::Bind(&MyClass::Foo, GetWeakPtr()); -// -// The callback will not be issued if the object is destroyed at the time -// it's issued. DANGER: weak pointers are not threadsafe, so don't use this -// when passing between threads! -// -// BINDING A CLASS METHOD WITH MANUAL LIFETIME MANAGEMENT -// -// base::Bind(&MyClass::Foo, base::Unretained(this)); -// -// This disables all lifetime management on the object. You're responsible -// for making sure the object is alive at the time of the call. You break it, -// you own it! -// -// BINDING A CLASS METHOD AND HAVING THE CALLBACK OWN THE CLASS -// -// MyClass* myclass = new MyClass; -// base::Bind(&MyClass::Foo, base::Owned(myclass)); -// -// The object will be deleted when the callback is destroyed, even if it's -// not run (like if you post a task during shutdown). Potentially useful for -// "fire and forget" cases. -// -// IGNORING RETURN VALUES -// -// Sometimes you want to call a function that returns a value in a callback -// that doesn't expect a return value. -// -// int DoSomething(int arg) { cout << arg << endl; } -// base::Callback) cb = -// base::Bind(base::IgnoreResult(&DoSomething)); -// -// -// ----------------------------------------------------------------------------- -// Quick reference for binding parameters to Bind() -// ----------------------------------------------------------------------------- -// -// Bound parameters are specified as arguments to Bind() and are passed to the -// function. A callback with no parameters or no unbound parameters is called a -// Closure (base::Callback and base::Closure are the same thing). -// -// PASSING PARAMETERS OWNED BY THE CALLBACK -// -// void Foo(int* arg) { cout << *arg << endl; } -// int* pn = new int(1); -// base::Closure foo_callback = base::Bind(&foo, base::Owned(pn)); -// -// The parameter will be deleted when the callback is destroyed, even if it's -// not run (like if you post a task during shutdown). -// -// PASSING PARAMETERS AS A scoped_ptr -// -// void TakesOwnership(scoped_ptr arg) {} -// scoped_ptr f(new Foo); -// // f becomes null during the following call. -// base::Closure cb = base::Bind(&TakesOwnership, base::Passed(&f)); -// -// Ownership of the parameter will be with the callback until the it is run, -// when ownership is passed to the callback function. This means the callback -// can only be run once. If the callback is never run, it will delete the -// object when it's destroyed. -// -// PASSING PARAMETERS AS A scoped_refptr -// -// void TakesOneRef(scoped_refptr arg) {} -// scoped_refptr f(new Foo) -// base::Closure cb = base::Bind(&TakesOneRef, f); -// -// This should "just work." The closure will take a reference as long as it -// is alive, and another reference will be taken for the called function. -// -// PASSING PARAMETERS BY REFERENCE -// -// void foo(int arg) { cout << arg << endl } -// int n = 1; -// base::Closure has_ref = base::Bind(&foo, base::ConstRef(n)); -// n = 2; -// has_ref.Run(); // Prints "2" -// -// Normally parameters are copied in the closure. DANGER: ConstRef stores a -// const reference instead, referencing the original parameter. This means -// that you must ensure the object outlives the callback! -// -// -// ----------------------------------------------------------------------------- -// Implementation notes -// ----------------------------------------------------------------------------- -// -// WHERE IS THIS DESIGN FROM: -// -// The design Callback and Bind is heavily influenced by C++'s -// tr1::function/tr1::bind, and by the "Google Callback" system used inside -// Google. -// -// -// HOW THE IMPLEMENTATION WORKS: -// -// There are three main components to the system: -// 1) The Callback classes. -// 2) The Bind() functions. -// 3) The arguments wrappers (e.g., Unretained() and ConstRef()). -// -// The Callback classes represent a generic function pointer. Internally, -// it stores a refcounted piece of state that represents the target function -// and all its bound parameters. Each Callback specialization has a templated -// constructor that takes an BindState<>*. In the context of the constructor, -// the static type of this BindState<> pointer uniquely identifies the -// function it is representing, all its bound parameters, and a Run() method -// that is capable of invoking the target. -// -// Callback's constructor takes the BindState<>* that has the full static type -// and erases the target function type as well as the types of the bound -// parameters. It does this by storing a pointer to the specific Run() -// function, and upcasting the state of BindState<>* to a -// BindStateBase*. This is safe as long as this BindStateBase pointer -// is only used with the stored Run() pointer. -// -// To BindState<> objects are created inside the Bind() functions. -// These functions, along with a set of internal templates, are responsible for -// -// - Unwrapping the function signature into return type, and parameters -// - Determining the number of parameters that are bound -// - Creating the BindState storing the bound parameters -// - Performing compile-time asserts to avoid error-prone behavior -// - Returning an Callback<> with an arity matching the number of unbound -// parameters and that knows the correct refcounting semantics for the -// target object if we are binding a method. -// -// The Bind functions do the above using type-inference, and template -// specializations. -// -// By default Bind() will store copies of all bound parameters, and attempt -// to refcount a target object if the function being bound is a class method. -// These copies are created even if the function takes parameters as const -// references. (Binding to non-const references is forbidden, see bind.h.) -// -// To change this behavior, we introduce a set of argument wrappers -// (e.g., Unretained(), and ConstRef()). These are simple container templates -// that are passed by value, and wrap a pointer to argument. See the -// file-level comment in base/bind_helpers.h for more info. -// -// These types are passed to the Unwrap() functions, and the MaybeRefcount() -// functions respectively to modify the behavior of Bind(). The Unwrap() -// and MaybeRefcount() functions change behavior by doing partial -// specialization based on whether or not a parameter is a wrapper type. -// -// ConstRef() is similar to tr1::cref. Unretained() is specific to Chromium. -// -// -// WHY NOT TR1 FUNCTION/BIND? -// -// Direct use of tr1::function and tr1::bind was considered, but ultimately -// rejected because of the number of copy constructors invocations involved -// in the binding of arguments during construction, and the forwarding of -// arguments during invocation. These copies will no longer be an issue in -// C++0x because C++0x will support rvalue reference allowing for the compiler -// to avoid these copies. However, waiting for C++0x is not an option. -// -// Measured with valgrind on gcc version 4.4.3 (Ubuntu 4.4.3-4ubuntu5), the -// tr1::bind call itself will invoke a non-trivial copy constructor three times -// for each bound parameter. Also, each when passing a tr1::function, each -// bound argument will be copied again. -// -// In addition to the copies taken at binding and invocation, copying a -// tr1::function causes a copy to be made of all the bound parameters and -// state. -// -// Furthermore, in Chromium, it is desirable for the Callback to take a -// reference on a target object when representing a class method call. This -// is not supported by tr1. -// -// Lastly, tr1::function and tr1::bind has a more general and flexible API. -// This includes things like argument reordering by use of -// tr1::bind::placeholder, support for non-const reference parameters, and some -// limited amount of subtyping of the tr1::function object (e.g., -// tr1::function is convertible to tr1::function). -// -// These are not features that are required in Chromium. Some of them, such as -// allowing for reference parameters, and subtyping of functions, may actually -// become a source of errors. Removing support for these features actually -// allows for a simpler implementation, and a terser Currying API. -// -// -// WHY NOT GOOGLE CALLBACKS? -// -// The Google callback system also does not support refcounting. Furthermore, -// its implementation has a number of strange edge cases with respect to type -// conversion of its arguments. In particular, the argument's constness must -// at times match exactly the function signature, or the type-inference might -// break. Given the above, writing a custom solution was easier. -// -// -// MISSING FUNCTIONALITY -// - Invoking the return of Bind. Bind(&foo).Run() does not work; -// - Binding arrays to functions that take a non-const pointer. -// Example: -// void Foo(const char* ptr); -// void Bar(char* ptr); -// Bind(&Foo, "test"); -// Bind(&Bar, "test"); // This fails because ptr is not const. - -namespace base { - -// First, we forward declare the Callback class template. This informs the -// compiler that the template only has 1 type parameter which is the function -// signature that the Callback is representing. -// -// After this, create template specializations for 0-$(MAX_ARITY) parameters. Note that -// even though the template typelist grows, the specialization still -// only has one type: the function signature. -// -// If you are thinking of forward declaring Callback in your own header file, -// please include "base/callback_forward.h" instead. -template -class Callback; - -namespace internal { -template -struct BindState; -} // namespace internal - - -$range ARITY 0..MAX_ARITY -$for ARITY [[ -$range ARG 1..ARITY - -$if ARITY == 0 [[ -template -class Callback : public internal::CallbackBase { -]] $else [[ -template -class Callback : public internal::CallbackBase { -]] - - public: - typedef R(RunType)($for ARG , [[A$(ARG)]]); - - Callback() : CallbackBase(NULL) { } - - // Note that this constructor CANNOT be explicit, and that Bind() CANNOT - // return the exact Callback<> type. See base/bind.h for details. - template - Callback(internal::BindState* bind_state) - : CallbackBase(bind_state) { - - // Force the assignment to a local variable of PolymorphicInvoke - // so the compiler will typecheck that the passed in Run() method has - // the correct type. - PolymorphicInvoke invoke_func = - &internal::BindState - ::InvokerType::Run; - polymorphic_invoke_ = reinterpret_cast(invoke_func); - } - - bool Equals(const Callback& other) const { - return CallbackBase::Equals(other); - } - - R Run($for ARG , - [[typename internal::CallbackParamTraits::ForwardType a$(ARG)]]) const { - PolymorphicInvoke f = - reinterpret_cast(polymorphic_invoke_); - - return f(bind_state_.get()[[]] -$if ARITY != 0 [[, ]] -$for ARG , - [[internal::CallbackForward(a$(ARG))]]); - } - - private: - typedef R(*PolymorphicInvoke)( - internal::BindStateBase*[[]] -$if ARITY != 0 [[, ]] -$for ARG , [[typename internal::CallbackParamTraits::ForwardType]]); - -}; - - -]] $$ for ARITY - -// Syntactic sugar to make Callbacks easier to declare since it -// will be used in a lot of APIs with delayed execution. -typedef Callback Closure; - -} // namespace base - -#endif // BASE_CALLBACK_H diff --git a/base/callback_forward.h b/base/callback_forward.h deleted file mode 100644 index 79832481af..0000000000 --- a/base/callback_forward.h +++ /dev/null @@ -1,17 +0,0 @@ -// Copyright (c) 2011 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef BASE_CALLBACK_FORWARD_H_ -#define BASE_CALLBACK_FORWARD_H_ - -namespace base { - -template -class Callback; - -typedef Callback Closure; - -} // namespace base - -#endif // BASE_CALLBACK_FORWARD_H diff --git a/base/callback_helpers.h b/base/callback_helpers.h deleted file mode 100644 index 52cb71bbf2..0000000000 --- a/base/callback_helpers.h +++ /dev/null @@ -1,30 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -// This defines helpful methods for dealing with Callbacks. Because Callbacks -// are implemented using templates, with a class per callback signature, adding -// methods to Callback<> itself is unattractive (lots of extra code gets -// generated). Instead, consider adding methods here. -// -// ResetAndReturn(&cb) is like cb.Reset() but allows executing a callback (via a -// copy) after the original callback is Reset(). This can be handy if Run() -// reads/writes the variable holding the Callback. - -#ifndef BASE_CALLBACK_HELPERS_H_ -#define BASE_CALLBACK_HELPERS_H_ - -#include "base/callback.h" - -namespace base { - -template -base::Callback ResetAndReturn(base::Callback* cb) { - base::Callback ret(*cb); - cb->Reset(); - return ret; -} - -} // namespace base - -#endif // BASE_CALLBACK_HELPERS_H_ diff --git a/base/callback_internal.cc b/base/callback_internal.cc deleted file mode 100644 index 5acade0ccb..0000000000 --- a/base/callback_internal.cc +++ /dev/null @@ -1,38 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "base/callback_internal.h" - -#include "base/logging.h" - -namespace base { -namespace internal { - -bool CallbackBase::is_null() const { - return bind_state_.get() == NULL; -} - -void CallbackBase::Reset() { - polymorphic_invoke_ = NULL; - // NULL the bind_state_ last, since it may be holding the last ref to whatever - // object owns us, and we may be deleted after that. - bind_state_ = NULL; -} - -bool CallbackBase::Equals(const CallbackBase& other) const { - return bind_state_.get() == other.bind_state_.get() && - polymorphic_invoke_ == other.polymorphic_invoke_; -} - -CallbackBase::CallbackBase(BindStateBase* bind_state) - : bind_state_(bind_state), - polymorphic_invoke_(NULL) { - DCHECK(!bind_state_.get() || bind_state_->HasOneRef()); -} - -CallbackBase::~CallbackBase() { -} - -} // namespace internal -} // namespace base diff --git a/base/callback_internal.h b/base/callback_internal.h deleted file mode 100644 index 5993824a5a..0000000000 --- a/base/callback_internal.h +++ /dev/null @@ -1,184 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -// This file contains utility functions and classes that help the -// implementation, and management of the Callback objects. - -#ifndef BASE_CALLBACK_INTERNAL_H_ -#define BASE_CALLBACK_INTERNAL_H_ - -#include - -#include "base/base_export.h" -#include "base/memory/ref_counted.h" -#include "base/memory/scoped_ptr.h" - -template -class ScopedVector; - -namespace base { -namespace internal { - -// BindStateBase is used to provide an opaque handle that the Callback -// class can use to represent a function object with bound arguments. It -// behaves as an existential type that is used by a corresponding -// DoInvoke function to perform the function execution. This allows -// us to shield the Callback class from the types of the bound argument via -// "type erasure." -class BindStateBase : public RefCountedThreadSafe { - protected: - friend class RefCountedThreadSafe; - virtual ~BindStateBase() {} -}; - -// Holds the Callback methods that don't require specialization to reduce -// template bloat. -class BASE_EXPORT CallbackBase { - public: - // Returns true if Callback is null (doesn't refer to anything). - bool is_null() const; - - // Returns the Callback into an uninitialized state. - void Reset(); - - protected: - // In C++, it is safe to cast function pointers to function pointers of - // another type. It is not okay to use void*. We create a InvokeFuncStorage - // that that can store our function pointer, and then cast it back to - // the original type on usage. - typedef void(*InvokeFuncStorage)(void); - - // Returns true if this callback equals |other|. |other| may be null. - bool Equals(const CallbackBase& other) const; - - // Allow initializing of |bind_state_| via the constructor to avoid default - // initialization of the scoped_refptr. We do not also initialize - // |polymorphic_invoke_| here because doing a normal assignment in the - // derived Callback templates makes for much nicer compiler errors. - explicit CallbackBase(BindStateBase* bind_state); - - // Force the destructor to be instantiated inside this translation unit so - // that our subclasses will not get inlined versions. Avoids more template - // bloat. - ~CallbackBase(); - - scoped_refptr bind_state_; - InvokeFuncStorage polymorphic_invoke_; -}; - -// This is a typetraits object that's used to take an argument type, and -// extract a suitable type for storing and forwarding arguments. -// -// In particular, it strips off references, and converts arrays to -// pointers for storage; and it avoids accidentally trying to create a -// "reference of a reference" if the argument is a reference type. -// -// This array type becomes an issue for storage because we are passing bound -// parameters by const reference. In this case, we end up passing an actual -// array type in the initializer list which C++ does not allow. This will -// break passing of C-string literals. -template -struct CallbackParamTraits { - typedef const T& ForwardType; - typedef T StorageType; -}; - -// The Storage should almost be impossible to trigger unless someone manually -// specifies type of the bind parameters. However, in case they do, -// this will guard against us accidentally storing a reference parameter. -// -// The ForwardType should only be used for unbound arguments. -template -struct CallbackParamTraits { - typedef T& ForwardType; - typedef T StorageType; -}; - -// Note that for array types, we implicitly add a const in the conversion. This -// means that it is not possible to bind array arguments to functions that take -// a non-const pointer. Trying to specialize the template based on a "const -// T[n]" does not seem to match correctly, so we are stuck with this -// restriction. -template -struct CallbackParamTraits { - typedef const T* ForwardType; - typedef const T* StorageType; -}; - -// See comment for CallbackParamTraits. -template -struct CallbackParamTraits { - typedef const T* ForwardType; - typedef const T* StorageType; -}; - -// Parameter traits for movable-but-not-copyable scopers. -// -// Callback<>/Bind() understands movable-but-not-copyable semantics where -// the type cannot be copied but can still have its state destructively -// transferred (aka. moved) to another instance of the same type by calling a -// helper function. When used with Bind(), this signifies transferal of the -// object's state to the target function. -// -// For these types, the ForwardType must not be a const reference, or a -// reference. A const reference is inappropriate, and would break const -// correctness, because we are implementing a destructive move. A non-const -// reference cannot be used with temporaries which means the result of a -// function or a cast would not be usable with Callback<> or Bind(). -// -// TODO(ajwong): We might be able to use SFINAE to search for the existence of -// a Pass() function in the type and avoid the whitelist in CallbackParamTraits -// and CallbackForward. -template -struct CallbackParamTraits > { - typedef scoped_ptr ForwardType; - typedef scoped_ptr StorageType; -}; - -template -struct CallbackParamTraits > { - typedef scoped_ptr_malloc ForwardType; - typedef scoped_ptr_malloc StorageType; -}; - -template -struct CallbackParamTraits > { - typedef ScopedVector ForwardType; - typedef ScopedVector StorageType; -}; - -// CallbackForward() is a very limited simulation of C++11's std::forward() -// used by the Callback/Bind system for a set of movable-but-not-copyable -// types. It is needed because forwarding a movable-but-not-copyable -// argument to another function requires us to invoke the proper move -// operator to create a rvalue version of the type. The supported types are -// whitelisted below as overloads of the CallbackForward() function. The -// default template compiles out to be a no-op. -// -// In C++11, std::forward would replace all uses of this function. However, it -// is impossible to implement a general std::forward with C++11 due to a lack -// of rvalue references. -// -// In addition to Callback/Bind, this is used by PostTaskAndReplyWithResult to -// simulate std::forward() and forward the result of one Callback as a -// parameter to another callback. This is to support Callbacks that return -// the movable-but-not-copyable types whitelisted above. -template -T& CallbackForward(T& t) { return t; } - -template -scoped_ptr CallbackForward(scoped_ptr& p) { return p.Pass(); } - -template -scoped_ptr_malloc CallbackForward(scoped_ptr_malloc& p) { - return p.Pass(); -} - -template -ScopedVector CallbackForward(ScopedVector& p) { return p.Pass(); } - -} // namespace internal -} // namespace base - -#endif // BASE_CALLBACK_INTERNAL_H_ diff --git a/base/callback_unittest.cc b/base/callback_unittest.cc deleted file mode 100644 index 6103b2e967..0000000000 --- a/base/callback_unittest.cc +++ /dev/null @@ -1,181 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "base/bind.h" -#include "base/callback.h" -#include "base/callback_helpers.h" -#include "base/callback_internal.h" -#include "base/memory/ref_counted.h" -#include "base/memory/scoped_ptr.h" -#include "testing/gtest/include/gtest/gtest.h" - -namespace base { - -namespace { - -struct FakeInvoker { - typedef void(RunType)(internal::BindStateBase*); - static void Run(internal::BindStateBase*) { - } -}; - -} // namespace - -namespace internal { -template -struct BindState; - -// White-box testpoints to inject into a Callback<> object for checking -// comparators and emptiness APIs. Use a BindState that is specialized -// based on a type we declared in the anonymous namespace above to remove any -// chance of colliding with another instantiation and breaking the -// one-definition-rule. -template <> -struct BindState - : public BindStateBase { - public: - typedef FakeInvoker InvokerType; -}; - -template <> -struct BindState - : public BindStateBase { - public: - typedef FakeInvoker InvokerType; -}; -} // namespace internal - -namespace { - -typedef internal::BindState - FakeBindState1; -typedef internal::BindState - FakeBindState2; - -class CallbackTest : public ::testing::Test { - public: - CallbackTest() - : callback_a_(new FakeBindState1()), - callback_b_(new FakeBindState2()) { - } - - virtual ~CallbackTest() { - } - - protected: - Callback callback_a_; - const Callback callback_b_; // Ensure APIs work with const. - Callback null_callback_; -}; - -// Ensure we can create unbound callbacks. We need this to be able to store -// them in class members that can be initialized later. -TEST_F(CallbackTest, DefaultConstruction) { - Callback c0; - Callback c1; - Callback c2; - Callback c3; - Callback c4; - Callback c5; - Callback c6; - - EXPECT_TRUE(c0.is_null()); - EXPECT_TRUE(c1.is_null()); - EXPECT_TRUE(c2.is_null()); - EXPECT_TRUE(c3.is_null()); - EXPECT_TRUE(c4.is_null()); - EXPECT_TRUE(c5.is_null()); - EXPECT_TRUE(c6.is_null()); -} - -TEST_F(CallbackTest, IsNull) { - EXPECT_TRUE(null_callback_.is_null()); - EXPECT_FALSE(callback_a_.is_null()); - EXPECT_FALSE(callback_b_.is_null()); -} - -TEST_F(CallbackTest, Equals) { - EXPECT_TRUE(callback_a_.Equals(callback_a_)); - EXPECT_FALSE(callback_a_.Equals(callback_b_)); - EXPECT_FALSE(callback_b_.Equals(callback_a_)); - - // We should compare based on instance, not type. - Callback callback_c(new FakeBindState1()); - Callback callback_a2 = callback_a_; - EXPECT_TRUE(callback_a_.Equals(callback_a2)); - EXPECT_FALSE(callback_a_.Equals(callback_c)); - - // Empty, however, is always equal to empty. - Callback empty2; - EXPECT_TRUE(null_callback_.Equals(empty2)); -} - -TEST_F(CallbackTest, Reset) { - // Resetting should bring us back to empty. - ASSERT_FALSE(callback_a_.is_null()); - ASSERT_FALSE(callback_a_.Equals(null_callback_)); - - callback_a_.Reset(); - - EXPECT_TRUE(callback_a_.is_null()); - EXPECT_TRUE(callback_a_.Equals(null_callback_)); -} - -struct TestForReentrancy { - TestForReentrancy() - : cb_already_run(false), - cb(Bind(&TestForReentrancy::AssertCBIsNull, Unretained(this))) { - } - void AssertCBIsNull() { - ASSERT_TRUE(cb.is_null()); - cb_already_run = true; - } - bool cb_already_run; - Closure cb; -}; - -TEST_F(CallbackTest, ResetAndReturn) { - TestForReentrancy tfr; - ASSERT_FALSE(tfr.cb.is_null()); - ASSERT_FALSE(tfr.cb_already_run); - ResetAndReturn(&tfr.cb).Run(); - ASSERT_TRUE(tfr.cb.is_null()); - ASSERT_TRUE(tfr.cb_already_run); -} - -class CallbackOwner : public base::RefCounted { - public: - explicit CallbackOwner(bool* deleted) { - callback_ = Bind(&CallbackOwner::Unused, this); - deleted_ = deleted; - } - void Reset() { - callback_.Reset(); - // We are deleted here if no-one else had a ref to us. - } - - private: - friend class base::RefCounted; - virtual ~CallbackOwner() { - *deleted_ = true; - } - void Unused() { - FAIL() << "Should never be called"; - } - - Closure callback_; - bool* deleted_; -}; - -TEST_F(CallbackTest, CallbackHasLastRefOnContainingObject) { - bool deleted = false; - CallbackOwner* owner = new CallbackOwner(&deleted); - owner->Reset(); - ASSERT_TRUE(deleted); -} - -} // namespace -} // namespace base diff --git a/base/callback_unittest.nc b/base/callback_unittest.nc deleted file mode 100644 index 9bddd1f836..0000000000 --- a/base/callback_unittest.nc +++ /dev/null @@ -1,50 +0,0 @@ -// Copyright (c) 2011 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "base/callback.h" - -namespace base { - -class Parent { -}; - -class Child : Parent { -}; - -#if defined(NCTEST_EQUALS_REQUIRES_SAMETYPE) // [r"no matching function for call to 'base::Callback::Equals\(base::Callback&\)'"] - -// Attempting to call comparison function on two callbacks of different type. -// -// This should be a compile time failure because each callback type should be -// considered distinct. -void WontCompile() { - Closure c1; - Callback c2; - c1.Equals(c2); -} - -#elif defined(NCTEST_CONSTRUCTION_FROM_SUBTYPE) // [r"conversion from 'base::Callback' to non-scalar type 'base::Callback'"] - -// Construction of Callback from Callback if A is supertype of B. -// -// While this is technically safe, most people aren't used to it when coding -// C++ so if this is happening, it is almost certainly an error. -void WontCompile() { - Callback cb_a; - Callback cb_b = cb_a; -} - -#elif defined(NCTEST_ASSIGNMENT_FROM_SUBTYPE) // [r"no match for 'operator=' in 'cb_a = cb_b'"] - -// Assignment of Callback from Callback if A is supertype of B. -// See explanation for NCTEST_CONSTRUCTION_FROM_SUBTYPE -void WontCompile() { - Callback cb_a; - Callback cb_b; - cb_a = cb_b; -} - -#endif - -} // namespace base diff --git a/base/cancelable_callback.h b/base/cancelable_callback.h deleted file mode 100644 index 8ef01996a9..0000000000 --- a/base/cancelable_callback.h +++ /dev/null @@ -1,272 +0,0 @@ -// Copyright (c) 2011 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. -// -// CancelableCallback is a wrapper around base::Callback that allows -// cancellation of a callback. CancelableCallback takes a reference on the -// wrapped callback until this object is destroyed or Reset()/Cancel() are -// called. -// -// NOTE: -// -// Calling CancellableCallback::Cancel() brings the object back to its natural, -// default-constructed state, i.e., CancellableCallback::callback() will return -// a null callback. -// -// THREAD-SAFETY: -// -// CancelableCallback objects must be created on, posted to, cancelled on, and -// destroyed on the same thread. -// -// -// EXAMPLE USAGE: -// -// In the following example, the test is verifying that RunIntensiveTest() -// Quit()s the message loop within 4 seconds. The cancelable callback is posted -// to the message loop, the intensive test runs, the message loop is run, -// then the callback is cancelled. -// -// void TimeoutCallback(const std::string& timeout_message) { -// FAIL() << timeout_message; -// MessageLoop::current()->QuitWhenIdle(); -// } -// -// CancelableClosure timeout(base::Bind(&TimeoutCallback, "Test timed out.")); -// MessageLoop::current()->PostDelayedTask(FROM_HERE, timeout.callback(), -// 4000) // 4 seconds to run. -// RunIntensiveTest(); -// MessageLoop::current()->Run(); -// timeout.Cancel(); // Hopefully this is hit before the timeout callback runs. -// - -#ifndef BASE_CANCELABLE_CALLBACK_H_ -#define BASE_CANCELABLE_CALLBACK_H_ - -#include "base/base_export.h" -#include "base/bind.h" -#include "base/callback.h" -#include "base/callback_internal.h" -#include "base/compiler_specific.h" -#include "base/logging.h" -#include "base/memory/weak_ptr.h" - -namespace base { - -template -class CancelableCallback; - -template <> -class CancelableCallback { - public: - CancelableCallback() : weak_factory_(this) {} - - // |callback| must not be null. - explicit CancelableCallback(const base::Callback& callback) - : weak_factory_(this), - callback_(callback) { - DCHECK(!callback.is_null()); - InitializeForwarder(); - } - - ~CancelableCallback() {} - - // Cancels and drops the reference to the wrapped callback. - void Cancel() { - weak_factory_.InvalidateWeakPtrs(); - forwarder_.Reset(); - callback_.Reset(); - } - - // Returns true if the wrapped callback has been cancelled. - bool IsCancelled() const { - return callback_.is_null(); - } - - // Sets |callback| as the closure that may be cancelled. |callback| may not - // be null. Outstanding and any previously wrapped callbacks are cancelled. - void Reset(const base::Callback& callback) { - DCHECK(!callback.is_null()); - - // Outstanding tasks (e.g., posted to a message loop) must not be called. - Cancel(); - - // |forwarder_| is no longer valid after Cancel(), so re-bind. - InitializeForwarder(); - - callback_ = callback; - } - - // Returns a callback that can be disabled by calling Cancel(). - const base::Callback& callback() const { - return forwarder_; - } - - private: - void Forward() { - callback_.Run(); - } - - // Helper method to bind |forwarder_| using a weak pointer from - // |weak_factory_|. - void InitializeForwarder() { - forwarder_ = base::Bind(&CancelableCallback::Forward, - weak_factory_.GetWeakPtr()); - } - - // Used to ensure Forward() is not run when this object is destroyed. - base::WeakPtrFactory > weak_factory_; - - // The wrapper closure. - base::Callback forwarder_; - - // The stored closure that may be cancelled. - base::Callback callback_; - - DISALLOW_COPY_AND_ASSIGN(CancelableCallback); -}; - -template -class CancelableCallback { - public: - CancelableCallback() : weak_factory_(this) {} - - // |callback| must not be null. - explicit CancelableCallback(const base::Callback& callback) - : weak_factory_(this), - callback_(callback) { - DCHECK(!callback.is_null()); - InitializeForwarder(); - } - - ~CancelableCallback() {} - - // Cancels and drops the reference to the wrapped callback. - void Cancel() { - weak_factory_.InvalidateWeakPtrs(); - forwarder_.Reset(); - callback_.Reset(); - } - - // Returns true if the wrapped callback has been cancelled. - bool IsCancelled() const { - return callback_.is_null(); - } - - // Sets |callback| as the closure that may be cancelled. |callback| may not - // be null. Outstanding and any previously wrapped callbacks are cancelled. - void Reset(const base::Callback& callback) { - DCHECK(!callback.is_null()); - - // Outstanding tasks (e.g., posted to a message loop) must not be called. - Cancel(); - - // |forwarder_| is no longer valid after Cancel(), so re-bind. - InitializeForwarder(); - - callback_ = callback; - } - - // Returns a callback that can be disabled by calling Cancel(). - const base::Callback& callback() const { - return forwarder_; - } - - private: - void Forward(A1 a1) const { - callback_.Run(a1); - } - - // Helper method to bind |forwarder_| using a weak pointer from - // |weak_factory_|. - void InitializeForwarder() { - forwarder_ = base::Bind(&CancelableCallback::Forward, - weak_factory_.GetWeakPtr()); - } - - // Used to ensure Forward() is not run when this object is destroyed. - base::WeakPtrFactory > weak_factory_; - - // The wrapper closure. - base::Callback forwarder_; - - // The stored closure that may be cancelled. - base::Callback callback_; - - DISALLOW_COPY_AND_ASSIGN(CancelableCallback); -}; - -template -class CancelableCallback { - public: - CancelableCallback() : weak_factory_(this) {} - - // |callback| must not be null. - explicit CancelableCallback(const base::Callback& callback) - : weak_factory_(this), - callback_(callback) { - DCHECK(!callback.is_null()); - InitializeForwarder(); - } - - ~CancelableCallback() {} - - // Cancels and drops the reference to the wrapped callback. - void Cancel() { - weak_factory_.InvalidateWeakPtrs(); - forwarder_.Reset(); - callback_.Reset(); - } - - // Returns true if the wrapped callback has been cancelled. - bool IsCancelled() const { - return callback_.is_null(); - } - - // Sets |callback| as the closure that may be cancelled. |callback| may not - // be null. Outstanding and any previously wrapped callbacks are cancelled. - void Reset(const base::Callback& callback) { - DCHECK(!callback.is_null()); - - // Outstanding tasks (e.g., posted to a message loop) must not be called. - Cancel(); - - // |forwarder_| is no longer valid after Cancel(), so re-bind. - InitializeForwarder(); - - callback_ = callback; - } - - // Returns a callback that can be disabled by calling Cancel(). - const base::Callback& callback() const { - return forwarder_; - } - - private: - void Forward(A1 a1, A2 a2) const { - callback_.Run(a1, a2); - } - - // Helper method to bind |forwarder_| using a weak pointer from - // |weak_factory_|. - void InitializeForwarder() { - forwarder_ = base::Bind(&CancelableCallback::Forward, - weak_factory_.GetWeakPtr()); - } - - // Used to ensure Forward() is not run when this object is destroyed. - base::WeakPtrFactory > weak_factory_; - - // The wrapper closure. - base::Callback forwarder_; - - // The stored closure that may be cancelled. - base::Callback callback_; - - DISALLOW_COPY_AND_ASSIGN(CancelableCallback); -}; - -typedef CancelableCallback CancelableClosure; - -} // namespace base - -#endif // BASE_CANCELABLE_CALLBACK_H_ diff --git a/base/cancelable_callback_unittest.cc b/base/cancelable_callback_unittest.cc deleted file mode 100644 index 89c603c953..0000000000 --- a/base/cancelable_callback_unittest.cc +++ /dev/null @@ -1,184 +0,0 @@ -// Copyright (c) 2011 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "base/cancelable_callback.h" - -#include "base/bind.h" -#include "base/bind_helpers.h" -#include "base/memory/ref_counted.h" -#include "base/message_loop/message_loop.h" -#include "base/run_loop.h" -#include "testing/gtest/include/gtest/gtest.h" - -namespace base { -namespace { - -class TestRefCounted : public RefCountedThreadSafe { - private: - friend class RefCountedThreadSafe; - ~TestRefCounted() {}; -}; - -void Increment(int* count) { (*count)++; } -void IncrementBy(int* count, int n) { (*count) += n; } -void RefCountedParam(const scoped_refptr& ref_counted) {} - -// Cancel(). -// - Callback can be run multiple times. -// - After Cancel(), Run() completes but has no effect. -TEST(CancelableCallbackTest, Cancel) { - int count = 0; - CancelableClosure cancelable( - base::Bind(&Increment, base::Unretained(&count))); - - base::Closure callback = cancelable.callback(); - callback.Run(); - EXPECT_EQ(1, count); - - callback.Run(); - EXPECT_EQ(2, count); - - cancelable.Cancel(); - callback.Run(); - EXPECT_EQ(2, count); -} - -// Cancel() called multiple times. -// - Cancel() cancels all copies of the wrapped callback. -// - Calling Cancel() more than once has no effect. -// - After Cancel(), callback() returns a null callback. -TEST(CancelableCallbackTest, MultipleCancel) { - int count = 0; - CancelableClosure cancelable( - base::Bind(&Increment, base::Unretained(&count))); - - base::Closure callback1 = cancelable.callback(); - base::Closure callback2 = cancelable.callback(); - cancelable.Cancel(); - - callback1.Run(); - EXPECT_EQ(0, count); - - callback2.Run(); - EXPECT_EQ(0, count); - - // Calling Cancel() again has no effect. - cancelable.Cancel(); - - // callback() of a cancelled callback is null. - base::Closure callback3 = cancelable.callback(); - EXPECT_TRUE(callback3.is_null()); -} - -// CancelableCallback destroyed before callback is run. -// - Destruction of CancelableCallback cancels outstanding callbacks. -TEST(CancelableCallbackTest, CallbackCanceledOnDestruction) { - int count = 0; - base::Closure callback; - - { - CancelableClosure cancelable( - base::Bind(&Increment, base::Unretained(&count))); - - callback = cancelable.callback(); - callback.Run(); - EXPECT_EQ(1, count); - } - - callback.Run(); - EXPECT_EQ(1, count); -} - -// Cancel() called on bound closure with a RefCounted parameter. -// - Cancel drops wrapped callback (and, implicitly, its bound arguments). -TEST(CancelableCallbackTest, CancelDropsCallback) { - scoped_refptr ref_counted = new TestRefCounted; - EXPECT_TRUE(ref_counted->HasOneRef()); - - CancelableClosure cancelable(base::Bind(RefCountedParam, ref_counted)); - EXPECT_FALSE(cancelable.IsCancelled()); - EXPECT_TRUE(ref_counted.get()); - EXPECT_FALSE(ref_counted->HasOneRef()); - - // There is only one reference to |ref_counted| after the Cancel(). - cancelable.Cancel(); - EXPECT_TRUE(cancelable.IsCancelled()); - EXPECT_TRUE(ref_counted.get()); - EXPECT_TRUE(ref_counted->HasOneRef()); -} - -// Reset(). -// - Reset() replaces the existing wrapped callback with a new callback. -// - Reset() deactivates outstanding callbacks. -TEST(CancelableCallbackTest, Reset) { - int count = 0; - CancelableClosure cancelable( - base::Bind(&Increment, base::Unretained(&count))); - - base::Closure callback = cancelable.callback(); - callback.Run(); - EXPECT_EQ(1, count); - - callback.Run(); - EXPECT_EQ(2, count); - - cancelable.Reset( - base::Bind(&IncrementBy, base::Unretained(&count), 3)); - EXPECT_FALSE(cancelable.IsCancelled()); - - // The stale copy of the cancelable callback is non-null. - ASSERT_FALSE(callback.is_null()); - - // The stale copy of the cancelable callback is no longer active. - callback.Run(); - EXPECT_EQ(2, count); - - base::Closure callback2 = cancelable.callback(); - ASSERT_FALSE(callback2.is_null()); - - callback2.Run(); - EXPECT_EQ(5, count); -} - -// IsCanceled(). -// - Cancel() transforms the CancelableCallback into a cancelled state. -TEST(CancelableCallbackTest, IsNull) { - CancelableClosure cancelable; - EXPECT_TRUE(cancelable.IsCancelled()); - - int count = 0; - cancelable.Reset(base::Bind(&Increment, - base::Unretained(&count))); - EXPECT_FALSE(cancelable.IsCancelled()); - - cancelable.Cancel(); - EXPECT_TRUE(cancelable.IsCancelled()); -} - -// CancelableCallback posted to a MessageLoop with PostTask. -// - Callbacks posted to a MessageLoop can be cancelled. -TEST(CancelableCallbackTest, PostTask) { - MessageLoop loop(MessageLoop::TYPE_DEFAULT); - - int count = 0; - CancelableClosure cancelable(base::Bind(&Increment, - base::Unretained(&count))); - - MessageLoop::current()->PostTask(FROM_HERE, cancelable.callback()); - RunLoop().RunUntilIdle(); - - EXPECT_EQ(1, count); - - MessageLoop::current()->PostTask(FROM_HERE, cancelable.callback()); - - // Cancel before running the message loop. - cancelable.Cancel(); - RunLoop().RunUntilIdle(); - - // Callback never ran due to cancellation; count is the same. - EXPECT_EQ(1, count); -} - -} // namespace -} // namespace base diff --git a/base/check_example.cc b/base/check_example.cc deleted file mode 100644 index 4b3f4287db..0000000000 --- a/base/check_example.cc +++ /dev/null @@ -1,25 +0,0 @@ -// Copyright (c) 2011 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -// This file is meant for analyzing the code generated by the CHECK -// macros in a small executable file that's easy to disassemble. - -#include "base/logging.h" - -// An official build shouldn't generate code to print out messages for -// the CHECK* macros, nor should it have the strings in the -// executable. - -void DoCheck(bool b) { - CHECK(b) << "DoCheck " << b; -} - -void DoCheckEq(int x, int y) { - CHECK_EQ(x, y); -} - -int main(int argc, const char* argv[]) { - DoCheck(argc > 1); - DoCheckEq(argc, 1); -} diff --git a/base/chromeos/chromeos_version.cc b/base/chromeos/chromeos_version.cc deleted file mode 100644 index 4a70cd5312..0000000000 --- a/base/chromeos/chromeos_version.cc +++ /dev/null @@ -1,24 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "base/chromeos/chromeos_version.h" - -#include -#include - -#include "base/logging.h" - -namespace base { -namespace chromeos { - -bool IsRunningOnChromeOS() { - // Check if the user name is chronos. Note that we don't go with - // getuid() + getpwuid_r() as it may end up reading /etc/passwd, which - // can be expensive. - const char* user = getenv("USER"); - return user && strcmp(user, "chronos") == 0; -} - -} // namespace chromeos -} // namespace base diff --git a/base/chromeos/chromeos_version.h b/base/chromeos/chromeos_version.h deleted file mode 100644 index 25acd43a9f..0000000000 --- a/base/chromeos/chromeos_version.h +++ /dev/null @@ -1,20 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef BASE_CHROMEOS_CHROMEOS_VERSION_H_ -#define BASE_CHROMEOS_CHROMEOS_VERSION_H_ - -#include "base/base_export.h" - -namespace base { -namespace chromeos { - -// Returns true if the browser is running on Chrome OS. -// Useful for implementing stubs for Linux desktop. -BASE_EXPORT bool IsRunningOnChromeOS(); - -} // namespace chromeos -} // namespace base - -#endif // BASE_CHROMEOS_CHROMEOS_VERSION_H_ diff --git a/base/command_line.cc b/base/command_line.cc deleted file mode 100644 index 36ac88f12c..0000000000 --- a/base/command_line.cc +++ /dev/null @@ -1,424 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "base/command_line.h" - -#include -#include - -#include "base/basictypes.h" -#include "base/files/file_path.h" -#include "base/logging.h" -#include "base/strings/string_split.h" -#include "base/strings/string_util.h" -#include "base/strings/utf_string_conversions.h" -#include "build/build_config.h" - -#if defined(OS_WIN) -#include -#include -#endif - -using base::FilePath; - -CommandLine* CommandLine::current_process_commandline_ = NULL; - -namespace { -const CommandLine::CharType kSwitchTerminator[] = FILE_PATH_LITERAL("--"); -const CommandLine::CharType kSwitchValueSeparator[] = FILE_PATH_LITERAL("="); -// Since we use a lazy match, make sure that longer versions (like "--") are -// listed before shorter versions (like "-") of similar prefixes. -#if defined(OS_WIN) -const CommandLine::CharType* const kSwitchPrefixes[] = {L"--", L"-", L"/"}; -#elif defined(OS_POSIX) -// Unixes don't use slash as a switch. -const CommandLine::CharType* const kSwitchPrefixes[] = {"--", "-"}; -#endif - -size_t GetSwitchPrefixLength(const CommandLine::StringType& string) { - for (size_t i = 0; i < arraysize(kSwitchPrefixes); ++i) { - CommandLine::StringType prefix(kSwitchPrefixes[i]); - if (string.compare(0, prefix.length(), prefix) == 0) - return prefix.length(); - } - return 0; -} - -// Fills in |switch_string| and |switch_value| if |string| is a switch. -// This will preserve the input switch prefix in the output |switch_string|. -bool IsSwitch(const CommandLine::StringType& string, - CommandLine::StringType* switch_string, - CommandLine::StringType* switch_value) { - switch_string->clear(); - switch_value->clear(); - size_t prefix_length = GetSwitchPrefixLength(string); - if (prefix_length == 0 || prefix_length == string.length()) - return false; - - const size_t equals_position = string.find(kSwitchValueSeparator); - *switch_string = string.substr(0, equals_position); - if (equals_position != CommandLine::StringType::npos) - *switch_value = string.substr(equals_position + 1); - return true; -} - -// Append switches and arguments, keeping switches before arguments. -void AppendSwitchesAndArguments(CommandLine& command_line, - const CommandLine::StringVector& argv) { - bool parse_switches = true; - for (size_t i = 1; i < argv.size(); ++i) { - CommandLine::StringType arg = argv[i]; - TrimWhitespace(arg, TRIM_ALL, &arg); - - CommandLine::StringType switch_string; - CommandLine::StringType switch_value; - parse_switches &= (arg != kSwitchTerminator); - if (parse_switches && IsSwitch(arg, &switch_string, &switch_value)) { -#if defined(OS_WIN) - command_line.AppendSwitchNative(WideToASCII(switch_string), switch_value); -#elif defined(OS_POSIX) - command_line.AppendSwitchNative(switch_string, switch_value); -#endif - } else { - command_line.AppendArgNative(arg); - } - } -} - -// Lowercase switches for backwards compatiblity *on Windows*. -std::string LowerASCIIOnWindows(const std::string& string) { -#if defined(OS_WIN) - return StringToLowerASCII(string); -#elif defined(OS_POSIX) - return string; -#endif -} - - -#if defined(OS_WIN) -// Quote a string as necessary for CommandLineToArgvW compatiblity *on Windows*. -std::wstring QuoteForCommandLineToArgvW(const std::wstring& arg) { - // We follow the quoting rules of CommandLineToArgvW. - // http://msdn.microsoft.com/en-us/library/17w5ykft.aspx - if (arg.find_first_of(L" \\\"") == std::wstring::npos) { - // No quoting necessary. - return arg; - } - - std::wstring out; - out.push_back(L'"'); - for (size_t i = 0; i < arg.size(); ++i) { - if (arg[i] == '\\') { - // Find the extent of this run of backslashes. - size_t start = i, end = start + 1; - for (; end < arg.size() && arg[end] == '\\'; ++end) - /* empty */; - size_t backslash_count = end - start; - - // Backslashes are escapes only if the run is followed by a double quote. - // Since we also will end the string with a double quote, we escape for - // either a double quote or the end of the string. - if (end == arg.size() || arg[end] == '"') { - // To quote, we need to output 2x as many backslashes. - backslash_count *= 2; - } - for (size_t j = 0; j < backslash_count; ++j) - out.push_back('\\'); - - // Advance i to one before the end to balance i++ in loop. - i = end - 1; - } else if (arg[i] == '"') { - out.push_back('\\'); - out.push_back('"'); - } else { - out.push_back(arg[i]); - } - } - out.push_back('"'); - - return out; -} -#endif - -} // namespace - -CommandLine::CommandLine(NoProgram no_program) - : argv_(1), - begin_args_(1) { -} - -CommandLine::CommandLine(const FilePath& program) - : argv_(1), - begin_args_(1) { - SetProgram(program); -} - -CommandLine::CommandLine(int argc, const CommandLine::CharType* const* argv) - : argv_(1), - begin_args_(1) { - InitFromArgv(argc, argv); -} - -CommandLine::CommandLine(const StringVector& argv) - : argv_(1), - begin_args_(1) { - InitFromArgv(argv); -} - -CommandLine::~CommandLine() { -} - -// static -bool CommandLine::Init(int argc, const char* const* argv) { - if (current_process_commandline_) { - // If this is intentional, Reset() must be called first. If we are using - // the shared build mode, we have to share a single object across multiple - // shared libraries. - return false; - } - - current_process_commandline_ = new CommandLine(NO_PROGRAM); -#if defined(OS_WIN) - current_process_commandline_->ParseFromString(::GetCommandLineW()); -#elif defined(OS_POSIX) - current_process_commandline_->InitFromArgv(argc, argv); -#endif - - return true; -} - -// static -void CommandLine::Reset() { - DCHECK(current_process_commandline_); - delete current_process_commandline_; - current_process_commandline_ = NULL; -} - -// static -CommandLine* CommandLine::ForCurrentProcess() { - DCHECK(current_process_commandline_); - return current_process_commandline_; -} - -// static -bool CommandLine::InitializedForCurrentProcess() { - return !!current_process_commandline_; -} - -#if defined(OS_WIN) -// static -CommandLine CommandLine::FromString(const std::wstring& command_line) { - CommandLine cmd(NO_PROGRAM); - cmd.ParseFromString(command_line); - return cmd; -} -#endif - -void CommandLine::InitFromArgv(int argc, - const CommandLine::CharType* const* argv) { - StringVector new_argv; - for (int i = 0; i < argc; ++i) - new_argv.push_back(argv[i]); - InitFromArgv(new_argv); -} - -void CommandLine::InitFromArgv(const StringVector& argv) { - argv_ = StringVector(1); - switches_.clear(); - begin_args_ = 1; - SetProgram(argv.empty() ? FilePath() : FilePath(argv[0])); - AppendSwitchesAndArguments(*this, argv); -} - -CommandLine::StringType CommandLine::GetCommandLineString() const { - StringType string(argv_[0]); -#if defined(OS_WIN) - string = QuoteForCommandLineToArgvW(string); -#endif - StringType params(GetArgumentsString()); - if (!params.empty()) { - string.append(StringType(FILE_PATH_LITERAL(" "))); - string.append(params); - } - return string; -} - -CommandLine::StringType CommandLine::GetArgumentsString() const { - StringType params; - // Append switches and arguments. - bool parse_switches = true; - for (size_t i = 1; i < argv_.size(); ++i) { - StringType arg = argv_[i]; - StringType switch_string; - StringType switch_value; - parse_switches &= arg != kSwitchTerminator; - if (i > 1) - params.append(StringType(FILE_PATH_LITERAL(" "))); - if (parse_switches && IsSwitch(arg, &switch_string, &switch_value)) { - params.append(switch_string); - if (!switch_value.empty()) { -#if defined(OS_WIN) - switch_value = QuoteForCommandLineToArgvW(switch_value); -#endif - params.append(kSwitchValueSeparator + switch_value); - } - } - else { -#if defined(OS_WIN) - arg = QuoteForCommandLineToArgvW(arg); -#endif - params.append(arg); - } - } - return params; -} - -FilePath CommandLine::GetProgram() const { - return FilePath(argv_[0]); -} - -void CommandLine::SetProgram(const FilePath& program) { - TrimWhitespace(program.value(), TRIM_ALL, &argv_[0]); -} - -bool CommandLine::HasSwitch(const std::string& switch_string) const { - return switches_.find(LowerASCIIOnWindows(switch_string)) != switches_.end(); -} - -std::string CommandLine::GetSwitchValueASCII( - const std::string& switch_string) const { - StringType value = GetSwitchValueNative(switch_string); - if (!IsStringASCII(value)) { - DLOG(WARNING) << "Value of switch (" << switch_string << ") must be ASCII."; - return std::string(); - } -#if defined(OS_WIN) - return WideToASCII(value); -#else - return value; -#endif -} - -FilePath CommandLine::GetSwitchValuePath( - const std::string& switch_string) const { - return FilePath(GetSwitchValueNative(switch_string)); -} - -CommandLine::StringType CommandLine::GetSwitchValueNative( - const std::string& switch_string) const { - SwitchMap::const_iterator result = switches_.end(); - result = switches_.find(LowerASCIIOnWindows(switch_string)); - return result == switches_.end() ? StringType() : result->second; -} - -void CommandLine::AppendSwitch(const std::string& switch_string) { - AppendSwitchNative(switch_string, StringType()); -} - -void CommandLine::AppendSwitchPath(const std::string& switch_string, - const FilePath& path) { - AppendSwitchNative(switch_string, path.value()); -} - -void CommandLine::AppendSwitchNative(const std::string& switch_string, - const CommandLine::StringType& value) { - std::string switch_key(LowerASCIIOnWindows(switch_string)); -#if defined(OS_WIN) - StringType combined_switch_string(ASCIIToWide(switch_key)); -#elif defined(OS_POSIX) - StringType combined_switch_string(switch_string); -#endif - size_t prefix_length = GetSwitchPrefixLength(combined_switch_string); - switches_[switch_key.substr(prefix_length)] = value; - // Preserve existing switch prefixes in |argv_|; only append one if necessary. - if (prefix_length == 0) - combined_switch_string = kSwitchPrefixes[0] + combined_switch_string; - if (!value.empty()) - combined_switch_string += kSwitchValueSeparator + value; - // Append the switch and update the switches/arguments divider |begin_args_|. - argv_.insert(argv_.begin() + begin_args_++, combined_switch_string); -} - -void CommandLine::AppendSwitchASCII(const std::string& switch_string, - const std::string& value_string) { -#if defined(OS_WIN) - AppendSwitchNative(switch_string, ASCIIToWide(value_string)); -#elif defined(OS_POSIX) - AppendSwitchNative(switch_string, value_string); -#endif -} - -void CommandLine::CopySwitchesFrom(const CommandLine& source, - const char* const switches[], - size_t count) { - for (size_t i = 0; i < count; ++i) { - if (source.HasSwitch(switches[i])) - AppendSwitchNative(switches[i], source.GetSwitchValueNative(switches[i])); - } -} - -CommandLine::StringVector CommandLine::GetArgs() const { - // Gather all arguments after the last switch (may include kSwitchTerminator). - StringVector args(argv_.begin() + begin_args_, argv_.end()); - // Erase only the first kSwitchTerminator (maybe "--" is a legitimate page?) - StringVector::iterator switch_terminator = - std::find(args.begin(), args.end(), kSwitchTerminator); - if (switch_terminator != args.end()) - args.erase(switch_terminator); - return args; -} - -void CommandLine::AppendArg(const std::string& value) { -#if defined(OS_WIN) - DCHECK(IsStringUTF8(value)); - AppendArgNative(UTF8ToWide(value)); -#elif defined(OS_POSIX) - AppendArgNative(value); -#endif -} - -void CommandLine::AppendArgPath(const FilePath& path) { - AppendArgNative(path.value()); -} - -void CommandLine::AppendArgNative(const CommandLine::StringType& value) { - argv_.push_back(value); -} - -void CommandLine::AppendArguments(const CommandLine& other, - bool include_program) { - if (include_program) - SetProgram(other.GetProgram()); - AppendSwitchesAndArguments(*this, other.argv()); -} - -void CommandLine::PrependWrapper(const CommandLine::StringType& wrapper) { - if (wrapper.empty()) - return; - // The wrapper may have embedded arguments (like "gdb --args"). In this case, - // we don't pretend to do anything fancy, we just split on spaces. - StringVector wrapper_argv; - base::SplitString(wrapper, FILE_PATH_LITERAL(' '), &wrapper_argv); - // Prepend the wrapper and update the switches/arguments |begin_args_|. - argv_.insert(argv_.begin(), wrapper_argv.begin(), wrapper_argv.end()); - begin_args_ += wrapper_argv.size(); -} - -#if defined(OS_WIN) -void CommandLine::ParseFromString(const std::wstring& command_line) { - std::wstring command_line_string; - TrimWhitespace(command_line, TRIM_ALL, &command_line_string); - if (command_line_string.empty()) - return; - - int num_args = 0; - wchar_t** args = NULL; - args = ::CommandLineToArgvW(command_line_string.c_str(), &num_args); - - DPLOG_IF(FATAL, !args) << "CommandLineToArgvW failed on command line: " - << command_line; - InitFromArgv(num_args, args); - LocalFree(args); -} -#endif diff --git a/base/command_line.h b/base/command_line.h deleted file mode 100644 index ed46c4f0d1..0000000000 --- a/base/command_line.h +++ /dev/null @@ -1,178 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -// This class works with command lines: building and parsing. -// Arguments with prefixes ('--', '-', and on Windows, '/') are switches. -// Switches will precede all other arguments without switch prefixes. -// Switches can optionally have values, delimited by '=', e.g., "-switch=value". -// An argument of "--" will terminate switch parsing during initialization, -// interpreting subsequent tokens as non-switch arguments, regardless of prefix. - -// There is a singleton read-only CommandLine that represents the command line -// that the current process was started with. It must be initialized in main(). - -#ifndef BASE_COMMAND_LINE_H_ -#define BASE_COMMAND_LINE_H_ - -#include -#include -#include -#include - -#include "base/base_export.h" -#include "build/build_config.h" - -namespace base { -class FilePath; -} - -class BASE_EXPORT CommandLine { - public: -#if defined(OS_WIN) - // The native command line string type. - typedef std::wstring StringType; -#elif defined(OS_POSIX) - typedef std::string StringType; -#endif - - typedef StringType::value_type CharType; - typedef std::vector StringVector; - typedef std::map SwitchMap; - - // A constructor for CommandLines that only carry switches and arguments. - enum NoProgram { NO_PROGRAM }; - explicit CommandLine(NoProgram no_program); - - // Construct a new command line with |program| as argv[0]. - explicit CommandLine(const base::FilePath& program); - - // Construct a new command line from an argument list. - CommandLine(int argc, const CharType* const* argv); - explicit CommandLine(const StringVector& argv); - - ~CommandLine(); - - // Initialize the current process CommandLine singleton. On Windows, ignores - // its arguments (we instead parse GetCommandLineW() directly) because we - // don't trust the CRT's parsing of the command line, but it still must be - // called to set up the command line. Returns false if initialization has - // already occurred, and true otherwise. Only the caller receiving a 'true' - // return value should take responsibility for calling Reset. - static bool Init(int argc, const char* const* argv); - - // Destroys the current process CommandLine singleton. This is necessary if - // you want to reset the base library to its initial state (for example, in an - // outer library that needs to be able to terminate, and be re-initialized). - // If Init is called only once, as in main(), Reset() is not necessary. - static void Reset(); - - // Get the singleton CommandLine representing the current process's - // command line. Note: returned value is mutable, but not thread safe; - // only mutate if you know what you're doing! - static CommandLine* ForCurrentProcess(); - - // Returns true if the CommandLine has been initialized for the given process. - static bool InitializedForCurrentProcess(); - -#if defined(OS_WIN) - static CommandLine FromString(const std::wstring& command_line); -#endif - - // Initialize from an argv vector. - void InitFromArgv(int argc, const CharType* const* argv); - void InitFromArgv(const StringVector& argv); - - // Constructs and returns the represented command line string. - // CAUTION! This should be avoided on POSIX because quoting behavior is - // unclear. - StringType GetCommandLineString() const; - - // Constructs and returns the represented arguments string. - // CAUTION! This should be avoided on POSIX because quoting behavior is - // unclear. - StringType GetArgumentsString() const; - - // Returns the original command line string as a vector of strings. - const StringVector& argv() const { return argv_; } - - // Get and Set the program part of the command line string (the first item). - base::FilePath GetProgram() const; - void SetProgram(const base::FilePath& program); - - // Returns true if this command line contains the given switch. - // (Switch names are case-insensitive). - bool HasSwitch(const std::string& switch_string) const; - - // Returns the value associated with the given switch. If the switch has no - // value or isn't present, this method returns the empty string. - std::string GetSwitchValueASCII(const std::string& switch_string) const; - base::FilePath GetSwitchValuePath(const std::string& switch_string) const; - StringType GetSwitchValueNative(const std::string& switch_string) const; - - // Get a copy of all switches, along with their values. - const SwitchMap& GetSwitches() const { return switches_; } - - // Append a switch [with optional value] to the command line. - // Note: Switches will precede arguments regardless of appending order. - void AppendSwitch(const std::string& switch_string); - void AppendSwitchPath(const std::string& switch_string, - const base::FilePath& path); - void AppendSwitchNative(const std::string& switch_string, - const StringType& value); - void AppendSwitchASCII(const std::string& switch_string, - const std::string& value); - - // Copy a set of switches (and any values) from another command line. - // Commonly used when launching a subprocess. - void CopySwitchesFrom(const CommandLine& source, - const char* const switches[], - size_t count); - - // Get the remaining arguments to the command. - StringVector GetArgs() const; - - // Append an argument to the command line. Note that the argument is quoted - // properly such that it is interpreted as one argument to the target command. - // AppendArg is primarily for ASCII; non-ASCII input is interpreted as UTF-8. - // Note: Switches will precede arguments regardless of appending order. - void AppendArg(const std::string& value); - void AppendArgPath(const base::FilePath& value); - void AppendArgNative(const StringType& value); - - // Append the switches and arguments from another command line to this one. - // If |include_program| is true, include |other|'s program as well. - void AppendArguments(const CommandLine& other, bool include_program); - - // Insert a command before the current command. - // Common for debuggers, like "valgrind" or "gdb --args". - void PrependWrapper(const StringType& wrapper); - -#if defined(OS_WIN) - // Initialize by parsing the given command line string. - // The program name is assumed to be the first item in the string. - void ParseFromString(const std::wstring& command_line); -#endif - - private: - // Disallow default constructor; a program name must be explicitly specified. - CommandLine(); - // Allow the copy constructor. A common pattern is to copy of the current - // process's command line and then add some flags to it. For example: - // CommandLine cl(*CommandLine::ForCurrentProcess()); - // cl.AppendSwitch(...); - - // The singleton CommandLine representing the current process's command line. - static CommandLine* current_process_commandline_; - - // The argv array: { program, [(--|-|/)switch[=value]]*, [--], [argument]* } - StringVector argv_; - - // Parsed-out switch keys and values. - SwitchMap switches_; - - // The index after the program and switches, any arguments start here. - size_t begin_args_; -}; - -#endif // BASE_COMMAND_LINE_H_ diff --git a/base/command_line_unittest.cc b/base/command_line_unittest.cc deleted file mode 100644 index 2c947fc39a..0000000000 --- a/base/command_line_unittest.cc +++ /dev/null @@ -1,360 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include -#include - -#include "base/basictypes.h" -#include "base/command_line.h" -#include "base/files/file_path.h" -#include "base/strings/utf_string_conversions.h" -#include "testing/gtest/include/gtest/gtest.h" - -using base::FilePath; - -// To test Windows quoting behavior, we use a string that has some backslashes -// and quotes. -// Consider the command-line argument: q\"bs1\bs2\\bs3q\\\" -// Here it is with C-style escapes. -static const CommandLine::StringType kTrickyQuoted = - FILE_PATH_LITERAL("q\\\"bs1\\bs2\\\\bs3q\\\\\\\""); -// It should be parsed by Windows as: q"bs1\bs2\\bs3q\" -// Here that is with C-style escapes. -static const CommandLine::StringType kTricky = - FILE_PATH_LITERAL("q\"bs1\\bs2\\\\bs3q\\\""); - -TEST(CommandLineTest, CommandLineConstructor) { - const CommandLine::CharType* argv[] = { - FILE_PATH_LITERAL("program"), - FILE_PATH_LITERAL("--foo="), - FILE_PATH_LITERAL("-bAr"), - FILE_PATH_LITERAL("-spaetzel=pierogi"), - FILE_PATH_LITERAL("-baz"), - FILE_PATH_LITERAL("flim"), - FILE_PATH_LITERAL("--other-switches=--dog=canine --cat=feline"), - FILE_PATH_LITERAL("-spaetzle=Crepe"), - FILE_PATH_LITERAL("-=loosevalue"), - FILE_PATH_LITERAL("-"), - FILE_PATH_LITERAL("FLAN"), - FILE_PATH_LITERAL("a"), - FILE_PATH_LITERAL("--input-translation=45--output-rotation"), - FILE_PATH_LITERAL("--"), - FILE_PATH_LITERAL("--"), - FILE_PATH_LITERAL("--not-a-switch"), - FILE_PATH_LITERAL("\"in the time of submarines...\""), - FILE_PATH_LITERAL("unquoted arg-with-space")}; - CommandLine cl(arraysize(argv), argv); - - EXPECT_FALSE(cl.GetCommandLineString().empty()); - EXPECT_FALSE(cl.HasSwitch("cruller")); - EXPECT_FALSE(cl.HasSwitch("flim")); - EXPECT_FALSE(cl.HasSwitch("program")); - EXPECT_FALSE(cl.HasSwitch("dog")); - EXPECT_FALSE(cl.HasSwitch("cat")); - EXPECT_FALSE(cl.HasSwitch("output-rotation")); - EXPECT_FALSE(cl.HasSwitch("not-a-switch")); - EXPECT_FALSE(cl.HasSwitch("--")); - - EXPECT_EQ(FilePath(FILE_PATH_LITERAL("program")).value(), - cl.GetProgram().value()); - - EXPECT_TRUE(cl.HasSwitch("foo")); - EXPECT_TRUE(cl.HasSwitch("bAr")); - EXPECT_TRUE(cl.HasSwitch("baz")); - EXPECT_TRUE(cl.HasSwitch("spaetzle")); -#if defined(OS_WIN) - EXPECT_TRUE(cl.HasSwitch("SPAETZLE")); -#endif - EXPECT_TRUE(cl.HasSwitch("other-switches")); - EXPECT_TRUE(cl.HasSwitch("input-translation")); - - EXPECT_EQ("Crepe", cl.GetSwitchValueASCII("spaetzle")); - EXPECT_EQ("", cl.GetSwitchValueASCII("Foo")); - EXPECT_EQ("", cl.GetSwitchValueASCII("bar")); - EXPECT_EQ("", cl.GetSwitchValueASCII("cruller")); - EXPECT_EQ("--dog=canine --cat=feline", cl.GetSwitchValueASCII( - "other-switches")); - EXPECT_EQ("45--output-rotation", cl.GetSwitchValueASCII("input-translation")); - - const CommandLine::StringVector& args = cl.GetArgs(); - ASSERT_EQ(8U, args.size()); - - std::vector::const_iterator iter = args.begin(); - EXPECT_EQ(FILE_PATH_LITERAL("flim"), *iter); - ++iter; - EXPECT_EQ(FILE_PATH_LITERAL("-"), *iter); - ++iter; - EXPECT_EQ(FILE_PATH_LITERAL("FLAN"), *iter); - ++iter; - EXPECT_EQ(FILE_PATH_LITERAL("a"), *iter); - ++iter; - EXPECT_EQ(FILE_PATH_LITERAL("--"), *iter); - ++iter; - EXPECT_EQ(FILE_PATH_LITERAL("--not-a-switch"), *iter); - ++iter; - EXPECT_EQ(FILE_PATH_LITERAL("\"in the time of submarines...\""), *iter); - ++iter; - EXPECT_EQ(FILE_PATH_LITERAL("unquoted arg-with-space"), *iter); - ++iter; - EXPECT_TRUE(iter == args.end()); -} - -TEST(CommandLineTest, CommandLineFromString) { -#if defined(OS_WIN) - CommandLine cl = CommandLine::FromString( - L"program --foo= -bAr /Spaetzel=pierogi /Baz flim " - L"--other-switches=\"--dog=canine --cat=feline\" " - L"-spaetzle=Crepe -=loosevalue FLAN " - L"--input-translation=\"45\"--output-rotation " - L"--quotes=" + kTrickyQuoted + L" " - L"-- -- --not-a-switch " - L"\"in the time of submarines...\""); - - EXPECT_FALSE(cl.GetCommandLineString().empty()); - EXPECT_FALSE(cl.HasSwitch("cruller")); - EXPECT_FALSE(cl.HasSwitch("flim")); - EXPECT_FALSE(cl.HasSwitch("program")); - EXPECT_FALSE(cl.HasSwitch("dog")); - EXPECT_FALSE(cl.HasSwitch("cat")); - EXPECT_FALSE(cl.HasSwitch("output-rotation")); - EXPECT_FALSE(cl.HasSwitch("not-a-switch")); - EXPECT_FALSE(cl.HasSwitch("--")); - - EXPECT_EQ(FilePath(FILE_PATH_LITERAL("program")).value(), - cl.GetProgram().value()); - - EXPECT_TRUE(cl.HasSwitch("foo")); - EXPECT_TRUE(cl.HasSwitch("bar")); - EXPECT_TRUE(cl.HasSwitch("baz")); - EXPECT_TRUE(cl.HasSwitch("spaetzle")); - EXPECT_TRUE(cl.HasSwitch("SPAETZLE")); - EXPECT_TRUE(cl.HasSwitch("other-switches")); - EXPECT_TRUE(cl.HasSwitch("input-translation")); - EXPECT_TRUE(cl.HasSwitch("quotes")); - - EXPECT_EQ("Crepe", cl.GetSwitchValueASCII("spaetzle")); - EXPECT_EQ("", cl.GetSwitchValueASCII("Foo")); - EXPECT_EQ("", cl.GetSwitchValueASCII("bar")); - EXPECT_EQ("", cl.GetSwitchValueASCII("cruller")); - EXPECT_EQ("--dog=canine --cat=feline", cl.GetSwitchValueASCII( - "other-switches")); - EXPECT_EQ("45--output-rotation", cl.GetSwitchValueASCII("input-translation")); - EXPECT_EQ(kTricky, cl.GetSwitchValueNative("quotes")); - - const CommandLine::StringVector& args = cl.GetArgs(); - ASSERT_EQ(5U, args.size()); - - std::vector::const_iterator iter = args.begin(); - EXPECT_EQ(FILE_PATH_LITERAL("flim"), *iter); - ++iter; - EXPECT_EQ(FILE_PATH_LITERAL("FLAN"), *iter); - ++iter; - EXPECT_EQ(FILE_PATH_LITERAL("--"), *iter); - ++iter; - EXPECT_EQ(FILE_PATH_LITERAL("--not-a-switch"), *iter); - ++iter; - EXPECT_EQ(FILE_PATH_LITERAL("in the time of submarines..."), *iter); - ++iter; - EXPECT_TRUE(iter == args.end()); - - // Check that a generated string produces an equivalent command line. - CommandLine cl_duplicate = CommandLine::FromString(cl.GetCommandLineString()); - EXPECT_EQ(cl.GetCommandLineString(), cl_duplicate.GetCommandLineString()); -#endif -} - -// Tests behavior with an empty input string. -TEST(CommandLineTest, EmptyString) { -#if defined(OS_WIN) - CommandLine cl_from_string = CommandLine::FromString(L""); - EXPECT_TRUE(cl_from_string.GetCommandLineString().empty()); - EXPECT_TRUE(cl_from_string.GetProgram().empty()); - EXPECT_EQ(1U, cl_from_string.argv().size()); - EXPECT_TRUE(cl_from_string.GetArgs().empty()); -#endif - CommandLine cl_from_argv(0, NULL); - EXPECT_TRUE(cl_from_argv.GetCommandLineString().empty()); - EXPECT_TRUE(cl_from_argv.GetProgram().empty()); - EXPECT_EQ(1U, cl_from_argv.argv().size()); - EXPECT_TRUE(cl_from_argv.GetArgs().empty()); -} - -TEST(CommandLineTest, GetArgumentsString) { - static const FilePath::CharType kPath1[] = - FILE_PATH_LITERAL("C:\\Some File\\With Spaces.ggg"); - static const FilePath::CharType kPath2[] = - FILE_PATH_LITERAL("C:\\no\\spaces.ggg"); - - static const char kFirstArgName[] = "first-arg"; - static const char kSecondArgName[] = "arg2"; - static const char kThirdArgName[] = "arg with space"; - static const char kFourthArgName[] = "nospace"; - - CommandLine cl(CommandLine::NO_PROGRAM); - cl.AppendSwitchPath(kFirstArgName, FilePath(kPath1)); - cl.AppendSwitchPath(kSecondArgName, FilePath(kPath2)); - cl.AppendArg(kThirdArgName); - cl.AppendArg(kFourthArgName); - -#if defined(OS_WIN) - CommandLine::StringType expected_first_arg(UTF8ToUTF16(kFirstArgName)); - CommandLine::StringType expected_second_arg(UTF8ToUTF16(kSecondArgName)); - CommandLine::StringType expected_third_arg(UTF8ToUTF16(kThirdArgName)); - CommandLine::StringType expected_fourth_arg(UTF8ToUTF16(kFourthArgName)); -#elif defined(OS_POSIX) - CommandLine::StringType expected_first_arg(kFirstArgName); - CommandLine::StringType expected_second_arg(kSecondArgName); - CommandLine::StringType expected_third_arg(kThirdArgName); - CommandLine::StringType expected_fourth_arg(kFourthArgName); -#endif - -#if defined(OS_WIN) -#define QUOTE_ON_WIN FILE_PATH_LITERAL("\"") -#else -#define QUOTE_ON_WIN FILE_PATH_LITERAL("") -#endif // OS_WIN - - CommandLine::StringType expected_str; - expected_str.append(FILE_PATH_LITERAL("--")) - .append(expected_first_arg) - .append(FILE_PATH_LITERAL("=")) - .append(QUOTE_ON_WIN) - .append(kPath1) - .append(QUOTE_ON_WIN) - .append(FILE_PATH_LITERAL(" ")) - .append(FILE_PATH_LITERAL("--")) - .append(expected_second_arg) - .append(FILE_PATH_LITERAL("=")) - .append(QUOTE_ON_WIN) - .append(kPath2) - .append(QUOTE_ON_WIN) - .append(FILE_PATH_LITERAL(" ")) - .append(QUOTE_ON_WIN) - .append(expected_third_arg) - .append(QUOTE_ON_WIN) - .append(FILE_PATH_LITERAL(" ")) - .append(expected_fourth_arg); - EXPECT_EQ(expected_str, cl.GetArgumentsString()); -} - -// Test methods for appending switches to a command line. -TEST(CommandLineTest, AppendSwitches) { - std::string switch1 = "switch1"; - std::string switch2 = "switch2"; - std::string value2 = "value"; - std::string switch3 = "switch3"; - std::string value3 = "a value with spaces"; - std::string switch4 = "switch4"; - std::string value4 = "\"a value with quotes\""; - std::string switch5 = "quotes"; - CommandLine::StringType value5 = kTricky; - - CommandLine cl(FilePath(FILE_PATH_LITERAL("Program"))); - - cl.AppendSwitch(switch1); - cl.AppendSwitchASCII(switch2, value2); - cl.AppendSwitchASCII(switch3, value3); - cl.AppendSwitchASCII(switch4, value4); - cl.AppendSwitchNative(switch5, value5); - - EXPECT_TRUE(cl.HasSwitch(switch1)); - EXPECT_TRUE(cl.HasSwitch(switch2)); - EXPECT_EQ(value2, cl.GetSwitchValueASCII(switch2)); - EXPECT_TRUE(cl.HasSwitch(switch3)); - EXPECT_EQ(value3, cl.GetSwitchValueASCII(switch3)); - EXPECT_TRUE(cl.HasSwitch(switch4)); - EXPECT_EQ(value4, cl.GetSwitchValueASCII(switch4)); - EXPECT_TRUE(cl.HasSwitch(switch5)); - EXPECT_EQ(value5, cl.GetSwitchValueNative(switch5)); - -#if defined(OS_WIN) - EXPECT_EQ(L"Program " - L"--switch1 " - L"--switch2=value " - L"--switch3=\"a value with spaces\" " - L"--switch4=\"\\\"a value with quotes\\\"\" " - L"--quotes=\"" + kTrickyQuoted + L"\"", - cl.GetCommandLineString()); -#endif -} - -TEST(CommandLineTest, AppendSwitchesDashDash) { - const CommandLine::CharType* raw_argv[] = { FILE_PATH_LITERAL("prog"), - FILE_PATH_LITERAL("--"), - FILE_PATH_LITERAL("--arg1") }; - CommandLine cl(arraysize(raw_argv), raw_argv); - - cl.AppendSwitch("switch1"); - cl.AppendSwitchASCII("switch2", "foo"); - - cl.AppendArg("--arg2"); - - EXPECT_EQ(FILE_PATH_LITERAL("prog --switch1 --switch2=foo -- --arg1 --arg2"), - cl.GetCommandLineString()); - CommandLine::StringVector cl_argv = cl.argv(); - EXPECT_EQ(FILE_PATH_LITERAL("prog"), cl_argv[0]); - EXPECT_EQ(FILE_PATH_LITERAL("--switch1"), cl_argv[1]); - EXPECT_EQ(FILE_PATH_LITERAL("--switch2=foo"), cl_argv[2]); - EXPECT_EQ(FILE_PATH_LITERAL("--"), cl_argv[3]); - EXPECT_EQ(FILE_PATH_LITERAL("--arg1"), cl_argv[4]); - EXPECT_EQ(FILE_PATH_LITERAL("--arg2"), cl_argv[5]); -} - -// Tests that when AppendArguments is called that the program is set correctly -// on the target CommandLine object and the switches from the source -// CommandLine are added to the target. -TEST(CommandLineTest, AppendArguments) { - CommandLine cl1(FilePath(FILE_PATH_LITERAL("Program"))); - cl1.AppendSwitch("switch1"); - cl1.AppendSwitchASCII("switch2", "foo"); - - CommandLine cl2(CommandLine::NO_PROGRAM); - cl2.AppendArguments(cl1, true); - EXPECT_EQ(cl1.GetProgram().value(), cl2.GetProgram().value()); - EXPECT_EQ(cl1.GetCommandLineString(), cl2.GetCommandLineString()); - - CommandLine c1(FilePath(FILE_PATH_LITERAL("Program1"))); - c1.AppendSwitch("switch1"); - CommandLine c2(FilePath(FILE_PATH_LITERAL("Program2"))); - c2.AppendSwitch("switch2"); - - c1.AppendArguments(c2, true); - EXPECT_EQ(c1.GetProgram().value(), c2.GetProgram().value()); - EXPECT_TRUE(c1.HasSwitch("switch1")); - EXPECT_TRUE(c1.HasSwitch("switch2")); -} - -#if defined(OS_WIN) -// Make sure that the command line string program paths are quoted as necessary. -// This only makes sense on Windows and the test is basically here to guard -// against regressions. -TEST(CommandLineTest, ProgramQuotes) { - // Check that quotes are not added for paths without spaces. - const FilePath kProgram(L"Program"); - CommandLine cl_program(kProgram); - EXPECT_EQ(kProgram.value(), cl_program.GetProgram().value()); - EXPECT_EQ(kProgram.value(), cl_program.GetCommandLineString()); - - const FilePath kProgramPath(L"Program Path"); - - // Check that quotes are not returned from GetProgram(). - CommandLine cl_program_path(kProgramPath); - EXPECT_EQ(kProgramPath.value(), cl_program_path.GetProgram().value()); - - // Check that quotes are added to command line string paths containing spaces. - CommandLine::StringType cmd_string(cl_program_path.GetCommandLineString()); - CommandLine::StringType program_string(cl_program_path.GetProgram().value()); - EXPECT_EQ('"', cmd_string[0]); - EXPECT_EQ(program_string, cmd_string.substr(1, program_string.length())); - EXPECT_EQ('"', cmd_string[program_string.length() + 1]); -} -#endif - -// Calling Init multiple times should not modify the previous CommandLine. -TEST(CommandLineTest, Init) { - CommandLine* initial = CommandLine::ForCurrentProcess(); - EXPECT_FALSE(CommandLine::Init(0, NULL)); - CommandLine* current = CommandLine::ForCurrentProcess(); - EXPECT_EQ(initial, current); -} diff --git a/base/compiler_specific.h b/base/compiler_specific.h deleted file mode 100644 index 07b680b784..0000000000 --- a/base/compiler_specific.h +++ /dev/null @@ -1,184 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef BASE_COMPILER_SPECIFIC_H_ -#define BASE_COMPILER_SPECIFIC_H_ - -#include "build/build_config.h" - -#if defined(COMPILER_MSVC) - -// Macros for suppressing and disabling warnings on MSVC. -// -// Warning numbers are enumerated at: -// http://msdn.microsoft.com/en-us/library/8x5x43k7(VS.80).aspx -// -// The warning pragma: -// http://msdn.microsoft.com/en-us/library/2c8f766e(VS.80).aspx -// -// Using __pragma instead of #pragma inside macros: -// http://msdn.microsoft.com/en-us/library/d9x1s805.aspx - -// MSVC_SUPPRESS_WARNING disables warning |n| for the remainder of the line and -// for the next line of the source file. -#define MSVC_SUPPRESS_WARNING(n) __pragma(warning(suppress:n)) - -// MSVC_PUSH_DISABLE_WARNING pushes |n| onto a stack of warnings to be disabled. -// The warning remains disabled until popped by MSVC_POP_WARNING. -#define MSVC_PUSH_DISABLE_WARNING(n) __pragma(warning(push)) \ - __pragma(warning(disable:n)) - -// MSVC_PUSH_WARNING_LEVEL pushes |n| as the global warning level. The level -// remains in effect until popped by MSVC_POP_WARNING(). Use 0 to disable all -// warnings. -#define MSVC_PUSH_WARNING_LEVEL(n) __pragma(warning(push, n)) - -// Pop effects of innermost MSVC_PUSH_* macro. -#define MSVC_POP_WARNING() __pragma(warning(pop)) - -#define MSVC_DISABLE_OPTIMIZE() __pragma(optimize("", off)) -#define MSVC_ENABLE_OPTIMIZE() __pragma(optimize("", on)) - -// Allows exporting a class that inherits from a non-exported base class. -// This uses suppress instead of push/pop because the delimiter after the -// declaration (either "," or "{") has to be placed before the pop macro. -// -// Example usage: -// class EXPORT_API Foo : NON_EXPORTED_BASE(public Bar) { -// -// MSVC Compiler warning C4275: -// non dll-interface class 'Bar' used as base for dll-interface class 'Foo'. -// Note that this is intended to be used only when no access to the base class' -// static data is done through derived classes or inline methods. For more info, -// see http://msdn.microsoft.com/en-us/library/3tdb471s(VS.80).aspx -#define NON_EXPORTED_BASE(code) MSVC_SUPPRESS_WARNING(4275) \ - code - -#else // Not MSVC - -#define MSVC_SUPPRESS_WARNING(n) -#define MSVC_PUSH_DISABLE_WARNING(n) -#define MSVC_PUSH_WARNING_LEVEL(n) -#define MSVC_POP_WARNING() -#define MSVC_DISABLE_OPTIMIZE() -#define MSVC_ENABLE_OPTIMIZE() -#define NON_EXPORTED_BASE(code) code - -#endif // COMPILER_MSVC - - -// Annotate a variable indicating it's ok if the variable is not used. -// (Typically used to silence a compiler warning when the assignment -// is important for some other reason.) -// Use like: -// int x ALLOW_UNUSED = ...; -#if defined(COMPILER_GCC) -#define ALLOW_UNUSED __attribute__((unused)) -#else -#define ALLOW_UNUSED -#endif - -// Annotate a function indicating it should not be inlined. -// Use like: -// NOINLINE void DoStuff() { ... } -#if defined(COMPILER_GCC) -#define NOINLINE __attribute__((noinline)) -#elif defined(COMPILER_MSVC) -#define NOINLINE __declspec(noinline) -#else -#define NOINLINE -#endif - -// Specify memory alignment for structs, classes, etc. -// Use like: -// class ALIGNAS(16) MyClass { ... } -// ALIGNAS(16) int array[4]; -#if defined(COMPILER_MSVC) -#define ALIGNAS(byte_alignment) __declspec(align(byte_alignment)) -#elif defined(COMPILER_GCC) -#define ALIGNAS(byte_alignment) __attribute__((aligned(byte_alignment))) -#endif - -// Return the byte alignment of the given type (available at compile time). Use -// sizeof(type) prior to checking __alignof to workaround Visual C++ bug: -// http://goo.gl/isH0C -// Use like: -// ALIGNOF(int32) // this would be 4 -#if defined(COMPILER_MSVC) -#define ALIGNOF(type) (sizeof(type) - sizeof(type) + __alignof(type)) -#elif defined(COMPILER_GCC) -#define ALIGNOF(type) __alignof__(type) -#endif - -// Annotate a virtual method indicating it must be overriding a virtual -// method in the parent class. -// Use like: -// virtual void foo() OVERRIDE; -#if defined(COMPILER_MSVC) -#define OVERRIDE override -#elif defined(__clang__) -#define OVERRIDE override -#else -#define OVERRIDE -#endif - -// Annotate a virtual method indicating that subclasses must not override it, -// or annotate a class to indicate that it cannot be subclassed. -// Use like: -// virtual void foo() FINAL; -// class B FINAL : public A {}; -#if defined(COMPILER_MSVC) -// TODO(jered): Change this to "final" when chromium no longer uses MSVC 2010. -#define FINAL sealed -#elif defined(__clang__) -#define FINAL final -#else -#define FINAL -#endif - -// Annotate a function indicating the caller must examine the return value. -// Use like: -// int foo() WARN_UNUSED_RESULT; -// To explicitly ignore a result, see |ignore_result()| in . -#if defined(COMPILER_GCC) -#define WARN_UNUSED_RESULT __attribute__((warn_unused_result)) -#else -#define WARN_UNUSED_RESULT -#endif - -// Tell the compiler a function is using a printf-style format string. -// |format_param| is the one-based index of the format string parameter; -// |dots_param| is the one-based index of the "..." parameter. -// For v*printf functions (which take a va_list), pass 0 for dots_param. -// (This is undocumented but matches what the system C headers do.) -#if defined(COMPILER_GCC) -#define PRINTF_FORMAT(format_param, dots_param) \ - __attribute__((format(printf, format_param, dots_param))) -#else -#define PRINTF_FORMAT(format_param, dots_param) -#endif - -// WPRINTF_FORMAT is the same, but for wide format strings. -// This doesn't appear to yet be implemented in any compiler. -// See http://gcc.gnu.org/bugzilla/show_bug.cgi?id=38308 . -#define WPRINTF_FORMAT(format_param, dots_param) -// If available, it would look like: -// __attribute__((format(wprintf, format_param, dots_param))) - - -// MemorySanitizer annotations. -#ifdef MEMORY_SANITIZER -extern "C" { -void __msan_unpoison(const void *p, unsigned long s); -} // extern "C" - -// Mark a memory region fully initialized. -// Use this to annotate code that deliberately reads uninitialized data, for -// example a GC scavenging root set pointers from the stack. -#define MSAN_UNPOISON(p, s) __msan_unpoison(p, s) -#else // MEMORY_SANITIZER -#define MSAN_UNPOISON(p, s) -#endif // MEMORY_SANITIZER - -#endif // BASE_COMPILER_SPECIFIC_H_ diff --git a/base/containers/hash_tables.h b/base/containers/hash_tables.h deleted file mode 100644 index 2a2b52f9da..0000000000 --- a/base/containers/hash_tables.h +++ /dev/null @@ -1,264 +0,0 @@ -// Copyright (c) 2011 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. -// - -// -// Deal with the differences between Microsoft and GNU implemenations -// of hash_map. Allows all platforms to use |base::hash_map| and -// |base::hash_set|. -// eg: -// base::hash_map my_map; -// base::hash_set my_set; -// -// NOTE: It is an explicit non-goal of this class to provide a generic hash -// function for pointers. If you want to hash a pointers to a particular class, -// please define the template specialization elsewhere (for example, in its -// header file) and keep it specific to just pointers to that class. This is -// because identity hashes are not desirable for all types that might show up -// in containers as pointers. - -#ifndef BASE_CONTAINERS_HASH_TABLES_H_ -#define BASE_CONTAINERS_HASH_TABLES_H_ - -#include - -#include "base/basictypes.h" -#include "base/strings/string16.h" -#include "build/build_config.h" - -#if defined(COMPILER_MSVC) -#include -#include - -#define BASE_HASH_NAMESPACE stdext - -#elif defined(COMPILER_GCC) -#if defined(OS_ANDROID) -#define BASE_HASH_NAMESPACE std -#else -#define BASE_HASH_NAMESPACE __gnu_cxx -#endif - -// This is a hack to disable the gcc 4.4 warning about hash_map and hash_set -// being deprecated. We can get rid of this when we upgrade to VS2008 and we -// can use and . -#ifdef __DEPRECATED -#define CHROME_OLD__DEPRECATED __DEPRECATED -#undef __DEPRECATED -#endif - -#if defined(OS_ANDROID) -#include -#include -#else -#include -#include -#endif - -#include - -#ifdef CHROME_OLD__DEPRECATED -#define __DEPRECATED CHROME_OLD__DEPRECATED -#undef CHROME_OLD__DEPRECATED -#endif - -namespace BASE_HASH_NAMESPACE { - -#if !defined(OS_ANDROID) -// The GNU C++ library provides identity hash functions for many integral types, -// but not for |long long|. This hash function will truncate if |size_t| is -// narrower than |long long|. This is probably good enough for what we will -// use it for. - -#define DEFINE_TRIVIAL_HASH(integral_type) \ - template<> \ - struct hash { \ - std::size_t operator()(integral_type value) const { \ - return static_cast(value); \ - } \ - } - -DEFINE_TRIVIAL_HASH(long long); -DEFINE_TRIVIAL_HASH(unsigned long long); - -#undef DEFINE_TRIVIAL_HASH -#endif // !defined(OS_ANDROID) - -// Implement string hash functions so that strings of various flavors can -// be used as keys in STL maps and sets. The hash algorithm comes from the -// GNU C++ library, in . It is duplicated here because GCC -// versions prior to 4.3.2 are unable to compile when RTTI -// is disabled, as it is in our build. - -#define DEFINE_STRING_HASH(string_type) \ - template<> \ - struct hash { \ - std::size_t operator()(const string_type& s) const { \ - std::size_t result = 0; \ - for (string_type::const_iterator i = s.begin(); i != s.end(); ++i) \ - result = (result * 131) + *i; \ - return result; \ - } \ - } - -DEFINE_STRING_HASH(std::string); -DEFINE_STRING_HASH(string16); - -#undef DEFINE_STRING_HASH - -} // namespace BASE_HASH_NAMESPACE - -#else // COMPILER -#error define BASE_HASH_NAMESPACE for your compiler -#endif // COMPILER - -namespace base { -using BASE_HASH_NAMESPACE::hash_map; -using BASE_HASH_NAMESPACE::hash_multimap; -using BASE_HASH_NAMESPACE::hash_multiset; -using BASE_HASH_NAMESPACE::hash_set; - -// Implement hashing for pairs of at-most 32 bit integer values. -// When size_t is 32 bits, we turn the 64-bit hash code into 32 bits by using -// multiply-add hashing. This algorithm, as described in -// Theorem 4.3.3 of the thesis "Über die Komplexität der Multiplikation in -// eingeschränkten Branchingprogrammmodellen" by Woelfel, is: -// -// h32(x32, y32) = (h64(x32, y32) * rand_odd64 + rand16 * 2^16) % 2^64 / 2^32 -// -// Contact danakj@chromium.org for any questions. -inline std::size_t HashInts32(uint32 value1, uint32 value2) { - uint64 value1_64 = value1; - uint64 hash64 = (value1_64 << 32) | value2; - - if (sizeof(std::size_t) >= sizeof(uint64)) - return static_cast(hash64); - - uint64 odd_random = 481046412LL << 32 | 1025306955LL; - uint32 shift_random = 10121U << 16; - - hash64 = hash64 * odd_random + shift_random; - std::size_t high_bits = static_cast( - hash64 >> (sizeof(uint64) - sizeof(std::size_t))); - return high_bits; -} - -// Implement hashing for pairs of up-to 64-bit integer values. -// We use the compound integer hash method to produce a 64-bit hash code, by -// breaking the two 64-bit inputs into 4 32-bit values: -// http://opendatastructures.org/versions/edition-0.1d/ods-java/node33.html#SECTION00832000000000000000 -// Then we reduce our result to 32 bits if required, similar to above. -inline std::size_t HashInts64(uint64 value1, uint64 value2) { - uint32 short_random1 = 842304669U; - uint32 short_random2 = 619063811U; - uint32 short_random3 = 937041849U; - uint32 short_random4 = 3309708029U; - - uint32 value1a = static_cast(value1 & 0xffffffff); - uint32 value1b = static_cast((value1 >> 32) & 0xffffffff); - uint32 value2a = static_cast(value2 & 0xffffffff); - uint32 value2b = static_cast((value2 >> 32) & 0xffffffff); - - uint64 product1 = static_cast(value1a) * short_random1; - uint64 product2 = static_cast(value1b) * short_random2; - uint64 product3 = static_cast(value2a) * short_random3; - uint64 product4 = static_cast(value2b) * short_random4; - - uint64 hash64 = product1 + product2 + product3 + product4; - - if (sizeof(std::size_t) >= sizeof(uint64)) - return static_cast(hash64); - - uint64 odd_random = 1578233944LL << 32 | 194370989LL; - uint32 shift_random = 20591U << 16; - - hash64 = hash64 * odd_random + shift_random; - std::size_t high_bits = static_cast( - hash64 >> (sizeof(uint64) - sizeof(std::size_t))); - return high_bits; -} - -#define DEFINE_32BIT_PAIR_HASH(Type1, Type2) \ -inline std::size_t HashPair(Type1 value1, Type2 value2) { \ - return HashInts32(value1, value2); \ -} - -DEFINE_32BIT_PAIR_HASH(int16, int16); -DEFINE_32BIT_PAIR_HASH(int16, uint16); -DEFINE_32BIT_PAIR_HASH(int16, int32); -DEFINE_32BIT_PAIR_HASH(int16, uint32); -DEFINE_32BIT_PAIR_HASH(uint16, int16); -DEFINE_32BIT_PAIR_HASH(uint16, uint16); -DEFINE_32BIT_PAIR_HASH(uint16, int32); -DEFINE_32BIT_PAIR_HASH(uint16, uint32); -DEFINE_32BIT_PAIR_HASH(int32, int16); -DEFINE_32BIT_PAIR_HASH(int32, uint16); -DEFINE_32BIT_PAIR_HASH(int32, int32); -DEFINE_32BIT_PAIR_HASH(int32, uint32); -DEFINE_32BIT_PAIR_HASH(uint32, int16); -DEFINE_32BIT_PAIR_HASH(uint32, uint16); -DEFINE_32BIT_PAIR_HASH(uint32, int32); -DEFINE_32BIT_PAIR_HASH(uint32, uint32); - -#undef DEFINE_32BIT_PAIR_HASH - -#define DEFINE_64BIT_PAIR_HASH(Type1, Type2) \ -inline std::size_t HashPair(Type1 value1, Type2 value2) { \ - return HashInts64(value1, value2); \ -} - -DEFINE_64BIT_PAIR_HASH(int16, int64); -DEFINE_64BIT_PAIR_HASH(int16, uint64); -DEFINE_64BIT_PAIR_HASH(uint16, int64); -DEFINE_64BIT_PAIR_HASH(uint16, uint64); -DEFINE_64BIT_PAIR_HASH(int32, int64); -DEFINE_64BIT_PAIR_HASH(int32, uint64); -DEFINE_64BIT_PAIR_HASH(uint32, int64); -DEFINE_64BIT_PAIR_HASH(uint32, uint64); -DEFINE_64BIT_PAIR_HASH(int64, int16); -DEFINE_64BIT_PAIR_HASH(int64, uint16); -DEFINE_64BIT_PAIR_HASH(int64, int32); -DEFINE_64BIT_PAIR_HASH(int64, uint32); -DEFINE_64BIT_PAIR_HASH(int64, int64); -DEFINE_64BIT_PAIR_HASH(int64, uint64); -DEFINE_64BIT_PAIR_HASH(uint64, int16); -DEFINE_64BIT_PAIR_HASH(uint64, uint16); -DEFINE_64BIT_PAIR_HASH(uint64, int32); -DEFINE_64BIT_PAIR_HASH(uint64, uint32); -DEFINE_64BIT_PAIR_HASH(uint64, int64); -DEFINE_64BIT_PAIR_HASH(uint64, uint64); - -#undef DEFINE_64BIT_PAIR_HASH -} // namespace base - -namespace BASE_HASH_NAMESPACE { - -// Implement methods for hashing a pair of integers, so they can be used as -// keys in STL containers. - -#if defined(COMPILER_MSVC) - -template -inline std::size_t hash_value(const std::pair& value) { - return base::HashPair(value.first, value.second); -} - -#elif defined(COMPILER_GCC) -template -struct hash > { - std::size_t operator()(std::pair value) const { - return base::HashPair(value.first, value.second); - } -}; - -#else -#error define hash > for your compiler -#endif // COMPILER - -} - -#undef DEFINE_PAIR_HASH_FUNCTION_START -#undef DEFINE_PAIR_HASH_FUNCTION_END - -#endif // BASE_CONTAINERS_HASH_TABLES_H_ diff --git a/base/containers/hash_tables_unittest.cc b/base/containers/hash_tables_unittest.cc deleted file mode 100644 index 65724ecae2..0000000000 --- a/base/containers/hash_tables_unittest.cc +++ /dev/null @@ -1,53 +0,0 @@ -// Copyright 2013 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "base/containers/hash_tables.h" - -#include "base/basictypes.h" -#include "testing/gtest/include/gtest/gtest.h" - -namespace { - -class HashPairTest : public testing::Test { -}; - -#define INSERT_PAIR_TEST(Type, value1, value2) \ - { \ - Type pair(value1, value2); \ - base::hash_map map; \ - map[pair] = 1; \ - } - -// Verify that a hash_map can be constructed for pairs of integers of various -// sizes. -TEST_F(HashPairTest, IntegerPairs) { - typedef std::pair Int16Int16Pair; - typedef std::pair Int16Int32Pair; - typedef std::pair Int16Int64Pair; - - INSERT_PAIR_TEST(Int16Int16Pair, 4, 6); - INSERT_PAIR_TEST(Int16Int32Pair, 9, (1 << 29) + 378128932); - INSERT_PAIR_TEST(Int16Int64Pair, 10, - (GG_INT64_C(1) << 60) + GG_INT64_C(78931732321)); - - typedef std::pair Int32Int16Pair; - typedef std::pair Int32Int32Pair; - typedef std::pair Int32Int64Pair; - - INSERT_PAIR_TEST(Int32Int16Pair, 4, 6); - INSERT_PAIR_TEST(Int32Int32Pair, 9, (1 << 29) + 378128932); - INSERT_PAIR_TEST(Int32Int64Pair, 10, - (GG_INT64_C(1) << 60) + GG_INT64_C(78931732321)); - - typedef std::pair Int64Int16Pair; - typedef std::pair Int64Int32Pair; - typedef std::pair Int64Int64Pair; - - INSERT_PAIR_TEST(Int64Int16Pair, 4, 6); - INSERT_PAIR_TEST(Int64Int32Pair, 9, (1 << 29) + 378128932); - INSERT_PAIR_TEST(Int64Int64Pair, 10, - (GG_INT64_C(1) << 60) + GG_INT64_C(78931732321)); -} - -} // namespace diff --git a/base/containers/linked_list.h b/base/containers/linked_list.h deleted file mode 100644 index 25bbe762cb..0000000000 --- a/base/containers/linked_list.h +++ /dev/null @@ -1,164 +0,0 @@ -// Copyright (c) 2009 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef BASE_CONTAINERS_LINKED_LIST_H_ -#define BASE_CONTAINERS_LINKED_LIST_H_ - -// Simple LinkedList type. (See the Q&A section to understand how this -// differs from std::list). -// -// To use, start by declaring the class which will be contained in the linked -// list, as extending LinkNode (this gives it next/previous pointers). -// -// class MyNodeType : public LinkNode { -// ... -// }; -// -// Next, to keep track of the list's head/tail, use a LinkedList instance: -// -// LinkedList list; -// -// To add elements to the list, use any of LinkedList::Append, -// LinkNode::InsertBefore, or LinkNode::InsertAfter: -// -// LinkNode* n1 = ...; -// LinkNode* n2 = ...; -// LinkNode* n3 = ...; -// -// list.Append(n1); -// list.Append(n3); -// n3->InsertBefore(n3); -// -// Lastly, to iterate through the linked list forwards: -// -// for (LinkNode* node = list.head(); -// node != list.end(); -// node = node->next()) { -// MyNodeType* value = node->value(); -// ... -// } -// -// Or to iterate the linked list backwards: -// -// for (LinkNode* node = list.tail(); -// node != list.end(); -// node = node->previous()) { -// MyNodeType* value = node->value(); -// ... -// } -// -// Questions and Answers: -// -// Q. Should I use std::list or base::LinkedList? -// -// A. The main reason to use base::LinkedList over std::list is -// performance. If you don't care about the performance differences -// then use an STL container, as it makes for better code readability. -// -// Comparing the performance of base::LinkedList to std::list: -// -// * Erasing an element of type T* from base::LinkedList is -// an O(1) operation. Whereas for std::list it is O(n). -// That is because with std::list you must obtain an -// iterator to the T* element before you can call erase(iterator). -// -// * Insertion operations with base::LinkedList never require -// heap allocations. -// -// Q. How does base::LinkedList implementation differ from std::list? -// -// A. Doubly-linked lists are made up of nodes that contain "next" and -// "previous" pointers that reference other nodes in the list. -// -// With base::LinkedList, the type being inserted already reserves -// space for the "next" and "previous" pointers (base::LinkNode*). -// Whereas with std::list the type can be anything, so the implementation -// needs to glue on the "next" and "previous" pointers using -// some internal node type. - -namespace base { - -template -class LinkNode { - public: - LinkNode() : previous_(0), next_(0) {} - LinkNode(LinkNode* previous, LinkNode* next) - : previous_(previous), next_(next) {} - - // Insert |this| into the linked list, before |e|. - void InsertBefore(LinkNode* e) { - this->next_ = e; - this->previous_ = e->previous_; - e->previous_->next_ = this; - e->previous_ = this; - } - - // Insert |this| into the linked list, after |e|. - void InsertAfter(LinkNode* e) { - this->next_ = e->next_; - this->previous_ = e; - e->next_->previous_ = this; - e->next_ = this; - } - - // Remove |this| from the linked list. - void RemoveFromList() { - this->previous_->next_ = this->next_; - this->next_->previous_ = this->previous_; - } - - LinkNode* previous() const { - return previous_; - } - - LinkNode* next() const { - return next_; - } - - // Cast from the node-type to the value type. - const T* value() const { - return static_cast(this); - } - - T* value() { - return static_cast(this); - } - - private: - LinkNode* previous_; - LinkNode* next_; -}; - -template -class LinkedList { - public: - // The "root" node is self-referential, and forms the basis of a circular - // list (root_.next() will point back to the start of the list, - // and root_->previous() wraps around to the end of the list). - LinkedList() : root_(&root_, &root_) {} - - // Appends |e| to the end of the linked list. - void Append(LinkNode* e) { - e->InsertBefore(&root_); - } - - LinkNode* head() const { - return root_.next(); - } - - LinkNode* tail() const { - return root_.previous(); - } - - const LinkNode* end() const { - return &root_; - } - - private: - LinkNode root_; -}; - -} // namespace base - -#endif // BASE_CONTAINERS_LINKED_LIST_H_ diff --git a/base/containers/linked_list_unittest.cc b/base/containers/linked_list_unittest.cc deleted file mode 100644 index 801e3028a0..0000000000 --- a/base/containers/linked_list_unittest.cc +++ /dev/null @@ -1,261 +0,0 @@ -// Copyright (c) 2009 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "base/basictypes.h" -#include "base/containers/linked_list.h" -#include "testing/gtest/include/gtest/gtest.h" - -namespace base { -namespace { - -class Node : public LinkNode { - public: - explicit Node(int id) : id_(id) {} - - int id() const { return id_; } - - private: - int id_; -}; - -class MultipleInheritanceNodeBase { - public: - MultipleInheritanceNodeBase() : field_taking_up_space_(0) {} - int field_taking_up_space_; -}; - -class MultipleInheritanceNode : public MultipleInheritanceNodeBase, - public LinkNode { - public: - MultipleInheritanceNode() {} -}; - -// Checks that when iterating |list| (either from head to tail, or from -// tail to head, as determined by |forward|), we get back |node_ids|, -// which is an array of size |num_nodes|. -void ExpectListContentsForDirection(const LinkedList& list, - int num_nodes, const int* node_ids, bool forward) { - int i = 0; - for (const LinkNode* node = (forward ? list.head() : list.tail()); - node != list.end(); - node = (forward ? node->next() : node->previous())) { - ASSERT_LT(i, num_nodes); - int index_of_id = forward ? i : num_nodes - i - 1; - EXPECT_EQ(node_ids[index_of_id], node->value()->id()); - ++i; - } - EXPECT_EQ(num_nodes, i); -} - -void ExpectListContents(const LinkedList& list, - int num_nodes, - const int* node_ids) { - { - SCOPED_TRACE("Iterating forward (from head to tail)"); - ExpectListContentsForDirection(list, num_nodes, node_ids, true); - } - { - SCOPED_TRACE("Iterating backward (from tail to head)"); - ExpectListContentsForDirection(list, num_nodes, node_ids, false); - } -} - -TEST(LinkedList, Empty) { - LinkedList list; - EXPECT_EQ(list.end(), list.head()); - EXPECT_EQ(list.end(), list.tail()); - ExpectListContents(list, 0, NULL); -} - -TEST(LinkedList, Append) { - LinkedList list; - ExpectListContents(list, 0, NULL); - - Node n1(1); - list.Append(&n1); - - EXPECT_EQ(&n1, list.head()); - EXPECT_EQ(&n1, list.tail()); - { - const int expected[] = {1}; - ExpectListContents(list, arraysize(expected), expected); - } - - Node n2(2); - list.Append(&n2); - - EXPECT_EQ(&n1, list.head()); - EXPECT_EQ(&n2, list.tail()); - { - const int expected[] = {1, 2}; - ExpectListContents(list, arraysize(expected), expected); - } - - Node n3(3); - list.Append(&n3); - - EXPECT_EQ(&n1, list.head()); - EXPECT_EQ(&n3, list.tail()); - { - const int expected[] = {1, 2, 3}; - ExpectListContents(list, arraysize(expected), expected); - } -} - -TEST(LinkedList, RemoveFromList) { - LinkedList list; - - Node n1(1); - Node n2(2); - Node n3(3); - Node n4(4); - Node n5(5); - - list.Append(&n1); - list.Append(&n2); - list.Append(&n3); - list.Append(&n4); - list.Append(&n5); - - EXPECT_EQ(&n1, list.head()); - EXPECT_EQ(&n5, list.tail()); - { - const int expected[] = {1, 2, 3, 4, 5}; - ExpectListContents(list, arraysize(expected), expected); - } - - // Remove from the middle. - n3.RemoveFromList(); - - EXPECT_EQ(&n1, list.head()); - EXPECT_EQ(&n5, list.tail()); - { - const int expected[] = {1, 2, 4, 5}; - ExpectListContents(list, arraysize(expected), expected); - } - - // Remove from the tail. - n5.RemoveFromList(); - - EXPECT_EQ(&n1, list.head()); - EXPECT_EQ(&n4, list.tail()); - { - const int expected[] = {1, 2, 4}; - ExpectListContents(list, arraysize(expected), expected); - } - - // Remove from the head. - n1.RemoveFromList(); - - EXPECT_EQ(&n2, list.head()); - EXPECT_EQ(&n4, list.tail()); - { - const int expected[] = {2, 4}; - ExpectListContents(list, arraysize(expected), expected); - } - - // Empty the list. - n2.RemoveFromList(); - n4.RemoveFromList(); - - ExpectListContents(list, 0, NULL); - EXPECT_EQ(list.end(), list.head()); - EXPECT_EQ(list.end(), list.tail()); - - // Fill the list once again. - list.Append(&n1); - list.Append(&n2); - list.Append(&n3); - list.Append(&n4); - list.Append(&n5); - - EXPECT_EQ(&n1, list.head()); - EXPECT_EQ(&n5, list.tail()); - { - const int expected[] = {1, 2, 3, 4, 5}; - ExpectListContents(list, arraysize(expected), expected); - } -} - -TEST(LinkedList, InsertBefore) { - LinkedList list; - - Node n1(1); - Node n2(2); - Node n3(3); - Node n4(4); - - list.Append(&n1); - list.Append(&n2); - - EXPECT_EQ(&n1, list.head()); - EXPECT_EQ(&n2, list.tail()); - { - const int expected[] = {1, 2}; - ExpectListContents(list, arraysize(expected), expected); - } - - n3.InsertBefore(&n2); - - EXPECT_EQ(&n1, list.head()); - EXPECT_EQ(&n2, list.tail()); - { - const int expected[] = {1, 3, 2}; - ExpectListContents(list, arraysize(expected), expected); - } - - n4.InsertBefore(&n1); - - EXPECT_EQ(&n4, list.head()); - EXPECT_EQ(&n2, list.tail()); - { - const int expected[] = {4, 1, 3, 2}; - ExpectListContents(list, arraysize(expected), expected); - } -} - -TEST(LinkedList, InsertAfter) { - LinkedList list; - - Node n1(1); - Node n2(2); - Node n3(3); - Node n4(4); - - list.Append(&n1); - list.Append(&n2); - - EXPECT_EQ(&n1, list.head()); - EXPECT_EQ(&n2, list.tail()); - { - const int expected[] = {1, 2}; - ExpectListContents(list, arraysize(expected), expected); - } - - n3.InsertAfter(&n2); - - EXPECT_EQ(&n1, list.head()); - EXPECT_EQ(&n3, list.tail()); - { - const int expected[] = {1, 2, 3}; - ExpectListContents(list, arraysize(expected), expected); - } - - n4.InsertAfter(&n1); - - EXPECT_EQ(&n1, list.head()); - EXPECT_EQ(&n3, list.tail()); - { - const int expected[] = {1, 4, 2, 3}; - ExpectListContents(list, arraysize(expected), expected); - } -} - -TEST(LinkedList, MultipleInheritanceNode) { - MultipleInheritanceNode node; - EXPECT_EQ(&node, node.value()); -} - -} // namespace -} // namespace base diff --git a/base/containers/mru_cache.h b/base/containers/mru_cache.h deleted file mode 100644 index e59e909839..0000000000 --- a/base/containers/mru_cache.h +++ /dev/null @@ -1,305 +0,0 @@ -// Copyright (c) 2011 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -// This file contains a template for a Most Recently Used cache that allows -// constant-time access to items using a key, but easy identification of the -// least-recently-used items for removal. Each key can only be associated with -// one payload item at a time. -// -// The key object will be stored twice, so it should support efficient copying. -// -// NOTE: While all operations are O(1), this code is written for -// legibility rather than optimality. If future profiling identifies this as -// a bottleneck, there is room for smaller values of 1 in the O(1). :] - -#ifndef BASE_CONTAINERS_MRU_CACHE_H_ -#define BASE_CONTAINERS_MRU_CACHE_H_ - -#include -#include -#include - -#include "base/basictypes.h" -#include "base/containers/hash_tables.h" -#include "base/logging.h" - -namespace base { - -// MRUCacheBase ---------------------------------------------------------------- - -// This template is used to standardize map type containers that can be used -// by MRUCacheBase. This level of indirection is necessary because of the way -// that template template params and default template params interact. -template -struct MRUCacheStandardMap { - typedef std::map Type; -}; - -// Base class for the MRU cache specializations defined below. -// The deletor will get called on all payloads that are being removed or -// replaced. -template class MapType = MRUCacheStandardMap> -class MRUCacheBase { - public: - // The payload of the list. This maintains a copy of the key so we can - // efficiently delete things given an element of the list. - typedef std::pair value_type; - - private: - typedef std::list PayloadList; - typedef typename MapType::Type KeyIndex; - - public: - typedef typename PayloadList::size_type size_type; - - typedef typename PayloadList::iterator iterator; - typedef typename PayloadList::const_iterator const_iterator; - typedef typename PayloadList::reverse_iterator reverse_iterator; - typedef typename PayloadList::const_reverse_iterator const_reverse_iterator; - - enum { NO_AUTO_EVICT = 0 }; - - // The max_size is the size at which the cache will prune its members to when - // a new item is inserted. If the caller wants to manager this itself (for - // example, maybe it has special work to do when something is evicted), it - // can pass NO_AUTO_EVICT to not restrict the cache size. - explicit MRUCacheBase(size_type max_size) : max_size_(max_size) { - } - - MRUCacheBase(size_type max_size, const DeletorType& deletor) - : max_size_(max_size), deletor_(deletor) { - } - - virtual ~MRUCacheBase() { - iterator i = begin(); - while (i != end()) - i = Erase(i); - } - - size_type max_size() const { return max_size_; } - - // Inserts a payload item with the given key. If an existing item has - // the same key, it is removed prior to insertion. An iterator indicating the - // inserted item will be returned (this will always be the front of the list). - // - // The payload will be copied. In the case of an OwningMRUCache, this function - // will take ownership of the pointer. - iterator Put(const KeyType& key, const PayloadType& payload) { - // Remove any existing payload with that key. - typename KeyIndex::iterator index_iter = index_.find(key); - if (index_iter != index_.end()) { - // Erase the reference to it. This will call the deletor on the removed - // element. The index reference will be replaced in the code below. - Erase(index_iter->second); - } else if (max_size_ != NO_AUTO_EVICT) { - // New item is being inserted which might make it larger than the maximum - // size: kick the oldest thing out if necessary. - ShrinkToSize(max_size_ - 1); - } - - ordering_.push_front(value_type(key, payload)); - index_.insert(std::make_pair(key, ordering_.begin())); - return ordering_.begin(); - } - - // Retrieves the contents of the given key, or end() if not found. This method - // has the side effect of moving the requested item to the front of the - // recency list. - // - // TODO(brettw) We may want a const version of this function in the future. - iterator Get(const KeyType& key) { - typename KeyIndex::iterator index_iter = index_.find(key); - if (index_iter == index_.end()) - return end(); - typename PayloadList::iterator iter = index_iter->second; - - // Move the touched item to the front of the recency ordering. - ordering_.splice(ordering_.begin(), ordering_, iter); - return ordering_.begin(); - } - - // Retrieves the payload associated with a given key and returns it via - // result without affecting the ordering (unlike Get). - // - // TODO(brettw) We may want a const version of this function in the future. - iterator Peek(const KeyType& key) { - typename KeyIndex::const_iterator index_iter = index_.find(key); - if (index_iter == index_.end()) - return end(); - return index_iter->second; - } - - // Erases the item referenced by the given iterator. An iterator to the item - // following it will be returned. The iterator must be valid. - iterator Erase(iterator pos) { - deletor_(pos->second); - index_.erase(pos->first); - return ordering_.erase(pos); - } - - // MRUCache entries are often processed in reverse order, so we add this - // convenience function (not typically defined by STL containers). - reverse_iterator Erase(reverse_iterator pos) { - // We have to actually give it the incremented iterator to delete, since - // the forward iterator that base() returns is actually one past the item - // being iterated over. - return reverse_iterator(Erase((++pos).base())); - } - - // Shrinks the cache so it only holds |new_size| items. If |new_size| is - // bigger or equal to the current number of items, this will do nothing. - void ShrinkToSize(size_type new_size) { - for (size_type i = size(); i > new_size; i--) - Erase(rbegin()); - } - - // Deletes everything from the cache. - void Clear() { - for (typename PayloadList::iterator i(ordering_.begin()); - i != ordering_.end(); ++i) - deletor_(i->second); - index_.clear(); - ordering_.clear(); - } - - // Returns the number of elements in the cache. - size_type size() const { - // We don't use ordering_.size() for the return value because - // (as a linked list) it can be O(n). - DCHECK(index_.size() == ordering_.size()); - return index_.size(); - } - - // Allows iteration over the list. Forward iteration starts with the most - // recent item and works backwards. - // - // Note that since these iterators are actually iterators over a list, you - // can keep them as you insert or delete things (as long as you don't delete - // the one you are pointing to) and they will still be valid. - iterator begin() { return ordering_.begin(); } - const_iterator begin() const { return ordering_.begin(); } - iterator end() { return ordering_.end(); } - const_iterator end() const { return ordering_.end(); } - - reverse_iterator rbegin() { return ordering_.rbegin(); } - const_reverse_iterator rbegin() const { return ordering_.rbegin(); } - reverse_iterator rend() { return ordering_.rend(); } - const_reverse_iterator rend() const { return ordering_.rend(); } - - bool empty() const { return ordering_.empty(); } - - private: - PayloadList ordering_; - KeyIndex index_; - - size_type max_size_; - - DeletorType deletor_; - - DISALLOW_COPY_AND_ASSIGN(MRUCacheBase); -}; - -// MRUCache -------------------------------------------------------------------- - -// A functor that does nothing. Used by the MRUCache. -template -class MRUCacheNullDeletor { - public: - void operator()(PayloadType& payload) { - } -}; - -// A container that does not do anything to free its data. Use this when storing -// value types (as opposed to pointers) in the list. -template -class MRUCache : public MRUCacheBase > { - private: - typedef MRUCacheBase > ParentType; - - public: - // See MRUCacheBase, noting the possibility of using NO_AUTO_EVICT. - explicit MRUCache(typename ParentType::size_type max_size) - : ParentType(max_size) { - } - virtual ~MRUCache() { - } - - private: - DISALLOW_COPY_AND_ASSIGN(MRUCache); -}; - -// OwningMRUCache -------------------------------------------------------------- - -template -class MRUCachePointerDeletor { - public: - void operator()(PayloadType& payload) { - delete payload; - } -}; - -// A cache that owns the payload type, which must be a non-const pointer type. -// The pointers will be deleted when they are removed, replaced, or when the -// cache is destroyed. -template -class OwningMRUCache - : public MRUCacheBase > { - private: - typedef MRUCacheBase > ParentType; - - public: - // See MRUCacheBase, noting the possibility of using NO_AUTO_EVICT. - explicit OwningMRUCache(typename ParentType::size_type max_size) - : ParentType(max_size) { - } - virtual ~OwningMRUCache() { - } - - private: - DISALLOW_COPY_AND_ASSIGN(OwningMRUCache); -}; - -// HashingMRUCache ------------------------------------------------------------ - -template -struct MRUCacheHashMap { - typedef base::hash_map Type; -}; - -// This class is similar to MRUCache, except that it uses base::hash_map as -// the map type instead of std::map. Note that your KeyType must be hashable -// to use this cache. -template -class HashingMRUCache : public MRUCacheBase, - MRUCacheHashMap> { - private: - typedef MRUCacheBase, - MRUCacheHashMap> ParentType; - - public: - // See MRUCacheBase, noting the possibility of using NO_AUTO_EVICT. - explicit HashingMRUCache(typename ParentType::size_type max_size) - : ParentType(max_size) { - } - virtual ~HashingMRUCache() { - } - - private: - DISALLOW_COPY_AND_ASSIGN(HashingMRUCache); -}; - -} // namespace base - -#endif // BASE_CONTAINERS_MRU_CACHE_H_ diff --git a/base/containers/mru_cache_unittest.cc b/base/containers/mru_cache_unittest.cc deleted file mode 100644 index a8e893213c..0000000000 --- a/base/containers/mru_cache_unittest.cc +++ /dev/null @@ -1,271 +0,0 @@ -// Copyright (c) 2011 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "base/basictypes.h" -#include "base/containers/mru_cache.h" -#include "testing/gtest/include/gtest/gtest.h" - -namespace { - -int cached_item_live_count = 0; - -struct CachedItem { - CachedItem() : value(0) { - cached_item_live_count++; - } - - explicit CachedItem(int new_value) : value(new_value) { - cached_item_live_count++; - } - - explicit CachedItem(const CachedItem& other) : value(other.value) { - cached_item_live_count++; - } - - ~CachedItem() { - cached_item_live_count--; - } - - int value; -}; - -} // namespace - -TEST(MRUCacheTest, Basic) { - typedef base::MRUCache Cache; - Cache cache(Cache::NO_AUTO_EVICT); - - // Check failure conditions - { - CachedItem test_item; - EXPECT_TRUE(cache.Get(0) == cache.end()); - EXPECT_TRUE(cache.Peek(0) == cache.end()); - } - - static const int kItem1Key = 5; - CachedItem item1(10); - Cache::iterator inserted_item = cache.Put(kItem1Key, item1); - EXPECT_EQ(1U, cache.size()); - - // Check that item1 was properly inserted. - { - Cache::iterator found = cache.Get(kItem1Key); - EXPECT_TRUE(inserted_item == cache.begin()); - EXPECT_TRUE(found != cache.end()); - - found = cache.Peek(kItem1Key); - EXPECT_TRUE(found != cache.end()); - - EXPECT_EQ(kItem1Key, found->first); - EXPECT_EQ(item1.value, found->second.value); - } - - static const int kItem2Key = 7; - CachedItem item2(12); - cache.Put(kItem2Key, item2); - EXPECT_EQ(2U, cache.size()); - - // Check that item1 is the oldest since item2 was added afterwards. - { - Cache::reverse_iterator oldest = cache.rbegin(); - ASSERT_TRUE(oldest != cache.rend()); - EXPECT_EQ(kItem1Key, oldest->first); - EXPECT_EQ(item1.value, oldest->second.value); - } - - // Check that item1 is still accessible by key. - { - Cache::iterator test_item = cache.Get(kItem1Key); - ASSERT_TRUE(test_item != cache.end()); - EXPECT_EQ(kItem1Key, test_item->first); - EXPECT_EQ(item1.value, test_item->second.value); - } - - // Check that retrieving item1 pushed item2 to oldest. - { - Cache::reverse_iterator oldest = cache.rbegin(); - ASSERT_TRUE(oldest != cache.rend()); - EXPECT_EQ(kItem2Key, oldest->first); - EXPECT_EQ(item2.value, oldest->second.value); - } - - // Remove the oldest item and check that item1 is now the only member. - { - Cache::reverse_iterator next = cache.Erase(cache.rbegin()); - - EXPECT_EQ(1U, cache.size()); - - EXPECT_TRUE(next == cache.rbegin()); - EXPECT_EQ(kItem1Key, next->first); - EXPECT_EQ(item1.value, next->second.value); - - cache.Erase(cache.begin()); - EXPECT_EQ(0U, cache.size()); - } - - // Check that Clear() works properly. - cache.Put(kItem1Key, item1); - cache.Put(kItem2Key, item2); - EXPECT_EQ(2U, cache.size()); - cache.Clear(); - EXPECT_EQ(0U, cache.size()); -} - -TEST(MRUCacheTest, GetVsPeek) { - typedef base::MRUCache Cache; - Cache cache(Cache::NO_AUTO_EVICT); - - static const int kItem1Key = 1; - CachedItem item1(10); - cache.Put(kItem1Key, item1); - - static const int kItem2Key = 2; - CachedItem item2(20); - cache.Put(kItem2Key, item2); - - // This should do nothing since the size is bigger than the number of items. - cache.ShrinkToSize(100); - - // Check that item1 starts out as oldest - { - Cache::reverse_iterator iter = cache.rbegin(); - ASSERT_TRUE(iter != cache.rend()); - EXPECT_EQ(kItem1Key, iter->first); - EXPECT_EQ(item1.value, iter->second.value); - } - - // Check that Peek doesn't change ordering - { - Cache::iterator peekiter = cache.Peek(kItem1Key); - ASSERT_TRUE(peekiter != cache.end()); - - Cache::reverse_iterator iter = cache.rbegin(); - ASSERT_TRUE(iter != cache.rend()); - EXPECT_EQ(kItem1Key, iter->first); - EXPECT_EQ(item1.value, iter->second.value); - } -} - -TEST(MRUCacheTest, KeyReplacement) { - typedef base::MRUCache Cache; - Cache cache(Cache::NO_AUTO_EVICT); - - static const int kItem1Key = 1; - CachedItem item1(10); - cache.Put(kItem1Key, item1); - - static const int kItem2Key = 2; - CachedItem item2(20); - cache.Put(kItem2Key, item2); - - static const int kItem3Key = 3; - CachedItem item3(30); - cache.Put(kItem3Key, item3); - - static const int kItem4Key = 4; - CachedItem item4(40); - cache.Put(kItem4Key, item4); - - CachedItem item5(50); - cache.Put(kItem3Key, item5); - - EXPECT_EQ(4U, cache.size()); - for (int i = 0; i < 3; ++i) { - Cache::reverse_iterator iter = cache.rbegin(); - ASSERT_TRUE(iter != cache.rend()); - } - - // Make it so only the most important element is there. - cache.ShrinkToSize(1); - - Cache::iterator iter = cache.begin(); - EXPECT_EQ(kItem3Key, iter->first); - EXPECT_EQ(item5.value, iter->second.value); -} - -// Make sure that the owning version release its pointers properly. -TEST(MRUCacheTest, Owning) { - typedef base::OwningMRUCache Cache; - Cache cache(Cache::NO_AUTO_EVICT); - - int initial_count = cached_item_live_count; - - // First insert and item and then overwrite it. - static const int kItem1Key = 1; - cache.Put(kItem1Key, new CachedItem(20)); - cache.Put(kItem1Key, new CachedItem(22)); - - // There should still be one item, and one extra live item. - Cache::iterator iter = cache.Get(kItem1Key); - EXPECT_EQ(1U, cache.size()); - EXPECT_TRUE(iter != cache.end()); - EXPECT_EQ(initial_count + 1, cached_item_live_count); - - // Now remove it. - cache.Erase(cache.begin()); - EXPECT_EQ(initial_count, cached_item_live_count); - - // Now try another cache that goes out of scope to make sure its pointers - // go away. - { - Cache cache2(Cache::NO_AUTO_EVICT); - cache2.Put(1, new CachedItem(20)); - cache2.Put(2, new CachedItem(20)); - } - - // There should be no objects leaked. - EXPECT_EQ(initial_count, cached_item_live_count); - - // Check that Clear() also frees things correctly. - { - Cache cache2(Cache::NO_AUTO_EVICT); - cache2.Put(1, new CachedItem(20)); - cache2.Put(2, new CachedItem(20)); - EXPECT_EQ(initial_count + 2, cached_item_live_count); - cache2.Clear(); - EXPECT_EQ(initial_count, cached_item_live_count); - } -} - -TEST(MRUCacheTest, AutoEvict) { - typedef base::OwningMRUCache Cache; - static const Cache::size_type kMaxSize = 3; - - int initial_count = cached_item_live_count; - - { - Cache cache(kMaxSize); - - static const int kItem1Key = 1, kItem2Key = 2, kItem3Key = 3, kItem4Key = 4; - cache.Put(kItem1Key, new CachedItem(20)); - cache.Put(kItem2Key, new CachedItem(21)); - cache.Put(kItem3Key, new CachedItem(22)); - cache.Put(kItem4Key, new CachedItem(23)); - - // The cache should only have kMaxSize items in it even though we inserted - // more. - EXPECT_EQ(kMaxSize, cache.size()); - } - - // There should be no objects leaked. - EXPECT_EQ(initial_count, cached_item_live_count); -} - -TEST(MRUCacheTest, HashingMRUCache) { - // Very simple test to make sure that the hashing cache works correctly. - typedef base::HashingMRUCache Cache; - Cache cache(Cache::NO_AUTO_EVICT); - - CachedItem one(1); - cache.Put("First", one); - - CachedItem two(2); - cache.Put("Second", two); - - EXPECT_EQ(one.value, cache.Get("First")->second.value); - EXPECT_EQ(two.value, cache.Get("Second")->second.value); - cache.ShrinkToSize(1); - EXPECT_EQ(two.value, cache.Get("Second")->second.value); - EXPECT_TRUE(cache.Get("First") == cache.end()); -} diff --git a/base/containers/small_map.h b/base/containers/small_map.h deleted file mode 100644 index df3d22ae9a..0000000000 --- a/base/containers/small_map.h +++ /dev/null @@ -1,652 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef BASE_CONTAINERS_SMALL_MAP_H_ -#define BASE_CONTAINERS_SMALL_MAP_H_ - -#include -#include -#include - -#include "base/basictypes.h" -#include "base/containers/hash_tables.h" -#include "base/logging.h" -#include "base/memory/manual_constructor.h" - -namespace base { - -// An STL-like associative container which starts out backed by a simple -// array but switches to some other container type if it grows beyond a -// fixed size. -// -// WHAT TYPE OF MAP SHOULD YOU USE? -// -------------------------------- -// -// - std::map should be the default if you're not sure, since it's the most -// difficult to mess up. Generally this is backed by a red-black tree. It -// will generate a lot of code (if you use a common key type like int or -// string the linker will probably emiminate the duplicates). It will -// do heap allocations for each element. -// -// - If you only ever keep a couple of items and have very simple usage, -// consider whether a using a vector and brute-force searching it will be -// the most efficient. It's not a lot of generated code (less then a -// red-black tree if your key is "weird" and not eliminated as duplicate of -// something else) and will probably be faster and do fewer heap allocations -// than std::map if you have just a couple of items. -// -// - base::hash_map should be used if you need O(1) lookups. It may waste -// space in the hash table, and it can be easy to write correct-looking -// code with the default hash function being wrong or poorly-behaving. -// -// - SmallMap combines the performance benefits of the brute-force-searched -// vector for small cases (no extra heap allocations), but can efficiently -// fall back if you end up adding many items. It will generate more code -// than std::map (at least 160 bytes for operator[]) which is bad if you -// have a "weird" key where map functions can't be -// duplicate-code-eliminated. If you have a one-off key and aren't in -// performance-critical code, this bloat may negate some of the benefits and -// you should consider on of the other options. -// -// SmallMap will pick up the comparator from the underlying map type. In -// std::map (and in MSVC additionally hash_map) only a "less" operator is -// defined, which requires us to do two comparisons per element when doing the -// brute-force search in the simple array. -// -// We define default overrides for the common map types to avoid this -// double-compare, but you should be aware of this if you use your own -// operator< for your map and supply yor own version of == to the SmallMap. -// You can use regular operator== by just doing: -// -// base::SmallMap, 4, std::equal_to > -// -// -// USAGE -// ----- -// -// NormalMap: The map type to fall back to. This also defines the key -// and value types for the SmallMap. -// kArraySize: The size of the initial array of results. This will be -// allocated with the SmallMap object rather than separately on -// the heap. Once the map grows beyond this size, the map type -// will be used instead. -// EqualKey: A functor which tests two keys for equality. If the wrapped -// map type has a "key_equal" member (hash_map does), then that will -// be used by default. If the wrapped map type has a strict weak -// ordering "key_compare" (std::map does), that will be used to -// implement equality by default. -// MapInit: A functor that takes a ManualConstructor* and uses it to -// initialize the map. This functor will be called at most once per -// SmallMap, when the map exceeds the threshold of kArraySize and we -// are about to copy values from the array to the map. The functor -// *must* call one of the Init() methods provided by -// ManualConstructor, since after it runs we assume that the NormalMap -// has been initialized. -// -// example: -// base::SmallMap< std::map > days; -// days["sunday" ] = 0; -// days["monday" ] = 1; -// days["tuesday" ] = 2; -// days["wednesday"] = 3; -// days["thursday" ] = 4; -// days["friday" ] = 5; -// days["saturday" ] = 6; -// -// You should assume that SmallMap might invalidate all the iterators -// on any call to erase(), insert() and operator[]. - -namespace internal { - -template -class SmallMapDefaultInit { - public: - void operator()(ManualConstructor* map) const { - map->Init(); - } -}; - -// has_key_equal::value is true iff there exists a type M::key_equal. This is -// used to dispatch to one of the select_equal_key<> metafunctions below. -template -struct has_key_equal { - typedef char sml; // "small" is sometimes #defined so we use an abbreviation. - typedef struct { char dummy[2]; } big; - // Two functions, one accepts types that have a key_equal member, and one that - // accepts anything. They each return a value of a different size, so we can - // determine at compile-time which function would have been called. - template static big test(typename U::key_equal*); - template static sml test(...); - // Determines if M::key_equal exists by looking at the size of the return - // type of the compiler-chosen test() function. - static const bool value = (sizeof(test(0)) == sizeof(big)); -}; -template const bool has_key_equal::value; - -// Base template used for map types that do NOT have an M::key_equal member, -// e.g., std::map<>. These maps have a strict weak ordering comparator rather -// than an equality functor, so equality will be implemented in terms of that -// comparator. -// -// There's a partial specialization of this template below for map types that do -// have an M::key_equal member. -template -struct select_equal_key { - struct equal_key { - bool operator()(const typename M::key_type& left, - const typename M::key_type& right) { - // Implements equality in terms of a strict weak ordering comparator. - typename M::key_compare comp; - return !comp(left, right) && !comp(right, left); - } - }; -}; - -// Provide overrides to use operator== for key compare for the "normal" map and -// hash map types. If you override the default comparator or allocator for a -// map or hash_map, or use another type of map, this won't get used. -// -// If we switch to using std::unordered_map for base::hash_map, then the -// hash_map specialization can be removed. -template -struct select_equal_key< std::map, false> { - struct equal_key { - bool operator()(const KeyType& left, const KeyType& right) { - return left == right; - } - }; -}; -template -struct select_equal_key< base::hash_map, false> { - struct equal_key { - bool operator()(const KeyType& left, const KeyType& right) { - return left == right; - } - }; -}; - -// Partial template specialization handles case where M::key_equal exists, e.g., -// hash_map<>. -template -struct select_equal_key { - typedef typename M::key_equal equal_key; -}; - -} // namespace internal - -template ::value>::equal_key, - typename MapInit = internal::SmallMapDefaultInit > -class SmallMap { - // We cannot rely on the compiler to reject array of size 0. In - // particular, gcc 2.95.3 does it but later versions allow 0-length - // arrays. Therefore, we explicitly reject non-positive kArraySize - // here. - COMPILE_ASSERT(kArraySize > 0, default_initial_size_should_be_positive); - - public: - typedef typename NormalMap::key_type key_type; - typedef typename NormalMap::mapped_type data_type; - typedef typename NormalMap::mapped_type mapped_type; - typedef typename NormalMap::value_type value_type; - typedef EqualKey key_equal; - - SmallMap() : size_(0), functor_(MapInit()) {} - - explicit SmallMap(const MapInit& functor) : size_(0), functor_(functor) {} - - // Allow copy-constructor and assignment, since STL allows them too. - SmallMap(const SmallMap& src) { - // size_ and functor_ are initted in InitFrom() - InitFrom(src); - } - void operator=(const SmallMap& src) { - if (&src == this) return; - - // This is not optimal. If src and dest are both using the small - // array, we could skip the teardown and reconstruct. One problem - // to be resolved is that the value_type itself is pair, and const K is not assignable. - Destroy(); - InitFrom(src); - } - ~SmallMap() { - Destroy(); - } - - class const_iterator; - - class iterator { - public: - typedef typename NormalMap::iterator::iterator_category iterator_category; - typedef typename NormalMap::iterator::value_type value_type; - typedef typename NormalMap::iterator::difference_type difference_type; - typedef typename NormalMap::iterator::pointer pointer; - typedef typename NormalMap::iterator::reference reference; - - inline iterator(): array_iter_(NULL) {} - - inline iterator& operator++() { - if (array_iter_ != NULL) { - ++array_iter_; - } else { - ++hash_iter_; - } - return *this; - } - inline iterator operator++(int /*unused*/) { - iterator result(*this); - ++(*this); - return result; - } - inline iterator& operator--() { - if (array_iter_ != NULL) { - --array_iter_; - } else { - --hash_iter_; - } - return *this; - } - inline iterator operator--(int /*unused*/) { - iterator result(*this); - --(*this); - return result; - } - inline value_type* operator->() const { - if (array_iter_ != NULL) { - return array_iter_->get(); - } else { - return hash_iter_.operator->(); - } - } - - inline value_type& operator*() const { - if (array_iter_ != NULL) { - return *array_iter_->get(); - } else { - return *hash_iter_; - } - } - - inline bool operator==(const iterator& other) const { - if (array_iter_ != NULL) { - return array_iter_ == other.array_iter_; - } else { - return other.array_iter_ == NULL && hash_iter_ == other.hash_iter_; - } - } - - inline bool operator!=(const iterator& other) const { - return !(*this == other); - } - - bool operator==(const const_iterator& other) const; - bool operator!=(const const_iterator& other) const; - - private: - friend class SmallMap; - friend class const_iterator; - inline explicit iterator(ManualConstructor* init) - : array_iter_(init) {} - inline explicit iterator(const typename NormalMap::iterator& init) - : array_iter_(NULL), hash_iter_(init) {} - - ManualConstructor* array_iter_; - typename NormalMap::iterator hash_iter_; - }; - - class const_iterator { - public: - typedef typename NormalMap::const_iterator::iterator_category - iterator_category; - typedef typename NormalMap::const_iterator::value_type value_type; - typedef typename NormalMap::const_iterator::difference_type difference_type; - typedef typename NormalMap::const_iterator::pointer pointer; - typedef typename NormalMap::const_iterator::reference reference; - - inline const_iterator(): array_iter_(NULL) {} - // Non-explicit ctor lets us convert regular iterators to const iterators - inline const_iterator(const iterator& other) - : array_iter_(other.array_iter_), hash_iter_(other.hash_iter_) {} - - inline const_iterator& operator++() { - if (array_iter_ != NULL) { - ++array_iter_; - } else { - ++hash_iter_; - } - return *this; - } - inline const_iterator operator++(int /*unused*/) { - const_iterator result(*this); - ++(*this); - return result; - } - - inline const_iterator& operator--() { - if (array_iter_ != NULL) { - --array_iter_; - } else { - --hash_iter_; - } - return *this; - } - inline const_iterator operator--(int /*unused*/) { - const_iterator result(*this); - --(*this); - return result; - } - - inline const value_type* operator->() const { - if (array_iter_ != NULL) { - return array_iter_->get(); - } else { - return hash_iter_.operator->(); - } - } - - inline const value_type& operator*() const { - if (array_iter_ != NULL) { - return *array_iter_->get(); - } else { - return *hash_iter_; - } - } - - inline bool operator==(const const_iterator& other) const { - if (array_iter_ != NULL) { - return array_iter_ == other.array_iter_; - } else { - return other.array_iter_ == NULL && hash_iter_ == other.hash_iter_; - } - } - - inline bool operator!=(const const_iterator& other) const { - return !(*this == other); - } - - private: - friend class SmallMap; - inline explicit const_iterator( - const ManualConstructor* init) - : array_iter_(init) {} - inline explicit const_iterator( - const typename NormalMap::const_iterator& init) - : array_iter_(NULL), hash_iter_(init) {} - - const ManualConstructor* array_iter_; - typename NormalMap::const_iterator hash_iter_; - }; - - iterator find(const key_type& key) { - key_equal compare; - if (size_ >= 0) { - for (int i = 0; i < size_; i++) { - if (compare(array_[i]->first, key)) { - return iterator(array_ + i); - } - } - return iterator(array_ + size_); - } else { - return iterator(map()->find(key)); - } - } - - const_iterator find(const key_type& key) const { - key_equal compare; - if (size_ >= 0) { - for (int i = 0; i < size_; i++) { - if (compare(array_[i]->first, key)) { - return const_iterator(array_ + i); - } - } - return const_iterator(array_ + size_); - } else { - return const_iterator(map()->find(key)); - } - } - - // Invalidates iterators. - data_type& operator[](const key_type& key) { - key_equal compare; - - if (size_ >= 0) { - // operator[] searches backwards, favoring recently-added - // elements. - for (int i = size_-1; i >= 0; --i) { - if (compare(array_[i]->first, key)) { - return array_[i]->second; - } - } - if (size_ == kArraySize) { - ConvertToRealMap(); - return (*map_)[key]; - } else { - array_[size_].Init(key, data_type()); - return array_[size_++]->second; - } - } else { - return (*map_)[key]; - } - } - - // Invalidates iterators. - std::pair insert(const value_type& x) { - key_equal compare; - - if (size_ >= 0) { - for (int i = 0; i < size_; i++) { - if (compare(array_[i]->first, x.first)) { - return std::make_pair(iterator(array_ + i), false); - } - } - if (size_ == kArraySize) { - ConvertToRealMap(); // Invalidates all iterators! - std::pair ret = map_->insert(x); - return std::make_pair(iterator(ret.first), ret.second); - } else { - array_[size_].Init(x); - return std::make_pair(iterator(array_ + size_++), true); - } - } else { - std::pair ret = map_->insert(x); - return std::make_pair(iterator(ret.first), ret.second); - } - } - - // Invalidates iterators. - template - void insert(InputIterator f, InputIterator l) { - while (f != l) { - insert(*f); - ++f; - } - } - - iterator begin() { - if (size_ >= 0) { - return iterator(array_); - } else { - return iterator(map_->begin()); - } - } - const_iterator begin() const { - if (size_ >= 0) { - return const_iterator(array_); - } else { - return const_iterator(map_->begin()); - } - } - - iterator end() { - if (size_ >= 0) { - return iterator(array_ + size_); - } else { - return iterator(map_->end()); - } - } - const_iterator end() const { - if (size_ >= 0) { - return const_iterator(array_ + size_); - } else { - return const_iterator(map_->end()); - } - } - - void clear() { - if (size_ >= 0) { - for (int i = 0; i < size_; i++) { - array_[i].Destroy(); - } - } else { - map_.Destroy(); - } - size_ = 0; - } - - // Invalidates iterators. - void erase(const iterator& position) { - if (size_ >= 0) { - int i = position.array_iter_ - array_; - array_[i].Destroy(); - --size_; - if (i != size_) { - array_[i].Init(*array_[size_]); - array_[size_].Destroy(); - } - } else { - map_->erase(position.hash_iter_); - } - } - - size_t erase(const key_type& key) { - iterator iter = find(key); - if (iter == end()) return 0u; - erase(iter); - return 1u; - } - - size_t count(const key_type& key) const { - return (find(key) == end()) ? 0 : 1; - } - - size_t size() const { - if (size_ >= 0) { - return static_cast(size_); - } else { - return map_->size(); - } - } - - bool empty() const { - if (size_ >= 0) { - return (size_ == 0); - } else { - return map_->empty(); - } - } - - // Returns true if we have fallen back to using the underlying map - // representation. - bool UsingFullMap() const { - return size_ < 0; - } - - inline NormalMap* map() { - CHECK(UsingFullMap()); - return map_.get(); - } - inline const NormalMap* map() const { - CHECK(UsingFullMap()); - return map_.get(); - } - - private: - int size_; // negative = using hash_map - - MapInit functor_; - - // We want to call constructors and destructors manually, but we don't - // want to allocate and deallocate the memory used for them separately. - // So, we use this crazy ManualConstructor class. - // - // Since array_ and map_ are mutually exclusive, we'll put them in a - // union, too. We add in a dummy_ value which quiets MSVC from otherwise - // giving an erroneous "union member has copy constructor" error message - // (C2621). This dummy member has to come before array_ to quiet the - // compiler. - // - // TODO(brettw) remove this and use C++11 unions when we require C++11. - union { - ManualConstructor dummy_; - ManualConstructor array_[kArraySize]; - ManualConstructor map_; - }; - - void ConvertToRealMap() { - // Move the current elements into a temporary array. - ManualConstructor temp_array[kArraySize]; - - for (int i = 0; i < kArraySize; i++) { - temp_array[i].Init(*array_[i]); - array_[i].Destroy(); - } - - // Initialize the map. - size_ = -1; - functor_(&map_); - - // Insert elements into it. - for (int i = 0; i < kArraySize; i++) { - map_->insert(*temp_array[i]); - temp_array[i].Destroy(); - } - } - - // Helpers for constructors and destructors. - void InitFrom(const SmallMap& src) { - functor_ = src.functor_; - size_ = src.size_; - if (src.size_ >= 0) { - for (int i = 0; i < size_; i++) { - array_[i].Init(*src.array_[i]); - } - } else { - functor_(&map_); - (*map_.get()) = (*src.map_.get()); - } - } - void Destroy() { - if (size_ >= 0) { - for (int i = 0; i < size_; i++) { - array_[i].Destroy(); - } - } else { - map_.Destroy(); - } - } -}; - -template -inline bool SmallMap::iterator::operator==( - const const_iterator& other) const { - return other == *this; -} -template -inline bool SmallMap::iterator::operator!=( - const const_iterator& other) const { - return other != *this; -} - -} // namespace base - -#endif // BASE_CONTAINERS_SMALL_MAP_H_ diff --git a/base/containers/small_map_unittest.cc b/base/containers/small_map_unittest.cc deleted file mode 100644 index b911bee655..0000000000 --- a/base/containers/small_map_unittest.cc +++ /dev/null @@ -1,492 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "base/containers/small_map.h" - -#include - -#include -#include -#include - -#include "base/containers/hash_tables.h" -#include "base/logging.h" -#include "testing/gtest/include/gtest/gtest.h" - -namespace base { - -TEST(SmallMap, General) { - SmallMap > m; - - EXPECT_TRUE(m.empty()); - - m[0] = 5; - - EXPECT_FALSE(m.empty()); - EXPECT_EQ(m.size(), 1u); - - m[9] = 2; - - EXPECT_FALSE(m.empty()); - EXPECT_EQ(m.size(), 2u); - - EXPECT_EQ(m[9], 2); - EXPECT_EQ(m[0], 5); - EXPECT_FALSE(m.UsingFullMap()); - - SmallMap >::iterator iter(m.begin()); - ASSERT_TRUE(iter != m.end()); - EXPECT_EQ(iter->first, 0); - EXPECT_EQ(iter->second, 5); - ++iter; - ASSERT_TRUE(iter != m.end()); - EXPECT_EQ((*iter).first, 9); - EXPECT_EQ((*iter).second, 2); - ++iter; - EXPECT_TRUE(iter == m.end()); - - m[8] = 23; - m[1234] = 90; - m[-5] = 6; - - EXPECT_EQ(m[ 9], 2); - EXPECT_EQ(m[ 0], 5); - EXPECT_EQ(m[1234], 90); - EXPECT_EQ(m[ 8], 23); - EXPECT_EQ(m[ -5], 6); - EXPECT_EQ(m.size(), 5u); - EXPECT_FALSE(m.empty()); - EXPECT_TRUE(m.UsingFullMap()); - - iter = m.begin(); - for (int i = 0; i < 5; i++) { - EXPECT_TRUE(iter != m.end()); - ++iter; - } - EXPECT_TRUE(iter == m.end()); - - const SmallMap >& ref = m; - EXPECT_TRUE(ref.find(1234) != m.end()); - EXPECT_TRUE(ref.find(5678) == m.end()); -} - -TEST(SmallMap, PostFixIteratorIncrement) { - SmallMap > m; - m[0] = 5; - m[2] = 3; - - { - SmallMap >::iterator iter(m.begin()); - SmallMap >::iterator last(iter++); - ++last; - EXPECT_TRUE(last == iter); - } - - { - SmallMap >::const_iterator iter(m.begin()); - SmallMap >::const_iterator last(iter++); - ++last; - EXPECT_TRUE(last == iter); - } -} - -// Based on the General testcase. -TEST(SmallMap, CopyConstructor) { - SmallMap > src; - - { - SmallMap > m(src); - EXPECT_TRUE(m.empty()); - } - - src[0] = 5; - - { - SmallMap > m(src); - EXPECT_FALSE(m.empty()); - EXPECT_EQ(m.size(), 1u); - } - - src[9] = 2; - - { - SmallMap > m(src); - EXPECT_FALSE(m.empty()); - EXPECT_EQ(m.size(), 2u); - - EXPECT_EQ(m[9], 2); - EXPECT_EQ(m[0], 5); - EXPECT_FALSE(m.UsingFullMap()); - } - - src[8] = 23; - src[1234] = 90; - src[-5] = 6; - - { - SmallMap > m(src); - EXPECT_EQ(m[ 9], 2); - EXPECT_EQ(m[ 0], 5); - EXPECT_EQ(m[1234], 90); - EXPECT_EQ(m[ 8], 23); - EXPECT_EQ(m[ -5], 6); - EXPECT_EQ(m.size(), 5u); - EXPECT_FALSE(m.empty()); - EXPECT_TRUE(m.UsingFullMap()); - } -} - -template -static void SmallMapToMap(SmallMap const& src, inner* dest) { - typename SmallMap::const_iterator it; - for (it = src.begin(); it != src.end(); ++it) { - dest->insert(std::make_pair(it->first, it->second)); - } -} - -template -static bool SmallMapEqual(SmallMap const& a, - SmallMap const& b) { - inner ia, ib; - SmallMapToMap(a, &ia); - SmallMapToMap(b, &ib); - - // On most systems we can use operator== here, but under some lesser STL - // implementations it doesn't seem to work. So we manually compare. - if (ia.size() != ib.size()) - return false; - for (typename inner::iterator ia_it = ia.begin(), ib_it = ib.begin(); - ia_it != ia.end(); ++ia_it, ++ib_it) { - if (*ia_it != *ib_it) - return false; - } - return true; -} - -TEST(SmallMap, AssignmentOperator) { - SmallMap > src_small; - SmallMap > src_large; - - src_small[1] = 20; - src_small[2] = 21; - src_small[3] = 22; - EXPECT_FALSE(src_small.UsingFullMap()); - - src_large[1] = 20; - src_large[2] = 21; - src_large[3] = 22; - src_large[5] = 23; - src_large[6] = 24; - src_large[7] = 25; - EXPECT_TRUE(src_large.UsingFullMap()); - - // Assignments to empty. - SmallMap > dest_small; - dest_small = src_small; - EXPECT_TRUE(SmallMapEqual(dest_small, src_small)); - EXPECT_EQ(dest_small.UsingFullMap(), - src_small.UsingFullMap()); - - SmallMap > dest_large; - dest_large = src_large; - EXPECT_TRUE(SmallMapEqual(dest_large, src_large)); - EXPECT_EQ(dest_large.UsingFullMap(), - src_large.UsingFullMap()); - - // Assignments which assign from full to small, and vice versa. - dest_small = src_large; - EXPECT_TRUE(SmallMapEqual(dest_small, src_large)); - EXPECT_EQ(dest_small.UsingFullMap(), - src_large.UsingFullMap()); - - dest_large = src_small; - EXPECT_TRUE(SmallMapEqual(dest_large, src_small)); - EXPECT_EQ(dest_large.UsingFullMap(), - src_small.UsingFullMap()); - - // Double check that SmallMapEqual works: - dest_large[42] = 666; - EXPECT_FALSE(SmallMapEqual(dest_large, src_small)); -} - -TEST(SmallMap, Insert) { - SmallMap > sm; - - // loop through the transition from small map to map. - for (int i = 1; i <= 10; ++i) { - VLOG(1) << "Iteration " << i; - // insert an element - std::pair >::iterator, - bool> ret; - ret = sm.insert(std::make_pair(i, 100*i)); - EXPECT_TRUE(ret.second); - EXPECT_TRUE(ret.first == sm.find(i)); - EXPECT_EQ(ret.first->first, i); - EXPECT_EQ(ret.first->second, 100*i); - - // try to insert it again with different value, fails, but we still get an - // iterator back with the original value. - ret = sm.insert(std::make_pair(i, -i)); - EXPECT_FALSE(ret.second); - EXPECT_TRUE(ret.first == sm.find(i)); - EXPECT_EQ(ret.first->first, i); - EXPECT_EQ(ret.first->second, 100*i); - - // check the state of the map. - for (int j = 1; j <= i; ++j) { - SmallMap >::iterator it = sm.find(j); - EXPECT_TRUE(it != sm.end()); - EXPECT_EQ(it->first, j); - EXPECT_EQ(it->second, j * 100); - } - EXPECT_EQ(sm.size(), static_cast(i)); - EXPECT_FALSE(sm.empty()); - } -} - -TEST(SmallMap, InsertRange) { - // loop through the transition from small map to map. - for (int elements = 0; elements <= 10; ++elements) { - VLOG(1) << "Elements " << elements; - hash_map normal_map; - for (int i = 1; i <= elements; ++i) { - normal_map.insert(std::make_pair(i, 100*i)); - } - - SmallMap > sm; - sm.insert(normal_map.begin(), normal_map.end()); - EXPECT_EQ(normal_map.size(), sm.size()); - for (int i = 1; i <= elements; ++i) { - VLOG(1) << "Iteration " << i; - EXPECT_TRUE(sm.find(i) != sm.end()); - EXPECT_EQ(sm.find(i)->first, i); - EXPECT_EQ(sm.find(i)->second, 100*i); - } - } -} - -TEST(SmallMap, Erase) { - SmallMap > m; - SmallMap >::iterator iter; - - m["monday"] = 1; - m["tuesday"] = 2; - m["wednesday"] = 3; - - EXPECT_EQ(m["monday" ], 1); - EXPECT_EQ(m["tuesday" ], 2); - EXPECT_EQ(m["wednesday"], 3); - EXPECT_EQ(m.count("tuesday"), 1u); - EXPECT_FALSE(m.UsingFullMap()); - - iter = m.begin(); - ASSERT_TRUE(iter != m.end()); - EXPECT_EQ(iter->first, "monday"); - EXPECT_EQ(iter->second, 1); - ++iter; - ASSERT_TRUE(iter != m.end()); - EXPECT_EQ(iter->first, "tuesday"); - EXPECT_EQ(iter->second, 2); - ++iter; - ASSERT_TRUE(iter != m.end()); - EXPECT_EQ(iter->first, "wednesday"); - EXPECT_EQ(iter->second, 3); - ++iter; - EXPECT_TRUE(iter == m.end()); - - EXPECT_EQ(m.erase("tuesday"), 1u); - - EXPECT_EQ(m["monday" ], 1); - EXPECT_EQ(m["wednesday"], 3); - EXPECT_EQ(m.count("tuesday"), 0u); - EXPECT_EQ(m.erase("tuesday"), 0u); - - iter = m.begin(); - ASSERT_TRUE(iter != m.end()); - EXPECT_EQ(iter->first, "monday"); - EXPECT_EQ(iter->second, 1); - ++iter; - ASSERT_TRUE(iter != m.end()); - EXPECT_EQ(iter->first, "wednesday"); - EXPECT_EQ(iter->second, 3); - ++iter; - EXPECT_TRUE(iter == m.end()); - - m["thursday"] = 4; - m["friday"] = 5; - EXPECT_EQ(m.size(), 4u); - EXPECT_FALSE(m.empty()); - EXPECT_FALSE(m.UsingFullMap()); - - m["saturday"] = 6; - EXPECT_TRUE(m.UsingFullMap()); - - EXPECT_EQ(m.count("friday"), 1u); - EXPECT_EQ(m.erase("friday"), 1u); - EXPECT_TRUE(m.UsingFullMap()); - EXPECT_EQ(m.count("friday"), 0u); - EXPECT_EQ(m.erase("friday"), 0u); - - EXPECT_EQ(m.size(), 4u); - EXPECT_FALSE(m.empty()); - EXPECT_EQ(m.erase("monday"), 1u); - EXPECT_EQ(m.size(), 3u); - EXPECT_FALSE(m.empty()); - - m.clear(); - EXPECT_FALSE(m.UsingFullMap()); - EXPECT_EQ(m.size(), 0u); - EXPECT_TRUE(m.empty()); -} - -TEST(SmallMap, NonHashMap) { - SmallMap, 4, std::equal_to > m; - EXPECT_TRUE(m.empty()); - - m[9] = 2; - m[0] = 5; - - EXPECT_EQ(m[9], 2); - EXPECT_EQ(m[0], 5); - EXPECT_EQ(m.size(), 2u); - EXPECT_FALSE(m.empty()); - EXPECT_FALSE(m.UsingFullMap()); - - SmallMap, 4, std::equal_to >::iterator iter( - m.begin()); - ASSERT_TRUE(iter != m.end()); - EXPECT_EQ(iter->first, 9); - EXPECT_EQ(iter->second, 2); - ++iter; - ASSERT_TRUE(iter != m.end()); - EXPECT_EQ(iter->first, 0); - EXPECT_EQ(iter->second, 5); - ++iter; - EXPECT_TRUE(iter == m.end()); - --iter; - ASSERT_TRUE(iter != m.end()); - EXPECT_EQ(iter->first, 0); - EXPECT_EQ(iter->second, 5); - - m[8] = 23; - m[1234] = 90; - m[-5] = 6; - - EXPECT_EQ(m[ 9], 2); - EXPECT_EQ(m[ 0], 5); - EXPECT_EQ(m[1234], 90); - EXPECT_EQ(m[ 8], 23); - EXPECT_EQ(m[ -5], 6); - EXPECT_EQ(m.size(), 5u); - EXPECT_FALSE(m.empty()); - EXPECT_TRUE(m.UsingFullMap()); - - iter = m.begin(); - ASSERT_TRUE(iter != m.end()); - EXPECT_EQ(iter->first, -5); - EXPECT_EQ(iter->second, 6); - ++iter; - ASSERT_TRUE(iter != m.end()); - EXPECT_EQ(iter->first, 0); - EXPECT_EQ(iter->second, 5); - ++iter; - ASSERT_TRUE(iter != m.end()); - EXPECT_EQ(iter->first, 8); - EXPECT_EQ(iter->second, 23); - ++iter; - ASSERT_TRUE(iter != m.end()); - EXPECT_EQ(iter->first, 9); - EXPECT_EQ(iter->second, 2); - ++iter; - ASSERT_TRUE(iter != m.end()); - EXPECT_EQ(iter->first, 1234); - EXPECT_EQ(iter->second, 90); - ++iter; - EXPECT_TRUE(iter == m.end()); - --iter; - ASSERT_TRUE(iter != m.end()); - EXPECT_EQ(iter->first, 1234); - EXPECT_EQ(iter->second, 90); -} - -TEST(SmallMap, DefaultEqualKeyWorks) { - // If these tests compile, they pass. The EXPECT calls are only there to avoid - // unused variable warnings. - SmallMap > hm; - EXPECT_EQ(0u, hm.size()); - SmallMap > m; - EXPECT_EQ(0u, m.size()); -} - -namespace { - -class hash_map_add_item : public hash_map { - public: - hash_map_add_item() : hash_map() {} - explicit hash_map_add_item(const std::pair& item) - : hash_map() { - insert(item); - } -}; - -void InitMap(ManualConstructor* map_ctor) { - map_ctor->Init(std::make_pair(0, 0)); -} - -class hash_map_add_item_initializer { - public: - explicit hash_map_add_item_initializer(int item_to_add) - : item_(item_to_add) {} - hash_map_add_item_initializer() - : item_(0) {} - void operator()(ManualConstructor* map_ctor) const { - map_ctor->Init(std::make_pair(item_, item_)); - } - - int item_; -}; - -} // anonymous namespace - -TEST(SmallMap, SubclassInitializationWithFunctionPointer) { - SmallMap, - void (&)(ManualConstructor*)> m(InitMap); - - EXPECT_TRUE(m.empty()); - - m[1] = 1; - m[2] = 2; - m[3] = 3; - m[4] = 4; - - EXPECT_EQ(4u, m.size()); - EXPECT_EQ(0u, m.count(0)); - - m[5] = 5; - EXPECT_EQ(6u, m.size()); - // Our function adds an extra item when we convert to a map. - EXPECT_EQ(1u, m.count(0)); -} - -TEST(SmallMap, SubclassInitializationWithFunctionObject) { - SmallMap, - hash_map_add_item_initializer> m(hash_map_add_item_initializer(-1)); - - EXPECT_TRUE(m.empty()); - - m[1] = 1; - m[2] = 2; - m[3] = 3; - m[4] = 4; - - EXPECT_EQ(4u, m.size()); - EXPECT_EQ(0u, m.count(-1)); - - m[5] = 5; - EXPECT_EQ(6u, m.size()); - // Our functor adds an extra item when we convert to a map. - EXPECT_EQ(1u, m.count(-1)); -} - -} // namespace base diff --git a/base/containers/stack_container.h b/base/containers/stack_container.h deleted file mode 100644 index f0106d73f2..0000000000 --- a/base/containers/stack_container.h +++ /dev/null @@ -1,258 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef BASE_CONTAINERS_STACK_CONTAINER_H_ -#define BASE_CONTAINERS_STACK_CONTAINER_H_ - -#include -#include - -#include "base/basictypes.h" -#include "base/memory/aligned_memory.h" -#include "base/strings/string16.h" -#include "build/build_config.h" - -namespace base { - -// This allocator can be used with STL containers to provide a stack buffer -// from which to allocate memory and overflows onto the heap. This stack buffer -// would be allocated on the stack and allows us to avoid heap operations in -// some situations. -// -// STL likes to make copies of allocators, so the allocator itself can't hold -// the data. Instead, we make the creator responsible for creating a -// StackAllocator::Source which contains the data. Copying the allocator -// merely copies the pointer to this shared source, so all allocators created -// based on our allocator will share the same stack buffer. -// -// This stack buffer implementation is very simple. The first allocation that -// fits in the stack buffer will use the stack buffer. Any subsequent -// allocations will not use the stack buffer, even if there is unused room. -// This makes it appropriate for array-like containers, but the caller should -// be sure to reserve() in the container up to the stack buffer size. Otherwise -// the container will allocate a small array which will "use up" the stack -// buffer. -template -class StackAllocator : public std::allocator { - public: - typedef typename std::allocator::pointer pointer; - typedef typename std::allocator::size_type size_type; - - // Backing store for the allocator. The container owner is responsible for - // maintaining this for as long as any containers using this allocator are - // live. - struct Source { - Source() : used_stack_buffer_(false) { - } - - // Casts the buffer in its right type. - T* stack_buffer() { return stack_buffer_.template data_as(); } - const T* stack_buffer() const { - return stack_buffer_.template data_as(); - } - - // The buffer itself. It is not of type T because we don't want the - // constructors and destructors to be automatically called. Define a POD - // buffer of the right size instead. - base::AlignedMemory stack_buffer_; -#if defined(__GNUC__) && !defined(ARCH_CPU_X86_FAMILY) - COMPILE_ASSERT(ALIGNOF(T) <= 16, crbug_115612); -#endif - - // Set when the stack buffer is used for an allocation. We do not track - // how much of the buffer is used, only that somebody is using it. - bool used_stack_buffer_; - }; - - // Used by containers when they want to refer to an allocator of type U. - template - struct rebind { - typedef StackAllocator other; - }; - - // For the straight up copy c-tor, we can share storage. - StackAllocator(const StackAllocator& rhs) - : std::allocator(), source_(rhs.source_) { - } - - // ISO C++ requires the following constructor to be defined, - // and std::vector in VC++2008SP1 Release fails with an error - // in the class _Container_base_aux_alloc_real (from ) - // if the constructor does not exist. - // For this constructor, we cannot share storage; there's - // no guarantee that the Source buffer of Ts is large enough - // for Us. - // TODO: If we were fancy pants, perhaps we could share storage - // iff sizeof(T) == sizeof(U). - template - StackAllocator(const StackAllocator& other) - : source_(NULL) { - } - - explicit StackAllocator(Source* source) : source_(source) { - } - - // Actually do the allocation. Use the stack buffer if nobody has used it yet - // and the size requested fits. Otherwise, fall through to the standard - // allocator. - pointer allocate(size_type n, void* hint = 0) { - if (source_ != NULL && !source_->used_stack_buffer_ - && n <= stack_capacity) { - source_->used_stack_buffer_ = true; - return source_->stack_buffer(); - } else { - return std::allocator::allocate(n, hint); - } - } - - // Free: when trying to free the stack buffer, just mark it as free. For - // non-stack-buffer pointers, just fall though to the standard allocator. - void deallocate(pointer p, size_type n) { - if (source_ != NULL && p == source_->stack_buffer()) - source_->used_stack_buffer_ = false; - else - std::allocator::deallocate(p, n); - } - - private: - Source* source_; -}; - -// A wrapper around STL containers that maintains a stack-sized buffer that the -// initial capacity of the vector is based on. Growing the container beyond the -// stack capacity will transparently overflow onto the heap. The container must -// support reserve(). -// -// WATCH OUT: the ContainerType MUST use the proper StackAllocator for this -// type. This object is really intended to be used only internally. You'll want -// to use the wrappers below for different types. -template -class StackContainer { - public: - typedef TContainerType ContainerType; - typedef typename ContainerType::value_type ContainedType; - typedef StackAllocator Allocator; - - // Allocator must be constructed before the container! - StackContainer() : allocator_(&stack_data_), container_(allocator_) { - // Make the container use the stack allocation by reserving our buffer size - // before doing anything else. - container_.reserve(stack_capacity); - } - - // Getters for the actual container. - // - // Danger: any copies of this made using the copy constructor must have - // shorter lifetimes than the source. The copy will share the same allocator - // and therefore the same stack buffer as the original. Use std::copy to - // copy into a "real" container for longer-lived objects. - ContainerType& container() { return container_; } - const ContainerType& container() const { return container_; } - - // Support operator-> to get to the container. This allows nicer syntax like: - // StackContainer<...> foo; - // std::sort(foo->begin(), foo->end()); - ContainerType* operator->() { return &container_; } - const ContainerType* operator->() const { return &container_; } - -#ifdef UNIT_TEST - // Retrieves the stack source so that that unit tests can verify that the - // buffer is being used properly. - const typename Allocator::Source& stack_data() const { - return stack_data_; - } -#endif - - protected: - typename Allocator::Source stack_data_; - Allocator allocator_; - ContainerType container_; - - DISALLOW_COPY_AND_ASSIGN(StackContainer); -}; - -// StackString ----------------------------------------------------------------- - -template -class StackString : public StackContainer< - std::basic_string, - StackAllocator >, - stack_capacity> { - public: - StackString() : StackContainer< - std::basic_string, - StackAllocator >, - stack_capacity>() { - } - - private: - DISALLOW_COPY_AND_ASSIGN(StackString); -}; - -// StackStrin16 ---------------------------------------------------------------- - -template -class StackString16 : public StackContainer< - std::basic_string >, - stack_capacity> { - public: - StackString16() : StackContainer< - std::basic_string >, - stack_capacity>() { - } - - private: - DISALLOW_COPY_AND_ASSIGN(StackString16); -}; - -// StackVector ----------------------------------------------------------------- - -// Example: -// StackVector foo; -// foo->push_back(22); // we have overloaded operator-> -// foo[0] = 10; // as well as operator[] -template -class StackVector : public StackContainer< - std::vector >, - stack_capacity> { - public: - StackVector() : StackContainer< - std::vector >, - stack_capacity>() { - } - - // We need to put this in STL containers sometimes, which requires a copy - // constructor. We can't call the regular copy constructor because that will - // take the stack buffer from the original. Here, we create an empty object - // and make a stack buffer of its own. - StackVector(const StackVector& other) - : StackContainer< - std::vector >, - stack_capacity>() { - this->container().assign(other->begin(), other->end()); - } - - StackVector& operator=( - const StackVector& other) { - this->container().assign(other->begin(), other->end()); - return *this; - } - - // Vectors are commonly indexed, which isn't very convenient even with - // operator-> (using "->at()" does exception stuff we don't want). - T& operator[](size_t i) { return this->container().operator[](i); } - const T& operator[](size_t i) const { - return this->container().operator[](i); - } -}; - -} // namespace base - -#endif // BASE_CONTAINERS_STACK_CONTAINER_H_ diff --git a/base/containers/stack_container_unittest.cc b/base/containers/stack_container_unittest.cc deleted file mode 100644 index e6c19145bf..0000000000 --- a/base/containers/stack_container_unittest.cc +++ /dev/null @@ -1,143 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "base/containers/stack_container.h" - -#include - -#include "base/memory/aligned_memory.h" -#include "base/memory/ref_counted.h" -#include "testing/gtest/include/gtest/gtest.h" - -namespace base { - -namespace { - -class Dummy : public base::RefCounted { - public: - explicit Dummy(int* alive) : alive_(alive) { - ++*alive_; - } - - private: - friend class base::RefCounted; - - ~Dummy() { - --*alive_; - } - - int* const alive_; -}; - -} // namespace - -TEST(StackContainer, Vector) { - const int stack_size = 3; - StackVector vect; - const int* stack_buffer = &vect.stack_data().stack_buffer()[0]; - - // The initial |stack_size| elements should appear in the stack buffer. - EXPECT_EQ(static_cast(stack_size), vect.container().capacity()); - for (int i = 0; i < stack_size; i++) { - vect.container().push_back(i); - EXPECT_EQ(stack_buffer, &vect.container()[0]); - EXPECT_TRUE(vect.stack_data().used_stack_buffer_); - } - - // Adding more elements should push the array onto the heap. - for (int i = 0; i < stack_size; i++) { - vect.container().push_back(i + stack_size); - EXPECT_NE(stack_buffer, &vect.container()[0]); - EXPECT_FALSE(vect.stack_data().used_stack_buffer_); - } - - // The array should still be in order. - for (int i = 0; i < stack_size * 2; i++) - EXPECT_EQ(i, vect.container()[i]); - - // Resize to smaller. Our STL implementation won't reallocate in this case, - // otherwise it might use our stack buffer. We reserve right after the resize - // to guarantee it isn't using the stack buffer, even though it doesn't have - // much data. - vect.container().resize(stack_size); - vect.container().reserve(stack_size * 2); - EXPECT_FALSE(vect.stack_data().used_stack_buffer_); - - // Copying the small vector to another should use the same allocator and use - // the now-unused stack buffer. GENERALLY CALLERS SHOULD NOT DO THIS since - // they have to get the template types just right and it can cause errors. - std::vector > other(vect.container()); - EXPECT_EQ(stack_buffer, &other.front()); - EXPECT_TRUE(vect.stack_data().used_stack_buffer_); - for (int i = 0; i < stack_size; i++) - EXPECT_EQ(i, other[i]); -} - -TEST(StackContainer, VectorDoubleDelete) { - // Regression testing for double-delete. - typedef StackVector, 2> Vector; - typedef Vector::ContainerType Container; - Vector vect; - - int alive = 0; - scoped_refptr dummy(new Dummy(&alive)); - EXPECT_EQ(alive, 1); - - vect->push_back(dummy); - EXPECT_EQ(alive, 1); - - Dummy* dummy_unref = dummy.get(); - dummy = NULL; - EXPECT_EQ(alive, 1); - - Container::iterator itr = std::find(vect->begin(), vect->end(), dummy_unref); - EXPECT_EQ(itr->get(), dummy_unref); - vect->erase(itr); - EXPECT_EQ(alive, 0); - - // Shouldn't crash at exit. -} - -namespace { - -template -class AlignedData { - public: - AlignedData() { memset(data_.void_data(), 0, alignment); } - ~AlignedData() {} - base::AlignedMemory data_; -}; - -} // anonymous namespace - -#define EXPECT_ALIGNED(ptr, align) \ - EXPECT_EQ(0u, reinterpret_cast(ptr) & (align - 1)) - -TEST(StackContainer, BufferAlignment) { - StackVector text; - text->push_back(L'A'); - EXPECT_ALIGNED(&text[0], ALIGNOF(wchar_t)); - - StackVector doubles; - doubles->push_back(0.0); - EXPECT_ALIGNED(&doubles[0], ALIGNOF(double)); - - StackVector, 1> aligned16; - aligned16->push_back(AlignedData<16>()); - EXPECT_ALIGNED(&aligned16[0], 16); - -#if !defined(__GNUC__) || defined(ARCH_CPU_X86_FAMILY) - // It seems that non-X86 gcc doesn't respect greater than 16 byte alignment. - // See http://gcc.gnu.org/bugzilla/show_bug.cgi?id=33721 for details. - // TODO(sbc):re-enable this if GCC starts respecting higher alignments. - StackVector, 1> aligned256; - aligned256->push_back(AlignedData<256>()); - EXPECT_ALIGNED(&aligned256[0], 256); -#endif -} - -template class StackVector; -template class StackVector, 2>; - -} // namespace base diff --git a/base/cpu.cc b/base/cpu.cc deleted file mode 100644 index 1761529e04..0000000000 --- a/base/cpu.cc +++ /dev/null @@ -1,162 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "base/cpu.h" - -#include - -#include - -#include "build/build_config.h" - -#if defined(ARCH_CPU_X86_FAMILY) -#if defined(_MSC_VER) -#include -#endif -#endif - -namespace base { - -CPU::CPU() - : signature_(0), - type_(0), - family_(0), - model_(0), - stepping_(0), - ext_model_(0), - ext_family_(0), - has_mmx_(false), - has_sse_(false), - has_sse2_(false), - has_sse3_(false), - has_ssse3_(false), - has_sse41_(false), - has_sse42_(false), - has_non_stop_time_stamp_counter_(false), - cpu_vendor_("unknown") { - Initialize(); -} - -#if defined(ARCH_CPU_X86_FAMILY) -#ifndef _MSC_VER - -#if defined(__pic__) && defined(__i386__) - -void __cpuid(int cpu_info[4], int info_type) { - __asm__ volatile ( - "mov %%ebx, %%edi\n" - "cpuid\n" - "xchg %%edi, %%ebx\n" - : "=a"(cpu_info[0]), "=D"(cpu_info[1]), "=c"(cpu_info[2]), "=d"(cpu_info[3]) - : "a"(info_type) - ); -} - -void __cpuidex(int cpu_info[4], int info_type, int info_index) { - __asm__ volatile ( - "mov %%ebx, %%edi\n" - "cpuid\n" - "xchg %%edi, %%ebx\n" - : "=a"(cpu_info[0]), "=D"(cpu_info[1]), "=c"(cpu_info[2]), "=d"(cpu_info[3]) - : "a"(info_type), "c"(info_index) - ); -} - -#else - -void __cpuid(int cpu_info[4], int info_type) { - __asm__ volatile ( - "cpuid \n\t" - : "=a"(cpu_info[0]), "=b"(cpu_info[1]), "=c"(cpu_info[2]), "=d"(cpu_info[3]) - : "a"(info_type) - ); -} - -void __cpuidex(int cpu_info[4], int info_type, int info_index) { - __asm__ volatile ( - "cpuid \n\t" - : "=a"(cpu_info[0]), "=b"(cpu_info[1]), "=c"(cpu_info[2]), "=d"(cpu_info[3]) - : "a"(info_type), "c"(info_index) - ); -} - -#endif -#endif // _MSC_VER -#endif // ARCH_CPU_X86_FAMILY - -void CPU::Initialize() { -#if defined(ARCH_CPU_X86_FAMILY) - int cpu_info[4] = {-1}; - char cpu_string[48]; - - // __cpuid with an InfoType argument of 0 returns the number of - // valid Ids in CPUInfo[0] and the CPU identification string in - // the other three array elements. The CPU identification string is - // not in linear order. The code below arranges the information - // in a human readable form. The human readable order is CPUInfo[1] | - // CPUInfo[3] | CPUInfo[2]. CPUInfo[2] and CPUInfo[3] are swapped - // before using memcpy to copy these three array elements to cpu_string. - __cpuid(cpu_info, 0); - int num_ids = cpu_info[0]; - std::swap(cpu_info[2], cpu_info[3]); - memcpy(cpu_string, &cpu_info[1], 3 * sizeof(cpu_info[1])); - cpu_vendor_.assign(cpu_string, 3 * sizeof(cpu_info[1])); - - // Interpret CPU feature information. - if (num_ids > 0) { - __cpuid(cpu_info, 1); - signature_ = cpu_info[0]; - stepping_ = cpu_info[0] & 0xf; - model_ = ((cpu_info[0] >> 4) & 0xf) + ((cpu_info[0] >> 12) & 0xf0); - family_ = (cpu_info[0] >> 8) & 0xf; - type_ = (cpu_info[0] >> 12) & 0x3; - ext_model_ = (cpu_info[0] >> 16) & 0xf; - ext_family_ = (cpu_info[0] >> 20) & 0xff; - has_mmx_ = (cpu_info[3] & 0x00800000) != 0; - has_sse_ = (cpu_info[3] & 0x02000000) != 0; - has_sse2_ = (cpu_info[3] & 0x04000000) != 0; - has_sse3_ = (cpu_info[2] & 0x00000001) != 0; - has_ssse3_ = (cpu_info[2] & 0x00000200) != 0; - has_sse41_ = (cpu_info[2] & 0x00080000) != 0; - has_sse42_ = (cpu_info[2] & 0x00100000) != 0; - has_avx_ = (cpu_info[2] & 0x10000000) != 0; - } - - // Get the brand string of the cpu. - __cpuid(cpu_info, 0x80000000); - const int parameter_end = 0x80000004; - int max_parameter = cpu_info[0]; - - if (cpu_info[0] >= parameter_end) { - char* cpu_string_ptr = cpu_string; - - for (int parameter = 0x80000002; parameter <= parameter_end && - cpu_string_ptr < &cpu_string[sizeof(cpu_string)]; parameter++) { - __cpuid(cpu_info, parameter); - memcpy(cpu_string_ptr, cpu_info, sizeof(cpu_info)); - cpu_string_ptr += sizeof(cpu_info); - } - cpu_brand_.assign(cpu_string, cpu_string_ptr - cpu_string); - } - - const int parameter_containing_non_stop_time_stamp_counter = 0x80000007; - if (max_parameter >= parameter_containing_non_stop_time_stamp_counter) { - __cpuid(cpu_info, parameter_containing_non_stop_time_stamp_counter); - has_non_stop_time_stamp_counter_ = (cpu_info[3] & (1 << 8)) != 0; - } -#endif -} - -CPU::IntelMicroArchitecture CPU::GetIntelMicroArchitecture() const { - if (has_avx()) return AVX; - if (has_sse42()) return SSE42; - if (has_sse41()) return SSE41; - if (has_ssse3()) return SSSE3; - if (has_sse3()) return SSE3; - if (has_sse2()) return SSE2; - if (has_sse()) return SSE; - return PENTIUM; -} - -} // namespace base diff --git a/base/cpu.h b/base/cpu.h deleted file mode 100644 index 509763e170..0000000000 --- a/base/cpu.h +++ /dev/null @@ -1,81 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef BASE_CPU_H_ -#define BASE_CPU_H_ - -#include - -#include "base/base_export.h" - -namespace base { - -// Query information about the processor. -class BASE_EXPORT CPU { - public: - // Constructor - CPU(); - - enum IntelMicroArchitecture { - PENTIUM, - SSE, - SSE2, - SSE3, - SSSE3, - SSE41, - SSE42, - AVX, - MAX_INTEL_MICRO_ARCHITECTURE - }; - - // Accessors for CPU information. - const std::string& vendor_name() const { return cpu_vendor_; } - int signature() const { return signature_; } - int stepping() const { return stepping_; } - int model() const { return model_; } - int family() const { return family_; } - int type() const { return type_; } - int extended_model() const { return ext_model_; } - int extended_family() const { return ext_family_; } - bool has_mmx() const { return has_mmx_; } - bool has_sse() const { return has_sse_; } - bool has_sse2() const { return has_sse2_; } - bool has_sse3() const { return has_sse3_; } - bool has_ssse3() const { return has_ssse3_; } - bool has_sse41() const { return has_sse41_; } - bool has_sse42() const { return has_sse42_; } - bool has_avx() const { return has_avx_; } - bool has_non_stop_time_stamp_counter() const { - return has_non_stop_time_stamp_counter_; - } - IntelMicroArchitecture GetIntelMicroArchitecture() const; - const std::string& cpu_brand() const { return cpu_brand_; } - - private: - // Query the processor for CPUID information. - void Initialize(); - - int signature_; // raw form of type, family, model, and stepping - int type_; // process type - int family_; // family of the processor - int model_; // model of processor - int stepping_; // processor revision number - int ext_model_; - int ext_family_; - bool has_mmx_; - bool has_sse_; - bool has_sse2_; - bool has_sse3_; - bool has_ssse3_; - bool has_sse41_; - bool has_sse42_; - bool has_avx_; - bool has_non_stop_time_stamp_counter_; - std::string cpu_vendor_; - std::string cpu_brand_; -}; - -} // namespace base - -#endif // BASE_CPU_H_ diff --git a/base/cpu_unittest.cc b/base/cpu_unittest.cc deleted file mode 100644 index 18bf959a55..0000000000 --- a/base/cpu_unittest.cc +++ /dev/null @@ -1,93 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "base/cpu.h" -#include "build/build_config.h" - -#include "testing/gtest/include/gtest/gtest.h" - -// Tests whether we can run extended instructions represented by the CPU -// information. This test actually executes some extended instructions (such as -// MMX, SSE, etc.) supported by the CPU and sees we can run them without -// "undefined instruction" exceptions. That is, this test succeeds when this -// test finishes without a crash. -TEST(CPU, RunExtendedInstructions) { -#if defined(ARCH_CPU_X86_FAMILY) - // Retrieve the CPU information. - base::CPU cpu; - -// TODO(jschuh): crbug.com/168866 Find a way to enable this on Win64. -#if defined(OS_WIN) && !defined(_M_X64) - ASSERT_TRUE(cpu.has_mmx()); - - // Execute an MMX instruction. - __asm emms; - - if (cpu.has_sse()) { - // Execute an SSE instruction. - __asm xorps xmm0, xmm0; - } - - if (cpu.has_sse2()) { - // Execute an SSE 2 instruction. - __asm psrldq xmm0, 0; - } - - if (cpu.has_sse3()) { - // Execute an SSE 3 instruction. - __asm addsubpd xmm0, xmm0; - } - - if (cpu.has_ssse3()) { - // Execute a Supplimental SSE 3 instruction. - __asm psignb xmm0, xmm0; - } - - if (cpu.has_sse41()) { - // Execute an SSE 4.1 instruction. - __asm pmuldq xmm0, xmm0; - } - - if (cpu.has_sse42()) { - // Execute an SSE 4.2 instruction. - __asm crc32 eax, eax; - } -#elif defined(OS_POSIX) && defined(__x86_64__) - ASSERT_TRUE(cpu.has_mmx()); - - // Execute an MMX instruction. - __asm__ __volatile__("emms\n" : : : "mm0"); - - if (cpu.has_sse()) { - // Execute an SSE instruction. - __asm__ __volatile__("xorps %%xmm0, %%xmm0\n" : : : "xmm0"); - } - - if (cpu.has_sse2()) { - // Execute an SSE 2 instruction. - __asm__ __volatile__("psrldq $0, %%xmm0\n" : : : "xmm0"); - } - - if (cpu.has_sse3()) { - // Execute an SSE 3 instruction. - __asm__ __volatile__("addsubpd %%xmm0, %%xmm0\n" : : : "xmm0"); - } - - if (cpu.has_ssse3()) { - // Execute a Supplimental SSE 3 instruction. - __asm__ __volatile__("psignb %%xmm0, %%xmm0\n" : : : "xmm0"); - } - - if (cpu.has_sse41()) { - // Execute an SSE 4.1 instruction. - __asm__ __volatile__("pmuldq %%xmm0, %%xmm0\n" : : : "xmm0"); - } - - if (cpu.has_sse42()) { - // Execute an SSE 4.2 instruction. - __asm__ __volatile__("crc32 %%eax, %%eax\n" : : : "eax"); - } -#endif -#endif -} diff --git a/base/critical_closure.h b/base/critical_closure.h deleted file mode 100644 index ca51ed5cef..0000000000 --- a/base/critical_closure.h +++ /dev/null @@ -1,37 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef BASE_CRITICAL_CLOSURE_H_ -#define BASE_CRITICAL_CLOSURE_H_ - -#include "base/callback.h" - -namespace base { - -// Returns a closure that will continue to run for a period of time when the -// application goes to the background if possible on platforms where -// applications don't execute while backgrounded, otherwise the original task is -// returned. -// -// Example: -// file_message_loop_proxy_->PostTask( -// FROM_HERE, -// MakeCriticalClosure(base::Bind(&WriteToDiskTask, path_, data))); -// -// Note new closures might be posted in this closure. If the new closures need -// background running time, |MakeCriticalClosure| should be applied on them -// before posting. -#if defined(OS_IOS) -base::Closure MakeCriticalClosure(const base::Closure& closure); -#else -inline base::Closure MakeCriticalClosure(const base::Closure& closure) { - // No-op for platforms where the application does not need to acquire - // background time for closures to finish when it goes into the background. - return closure; -} -#endif // !defined(OS_IOS) - -} // namespace base - -#endif // BASE_CRITICAL_CLOSURE_H_ diff --git a/base/critical_closure_ios.mm b/base/critical_closure_ios.mm deleted file mode 100644 index d605cad0a2..0000000000 --- a/base/critical_closure_ios.mm +++ /dev/null @@ -1,49 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "base/critical_closure.h" - -#import - -#include "base/bind.h" -#include "base/ios/scoped_critical_action.h" -#include "base/memory/ref_counted.h" - -namespace { - -// This class wraps a closure so it can continue to run for a period of time -// when the application goes to the background by using -// |base::ios::ScopedCriticalAction|. -class CriticalClosure : public base::RefCountedThreadSafe { - public: - explicit CriticalClosure(base::Closure* closure) : closure_(closure) { - } - - void Run() { - closure_->Run(); - } - - private: - friend class base::RefCountedThreadSafe; - - virtual ~CriticalClosure() {} - - base::ios::ScopedCriticalAction criticial_action_; - scoped_ptr closure_; - - DISALLOW_COPY_AND_ASSIGN(CriticalClosure); -}; - -} // namespace - -namespace base { - -base::Closure MakeCriticalClosure(const base::Closure& closure) { - DCHECK([[UIDevice currentDevice] isMultitaskingSupported]); - scoped_refptr critical_closure( - new CriticalClosure(new base::Closure(closure))); - return base::Bind(&CriticalClosure::Run, critical_closure.get()); -} - -} // namespace base diff --git a/base/data/file_version_info_unittest/FileVersionInfoTest1.dll b/base/data/file_version_info_unittest/FileVersionInfoTest1.dll deleted file mode 100755 index bdf8dc034683db88569e4a69cf815142c8edd42c..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 13824 zcmeHO4OEoZnZCo14vJxtKuQ`l6N@Q{kE5!|!tEELbovE2?_= zEn5zH{hzrUgBLbDe7OVlD}V33>_NWjd#%xY%jG6sf8ufr=fC5!ir3pOxAWY6xsB%? zQU11Q?&tX$Z?lK`h>fVy!C1K}nVo)dq%77p#uDzCuTnFnLCcazYhNaEs%v>&!^;T~ ze^Cqhji(L3s61D}7|2KvBDtA7T3yaq0a_PkGge7tJ7YUjs4y#mXvD+}+ymZOr1)z1 zbF=13%h*9xJjb==9MRn+qG>!0i0mVn83f8mTE;fy1YAvG6Kq`&X<)Y?PY1*$JG#z^ zu(6BDAm{)z_$7e2WXCXa0>MBt+8R=U(7^S@f&f)YcG4GcxBJ0(8e``UBHIjrxMXMS z!MN(D#s7l``VTK*n!%BoR3m*TzXyGnO0(1|F{MU+6qW9wBD#qn9tQ#ei-tC@7rcpwvN=Pj)Lt}Tvv;qccQf^OROgbh%1lcznKu%twaofD@a{dy^Et?g}8%O~cePgvS&myfC-c)Yhl-E-oY zV_GGuTUo7qfatJ$*pUh{o48M^80$G9Cd=DFkSZ=nDy6bh?u~NwfA2Pgs1%Z=_2Z=d zNwh1SYI!v=J5tYYhYF04g-W=$oH zPi5U(v2>t;X(7Rsj0Z5WFrcWWQpwPv%w@TLSh<7Lm#G^k7LgbW-O+6;fHf?%K>j*) zg#mbxLp?OFl`cfd;xd}k(B1M@5Ty!r?+Uf-j`HV4_}7yuaEtiy`tu+BUQudVnTO$U z^L*u21eyx#ybO%Pa~dcDjx`R_%0HbFTlsTpwYM^SL0;5G^i5i*2>F1QIvXV z*g0{#{0uzITWjPD-g>O@F*vQp6GoRx#&*~#P1YzGWN^==`g(37w=I;6Np2kMzL&`g z%<&w#3;y!Ln&G6Z9aLVAa=kFnIEXz}y;k^j{+pp&@|I5{TAs2h3n=fNQb`Nisf(1V zn%dq4=P=~7p3~^rwV&=WQfHF1NQ)5cZO_VleH_$@JA{GrZCD}s$HY54G7eoOBMS^` zYigBK=s=!O50_?Tf`RQH1AoszYeJ)#(t5W%0oP3wc#fbq&nrN~$wVhc`7Mxo2I}j@ zxlleIO`gNVbr48C1X_KsiFotcvliBe)N5;%jBIq7w_HY}xY$D(k2dHK(=aIuYX~VB zL{O4xpyyvkKlyK_^}Il%GHD?m8P5FpF|?{`l{46-Cb;R{Qwicc7;Yd7Cd6nIF5*#m zN|JkiT`!hL1MF12G&!N|E@a|e(wtt5U&+`CURt&ADRy{A)DqNin(mN8%*6TrK|$3#7h&P;$%N?s0w|T)X_n<z4OCwchrOGFsq%_%*x$FH86jThW;07~7WH9PAhq=MOv1kuvN&gYqL7 zBU}@6$qA^VQ#;i&K-xoG`#6(AsnW5ummC_ELmlgF{(ac-B3(@mJI2AuVp_2IF!`y7 zDvE~Ct++E>y)W3w$;#4d_z*|QwhP&az5{9jp|&82a0Vm1Xxad5nj&nw2;8zGLkmL7 zjs@vFTQtcVlP~aWsm!zG-DePAKgd&V#?!^w4ERWTLY zPs9VMs0}CMlCMcgVgtj;Nt}uehvu`l=PX3_@8iXDG^-h@SV;#e!PKgf=VJu*bjWJZ z=-Gh9Pw;s)`oi3d+zIxMCk z%H=Sydnj|zlTAC{!({GYO>O_-d$Fq#${&^{gK5$nthEGeJI9jpF9$w!;>51)?o%@0KUcZ14CacIn>Lk ztujKPgSvZ24NAUb&pImKeR;HdOckAu_!-~}cQCRwsf4#}I9vzPcE2ILL0eOlUl_Pv z0`HVA9vLFXog90B=^A!H!-JvQJ;ir{s@m6Ay=VVX{_u~mb1CA2o6+P%gJYBNV3K z@Ie*FG!7!XxXw>sR1};}>b?h4rH99a#G<&KN`#?x3lnXkbjWK!e>GI7tr1T-yAgyk7-!=Y4Dvw zdl>m7@9 zdcY51`+uOn@1WlW81G5gw;N>*jU6^kL!Nx`41BZjetfP1RHAGKXaT8!_tEz6fKk93 zfL8&}1HKK|33v+74p;{$2RsN60kQNlrg|qJR^OCywH*6~iGzbZ2RQyYz-KU*%+1;X zB7o8==4WeA?m)gd+E#{gfHk9bEv1GvK{oQCtrU3$pbGE+0x=tq1<(RA0r=jhxqzMJ z9H8p~TxN)M(Ytm0OOtT05H9)TXR;JOQUJ0;A z^EGIz12h6$fL1^!U^9UJZAJbx;90;EsD}a10CoVr2G|480lp152zUW-81O3K2mp69 z&2hkKz`KAkz0XYC8zz!$_(7;w)GrIp>g${vz*lutK zVr!~Ot8y2de06>mEBk)qUE-)RA;Xl-ul z=xp*ebZpVia5QZ8218Bl+MpP6dHq_0PG@Ss=loW8vlwh>@wU4+y8}V5-{a@(A7{*0xQ;V? z5@q<7dBa397VH;Gl6T!nx(DL=iWi8Dhrz}%$UJjf#Lv`DW1;*4WMejv>^kU;)hTa| z_Cxk+aCDQ*^sN43{m`3$bc{svSUoYi*Tw3iv*j~&GN-eotE&t@=DJtl>}Yof1jf=>QIWx3UtC#S zx6;0jv5ym-As>FTYh!;4eph?D-{}Z0HW@mFiWEYcK0&ZMhf-zk#r!Umrj_`DPeO?htJJ_vP%T702q;fWO z1UEUk3G8;%T&RjJ4jSh+E@X_GtP^!WX4jC~RIbTzv>MW-j?7o)S;-_hasF*7T2id#C}u&>4M zbcy}|O3>)wZ{03OS2Jwd(PssrCfiO|F$L#!BK^qZXq1Eo!aW z5)|DX)!q(wagc5%RAP@f)~s@r3kE*T*KJL)`*SuvFU0om*-W!9ITSB{328gs-;r`E zi)%_M+#UYFmYMmr+Zmgo7Zukyi_7Yq*cqG^kCv`2cQ~u6i>n=AisvDgS>$WzC9C|^ zfu`oRM>o=?l6ttdkGRFbR^hwHKi&CyDUL3l;`=FyQ*cdtNr$VtDX__X1KlOHUSA}J zuJ4y<#hsm;aE-oM6CdLtyZ@3>e7O9maANpzrgWgq2QAn-Sv9=iMM)dQO(=EZEgb;ei+6Si`l;5= zws0PjbEEEt3~`VZTJXi|C7aD`{!D+Q&jTuam2Sjr8gl z<1|F%ugcxe61iN6+eOyUI0BICL`hGo*;-gZDTgKh0p7?T@6fl15bNUn&*ED@`R>NL zam7H=!*U(|X<0G)?&Mw-f!!E0&6gXLO76)v_Be9#W(BMZ@tJ7ip41{@yx@EsAF{OQ zuNXLw&!iDQbTGC7e_5rPnRBu*2+vb2bn?0IN5?mNPCIySE#RZCD_Z8diKGrcw_nv? z1Fisi@WRT7-}LaD0U!V zp|y#7vIBX5wZVQ$vweTn=9r`wcHCGt8!tN*_JbtMgd857JW`3BhJBS#G>@(N) zW8~|CMts%w*{j1CT^F=IXpSQOt3v#_XJ#_qf7ep}xc^F_Q-%G3Vl6h)w5}q%K4V$@ zq>4nP53xvVg!bpy+D%CsPbz2%2HhPS+qY=DI@*0f+mcYgXAL%c+#OB9v1h&akQT( z0i;;ZDBknEL{x-J{Cbu-_ZWK1=HR;{@ zT(_`sNnybkX4?}R!WUwrx^@f&GwspQ{>ev=ckQ3+=&yROuoAE8($bZy9;&O07XH+A z+Dkr7pL*a^5Bxv%0ABxRRX7WEn{``tPwSr5eMPrh_YK`X-SfH^bua7sbwAM!>E6dxrS>3*e?b?@sg>VBtV`Z@Yk{cZY8{bGHV{(ikqZ`K#+AJnhVuhLiR*XcLtTlDSv zfWAxrlzzMZ%lfbC_vz2+nW5Zp(C|}3vT&!+Eck^j!Y<)u;bS4exX##W3>m*@e9m~# z_>yth_zUBI8<(5>rY_Sq(=(=Tn4UKsHJvcMZTf}jBhx3Q+s(_&cC*9$h`GhwW`5lK zjCqH7m-$8W%jP%DZ<+tq{GRy}v&y2eWLq4Ta?5H-Vkw*5lTb)>GDZtRGk}S+7`=^5^B>nxB*ZME;lZ`|`h;zc2sw{Gt4og0_Mu z3%*(KQo%nLEVgCY?zib|`L;$|o9%Jimu!D++hu#r_PXsY+o zHdZ*NFtzZu!py?Og;|C77wQVlg$0EV7Op5!yl8dN zlSR9VzEyOf=(|PVFZyxO&x`(z9=%$8ugAO|(!Z$h*Xs;ML$0B~U^kQ+R$vY)4RwYF z!v=%P;4!otIt`+s%dpiDHf%TSFzht!HXJs*V(2#Q!* zAR8_iCJh%2QwIEg;YT!qzjqCLP0BJ3E9E}f=)0Bxk7&u_cVO-h83&A`#?!{L#xdiRQEf^!X-!!s zqbb*9H`SRurgqa-Q`ofK^sH%zX{TwA>9A?QG-Nt%8ZnKU&eC5Bo0H6HbE-Mr{D8Rt zF;Z$SH@nQDxyu|j?=cUVN6nMwDRZi2q2&QfuElQYwCuF(vFx?HV(GV>wOq7JS<-Ve i@!7J$v??p03w?-+lM{cfb4H@BVp@N%gwjB$W`N1jsTW{itbiF#JEGX|Qj(=f}5@ zm(x$(+pnlPb#JZL7t(eG1Dk>^o!ZtGzds;oH}cwG*st~ZwH2#sw4DJDpP!MjKo>W? z?3S&Ee1XqQCE)oD4^MTXedX_bQ(n|7f6yMUw@$UN_Ty7+O#Y531#5Rqb+DSB+RWxg@G@hv@1Z)&2QN7tZ-dsjVF{q332ys!igOHgt`fyDF(}al`xEHe5u#%gR z&s{TDT0#yfk|pLo=L>wd0Md9S5cQA3>>%)rq9tTQe$dk*w7}Pl7=he^It!3g9Oybf zCPpsNG3Wtw@VS7b;=nNSgP~w6XiaJ$5SYD05}-+ogW3!79RUcQ!Pr@VsBcCVI9L-h8HoM z!*CYE8iv&js~A3{rIsBGS1`Ps;VOn*4A(N;z;F}88yNO5>}9xv;Vy;+hPxTw#&Cq; z9SlFs@GgdTGrX7KeGEU#@P39J%)`U%`2~iLF#IyZ{lM*-{?dDhM*8f0LZn|_k!5d# zfoS@w$E8ZF8#$cS!_T17$YHe{R!K`i?5UoSAs|jl9Vvu}$E7bq_jL_v*Y$6vrc%)C zc|xto>^+A`;N<8NYN-r*k_D*VTZ`!zC&gw}Jq$*}Qgr>ebO$)S1K|bId^}u;LQR@a zZBO??`=XE~&KG|nyBZ*p9((MXI0Nn1D&T8M)MHz;BfPP z?N%h30_(gIg2VHgXa*c_9;7S(OnPGF&#RM`QPXVM%YsfR4PkV24NK{i?obYjWl9Vy zO}sVgQub^`M+@XHVS1&HVPvo<<5@k?gi}5myzq4>wr6=8K98Y)XCB66o;0IN^V4)W zoNbIc$9tw@2`y(o3tHpErgoLI8Ip}G-I=(27IL!rA~c}`rLjKen5)k@?!s({=G`${ zE-4>sQRjI%JT9L-Nc)k)WAfRap{#>cb=WzBMI}q{5UF!ss)6(%I{T20ZIBIf4fs>% z?i!dn*SLJJ=BrIQ)#bqy#75B7d*8Vmi}A@B+1jqIlUCzox;&^5=GRM0KbGZ2ao9a^ zyR;J#X4E<B$c_Zjj&fWn(#mPE3n>yTkxv`P?$b1W@VUn8%d+sBW40pUo z??SwM@Mc)4+eM$(>gBW8r6!o`J<}<|0yu7@9!v=FEWDd#;b~Fo z{cWRA6;H6!jpF2lwx@&$cZu_&7{8po4bB(hNl1q;Ir8a7d9>#}Wzp|KZ?BcJBVabh zWY|=)NySDNiwRsrROt{g!S3cq>B4N+c)RI(=tIQC--{oL>s4SP#krHw>Y1qd5Ef6= zIaBmOSX0QR7MpYR_=Q*LuqTDIo+~Ng`~!Qja*K`$s`|Pbd6X`rC&o$Ujy;e8MLLT$ z4`S~?=8j05bQBp$<*q2gI>bd=@2ZgwgI3>8YNY2N&rD)b&!ZH1wD&UYDm7eA?d=2~ zN~!n8Iuc_2LwHG||B1Uq=S5K^rbnyCT&tyDV1YC?4vM_g!;iD`VD9o8m(Ji+85~Zd zgGFx3gRz}6P5L%8>0%VCbQ-Z%rocJH>R}W$*+fQfiH1e8l zPt}@k8+PEO)oPq_^4hG4-y#Z#vWWk%6^)6`vF!z|q0TX3;jr^OHHMvMPC zXbq>~lCMcul7ZngCF5elq4OE-JqMKo``P1pI;+`gtfYf32(>Gug&092J!CZ?dUs(# z$k|zV?6Fe;5>`RxKapjPUTRy;&H)d{@FG+v5s7_>guG-g!@Gb-M!Y_3wekGIK1+8> zO&?(C7_y9cWN^+P$)da@ho?m+O*ML?M4i)p&dGSTiPe+W=+k7d zgp_UD3#-=&sknNJWyPt-winQs-|!@NvTb{J&O$}z-ecmi#66zg*Tv<+v-T_AG30bCvIpn_aP?eNT@B|n!Z{l|#1#>xLSBGIDn@Ma`hlUZ6`iVOl;(OCI$DF9f#{c=HA!E*Xh<2m*)nq*T8#9 zH_Hrx;Vy=~!1Nk+QNxmVJ;_+i+ znuU{5GtHZ+vr#kcpxON>&1DbsZv(?k3^y=b#juiL!te|_ke5s|e2L*nhA%QKF+9%j z7{lioKF9DGhDRA5VfX~YLktfvd=z*#hiKwtzPe&w9e26+Wc`*!qDx(fEj_qU>{g}z zp>P`>7gW*&`XD$?6A0HaFUiBq2eH`cme;o3PG`M(UAW-@zMN?KBD5J#VrMLc!}fkk zTzX=))PuBWL{cohJ}D-&Gzo}ExRdcDpoyQH1kyw3bP$^dHWDIa{fO4mW>|#5bR0ft z;+V!kgg34WGnZr;r<1DhA+`AM73@Ro3866X4Me0vC7y$%6|K3PI?@8&*oU?X)YX6*z=KG{Jb(_M1>^wmy-#xyJIi@M z&FwM28gxXn04LlZlh0a0G>a2s!I4d`23bktM3-~Q&oxA|5B)Vkuj*E!(V*=DIO6ph z&>8^E01u!Y&;{56p#Qd^ehTn3;BmAgfSrI{fNucy0rY_H0uBM52OI&s0yql59Zhor za0c)WU<~js;38lepoHB801e;{z#>2{APx2@XC<1p_(I{94sA#Xdwc<{QLi^Q;d6dF-ztQf+I$`S7CspA1^hmLTc8PFYWbEB z-&6^DU5vg0^!zT*#<}Cr!p{!mLxM{E-G=rqz+u2xoJZwo4%34DlkHm$JX75Y@aTAG zN#+g3bt#?dox#APk{qJYxp=9+5E3Wy%CU*OSV&cC(%3sp!O5| zGuPO8=NkUGB>sg(MDqzCSwETo-eTkq#`;1Ym53D$&LW2vpZ@PpP*CGs!|jrEB+0!? z?*)*%QMq~7`18MOR9BW4=-1{~R8`?lNZju7?(RzbF_&MCv!jC#a)e}((o&6X4wwM>M|$o1h+P~yA`LYKS|e*sE1~i3292H3beL#RMLPn z#GcD&pa{7?Wd-em#+LUuyIbMYCZ5!#)^zZE7r8H)TOPofALM6+NONj!V#uywpp_4W zaOYEekr&Ft!5}UT38FuBtv@za+5<+8TR=R7yr1Ze|2RDwBMv^#=JC&k7GA*UKq^kzbz$Ro}*E1gxGkxlb;TT|lxoQKZ~iT(Rpp=&QWG++J_$_{#eN6B}U z)soNsEK5#CMN>yz{jR99^s=_fwu^U=F>!(^K0L+{E9&c6q(eAIqWZ z`=z|Ht}e!yWAB=YPsmWe|B_1V4wk}_L5r&?{c}+P>ckjheEQLr{Vd};dJ5?HE_WS0 z9g4F=$RzAg`fjxMI|xzXB03&pki+G8mw~ZFTa{{pR2|+u-M~(~rPh!YWEI|J-KbZR zN<7o@Q|0?tVyidiBYmd6mNIUvU+QCW@q(a$J)Bj4UDH zip@&YK_Up57$@OFEz=X?KZ3E4g-JH&YEWASe6-QR!>iap$>d??3$;nV1_V*l_xr0J zC%l|%@y0$pOm2q{Rj{*(S)ozr!uaXPHX#e>?~AUdY4KIBoZJuZjPOrSvkPS%xf8Zl z#dUpgzY^Y1FJlo+Q2v;I`NV^9#rEddm|d_P05y!*3rQpX)8cMpai42zt}mY+`wEOx zf$VL8Cy8++B1>bSW2>STT$)EAc;7N7Khl*)l*KKf5Z}46W2?5iv%?><=Z1rRTd38` zceaFc7@Au$( zww1M$C_-7hpEv`oM9(XrAozr>TDnKub072hIb*JtUQ_J3)d>&s>u`U}FJDuetBrpv zu;&)!>+{WetI?WowLk+O6zDx85G)JgH+ce%fp8Eex(h7eg*SHiS|8!J)&@57ez@G$ zTCkDZSlD9V4Fx>6F}I}n3)lLS7{V74qnbO0;#qopwEyR$#~u35b@W%GSK`7AzJjLa z&2lpWHzRN}0yiUYGXggw@c%6Wc>6zx7bS&$i+-E_DgD#>uj%*dzop-=e@_2`{w00C z{%86j{hRtx{aO8a{crS={yqIA{U7wiFwdYi+-ArzEH>y24;b_Yi=o)?kYTxDrJ>fa z&alDIX6P^k4c&$(4Lb~9HGJK$-*DbQj8(=%#-AJ0xI4L4F2HT&_HZw8A8{$Bb*6Sx z*z{%7Gp0kP7fr*aUzz^Pw9FhZcbm7HcbdOte$IT%eA4`u`B&x-%^#a@w=A_dEKbWK zmNv^~%VUCX`Y55n+yOxhF3aiGNXLVYutgEecR=3q>ecbxj)Gj0yJAxoEhxIRD8K0OqOTP76@9yCf6;42 zLq%=Hn~R?){&w+;#s5^i*silbVAtD=?9KMg_Q&jBvHz8QkNs8qYxXzoqxQ4*^Y-7^ zCHs5!OZGq5Ny)qtb;)fdIVForbR`dz=u0dm#U&4wEH7DEQd{!PlJAxLL&?h}Crj=q zU0k}Xbam+yrF%-hQ+lxU`=viD{b}hhOaGO=^lI_F9`kzG@PeV=pf{R~1;%2d!&qTl zjyZ4{8;niH4MvaAYwR#~83kjvahow>++o~h+-=-zJYsy=*l#>)954)LVGfkUR zX0=&s)|pM_0<**1VD_3j%-hTn^A7XV=3VC9=6&WP<^l7N`Gk4IJZe5ie<^HHT2vOb zCCl=lr5HIMQgf{SK^#A^n(sMvuQ({RNf(1`r`lyZ`_I diff --git a/base/debug/OWNERS b/base/debug/OWNERS deleted file mode 100644 index 4976ab1e77..0000000000 --- a/base/debug/OWNERS +++ /dev/null @@ -1,3 +0,0 @@ -per-file trace_event*=nduca@chromium.org -per-file trace_event*=dsinclair@chromium.org -per-file trace_event_android.cc=wangxianzhu@chromium.org diff --git a/base/debug/alias.cc b/base/debug/alias.cc deleted file mode 100644 index 6b0caaa6d1..0000000000 --- a/base/debug/alias.cc +++ /dev/null @@ -1,23 +0,0 @@ -// Copyright (c) 2011 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "base/debug/alias.h" -#include "build/build_config.h" - -namespace base { -namespace debug { - -#if defined(COMPILER_MSVC) -#pragma optimize("", off) -#endif - -void Alias(const void* var) { -} - -#if defined(COMPILER_MSVC) -#pragma optimize("", on) -#endif - -} // namespace debug -} // namespace base diff --git a/base/debug/alias.h b/base/debug/alias.h deleted file mode 100644 index 3b2ab64f33..0000000000 --- a/base/debug/alias.h +++ /dev/null @@ -1,21 +0,0 @@ -// Copyright (c) 2011 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef BASE_DEBUG_ALIAS_H_ -#define BASE_DEBUG_ALIAS_H_ - -#include "base/base_export.h" - -namespace base { -namespace debug { - -// Make the optimizer think that var is aliased. This is to prevent it from -// optimizing out variables that that would not otherwise be live at the point -// of a potential crash. -void BASE_EXPORT Alias(const void* var); - -} // namespace debug -} // namespace base - -#endif // BASE_DEBUG_ALIAS_H_ diff --git a/base/debug/crash_logging.cc b/base/debug/crash_logging.cc deleted file mode 100644 index 6a36a916c6..0000000000 --- a/base/debug/crash_logging.cc +++ /dev/null @@ -1,201 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "base/debug/crash_logging.h" - -#include -#include - -#include "base/debug/stack_trace.h" -#include "base/format_macros.h" -#include "base/logging.h" -#include "base/strings/string_util.h" -#include "base/strings/stringprintf.h" - -namespace base { -namespace debug { - -namespace { - -// Global map of crash key names to registration entries. -typedef std::map CrashKeyMap; -CrashKeyMap* g_crash_keys_ = NULL; - -// The maximum length of a single chunk. -size_t g_chunk_max_length_ = 0; - -// String used to format chunked key names. -const char kChunkFormatString[] = "%s-%" PRIuS; - -// The functions that are called to actually set the key-value pairs in the -// crash reportng system. -SetCrashKeyValueFuncT g_set_key_func_ = NULL; -ClearCrashKeyValueFuncT g_clear_key_func_ = NULL; - -// For a given |length|, computes the number of chunks a value of that size -// will occupy. -size_t NumChunksForLength(size_t length) { - return std::ceil(length / static_cast(g_chunk_max_length_)); -} - -// The longest max_length allowed by the system. -const size_t kLargestValueAllowed = 1024; - -} // namespace - -void SetCrashKeyValue(const base::StringPiece& key, - const base::StringPiece& value) { - if (!g_set_key_func_) - return; - - const CrashKey* crash_key = LookupCrashKey(key); - - // TODO(rsesek): Do this: - //DCHECK(crash_key) << "All crash keys must be registered before use " - // << "(key = " << key << ")"; - - // Handle the un-chunked case. - if (!crash_key || crash_key->max_length <= g_chunk_max_length_) { - g_set_key_func_(key, value); - return; - } - - // Unset the unused chunks. - std::vector chunks = - ChunkCrashKeyValue(*crash_key, value, g_chunk_max_length_); - for (size_t i = chunks.size(); - i < NumChunksForLength(crash_key->max_length); - ++i) { - g_clear_key_func_(base::StringPrintf(kChunkFormatString, key.data(), i+1)); - } - - // Set the chunked keys. - for (size_t i = 0; i < chunks.size(); ++i) { - g_set_key_func_(base::StringPrintf(kChunkFormatString, key.data(), i+1), - chunks[i]); - } -} - -void ClearCrashKey(const base::StringPiece& key) { - if (!g_clear_key_func_) - return; - - const CrashKey* crash_key = LookupCrashKey(key); - - // Handle the un-chunked case. - if (!crash_key || crash_key->max_length <= g_chunk_max_length_) { - g_clear_key_func_(key); - return; - } - - for (size_t i = 0; i < NumChunksForLength(crash_key->max_length); ++i) { - g_clear_key_func_(base::StringPrintf(kChunkFormatString, key.data(), i+1)); - } -} - -void SetCrashKeyToStackTrace(const base::StringPiece& key, - const StackTrace& trace) { - size_t count = 0; - const void* const* addresses = trace.Addresses(&count); - SetCrashKeyFromAddresses(key, addresses, count); -} - -void SetCrashKeyFromAddresses(const base::StringPiece& key, - const void* const* addresses, - size_t count) { - std::string value = ""; - if (addresses && count) { - const size_t kBreakpadValueMax = 255; - - std::vector hex_backtrace; - size_t length = 0; - - for (size_t i = 0; i < count; ++i) { - std::string s = base::StringPrintf("%p", addresses[i]); - length += s.length() + 1; - if (length > kBreakpadValueMax) - break; - hex_backtrace.push_back(s); - } - - value = JoinString(hex_backtrace, ' '); - - // Warn if this exceeds the breakpad limits. - DCHECK_LE(value.length(), kBreakpadValueMax); - } - - SetCrashKeyValue(key, value); -} - -ScopedCrashKey::ScopedCrashKey(const base::StringPiece& key, - const base::StringPiece& value) - : key_(key.as_string()) { - SetCrashKeyValue(key, value); -} - -ScopedCrashKey::~ScopedCrashKey() { - ClearCrashKey(key_); -} - -size_t InitCrashKeys(const CrashKey* const keys, size_t count, - size_t chunk_max_length) { - DCHECK(!g_crash_keys_) << "Crash logging may only be initialized once"; - if (!keys) { - delete g_crash_keys_; - g_crash_keys_ = NULL; - return 0; - } - - g_crash_keys_ = new CrashKeyMap; - g_chunk_max_length_ = chunk_max_length; - - size_t total_keys = 0; - for (size_t i = 0; i < count; ++i) { - g_crash_keys_->insert(std::make_pair(keys[i].key_name, keys[i])); - total_keys += NumChunksForLength(keys[i].max_length); - DCHECK_LT(keys[i].max_length, kLargestValueAllowed); - } - DCHECK_EQ(count, g_crash_keys_->size()) - << "Duplicate crash keys were registered"; - - return total_keys; -} - -const CrashKey* LookupCrashKey(const base::StringPiece& key) { - CrashKeyMap::const_iterator it = g_crash_keys_->find(key.as_string()); - if (it == g_crash_keys_->end()) - return NULL; - return &(it->second); -} - -void SetCrashKeyReportingFunctions( - SetCrashKeyValueFuncT set_key_func, - ClearCrashKeyValueFuncT clear_key_func) { - g_set_key_func_ = set_key_func; - g_clear_key_func_ = clear_key_func; -} - -std::vector ChunkCrashKeyValue(const CrashKey& crash_key, - const base::StringPiece& value, - size_t chunk_max_length) { - std::string value_string = value.substr(0, crash_key.max_length).as_string(); - std::vector chunks; - for (size_t offset = 0; offset < value_string.length(); ) { - std::string chunk = value_string.substr(offset, chunk_max_length); - chunks.push_back(chunk); - offset += chunk.length(); - } - return chunks; -} - -void ResetCrashLoggingForTesting() { - delete g_crash_keys_; - g_crash_keys_ = NULL; - g_chunk_max_length_ = 0; - g_set_key_func_ = NULL; - g_clear_key_func_ = NULL; -} - -} // namespace debug -} // namespace base diff --git a/base/debug/crash_logging.h b/base/debug/crash_logging.h deleted file mode 100644 index 376d011655..0000000000 --- a/base/debug/crash_logging.h +++ /dev/null @@ -1,104 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef BASE_DEBUG_CRASH_LOGGING_H_ -#define BASE_DEBUG_CRASH_LOGGING_H_ - -#include -#include - -#include "base/base_export.h" -#include "base/basictypes.h" -#include "base/strings/string_piece.h" - -// These functions add metadata to the upload payload when sending crash reports -// to the crash server. -// -// IMPORTANT: On OS X and Linux, the key/value pairs are only sent as part of -// the upload and are not included in the minidump! - -namespace base { -namespace debug { - -class StackTrace; - -// Set or clear a specific key-value pair from the crash metadata. Keys and -// values are terminated at the null byte. -BASE_EXPORT void SetCrashKeyValue(const base::StringPiece& key, - const base::StringPiece& value); -BASE_EXPORT void ClearCrashKey(const base::StringPiece& key); - -// Records the given StackTrace into a crash key. -BASE_EXPORT void SetCrashKeyToStackTrace(const base::StringPiece& key, - const StackTrace& trace); - -// Formats |count| instruction pointers from |addresses| using %p and -// sets the resulting string as a value for crash key |key|. A maximum of 23 -// items will be encoded, since breakpad limits values to 255 bytes. -BASE_EXPORT void SetCrashKeyFromAddresses(const base::StringPiece& key, - const void* const* addresses, - size_t count); - -// A scoper that sets the specified key to value for the lifetime of the -// object, and clears it on destruction. -class BASE_EXPORT ScopedCrashKey { - public: - ScopedCrashKey(const base::StringPiece& key, const base::StringPiece& value); - ~ScopedCrashKey(); - - private: - std::string key_; - - DISALLOW_COPY_AND_ASSIGN(ScopedCrashKey); -}; - -// Before setting values for a key, all the keys must be registered. -struct BASE_EXPORT CrashKey { - // The name of the crash key, used in the above functions. - const char* const key_name; - - // The maximum length for a value. If the value is longer than this, it will - // be truncated. If the value is larger than the |chunk_max_length| passed to - // InitCrashKeys() but less than this value, it will be split into multiple - // numbered chunks. - size_t max_length; -}; - -// Before the crash key logging mechanism can be used, all crash keys must be -// registered with this function. The function returns the amount of space -// the crash reporting implementation should allocate space for the registered -// crash keys. |chunk_max_length| is the maximum size that a value in a single -// chunk can be. -BASE_EXPORT size_t InitCrashKeys(const CrashKey* const keys, size_t count, - size_t chunk_max_length); - -// Returns the correspnding crash key object or NULL for a given key. -BASE_EXPORT const CrashKey* LookupCrashKey(const base::StringPiece& key); - -// In the platform crash reporting implementation, these functions set and -// clear the NUL-termianted key-value pairs. -typedef void (*SetCrashKeyValueFuncT)(const base::StringPiece&, - const base::StringPiece&); -typedef void (*ClearCrashKeyValueFuncT)(const base::StringPiece&); - -// Sets the function pointers that are used to integrate with the platform- -// specific crash reporting libraries. -BASE_EXPORT void SetCrashKeyReportingFunctions( - SetCrashKeyValueFuncT set_key_func, - ClearCrashKeyValueFuncT clear_key_func); - -// Helper function that breaks up a value according to the parameters -// specified by the crash key object. -BASE_EXPORT std::vector ChunkCrashKeyValue( - const CrashKey& crash_key, - const base::StringPiece& value, - size_t chunk_max_length); - -// Resets the crash key system so it can be reinitialized. For testing only. -BASE_EXPORT void ResetCrashLoggingForTesting(); - -} // namespace debug -} // namespace base - -#endif // BASE_DEBUG_CRASH_LOGGING_H_ diff --git a/base/debug/crash_logging_unittest.cc b/base/debug/crash_logging_unittest.cc deleted file mode 100644 index 8c252f02d8..0000000000 --- a/base/debug/crash_logging_unittest.cc +++ /dev/null @@ -1,182 +0,0 @@ -// Copyright (c) 2013 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "base/debug/crash_logging.h" - -#include -#include - -#include "base/bind.h" -#include "testing/gtest/include/gtest/gtest.h" - -namespace { - -std::map* key_values_ = NULL; - -} // namespace - -class CrashLoggingTest : public testing::Test { - public: - virtual void SetUp() { - key_values_ = new std::map; - base::debug::SetCrashKeyReportingFunctions( - &CrashLoggingTest::SetKeyValue, - &CrashLoggingTest::ClearKeyValue); - } - - virtual void TearDown() { - base::debug::ResetCrashLoggingForTesting(); - - delete key_values_; - key_values_ = NULL; - } - - private: - static void SetKeyValue(const base::StringPiece& key, - const base::StringPiece& value) { - (*key_values_)[key.as_string()] = value.as_string(); - } - - static void ClearKeyValue(const base::StringPiece& key) { - key_values_->erase(key.as_string()); - } -}; - -TEST_F(CrashLoggingTest, SetClearSingle) { - const char* kTestKey = "test-key"; - base::debug::CrashKey keys[] = { { kTestKey, 255 } }; - base::debug::InitCrashKeys(keys, arraysize(keys), 255); - - base::debug::SetCrashKeyValue(kTestKey, "value"); - EXPECT_EQ("value", (*key_values_)[kTestKey]); - - base::debug::ClearCrashKey(kTestKey); - EXPECT_TRUE(key_values_->end() == key_values_->find(kTestKey)); -} - -TEST_F(CrashLoggingTest, SetChunked) { - const char* kTestKey = "chunky"; - const char* kChunk1 = "chunky-1"; - const char* kChunk2 = "chunky-2"; - const char* kChunk3 = "chunky-3"; - base::debug::CrashKey keys[] = { { kTestKey, 15 } }; - base::debug::InitCrashKeys(keys, arraysize(keys), 5); - - std::map& values = *key_values_; - - // Fill only the first chunk. - base::debug::SetCrashKeyValue(kTestKey, "foo"); - EXPECT_EQ(1u, values.size()); - EXPECT_EQ("foo", values[kChunk1]); - EXPECT_TRUE(values.end() == values.find(kChunk2)); - EXPECT_TRUE(values.end() == values.find(kChunk3)); - - // Fill three chunks with truncation (max length is 15, this string is 20). - base::debug::SetCrashKeyValue(kTestKey, "five four three two"); - EXPECT_EQ(3u, values.size()); - EXPECT_EQ("five ", values[kChunk1]); - EXPECT_EQ("four ", values[kChunk2]); - EXPECT_EQ("three", values[kChunk3]); - - // Clear everything. - base::debug::ClearCrashKey(kTestKey); - EXPECT_EQ(0u, values.size()); - EXPECT_TRUE(values.end() == values.find(kChunk1)); - EXPECT_TRUE(values.end() == values.find(kChunk2)); - EXPECT_TRUE(values.end() == values.find(kChunk3)); - - // Refill all three chunks with truncation, then test that setting a smaller - // value clears the third chunk. - base::debug::SetCrashKeyValue(kTestKey, "five four three two"); - base::debug::SetCrashKeyValue(kTestKey, "allays"); - EXPECT_EQ(2u, values.size()); - EXPECT_EQ("allay", values[kChunk1]); - EXPECT_EQ("s", values[kChunk2]); - EXPECT_TRUE(values.end() == values.find(kChunk3)); - - // Clear everything. - base::debug::ClearCrashKey(kTestKey); - EXPECT_EQ(0u, values.size()); - EXPECT_TRUE(values.end() == values.find(kChunk1)); - EXPECT_TRUE(values.end() == values.find(kChunk2)); - EXPECT_TRUE(values.end() == values.find(kChunk3)); -} - -TEST_F(CrashLoggingTest, ScopedCrashKey) { - const char* kTestKey = "test-key"; - base::debug::CrashKey keys[] = { { kTestKey, 255 } }; - base::debug::InitCrashKeys(keys, arraysize(keys), 255); - - EXPECT_EQ(0u, key_values_->size()); - EXPECT_TRUE(key_values_->end() == key_values_->find(kTestKey)); - { - base::debug::ScopedCrashKey scoped_crash_key(kTestKey, "value"); - EXPECT_EQ("value", (*key_values_)[kTestKey]); - EXPECT_EQ(1u, key_values_->size()); - } - EXPECT_EQ(0u, key_values_->size()); - EXPECT_TRUE(key_values_->end() == key_values_->find(kTestKey)); -} - -TEST_F(CrashLoggingTest, InitSize) { - base::debug::CrashKey keys[] = { - { "chunked-3", 15 }, - { "single", 5 }, - { "chunked-6", 30 }, - }; - - size_t num_keys = base::debug::InitCrashKeys(keys, arraysize(keys), 5); - - EXPECT_EQ(10u, num_keys); - - EXPECT_TRUE(base::debug::LookupCrashKey("chunked-3")); - EXPECT_TRUE(base::debug::LookupCrashKey("single")); - EXPECT_TRUE(base::debug::LookupCrashKey("chunked-6")); - EXPECT_FALSE(base::debug::LookupCrashKey("chunked-6-4")); -} - -TEST_F(CrashLoggingTest, ChunkValue) { - using base::debug::ChunkCrashKeyValue; - - // Test truncation. - base::debug::CrashKey key = { "chunky", 10 }; - std::vector results = - ChunkCrashKeyValue(key, "hello world", 64); - ASSERT_EQ(1u, results.size()); - EXPECT_EQ("hello worl", results[0]); - - // Test short string. - results = ChunkCrashKeyValue(key, "hi", 10); - ASSERT_EQ(1u, results.size()); - EXPECT_EQ("hi", results[0]); - - // Test chunk pair. - key.max_length = 6; - results = ChunkCrashKeyValue(key, "foobar", 3); - ASSERT_EQ(2u, results.size()); - EXPECT_EQ("foo", results[0]); - EXPECT_EQ("bar", results[1]); - - // Test chunk pair truncation. - results = ChunkCrashKeyValue(key, "foobared", 3); - ASSERT_EQ(2u, results.size()); - EXPECT_EQ("foo", results[0]); - EXPECT_EQ("bar", results[1]); - - // Test extra chunks. - key.max_length = 100; - results = ChunkCrashKeyValue(key, "hello world", 3); - ASSERT_EQ(4u, results.size()); - EXPECT_EQ("hel", results[0]); - EXPECT_EQ("lo ", results[1]); - EXPECT_EQ("wor", results[2]); - EXPECT_EQ("ld", results[3]); -} - -TEST_F(CrashLoggingTest, ChunkRounding) { - // If max_length=12 and max_chunk_length=5, there should be 3 chunks, - // not 2. - base::debug::CrashKey key = { "round", 12 }; - EXPECT_EQ(3u, base::debug::InitCrashKeys(&key, 1, 5)); -} diff --git a/base/debug/debug_on_start_win.cc b/base/debug/debug_on_start_win.cc deleted file mode 100644 index 6ca88dde20..0000000000 --- a/base/debug/debug_on_start_win.cc +++ /dev/null @@ -1,74 +0,0 @@ -// Copyright (c) 2011 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "base/debug/debug_on_start_win.h" - -#include - -#include "base/base_switches.h" -#include "base/basictypes.h" -#include "base/debug/debugger.h" - -namespace base { -namespace debug { - -// Minimalist implementation to try to find a command line argument. We can use -// kernel32 exported functions but not the CRT functions because we're too early -// in the process startup. -// The code is not that bright and will find things like ---argument or -// /-/argument. -// Note: command_line is non-destructively modified. -bool DebugOnStart::FindArgument(wchar_t* command_line, const char* argument_c) { - wchar_t argument[50] = {}; - for (int i = 0; argument_c[i]; ++i) - argument[i] = argument_c[i]; - - int argument_len = lstrlen(argument); - int command_line_len = lstrlen(command_line); - while (command_line_len > argument_len) { - wchar_t first_char = command_line[0]; - wchar_t last_char = command_line[argument_len+1]; - // Try to find an argument. - if ((first_char == L'-' || first_char == L'/') && - (last_char == L' ' || last_char == 0 || last_char == L'=')) { - command_line[argument_len+1] = 0; - // Skip the - or / - if (lstrcmpi(command_line+1, argument) == 0) { - // Found it. - command_line[argument_len+1] = last_char; - return true; - } - // Fix back. - command_line[argument_len+1] = last_char; - } - // Continue searching. - ++command_line; - --command_line_len; - } - return false; -} - -// static -int __cdecl DebugOnStart::Init() { - // Try to find the argument. - if (FindArgument(GetCommandLine(), switches::kDebugOnStart)) { - // We can do 2 things here: - // - Ask for a debugger to attach to us. This involve reading the registry - // key and creating the process. - // - Do a int3. - - // It will fails if we run in a sandbox. That is expected. - base::debug::SpawnDebuggerOnProcess(GetCurrentProcessId()); - - // Wait for a debugger to come take us. - base::debug::WaitForDebugger(60, false); - } else if (FindArgument(GetCommandLine(), switches::kWaitForDebugger)) { - // Wait for a debugger to come take us. - base::debug::WaitForDebugger(60, true); - } - return 0; -} - -} // namespace debug -} // namespace base diff --git a/base/debug/debug_on_start_win.h b/base/debug/debug_on_start_win.h deleted file mode 100644 index edcaa0aa95..0000000000 --- a/base/debug/debug_on_start_win.h +++ /dev/null @@ -1,83 +0,0 @@ -// Copyright (c) 2011 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -// Define the necessary code and global data to look for kDebugOnStart command -// line argument. When the command line argument is detected, it invokes the -// debugger, if no system-wide debugger is registered, a debug break is done. - -#ifndef BASE_DEBUG_DEBUG_ON_START_WIN_H_ -#define BASE_DEBUG_DEBUG_ON_START_WIN_H_ - -#include "base/basictypes.h" -#include "build/build_config.h" - -// This only works on Windows. It's legal to include on other platforms, but -// will be a NOP. -#if defined(OS_WIN) - -#ifndef DECLSPEC_SELECTANY -#define DECLSPEC_SELECTANY __declspec(selectany) -#endif - -namespace base { -namespace debug { - -// There is no way for this code, as currently implemented, to work across DLLs. -// TODO(rvargas): It looks like we really don't use this code, at least not for -// Chrome. Figure out if it's really worth implementing something simpler. -#if !defined(COMPONENT_BUILD) - -// Debug on start functions and data. -class DebugOnStart { - public: - // Expected function type in the .CRT$XI* section. - // Note: See VC\crt\src\internal.h for reference. - typedef int (__cdecl *PIFV)(void); - - // Looks at the command line for kDebugOnStart argument. If found, it invokes - // the debugger, if this fails, it crashes. - static int __cdecl Init(); - - // Returns true if the 'argument' is present in the 'command_line'. It does - // not use the CRT, only Kernel32 functions. - static bool FindArgument(wchar_t* command_line, const char* argument); -}; - -// Set the function pointer to our function to look for a crash on start. The -// XIB section is started pretty early in the program initialization so in -// theory it should be called before any user created global variable -// initialization code and CRT initialization code. -// Note: See VC\crt\src\defsects.inc and VC\crt\src\crt0.c for reference. -#ifdef _WIN64 - -// "Fix" the segment. On x64, the .CRT segment is merged into the .rdata segment -// so it contains const data only. -#pragma const_seg(push, ".CRT$XIB") -// Declare the pointer so the CRT will find it. -extern const DebugOnStart::PIFV debug_on_start; -DECLSPEC_SELECTANY const DebugOnStart::PIFV debug_on_start = - &DebugOnStart::Init; -// Fix back the segment. -#pragma const_seg(pop) - -#else // _WIN64 - -// "Fix" the segment. On x86, the .CRT segment is merged into the .data segment -// so it contains non-const data only. -#pragma data_seg(push, ".CRT$XIB") -// Declare the pointer so the CRT will find it. -DECLSPEC_SELECTANY DebugOnStart::PIFV debug_on_start = &DebugOnStart::Init; -// Fix back the segment. -#pragma data_seg(pop) - -#endif // _WIN64 - -#endif // defined(COMPONENT_BUILD) - -} // namespace debug -} // namespace base - -#endif // defined(OS_WIN) - -#endif // BASE_DEBUG_DEBUG_ON_START_WIN_H_ diff --git a/base/debug/debugger.cc b/base/debug/debugger.cc deleted file mode 100644 index 79233c58c5..0000000000 --- a/base/debug/debugger.cc +++ /dev/null @@ -1,41 +0,0 @@ -// Copyright (c) 2011 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "base/debug/debugger.h" -#include "base/logging.h" -#include "base/threading/platform_thread.h" - -namespace base { -namespace debug { - -static bool is_debug_ui_suppressed = false; - -bool WaitForDebugger(int wait_seconds, bool silent) { -#if defined(OS_ANDROID) - // The pid from which we know which process to attach to are not output by - // android ddms, so we have to print it out explicitly. - DLOG(INFO) << "DebugUtil::WaitForDebugger(pid=" << static_cast(getpid()) - << ")"; -#endif - for (int i = 0; i < wait_seconds * 10; ++i) { - if (BeingDebugged()) { - if (!silent) - BreakDebugger(); - return true; - } - PlatformThread::Sleep(TimeDelta::FromMilliseconds(100)); - } - return false; -} - -void SetSuppressDebugUI(bool suppress) { - is_debug_ui_suppressed = suppress; -} - -bool IsDebugUISuppressed() { - return is_debug_ui_suppressed; -} - -} // namespace debug -} // namespace base diff --git a/base/debug/debugger.h b/base/debug/debugger.h deleted file mode 100644 index 4f368d986d..0000000000 --- a/base/debug/debugger.h +++ /dev/null @@ -1,48 +0,0 @@ -// Copyright (c) 2011 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -// This is a cross platform interface for helper functions related to -// debuggers. You should use this to test if you're running under a debugger, -// and if you would like to yield (breakpoint) into the debugger. - -#ifndef BASE_DEBUG_DEBUGGER_H -#define BASE_DEBUG_DEBUGGER_H - -#include "base/base_export.h" - -namespace base { -namespace debug { - -// Starts the registered system-wide JIT debugger to attach it to specified -// process. -BASE_EXPORT bool SpawnDebuggerOnProcess(unsigned process_id); - -// Waits wait_seconds seconds for a debugger to attach to the current process. -// When silent is false, an exception is thrown when a debugger is detected. -BASE_EXPORT bool WaitForDebugger(int wait_seconds, bool silent); - -// Returns true if the given process is being run under a debugger. -// -// On OS X, the underlying mechanism doesn't work when the sandbox is enabled. -// To get around this, this function caches its value. -// -// WARNING: Because of this, on OS X, a call MUST be made to this function -// BEFORE the sandbox is enabled. -BASE_EXPORT bool BeingDebugged(); - -// Break into the debugger, assumes a debugger is present. -BASE_EXPORT void BreakDebugger(); - -// Used in test code, this controls whether showing dialogs and breaking into -// the debugger is suppressed for debug errors, even in debug mode (normally -// release mode doesn't do this stuff -- this is controlled separately). -// Normally UI is not suppressed. This is normally used when running automated -// tests where we want a crash rather than a dialog or a debugger. -BASE_EXPORT void SetSuppressDebugUI(bool suppress); -BASE_EXPORT bool IsDebugUISuppressed(); - -} // namespace debug -} // namespace base - -#endif // BASE_DEBUG_DEBUGGER_H diff --git a/base/debug/debugger_posix.cc b/base/debug/debugger_posix.cc deleted file mode 100644 index 066c592bd4..0000000000 --- a/base/debug/debugger_posix.cc +++ /dev/null @@ -1,261 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "base/debug/debugger.h" -#include "build/build_config.h" - -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include - -#if defined(__GLIBCXX__) -#include -#endif - -#if defined(OS_MACOSX) -#include -#endif - -#if defined(OS_MACOSX) || defined(OS_BSD) -#include -#endif - -#if defined(OS_FREEBSD) -#include -#endif - -#include - -#include "base/basictypes.h" -#include "base/logging.h" -#include "base/memory/scoped_ptr.h" -#include "base/posix/eintr_wrapper.h" -#include "base/safe_strerror_posix.h" -#include "base/strings/string_piece.h" -#include "base/strings/stringprintf.h" - -#if defined(USE_SYMBOLIZE) -#include "base/third_party/symbolize/symbolize.h" -#endif - -#if defined(OS_ANDROID) -#include "base/threading/platform_thread.h" -#endif - -namespace base { -namespace debug { - -bool SpawnDebuggerOnProcess(unsigned process_id) { -#if OS_ANDROID || OS_NACL - NOTIMPLEMENTED(); - return false; -#else - const std::string debug_cmd = - StringPrintf("xterm -e 'gdb --pid=%u' &", process_id); - LOG(WARNING) << "Starting debugger on pid " << process_id - << " with command `" << debug_cmd << "`"; - int ret = system(debug_cmd.c_str()); - if (ret == -1) - return false; - return true; -#endif -} - -#if defined(OS_MACOSX) || defined(OS_BSD) - -// Based on Apple's recommended method as described in -// http://developer.apple.com/qa/qa2004/qa1361.html -bool BeingDebugged() { - // NOTE: This code MUST be async-signal safe (it's used by in-process - // stack dumping signal handler). NO malloc or stdio is allowed here. - // - // While some code used below may be async-signal unsafe, note how - // the result is cached (see |is_set| and |being_debugged| static variables - // right below). If this code is properly warmed-up early - // in the start-up process, it should be safe to use later. - - // If the process is sandboxed then we can't use the sysctl, so cache the - // value. - static bool is_set = false; - static bool being_debugged = false; - - if (is_set) - return being_debugged; - - // Initialize mib, which tells sysctl what info we want. In this case, - // we're looking for information about a specific process ID. - int mib[] = { - CTL_KERN, - KERN_PROC, - KERN_PROC_PID, - getpid() -#if defined(OS_OPENBSD) - , sizeof(struct kinfo_proc), - 0 -#endif - }; - - // Caution: struct kinfo_proc is marked __APPLE_API_UNSTABLE. The source and - // binary interfaces may change. - struct kinfo_proc info; - size_t info_size = sizeof(info); - -#if defined(OS_OPENBSD) - if (sysctl(mib, arraysize(mib), NULL, &info_size, NULL, 0) < 0) - return -1; - - mib[5] = (info_size / sizeof(struct kinfo_proc)); -#endif - - int sysctl_result = sysctl(mib, arraysize(mib), &info, &info_size, NULL, 0); - DCHECK_EQ(sysctl_result, 0); - if (sysctl_result != 0) { - is_set = true; - being_debugged = false; - return being_debugged; - } - - // This process is being debugged if the P_TRACED flag is set. - is_set = true; -#if defined(OS_FREEBSD) - being_debugged = (info.ki_flag & P_TRACED) != 0; -#elif defined(OS_BSD) - being_debugged = (info.p_flag & P_TRACED) != 0; -#else - being_debugged = (info.kp_proc.p_flag & P_TRACED) != 0; -#endif - return being_debugged; -} - -#elif defined(OS_LINUX) || defined(OS_ANDROID) - -// We can look in /proc/self/status for TracerPid. We are likely used in crash -// handling, so we are careful not to use the heap or have side effects. -// Another option that is common is to try to ptrace yourself, but then we -// can't detach without forking(), and that's not so great. -// static -bool BeingDebugged() { - // NOTE: This code MUST be async-signal safe (it's used by in-process - // stack dumping signal handler). NO malloc or stdio is allowed here. - - int status_fd = open("/proc/self/status", O_RDONLY); - if (status_fd == -1) - return false; - - // We assume our line will be in the first 1024 characters and that we can - // read this much all at once. In practice this will generally be true. - // This simplifies and speeds up things considerably. - char buf[1024]; - - ssize_t num_read = HANDLE_EINTR(read(status_fd, buf, sizeof(buf))); - if (HANDLE_EINTR(close(status_fd)) < 0) - return false; - - if (num_read <= 0) - return false; - - StringPiece status(buf, num_read); - StringPiece tracer("TracerPid:\t"); - - StringPiece::size_type pid_index = status.find(tracer); - if (pid_index == StringPiece::npos) - return false; - - // Our pid is 0 without a debugger, assume this for any pid starting with 0. - pid_index += tracer.size(); - return pid_index < status.size() && status[pid_index] != '0'; -} - -#else - -bool BeingDebugged() { - NOTIMPLEMENTED(); - return false; -} - -#endif - -// We want to break into the debugger in Debug mode, and cause a crash dump in -// Release mode. Breakpad behaves as follows: -// -// +-------+-----------------+-----------------+ -// | OS | Dump on SIGTRAP | Dump on SIGABRT | -// +-------+-----------------+-----------------+ -// | Linux | N | Y | -// | Mac | Y | N | -// +-------+-----------------+-----------------+ -// -// Thus we do the following: -// Linux: Debug mode, send SIGTRAP; Release mode, send SIGABRT. -// Mac: Always send SIGTRAP. - -#if defined(NDEBUG) && !defined(OS_MACOSX) && !defined(OS_ANDROID) -#define DEBUG_BREAK() abort() -#elif defined(OS_NACL) -// The NaCl verifier doesn't let use use int3. For now, we call abort(). We -// should ask for advice from some NaCl experts about the optimum thing here. -// http://code.google.com/p/nativeclient/issues/detail?id=645 -#define DEBUG_BREAK() abort() -#elif defined(OS_ANDROID) -// Though Android has a "helpful" process called debuggerd to catch native -// signals on the general assumption that they are fatal errors. If no debugger -// is attached, we call abort since Breakpad needs SIGABRT to create a dump. -// When debugger is attached, for ARM platform the bkpt instruction appears -// to cause SIGBUS which is trapped by debuggerd, and we've had great -// difficulty continuing in a debugger once we stop from SIG triggered by native -// code, use GDB to set |go| to 1 to resume execution; for X86 platform, use -// "int3" to setup breakpiont and raise SIGTRAP. -namespace { -void DebugBreak() { - if (!BeingDebugged()) { - abort(); - } else { -#if defined(ARCH_CPU_X86_FAMILY) - asm("int3"); -#else - volatile int go = 0; - while (!go) { - base::PlatformThread::Sleep(base::TimeDelta::FromMilliseconds(100)); - } -#endif - } -} -} // namespace -#define DEBUG_BREAK() DebugBreak() -#elif defined(ARCH_CPU_ARM_FAMILY) -// ARM && !ANDROID -#define DEBUG_BREAK() asm("bkpt 0") -#elif defined(ARCH_CPU_MIPS_FAMILY) -#define DEBUG_BREAK() asm("break 2") -#else -#define DEBUG_BREAK() asm("int3") -#endif - -void BreakDebugger() { - // NOTE: This code MUST be async-signal safe (it's used by in-process - // stack dumping signal handler). NO malloc or stdio is allowed here. - - DEBUG_BREAK(); -#if defined(OS_ANDROID) && !defined(OFFICIAL_BUILD) - // For Android development we always build release (debug builds are - // unmanageably large), so the unofficial build is used for debugging. It is - // helpful to be able to insert BreakDebugger() statements in the source, - // attach the debugger, inspect the state of the program and then resume it by - // setting the 'go' variable above. -#elif defined(NDEBUG) - // Terminate the program after signaling the debug break. - _exit(1); -#endif -} - -} // namespace debug -} // namespace base diff --git a/base/debug/debugger_win.cc b/base/debug/debugger_win.cc deleted file mode 100644 index b13dbfd148..0000000000 --- a/base/debug/debugger_win.cc +++ /dev/null @@ -1,114 +0,0 @@ -// Copyright (c) 2010 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "base/debug/debugger.h" - -#include -#include - -#include "base/basictypes.h" -#include "base/logging.h" - -namespace base { -namespace debug { - -namespace { - -// Minimalist key reader. -// Note: Does not use the CRT. -bool RegReadString(HKEY root, const wchar_t* subkey, - const wchar_t* value_name, wchar_t* buffer, int* len) { - HKEY key = NULL; - DWORD res = RegOpenKeyEx(root, subkey, 0, KEY_READ, &key); - if (ERROR_SUCCESS != res || key == NULL) - return false; - - DWORD type = 0; - DWORD buffer_size = *len * sizeof(wchar_t); - // We don't support REG_EXPAND_SZ. - res = RegQueryValueEx(key, value_name, NULL, &type, - reinterpret_cast(buffer), &buffer_size); - if (ERROR_SUCCESS == res && buffer_size != 0 && type == REG_SZ) { - // Make sure the buffer is NULL terminated. - buffer[*len - 1] = 0; - *len = lstrlen(buffer); - RegCloseKey(key); - return true; - } - RegCloseKey(key); - return false; -} - -// Replaces each "%ld" in input per a value. Not efficient but it works. -// Note: Does not use the CRT. -bool StringReplace(const wchar_t* input, int value, wchar_t* output, - int output_len) { - memset(output, 0, output_len*sizeof(wchar_t)); - int input_len = lstrlen(input); - - for (int i = 0; i < input_len; ++i) { - int current_output_len = lstrlen(output); - - if (input[i] == L'%' && input[i + 1] == L'l' && input[i + 2] == L'd') { - // Make sure we have enough place left. - if ((current_output_len + 12) >= output_len) - return false; - - // Cheap _itow(). - wsprintf(output+current_output_len, L"%d", value); - i += 2; - } else { - if (current_output_len >= output_len) - return false; - output[current_output_len] = input[i]; - } - } - return true; -} - -} // namespace - -// Note: Does not use the CRT. -bool SpawnDebuggerOnProcess(unsigned process_id) { - wchar_t reg_value[1026]; - int len = arraysize(reg_value); - if (RegReadString(HKEY_LOCAL_MACHINE, - L"SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\AeDebug", - L"Debugger", reg_value, &len)) { - wchar_t command_line[1026]; - if (StringReplace(reg_value, process_id, command_line, - arraysize(command_line))) { - // We don't mind if the debugger is present because it will simply fail - // to attach to this process. - STARTUPINFO startup_info = {0}; - startup_info.cb = sizeof(startup_info); - PROCESS_INFORMATION process_info = {0}; - - if (CreateProcess(NULL, command_line, NULL, NULL, FALSE, 0, NULL, NULL, - &startup_info, &process_info)) { - CloseHandle(process_info.hThread); - WaitForInputIdle(process_info.hProcess, 10000); - CloseHandle(process_info.hProcess); - return true; - } - } - } - return false; -} - -bool BeingDebugged() { - return ::IsDebuggerPresent() != 0; -} - -void BreakDebugger() { - if (IsDebugUISuppressed()) - _exit(1); - __debugbreak(); -#if defined(NDEBUG) - _exit(1); -#endif -} - -} // namespace debug -} // namespace base diff --git a/base/debug/leak_annotations.h b/base/debug/leak_annotations.h deleted file mode 100644 index 86e8ea911c..0000000000 --- a/base/debug/leak_annotations.h +++ /dev/null @@ -1,65 +0,0 @@ -// Copyright (c) 2011 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef BASE_DEBUG_LEAK_ANNOTATIONS_H_ -#define BASE_DEBUG_LEAK_ANNOTATIONS_H_ - -#include "build/build_config.h" - -// This file defines macros which can be used to annotate intentional memory -// leaks. Support for annotations is implemented in HeapChecker and -// LeakSanitizer. Annotated objects will be treated as a source of live -// pointers, i.e. any heap objects reachable by following pointers from an -// annotated object will not be reported as leaks. -// -// ANNOTATE_SCOPED_MEMORY_LEAK: all allocations made in the current scope -// will be annotated as leaks. -// ANNOTATE_LEAKING_OBJECT_PTR(X): the heap object referenced by pointer X will -// be annotated as a leak. -// -// Note that HeapChecker will report a fatal error if an object which has been -// annotated with ANNOTATE_LEAKING_OBJECT_PTR is later deleted (but -// LeakSanitizer won't). - -#if defined(OS_POSIX) && !defined(OS_MACOSX) && !defined(OS_NACL) && \ - defined(USE_HEAPCHECKER) - -#include "third_party/tcmalloc/chromium/src/gperftools/heap-checker.h" - -#define ANNOTATE_SCOPED_MEMORY_LEAK \ - HeapLeakChecker::Disabler heap_leak_checker_disabler; static_cast(0) - -#define ANNOTATE_LEAKING_OBJECT_PTR(X) \ - HeapLeakChecker::IgnoreObject(X) - -#elif defined(LEAK_SANITIZER) && !defined(OS_NACL) - -extern "C" { -void __lsan_disable(); -void __lsan_enable(); -void __lsan_ignore_object(const void *p); -} // extern "C" - -class ScopedLeakSanitizerDisabler { - public: - ScopedLeakSanitizerDisabler() { __lsan_disable(); } - ~ScopedLeakSanitizerDisabler() { __lsan_enable(); } - private: - DISALLOW_COPY_AND_ASSIGN(ScopedLeakSanitizerDisabler); -}; - -#define ANNOTATE_SCOPED_MEMORY_LEAK \ - ScopedLeakSanitizerDisabler leak_sanitizer_disabler; static_cast(0) - -#define ANNOTATE_LEAKING_OBJECT_PTR(X) __lsan_ignore_object(X); - -#else - -// If neither HeapChecker nor LSan are used, the annotations should be no-ops. -#define ANNOTATE_SCOPED_MEMORY_LEAK ((void)0) -#define ANNOTATE_LEAKING_OBJECT_PTR(X) ((void)0) - -#endif - -#endif // BASE_DEBUG_LEAK_ANNOTATIONS_H_ diff --git a/base/debug/leak_tracker.h b/base/debug/leak_tracker.h deleted file mode 100644 index 93cea39a0a..0000000000 --- a/base/debug/leak_tracker.h +++ /dev/null @@ -1,136 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef BASE_DEBUG_LEAK_TRACKER_H_ -#define BASE_DEBUG_LEAK_TRACKER_H_ - -// Only enable leak tracking in debug builds. -#ifndef NDEBUG -#define ENABLE_LEAK_TRACKER -#endif - -#ifdef ENABLE_LEAK_TRACKER -#include "base/containers/linked_list.h" -#include "base/debug/stack_trace.h" -#include "base/logging.h" -#endif // ENABLE_LEAK_TRACKER - -// LeakTracker is a helper to verify that all instances of a class -// have been destroyed. -// -// It is particularly useful for classes that are bound to a single thread -- -// before destroying that thread, one can check that there are no remaining -// instances of that class. -// -// For example, to enable leak tracking for class net::URLRequest, start by -// adding a member variable of type LeakTracker. -// -// class URLRequest { -// ... -// private: -// base::LeakTracker leak_tracker_; -// }; -// -// -// Next, when we believe all instances of net::URLRequest have been deleted: -// -// LeakTracker::CheckForLeaks(); -// -// Should the check fail (because there are live instances of net::URLRequest), -// then the allocation callstack for each leaked instances is dumped to -// the error log. -// -// If ENABLE_LEAK_TRACKER is not defined, then the check has no effect. - -namespace base { -namespace debug { - -#ifndef ENABLE_LEAK_TRACKER - -// If leak tracking is disabled, do nothing. -template -class LeakTracker { - public: - ~LeakTracker() {} - static void CheckForLeaks() {} - static int NumLiveInstances() { return -1; } -}; - -#else - -// If leak tracking is enabled we track where the object was allocated from. - -template -class LeakTracker : public LinkNode > { - public: - LeakTracker() { - instances()->Append(this); - } - - ~LeakTracker() { - this->RemoveFromList(); - } - - static void CheckForLeaks() { - // Walk the allocation list and print each entry it contains. - size_t count = 0; - - // Copy the first 3 leak allocation callstacks onto the stack. - // This way if we hit the CHECK() in a release build, the leak - // information will be available in mini-dump. - const size_t kMaxStackTracesToCopyOntoStack = 3; - StackTrace stacktraces[kMaxStackTracesToCopyOntoStack]; - - for (LinkNode >* node = instances()->head(); - node != instances()->end(); - node = node->next()) { - StackTrace& allocation_stack = node->value()->allocation_stack_; - - if (count < kMaxStackTracesToCopyOntoStack) - stacktraces[count] = allocation_stack; - - ++count; - if (LOG_IS_ON(ERROR)) { - LOG_STREAM(ERROR) << "Leaked " << node << " which was allocated by:"; - allocation_stack.OutputToStream(&LOG_STREAM(ERROR)); - } - } - - CHECK_EQ(0u, count); - - // Hack to keep |stacktraces| and |count| alive (so compiler - // doesn't optimize it out, and it will appear in mini-dumps). - if (count == 0x1234) { - for (size_t i = 0; i < kMaxStackTracesToCopyOntoStack; ++i) - stacktraces[i].PrintBacktrace(); - } - } - - static int NumLiveInstances() { - // Walk the allocation list and count how many entries it has. - int count = 0; - for (LinkNode >* node = instances()->head(); - node != instances()->end(); - node = node->next()) { - ++count; - } - return count; - } - - private: - // Each specialization of LeakTracker gets its own static storage. - static LinkedList >* instances() { - static LinkedList > list; - return &list; - } - - StackTrace allocation_stack_; -}; - -#endif // ENABLE_LEAK_TRACKER - -} // namespace debug -} // namespace base - -#endif // BASE_DEBUG_LEAK_TRACKER_H_ diff --git a/base/debug/leak_tracker_unittest.cc b/base/debug/leak_tracker_unittest.cc deleted file mode 100644 index 99df4c17e1..0000000000 --- a/base/debug/leak_tracker_unittest.cc +++ /dev/null @@ -1,113 +0,0 @@ -// Copyright (c) 2011 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "base/debug/leak_tracker.h" -#include "base/memory/scoped_ptr.h" -#include "testing/gtest/include/gtest/gtest.h" - -namespace base { -namespace debug { - -namespace { - -class ClassA { - private: - LeakTracker leak_tracker_; -}; - -class ClassB { - private: - LeakTracker leak_tracker_; -}; - -#ifndef ENABLE_LEAK_TRACKER - -// If leak tracking is disabled, we should do nothing. -TEST(LeakTrackerTest, NotEnabled) { - EXPECT_EQ(-1, LeakTracker::NumLiveInstances()); - EXPECT_EQ(-1, LeakTracker::NumLiveInstances()); - - // Use scoped_ptr so compiler doesn't complain about unused variables. - scoped_ptr a1(new ClassA); - scoped_ptr b1(new ClassB); - scoped_ptr b2(new ClassB); - - EXPECT_EQ(-1, LeakTracker::NumLiveInstances()); - EXPECT_EQ(-1, LeakTracker::NumLiveInstances()); -} - -#else - -TEST(LeakTrackerTest, Basic) { - { - ClassA a1; - - EXPECT_EQ(1, LeakTracker::NumLiveInstances()); - EXPECT_EQ(0, LeakTracker::NumLiveInstances()); - - ClassB b1; - ClassB b2; - - EXPECT_EQ(1, LeakTracker::NumLiveInstances()); - EXPECT_EQ(2, LeakTracker::NumLiveInstances()); - - scoped_ptr a2(new ClassA); - - EXPECT_EQ(2, LeakTracker::NumLiveInstances()); - EXPECT_EQ(2, LeakTracker::NumLiveInstances()); - - a2.reset(); - - EXPECT_EQ(1, LeakTracker::NumLiveInstances()); - EXPECT_EQ(2, LeakTracker::NumLiveInstances()); - } - - EXPECT_EQ(0, LeakTracker::NumLiveInstances()); - EXPECT_EQ(0, LeakTracker::NumLiveInstances()); -} - -// Try some orderings of create/remove to hit different cases in the linked-list -// assembly. -TEST(LeakTrackerTest, LinkedList) { - EXPECT_EQ(0, LeakTracker::NumLiveInstances()); - - scoped_ptr a1(new ClassA); - scoped_ptr a2(new ClassA); - scoped_ptr a3(new ClassA); - scoped_ptr a4(new ClassA); - - EXPECT_EQ(4, LeakTracker::NumLiveInstances()); - - // Remove the head of the list (a1). - a1.reset(); - EXPECT_EQ(3, LeakTracker::NumLiveInstances()); - - // Remove the tail of the list (a4). - a4.reset(); - EXPECT_EQ(2, LeakTracker::NumLiveInstances()); - - // Append to the new tail of the list (a3). - scoped_ptr a5(new ClassA); - EXPECT_EQ(3, LeakTracker::NumLiveInstances()); - - a2.reset(); - a3.reset(); - - EXPECT_EQ(1, LeakTracker::NumLiveInstances()); - - a5.reset(); - EXPECT_EQ(0, LeakTracker::NumLiveInstances()); -} - -TEST(LeakTrackerTest, NoOpCheckForLeaks) { - // There are no live instances of ClassA, so this should do nothing. - LeakTracker::CheckForLeaks(); -} - -#endif // ENABLE_LEAK_TRACKER - -} // namespace - -} // namespace debug -} // namespace base diff --git a/base/debug/proc_maps_linux.cc b/base/debug/proc_maps_linux.cc deleted file mode 100644 index 9557feb025..0000000000 --- a/base/debug/proc_maps_linux.cc +++ /dev/null @@ -1,101 +0,0 @@ -// Copyright (c) 2013 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "base/debug/proc_maps_linux.h" - -#if defined(OS_LINUX) -#include -#endif - -#include "base/file_util.h" -#include "base/strings/string_split.h" - -#if defined(OS_ANDROID) -// Bionic's inttypes.h defines PRI/SCNxPTR as an unsigned long int, which -// is incompatible with Bionic's stdint.h defining uintptr_t as a unsigned int: -// https://code.google.com/p/android/issues/detail?id=57218 -#undef SCNxPTR -#define SCNxPTR "x" -#endif - -namespace base { -namespace debug { - -bool ReadProcMaps(std::string* proc_maps) { - FilePath proc_maps_path("/proc/self/maps"); - return file_util::ReadFileToString(proc_maps_path, proc_maps); -} - -bool ParseProcMaps(const std::string& input, - std::vector* regions_out) { - std::vector regions; - - // This isn't async safe nor terribly efficient, but it doesn't need to be at - // this point in time. - std::vector lines; - SplitString(input, '\n', &lines); - - for (size_t i = 0; i < lines.size(); ++i) { - // Due to splitting on '\n' the last line should be empty. - if (i == lines.size() - 1) { - if (!lines[i].empty()) - return false; - break; - } - - MappedMemoryRegion region; - const char* line = lines[i].c_str(); - char permissions[5] = {'\0'}; // Ensure NUL-terminated string. - uint8 dev_major = 0; - uint8 dev_minor = 0; - long inode = 0; - int path_index = 0; - - // Sample format from man 5 proc: - // - // address perms offset dev inode pathname - // 08048000-08056000 r-xp 00000000 03:0c 64593 /usr/sbin/gpm - // - // The final %n term captures the offset in the input string, which is used - // to determine the path name. It *does not* increment the return value. - // Refer to man 3 sscanf for details. - if (sscanf(line, "%" SCNxPTR "-%" SCNxPTR " %4c %llx %hhx:%hhx %ld %n", - ®ion.start, ®ion.end, permissions, ®ion.offset, - &dev_major, &dev_minor, &inode, &path_index) < 7) { - return false; - } - - region.permissions = 0; - - if (permissions[0] == 'r') - region.permissions |= MappedMemoryRegion::READ; - else if (permissions[0] != '-') - return false; - - if (permissions[1] == 'w') - region.permissions |= MappedMemoryRegion::WRITE; - else if (permissions[1] != '-') - return false; - - if (permissions[2] == 'x') - region.permissions |= MappedMemoryRegion::EXECUTE; - else if (permissions[2] != '-') - return false; - - if (permissions[3] == 'p') - region.permissions |= MappedMemoryRegion::PRIVATE; - else if (permissions[3] != 's' && permissions[3] != 'S') // Shared memory. - return false; - - // Pushing then assigning saves us a string copy. - regions.push_back(region); - regions.back().path.assign(line + path_index); - } - - regions_out->swap(regions); - return true; -} - -} // namespace debug -} // namespace base diff --git a/base/debug/proc_maps_linux.h b/base/debug/proc_maps_linux.h deleted file mode 100644 index d055712444..0000000000 --- a/base/debug/proc_maps_linux.h +++ /dev/null @@ -1,56 +0,0 @@ -// Copyright (c) 2013 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef BASE_DEBUG_PROC_MAPS_LINUX_H_ -#define BASE_DEBUG_PROC_MAPS_LINUX_H_ - -#include -#include - -#include "base/base_export.h" -#include "base/basictypes.h" - -namespace base { -namespace debug { - -// Describes a region of mapped memory and the path of the file mapped. -struct MappedMemoryRegion { - enum Permission { - READ = 1 << 0, - WRITE = 1 << 1, - EXECUTE = 1 << 2, - PRIVATE = 1 << 3, // If set, region is private, otherwise it is shared. - }; - - // The address range [start,end) of mapped memory. - uintptr_t start; - uintptr_t end; - - // Byte offset into |path| of the range mapped into memory. - unsigned long long offset; - - // Bitmask of read/write/execute/private/shared permissions. - uint8 permissions; - - // Name of the file mapped into memory. - // - // NOTE: path names aren't guaranteed to point at valid files. For example, - // "[heap]" and "[stack]" are used to represent the location of the process' - // heap and stack, respectively. - std::string path; -}; - -// Reads the data from /proc/self/maps and stores the result in |proc_maps|. -// Returns true if successful, false otherwise. -BASE_EXPORT bool ReadProcMaps(std::string* proc_maps); - -// Parses /proc//maps input data and stores in |regions|. Returns true -// and updates |regions| if and only if all of |input| was successfully parsed. -BASE_EXPORT bool ParseProcMaps(const std::string& input, - std::vector* regions); - -} // namespace debug -} // namespace base - -#endif // BASE_DEBUG_PROC_MAPS_LINUX_H_ diff --git a/base/debug/proc_maps_linux_unittest.cc b/base/debug/proc_maps_linux_unittest.cc deleted file mode 100644 index 9b7d7dcc4a..0000000000 --- a/base/debug/proc_maps_linux_unittest.cc +++ /dev/null @@ -1,281 +0,0 @@ -// Copyright (c) 2013 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "base/debug/proc_maps_linux.h" -#include "base/files/file_path.h" -#include "base/path_service.h" -#include "base/strings/stringprintf.h" -#include "base/third_party/dynamic_annotations/dynamic_annotations.h" -#include "testing/gtest/include/gtest/gtest.h" - -namespace base { -namespace debug { - -TEST(ProcMapsTest, Empty) { - std::vector regions; - EXPECT_TRUE(ParseProcMaps("", ®ions)); - EXPECT_EQ(0u, regions.size()); -} - -TEST(ProcMapsTest, NoSpaces) { - static const char kNoSpaces[] = - "00400000-0040b000 r-xp 00002200 fc:00 794418 /bin/cat\n"; - - std::vector regions; - ASSERT_TRUE(ParseProcMaps(kNoSpaces, ®ions)); - ASSERT_EQ(1u, regions.size()); - - EXPECT_EQ(0x00400000u, regions[0].start); - EXPECT_EQ(0x0040b000u, regions[0].end); - EXPECT_EQ(0x00002200u, regions[0].offset); - EXPECT_EQ("/bin/cat", regions[0].path); -} - -TEST(ProcMapsTest, Spaces) { - static const char kSpaces[] = - "00400000-0040b000 r-xp 00002200 fc:00 794418 /bin/space cat\n"; - - std::vector regions; - ASSERT_TRUE(ParseProcMaps(kSpaces, ®ions)); - ASSERT_EQ(1u, regions.size()); - - EXPECT_EQ(0x00400000u, regions[0].start); - EXPECT_EQ(0x0040b000u, regions[0].end); - EXPECT_EQ(0x00002200u, regions[0].offset); - EXPECT_EQ("/bin/space cat", regions[0].path); -} - -TEST(ProcMapsTest, NoNewline) { - static const char kNoSpaces[] = - "00400000-0040b000 r-xp 00002200 fc:00 794418 /bin/cat"; - - std::vector regions; - ASSERT_FALSE(ParseProcMaps(kNoSpaces, ®ions)); -} - -TEST(ProcMapsTest, NoPath) { - static const char kNoPath[] = - "00400000-0040b000 rw-p 00000000 00:00 0 \n"; - - std::vector regions; - ASSERT_TRUE(ParseProcMaps(kNoPath, ®ions)); - ASSERT_EQ(1u, regions.size()); - - EXPECT_EQ(0x00400000u, regions[0].start); - EXPECT_EQ(0x0040b000u, regions[0].end); - EXPECT_EQ(0x00000000u, regions[0].offset); - EXPECT_EQ("", regions[0].path); -} - -TEST(ProcMapsTest, Heap) { - static const char kHeap[] = - "022ac000-022cd000 rw-p 00000000 00:00 0 [heap]\n"; - - std::vector regions; - ASSERT_TRUE(ParseProcMaps(kHeap, ®ions)); - ASSERT_EQ(1u, regions.size()); - - EXPECT_EQ(0x022ac000u, regions[0].start); - EXPECT_EQ(0x022cd000u, regions[0].end); - EXPECT_EQ(0x00000000u, regions[0].offset); - EXPECT_EQ("[heap]", regions[0].path); -} - -#if defined(ARCH_CPU_32_BITS) -TEST(ProcMapsTest, Stack32) { - static const char kStack[] = - "beb04000-beb25000 rw-p 00000000 00:00 0 [stack]\n"; - - std::vector regions; - ASSERT_TRUE(ParseProcMaps(kStack, ®ions)); - ASSERT_EQ(1u, regions.size()); - - EXPECT_EQ(0xbeb04000u, regions[0].start); - EXPECT_EQ(0xbeb25000u, regions[0].end); - EXPECT_EQ(0x00000000u, regions[0].offset); - EXPECT_EQ("[stack]", regions[0].path); -} -#elif defined(ARCH_CPU_64_BITS) -TEST(ProcMapsTest, Stack64) { - static const char kStack[] = - "7fff69c5b000-7fff69c7d000 rw-p 00000000 00:00 0 [stack]\n"; - - std::vector regions; - ASSERT_TRUE(ParseProcMaps(kStack, ®ions)); - ASSERT_EQ(1u, regions.size()); - - EXPECT_EQ(0x7fff69c5b000u, regions[0].start); - EXPECT_EQ(0x7fff69c7d000u, regions[0].end); - EXPECT_EQ(0x00000000u, regions[0].offset); - EXPECT_EQ("[stack]", regions[0].path); -} -#endif - -TEST(ProcMapsTest, Multiple) { - static const char kMultiple[] = - "00400000-0040b000 r-xp 00000000 fc:00 794418 /bin/cat\n" - "0060a000-0060b000 r--p 0000a000 fc:00 794418 /bin/cat\n" - "0060b000-0060c000 rw-p 0000b000 fc:00 794418 /bin/cat\n"; - - std::vector regions; - ASSERT_TRUE(ParseProcMaps(kMultiple, ®ions)); - ASSERT_EQ(3u, regions.size()); - - EXPECT_EQ(0x00400000u, regions[0].start); - EXPECT_EQ(0x0040b000u, regions[0].end); - EXPECT_EQ(0x00000000u, regions[0].offset); - EXPECT_EQ("/bin/cat", regions[0].path); - - EXPECT_EQ(0x0060a000u, regions[1].start); - EXPECT_EQ(0x0060b000u, regions[1].end); - EXPECT_EQ(0x0000a000u, regions[1].offset); - EXPECT_EQ("/bin/cat", regions[1].path); - - EXPECT_EQ(0x0060b000u, regions[2].start); - EXPECT_EQ(0x0060c000u, regions[2].end); - EXPECT_EQ(0x0000b000u, regions[2].offset); - EXPECT_EQ("/bin/cat", regions[2].path); -} - -TEST(ProcMapsTest, Permissions) { - static struct { - const char* input; - uint8 permissions; - } kTestCases[] = { - {"00400000-0040b000 ---s 00000000 fc:00 794418 /bin/cat\n", 0}, - {"00400000-0040b000 ---S 00000000 fc:00 794418 /bin/cat\n", 0}, - {"00400000-0040b000 r--s 00000000 fc:00 794418 /bin/cat\n", - MappedMemoryRegion::READ}, - {"00400000-0040b000 -w-s 00000000 fc:00 794418 /bin/cat\n", - MappedMemoryRegion::WRITE}, - {"00400000-0040b000 --xs 00000000 fc:00 794418 /bin/cat\n", - MappedMemoryRegion::EXECUTE}, - {"00400000-0040b000 rwxs 00000000 fc:00 794418 /bin/cat\n", - MappedMemoryRegion::READ | MappedMemoryRegion::WRITE | - MappedMemoryRegion::EXECUTE}, - {"00400000-0040b000 ---p 00000000 fc:00 794418 /bin/cat\n", - MappedMemoryRegion::PRIVATE}, - {"00400000-0040b000 r--p 00000000 fc:00 794418 /bin/cat\n", - MappedMemoryRegion::READ | MappedMemoryRegion::PRIVATE}, - {"00400000-0040b000 -w-p 00000000 fc:00 794418 /bin/cat\n", - MappedMemoryRegion::WRITE | MappedMemoryRegion::PRIVATE}, - {"00400000-0040b000 --xp 00000000 fc:00 794418 /bin/cat\n", - MappedMemoryRegion::EXECUTE | MappedMemoryRegion::PRIVATE}, - {"00400000-0040b000 rwxp 00000000 fc:00 794418 /bin/cat\n", - MappedMemoryRegion::READ | MappedMemoryRegion::WRITE | - MappedMemoryRegion::EXECUTE | MappedMemoryRegion::PRIVATE}, - }; - - for (size_t i = 0; i < ARRAYSIZE_UNSAFE(kTestCases); ++i) { - SCOPED_TRACE( - base::StringPrintf("kTestCases[%zu] = %s", i, kTestCases[i].input)); - - std::vector regions; - EXPECT_TRUE(ParseProcMaps(kTestCases[i].input, ®ions)); - EXPECT_EQ(1u, regions.size()); - if (regions.empty()) - continue; - EXPECT_EQ(kTestCases[i].permissions, regions[0].permissions); - } -} - -// ProcMapsTest.ReadProcMaps fails under TSan on Linux, -// see http://crbug.com/258451. -#if defined(THREAD_SANITIZER) -#define MAYBE_ReadProcMaps DISABLED_ReadProcMaps -#else -#define MAYBE_ReadProcMaps ReadProcMaps -#endif -TEST(ProcMapsTest, MAYBE_ReadProcMaps) { - std::string proc_maps; - ASSERT_TRUE(ReadProcMaps(&proc_maps)); - - std::vector regions; - ASSERT_TRUE(ParseProcMaps(proc_maps, ®ions)); - ASSERT_FALSE(regions.empty()); - - // We should be able to find both the current executable as well as the stack - // mapped into memory. Use the address of |proc_maps| as a way of finding the - // stack. - FilePath exe_path; - EXPECT_TRUE(PathService::Get(FILE_EXE, &exe_path)); - uintptr_t address = reinterpret_cast(&proc_maps); - bool found_exe = false; - bool found_stack = false; - bool found_address = false; - for (size_t i = 0; i < regions.size(); ++i) { - if (regions[i].path == exe_path.value()) { - // It's OK to find the executable mapped multiple times as there'll be - // multiple sections (e.g., text, data). - found_exe = true; - } - - if (regions[i].path == "[stack]") { - // Only check if |address| lies within the real stack when not running - // Valgrind, otherwise |address| will be on a stack that Valgrind creates. - if (!RunningOnValgrind()) { - EXPECT_GE(address, regions[i].start); - EXPECT_LT(address, regions[i].end); - } - - EXPECT_TRUE(regions[i].permissions & MappedMemoryRegion::READ); - EXPECT_TRUE(regions[i].permissions & MappedMemoryRegion::WRITE); - EXPECT_FALSE(regions[i].permissions & MappedMemoryRegion::EXECUTE); - EXPECT_TRUE(regions[i].permissions & MappedMemoryRegion::PRIVATE); - EXPECT_FALSE(found_stack) << "Found duplicate stacks"; - found_stack = true; - } - - if (address >= regions[i].start && address < regions[i].end) { - EXPECT_FALSE(found_address) << "Found same address in multiple regions"; - found_address = true; - } - } - - EXPECT_TRUE(found_exe); - EXPECT_TRUE(found_stack); - EXPECT_TRUE(found_address); -} - -TEST(ProcMapsTest, MissingFields) { - static const char* kTestCases[] = { - "00400000\n", // Missing end + beyond. - "00400000-0040b000\n", // Missing perms + beyond. - "00400000-0040b000 r-xp\n", // Missing offset + beyond. - "00400000-0040b000 r-xp 00000000\n", // Missing device + beyond. - "00400000-0040b000 r-xp 00000000 fc:00\n", // Missing inode + beyond. - "00400000-0040b000 00000000 fc:00 794418 /bin/cat\n", // Missing perms. - "00400000-0040b000 r-xp fc:00 794418 /bin/cat\n", // Missing offset. - "00400000-0040b000 r-xp 00000000 fc:00 /bin/cat\n", // Missing inode. - "00400000 r-xp 00000000 fc:00 794418 /bin/cat\n", // Missing end. - "-0040b000 r-xp 00000000 fc:00 794418 /bin/cat\n", // Missing start. - "00400000-0040b000 r-xp 00000000 794418 /bin/cat\n", // Missing device. - }; - - for (size_t i = 0; i < arraysize(kTestCases); ++i) { - SCOPED_TRACE(base::StringPrintf("kTestCases[%zu] = %s", i, kTestCases[i])); - std::vector regions; - EXPECT_FALSE(ParseProcMaps(kTestCases[i], ®ions)); - } -} - -TEST(ProcMapsTest, InvalidInput) { - static const char* kTestCases[] = { - "thisisal-0040b000 rwxp 00000000 fc:00 794418 /bin/cat\n", - "0040000d-linvalid rwxp 00000000 fc:00 794418 /bin/cat\n", - "00400000-0040b000 inpu 00000000 fc:00 794418 /bin/cat\n", - "00400000-0040b000 rwxp tforproc fc:00 794418 /bin/cat\n", - "00400000-0040b000 rwxp 00000000 ma:ps 794418 /bin/cat\n", - "00400000-0040b000 rwxp 00000000 fc:00 parse! /bin/cat\n", - }; - - for (size_t i = 0; i < arraysize(kTestCases); ++i) { - SCOPED_TRACE(base::StringPrintf("kTestCases[%zu] = %s", i, kTestCases[i])); - std::vector regions; - EXPECT_FALSE(ParseProcMaps(kTestCases[i], ®ions)); - } -} - -} // namespace debug -} // namespace base diff --git a/base/debug/profiler.cc b/base/debug/profiler.cc deleted file mode 100644 index 096e343e00..0000000000 --- a/base/debug/profiler.cc +++ /dev/null @@ -1,217 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "base/debug/profiler.h" - -#include - -#include "base/process/process_handle.h" -#include "base/strings/string_util.h" -#include "base/strings/stringprintf.h" - -#if defined(OS_WIN) -#include "base/win/pe_image.h" -#endif // defined(OS_WIN) - -#if defined(ENABLE_PROFILING) && !defined(NO_TCMALLOC) -#include "third_party/tcmalloc/chromium/src/gperftools/profiler.h" -#endif - -namespace base { -namespace debug { - -#if defined(ENABLE_PROFILING) && !defined(NO_TCMALLOC) - -static int profile_count = 0; - -void StartProfiling(const std::string& name) { - ++profile_count; - std::string full_name(name); - std::string pid = StringPrintf("%d", GetCurrentProcId()); - std::string count = StringPrintf("%d", profile_count); - ReplaceSubstringsAfterOffset(&full_name, 0, "{pid}", pid); - ReplaceSubstringsAfterOffset(&full_name, 0, "{count}", count); - ProfilerStart(full_name.c_str()); -} - -void StopProfiling() { - ProfilerFlush(); - ProfilerStop(); -} - -void FlushProfiling() { - ProfilerFlush(); -} - -bool BeingProfiled() { - return ProfilingIsEnabledForAllThreads(); -} - -void RestartProfilingAfterFork() { - ProfilerRegisterThread(); -} - -#else - -void StartProfiling(const std::string& name) { -} - -void StopProfiling() { -} - -void FlushProfiling() { -} - -bool BeingProfiled() { - return false; -} - -void RestartProfilingAfterFork() { -} - -#endif - -#if !defined(OS_WIN) - -bool IsBinaryInstrumented() { - return false; -} - -ReturnAddressLocationResolver GetProfilerReturnAddrResolutionFunc() { - return NULL; -} - -DynamicFunctionEntryHook GetProfilerDynamicFunctionEntryHookFunc() { - return NULL; -} - -AddDynamicSymbol GetProfilerAddDynamicSymbolFunc() { - return NULL; -} - -MoveDynamicSymbol GetProfilerMoveDynamicSymbolFunc() { - return NULL; -} - -#else // defined(OS_WIN) - -// http://blogs.msdn.com/oldnewthing/archive/2004/10/25/247180.aspx -extern "C" IMAGE_DOS_HEADER __ImageBase; - -bool IsBinaryInstrumented() { - enum InstrumentationCheckState { - UNINITIALIZED, - INSTRUMENTED_IMAGE, - NON_INSTRUMENTED_IMAGE, - }; - - static InstrumentationCheckState state = UNINITIALIZED; - - if (state == UNINITIALIZED) { - HMODULE this_module = reinterpret_cast(&__ImageBase); - base::win::PEImage image(this_module); - - // Check to be sure our image is structured as we'd expect. - DCHECK(image.VerifyMagic()); - - // Syzygy-instrumented binaries contain a PE image section named ".thunks", - // and all Syzygy-modified binaries contain the ".syzygy" image section. - // This is a very fast check, as it only looks at the image header. - if ((image.GetImageSectionHeaderByName(".thunks") != NULL) && - (image.GetImageSectionHeaderByName(".syzygy") != NULL)) { - state = INSTRUMENTED_IMAGE; - } else { - state = NON_INSTRUMENTED_IMAGE; - } - } - DCHECK(state != UNINITIALIZED); - - return state == INSTRUMENTED_IMAGE; -} - -namespace { - -struct FunctionSearchContext { - const char* name; - FARPROC function; -}; - -// Callback function to PEImage::EnumImportChunks. -bool FindResolutionFunctionInImports( - const base::win::PEImage &image, const char* module_name, - PIMAGE_THUNK_DATA unused_name_table, PIMAGE_THUNK_DATA import_address_table, - PVOID cookie) { - FunctionSearchContext* context = - reinterpret_cast(cookie); - - DCHECK_NE(static_cast(NULL), context); - DCHECK_EQ(static_cast(NULL), context->function); - - // Our import address table contains pointers to the functions we import - // at this point. Let's retrieve the first such function and use it to - // find the module this import was resolved to by the loader. - const wchar_t* function_in_module = - reinterpret_cast(import_address_table->u1.Function); - - // Retrieve the module by a function in the module. - const DWORD kFlags = GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS | - GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT; - HMODULE module = NULL; - if (!::GetModuleHandleEx(kFlags, function_in_module, &module)) { - // This can happen if someone IAT patches us to a thunk. - return true; - } - - // See whether this module exports the function we're looking for. - FARPROC exported_func = ::GetProcAddress(module, context->name); - if (exported_func != NULL) { - // We found it, return the function and terminate the enumeration. - context->function = exported_func; - return false; - } - - // Keep going. - return true; -} - -template -FunctionType FindFunctionInImports(const char* function_name) { - if (!IsBinaryInstrumented()) - return NULL; - - HMODULE this_module = reinterpret_cast(&__ImageBase); - base::win::PEImage image(this_module); - - FunctionSearchContext ctx = { function_name, NULL }; - image.EnumImportChunks(FindResolutionFunctionInImports, &ctx); - - return reinterpret_cast(ctx.function); -} - -} // namespace - -ReturnAddressLocationResolver GetProfilerReturnAddrResolutionFunc() { - return FindFunctionInImports( - "ResolveReturnAddressLocation"); -} - -DynamicFunctionEntryHook GetProfilerDynamicFunctionEntryHookFunc() { - return FindFunctionInImports( - "OnDynamicFunctionEntry"); -} - -AddDynamicSymbol GetProfilerAddDynamicSymbolFunc() { - return FindFunctionInImports( - "AddDynamicSymbol"); -} - -MoveDynamicSymbol GetProfilerMoveDynamicSymbolFunc() { - return FindFunctionInImports( - "MoveDynamicSymbol"); -} - -#endif // defined(OS_WIN) - -} // namespace debug -} // namespace base diff --git a/base/debug/profiler.h b/base/debug/profiler.h deleted file mode 100644 index e1dda89742..0000000000 --- a/base/debug/profiler.h +++ /dev/null @@ -1,90 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef BASE_DEBUG_PROFILER_H -#define BASE_DEBUG_PROFILER_H - -#include - -#include "base/base_export.h" -#include "base/basictypes.h" - -// The Profiler functions allow usage of the underlying sampling based -// profiler. If the application has not been built with the necessary -// flags (-DENABLE_PROFILING and not -DNO_TCMALLOC) then these functions -// are noops. -namespace base { -namespace debug { - -// Start profiling with the supplied name. -// {pid} will be replaced by the process' pid and {count} will be replaced -// by the count of the profile run (starts at 1 with each process). -BASE_EXPORT void StartProfiling(const std::string& name); - -// Stop profiling and write out data. -BASE_EXPORT void StopProfiling(); - -// Force data to be written to file. -BASE_EXPORT void FlushProfiling(); - -// Returns true if process is being profiled. -BASE_EXPORT bool BeingProfiled(); - -// Reset profiling after a fork, which disables timers. -BASE_EXPORT void RestartProfilingAfterFork(); - -// Returns true iff this executable is instrumented with the Syzygy profiler. -BASE_EXPORT bool IsBinaryInstrumented(); - -// There's a class of profilers that use "return address swizzling" to get a -// hook on function exits. This class of profilers uses some form of entry hook, -// like e.g. binary instrumentation, or a compiler flag, that calls a hook each -// time a function is invoked. The hook then switches the return address on the -// stack for the address of an exit hook function, and pushes the original -// return address to a shadow stack of some type. When in due course the CPU -// executes a return to the exit hook, the exit hook will do whatever work it -// does on function exit, then arrange to return to the original return address. -// This class of profiler does not play well with programs that look at the -// return address, as does e.g. V8. V8 uses the return address to certain -// runtime functions to find the JIT code that called it, and from there finds -// the V8 data structures associated to the JS function involved. -// A return address resolution function is used to fix this. It allows such -// programs to resolve a location on stack where a return address originally -// resided, to the shadow stack location where the profiler stashed it. -typedef uintptr_t (*ReturnAddressLocationResolver)( - uintptr_t return_addr_location); - -// This type declaration must match V8's FunctionEntryHook. -typedef void (*DynamicFunctionEntryHook)(uintptr_t function, - uintptr_t return_addr_location); - -// The functions below here are to support profiling V8-generated code. -// V8 has provisions for generating a call to an entry hook for newly generated -// JIT code, and it can push symbol information on code generation and advise -// when the garbage collector moves code. The functions declarations below here -// make glue between V8's facilities and a profiler. - -// This type declaration must match V8's FunctionEntryHook. -typedef void (*DynamicFunctionEntryHook)(uintptr_t function, - uintptr_t return_addr_location); - -typedef void (*AddDynamicSymbol)(const void* address, - size_t length, - const char* name, - size_t name_len); -typedef void (*MoveDynamicSymbol)(const void* address, const void* new_address); - - -// If this binary is instrumented and the instrumentation supplies a function -// for each of those purposes, find and return the function in question. -// Otherwise returns NULL. -BASE_EXPORT ReturnAddressLocationResolver GetProfilerReturnAddrResolutionFunc(); -BASE_EXPORT DynamicFunctionEntryHook GetProfilerDynamicFunctionEntryHookFunc(); -BASE_EXPORT AddDynamicSymbol GetProfilerAddDynamicSymbolFunc(); -BASE_EXPORT MoveDynamicSymbol GetProfilerMoveDynamicSymbolFunc(); - -} // namespace debug -} // namespace base - -#endif // BASE_DEBUG_DEBUGGER_H diff --git a/base/debug/stack_trace.cc b/base/debug/stack_trace.cc deleted file mode 100644 index 6fab183503..0000000000 --- a/base/debug/stack_trace.cc +++ /dev/null @@ -1,41 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "base/debug/stack_trace.h" - -#include "base/basictypes.h" - -#include - -#include -#include - -namespace base { -namespace debug { - -StackTrace::StackTrace(const void* const* trace, size_t count) { - count = std::min(count, arraysize(trace_)); - if (count) - memcpy(trace_, trace, count * sizeof(trace_[0])); - count_ = count; -} - -StackTrace::~StackTrace() { -} - -const void *const *StackTrace::Addresses(size_t* count) const { - *count = count_; - if (count_) - return trace_; - return NULL; -} - -std::string StackTrace::ToString() const { - std::stringstream stream; - OutputToStream(&stream); - return stream.str(); -} - -} // namespace debug -} // namespace base diff --git a/base/debug/stack_trace.h b/base/debug/stack_trace.h deleted file mode 100644 index 53bed3c5ac..0000000000 --- a/base/debug/stack_trace.h +++ /dev/null @@ -1,101 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef BASE_DEBUG_STACK_TRACE_H_ -#define BASE_DEBUG_STACK_TRACE_H_ - -#include -#include - -#include "base/base_export.h" -#include "build/build_config.h" - -#if defined(OS_POSIX) -#include -#endif - -#if defined(OS_WIN) -struct _EXCEPTION_POINTERS; -#endif - -namespace base { -namespace debug { - -// Enables stack dump to console output on exception and signals. -// When enabled, the process will quit immediately. This is meant to be used in -// unit_tests only! This is not thread-safe: only call from main thread. -BASE_EXPORT bool EnableInProcessStackDumping(); - -// A stacktrace can be helpful in debugging. For example, you can include a -// stacktrace member in a object (probably around #ifndef NDEBUG) so that you -// can later see where the given object was created from. -class BASE_EXPORT StackTrace { - public: - // Creates a stacktrace from the current location. - StackTrace(); - - // Creates a stacktrace from an existing array of instruction - // pointers (such as returned by Addresses()). |count| will be - // trimmed to |kMaxTraces|. - StackTrace(const void* const* trace, size_t count); - -#if defined(OS_WIN) - // Creates a stacktrace for an exception. - // Note: this function will throw an import not found (StackWalk64) exception - // on system without dbghelp 5.1. - StackTrace(_EXCEPTION_POINTERS* exception_pointers); -#endif - - // Copying and assignment are allowed with the default functions. - - ~StackTrace(); - - // Gets an array of instruction pointer values. |*count| will be set to the - // number of elements in the returned array. - const void* const* Addresses(size_t* count) const; - - // Prints a backtrace to stderr - void PrintBacktrace() const; - - // Resolves backtrace to symbols and write to stream. - void OutputToStream(std::ostream* os) const; - - // Resolves backtrace to symbols and returns as string. - std::string ToString() const; - - private: - // From http://msdn.microsoft.com/en-us/library/bb204633.aspx, - // the sum of FramesToSkip and FramesToCapture must be less than 63, - // so set it to 62. Even if on POSIX it could be a larger value, it usually - // doesn't give much more information. - static const int kMaxTraces = 62; - - void* trace_[kMaxTraces]; - - // The number of valid frames in |trace_|. - size_t count_; -}; - -namespace internal { - -#if defined(OS_POSIX) && !defined(OS_ANDROID) -// POSIX doesn't define any async-signal safe function for converting -// an integer to ASCII. We'll have to define our own version. -// itoa_r() converts a (signed) integer to ASCII. It returns "buf", if the -// conversion was successful or NULL otherwise. It never writes more than "sz" -// bytes. Output will be truncated as needed, and a NUL character is always -// appended. -BASE_EXPORT char *itoa_r(intptr_t i, - char *buf, - size_t sz, - int base, - size_t padding); -#endif // defined(OS_POSIX) && !defined(OS_ANDROID) - -} // namespace internal - -} // namespace debug -} // namespace base - -#endif // BASE_DEBUG_STACK_TRACE_H_ diff --git a/base/debug/stack_trace_android.cc b/base/debug/stack_trace_android.cc deleted file mode 100644 index 4c53d4a94c..0000000000 --- a/base/debug/stack_trace_android.cc +++ /dev/null @@ -1,132 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "base/debug/stack_trace.h" - -#include -#include - -#include "base/debug/proc_maps_linux.h" -#include "base/strings/stringprintf.h" -#include "base/threading/thread_restrictions.h" - -namespace { - -struct StackCrawlState { - StackCrawlState(uintptr_t* frames, size_t max_depth) - : frames(frames), - frame_count(0), - max_depth(max_depth), - have_skipped_self(false) {} - - uintptr_t* frames; - size_t frame_count; - size_t max_depth; - bool have_skipped_self; -}; - -// Clang's unwind.h doesn't provide _Unwind_GetIP on ARM, refer to -// http://llvm.org/bugs/show_bug.cgi?id=16564 for details. -#if defined(__clang__) -uintptr_t _Unwind_GetIP(_Unwind_Context* context) { - uintptr_t ip = 0; - _Unwind_VRS_Get(context, _UVRSC_CORE, 15, _UVRSD_UINT32, &ip); - return ip & ~static_cast(0x1); // Remove thumb mode bit. -} -#endif - -_Unwind_Reason_Code TraceStackFrame(_Unwind_Context* context, void* arg) { - StackCrawlState* state = static_cast(arg); - uintptr_t ip = _Unwind_GetIP(context); - - // The first stack frame is this function itself. Skip it. - if (ip != 0 && !state->have_skipped_self) { - state->have_skipped_self = true; - return _URC_NO_REASON; - } - - state->frames[state->frame_count++] = ip; - if (state->frame_count >= state->max_depth) - return _URC_END_OF_STACK; - return _URC_NO_REASON; -} - -} // namespace - -namespace base { -namespace debug { - -bool EnableInProcessStackDumping() { - // When running in an application, our code typically expects SIGPIPE - // to be ignored. Therefore, when testing that same code, it should run - // with SIGPIPE ignored as well. - // TODO(phajdan.jr): De-duplicate this SIGPIPE code. - struct sigaction action; - memset(&action, 0, sizeof(action)); - action.sa_handler = SIG_IGN; - sigemptyset(&action.sa_mask); - return (sigaction(SIGPIPE, &action, NULL) == 0); -} - -StackTrace::StackTrace() { - StackCrawlState state(reinterpret_cast(trace_), kMaxTraces); - _Unwind_Backtrace(&TraceStackFrame, &state); - count_ = state.frame_count; -} - -void StackTrace::PrintBacktrace() const { - std::string backtrace = ToString(); - __android_log_write(ANDROID_LOG_ERROR, "chromium", backtrace.c_str()); -} - -// NOTE: Native libraries in APKs are stripped before installing. Print out the -// relocatable address and library names so host computers can use tools to -// symbolize and demangle (e.g., addr2line, c++filt). -void StackTrace::OutputToStream(std::ostream* os) const { - std::string proc_maps; - std::vector regions; - // Allow IO to read /proc/self/maps. Reading this file doesn't hit the disk - // since it lives in procfs, and this is currently used to print a stack trace - // on fatal log messages in debug builds only. If the restriction is enabled - // then it will recursively trigger fatal failures when this enters on the - // UI thread. - base::ThreadRestrictions::ScopedAllowIO allow_io; - if (!ReadProcMaps(&proc_maps)) { - __android_log_write( - ANDROID_LOG_ERROR, "chromium", "Failed to read /proc/self/maps"); - } else if (!ParseProcMaps(proc_maps, ®ions)) { - __android_log_write( - ANDROID_LOG_ERROR, "chromium", "Failed to parse /proc/self/maps"); - } - - for (size_t i = 0; i < count_; ++i) { - // Subtract one as return address of function may be in the next - // function when a function is annotated as noreturn. - uintptr_t address = reinterpret_cast(trace_[i]) - 1; - - std::vector::iterator iter = regions.begin(); - while (iter != regions.end()) { - if (address >= iter->start && address < iter->end && - !iter->path.empty()) { - break; - } - ++iter; - } - - *os << base::StringPrintf("#%02d 0x%08x ", i, address); - - if (iter != regions.end()) { - uintptr_t rel_pc = address - iter->start + iter->offset; - const char* path = iter->path.c_str(); - *os << base::StringPrintf("%s+0x%08x", path, rel_pc); - } else { - *os << ""; - } - - *os << "\n"; - } -} - -} // namespace debug -} // namespace base diff --git a/base/debug/stack_trace_ios.mm b/base/debug/stack_trace_ios.mm deleted file mode 100644 index 998dd0dfc6..0000000000 --- a/base/debug/stack_trace_ios.mm +++ /dev/null @@ -1,53 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#import -#include -#include - -#include "base/logging.h" - -// This is just enough of a shim to let the support needed by test_support -// link. - -namespace base { -namespace debug { - -namespace { - -void StackDumpSignalHandler(int signal) { - // TODO(phajdan.jr): Fix async-signal unsafety. - LOG(ERROR) << "Received signal " << signal; - NSArray *stack_symbols = [NSThread callStackSymbols]; - for (NSString* stack_symbol in stack_symbols) { - fprintf(stderr, "\t%s\n", [stack_symbol UTF8String]); - } - _exit(1); -} - -} // namespace - -// TODO(phajdan.jr): Deduplicate, see copy in stack_trace_posix.cc. -bool EnableInProcessStackDumping() { - // When running in an application, our code typically expects SIGPIPE - // to be ignored. Therefore, when testing that same code, it should run - // with SIGPIPE ignored as well. - struct sigaction action; - action.sa_handler = SIG_IGN; - action.sa_flags = 0; - sigemptyset(&action.sa_mask); - bool success = (sigaction(SIGPIPE, &action, NULL) == 0); - - success &= (signal(SIGILL, &StackDumpSignalHandler) != SIG_ERR); - success &= (signal(SIGABRT, &StackDumpSignalHandler) != SIG_ERR); - success &= (signal(SIGFPE, &StackDumpSignalHandler) != SIG_ERR); - success &= (signal(SIGBUS, &StackDumpSignalHandler) != SIG_ERR); - success &= (signal(SIGSEGV, &StackDumpSignalHandler) != SIG_ERR); - success &= (signal(SIGSYS, &StackDumpSignalHandler) != SIG_ERR); - - return success; -} - -} // namespace debug -} // namespace base diff --git a/base/debug/stack_trace_posix.cc b/base/debug/stack_trace_posix.cc deleted file mode 100644 index 8a8ae47710..0000000000 --- a/base/debug/stack_trace_posix.cc +++ /dev/null @@ -1,556 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "base/debug/stack_trace.h" - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include - -#if defined(__GLIBCXX__) -#include -#endif - -#if defined(OS_MACOSX) -#include -#endif - -#include "base/basictypes.h" -#include "base/debug/debugger.h" -#include "base/logging.h" -#include "base/memory/scoped_ptr.h" -#include "base/posix/eintr_wrapper.h" -#include "base/strings/string_number_conversions.h" - -#if defined(USE_SYMBOLIZE) -#include "base/third_party/symbolize/symbolize.h" -#endif - -namespace base { -namespace debug { - -namespace { - -volatile sig_atomic_t in_signal_handler = 0; - -// The prefix used for mangled symbols, per the Itanium C++ ABI: -// http://www.codesourcery.com/cxx-abi/abi.html#mangling -const char kMangledSymbolPrefix[] = "_Z"; - -// Characters that can be used for symbols, generated by Ruby: -// (('a'..'z').to_a+('A'..'Z').to_a+('0'..'9').to_a + ['_']).join -const char kSymbolCharacters[] = - "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_"; - -#if !defined(USE_SYMBOLIZE) -// Demangles C++ symbols in the given text. Example: -// -// "out/Debug/base_unittests(_ZN10StackTraceC1Ev+0x20) [0x817778c]" -// => -// "out/Debug/base_unittests(StackTrace::StackTrace()+0x20) [0x817778c]" -void DemangleSymbols(std::string* text) { - // Note: code in this function is NOT async-signal safe (std::string uses - // malloc internally). - -#if defined(__GLIBCXX__) - - std::string::size_type search_from = 0; - while (search_from < text->size()) { - // Look for the start of a mangled symbol, from search_from. - std::string::size_type mangled_start = - text->find(kMangledSymbolPrefix, search_from); - if (mangled_start == std::string::npos) { - break; // Mangled symbol not found. - } - - // Look for the end of the mangled symbol. - std::string::size_type mangled_end = - text->find_first_not_of(kSymbolCharacters, mangled_start); - if (mangled_end == std::string::npos) { - mangled_end = text->size(); - } - std::string mangled_symbol = - text->substr(mangled_start, mangled_end - mangled_start); - - // Try to demangle the mangled symbol candidate. - int status = 0; - scoped_ptr_malloc demangled_symbol( - abi::__cxa_demangle(mangled_symbol.c_str(), NULL, 0, &status)); - if (status == 0) { // Demangling is successful. - // Remove the mangled symbol. - text->erase(mangled_start, mangled_end - mangled_start); - // Insert the demangled symbol. - text->insert(mangled_start, demangled_symbol.get()); - // Next time, we'll start right after the demangled symbol we inserted. - search_from = mangled_start + strlen(demangled_symbol.get()); - } else { - // Failed to demangle. Retry after the "_Z" we just found. - search_from = mangled_start + 2; - } - } - -#endif // defined(__GLIBCXX__) -} -#endif // !defined(USE_SYMBOLIZE) - -class BacktraceOutputHandler { - public: - virtual void HandleOutput(const char* output) = 0; - - protected: - virtual ~BacktraceOutputHandler() {} -}; - -void OutputPointer(void* pointer, BacktraceOutputHandler* handler) { - char buf[1024] = { '\0' }; - handler->HandleOutput(" [0x"); - internal::itoa_r(reinterpret_cast(pointer), - buf, sizeof(buf), 16, 12); - handler->HandleOutput(buf); - handler->HandleOutput("]"); -} - -void ProcessBacktrace(void *const *trace, - int size, - BacktraceOutputHandler* handler) { - // NOTE: This code MUST be async-signal safe (it's used by in-process - // stack dumping signal handler). NO malloc or stdio is allowed here. - -#if defined(USE_SYMBOLIZE) - for (int i = 0; i < size; ++i) { - OutputPointer(trace[i], handler); - handler->HandleOutput(" "); - - char buf[1024] = { '\0' }; - - // Subtract by one as return address of function may be in the next - // function when a function is annotated as noreturn. - void* address = static_cast(trace[i]) - 1; - if (google::Symbolize(address, buf, sizeof(buf))) - handler->HandleOutput(buf); - else - handler->HandleOutput(""); - - handler->HandleOutput("\n"); - } -#else - bool printed = false; - - // Below part is async-signal unsafe (uses malloc), so execute it only - // when we are not executing the signal handler. - if (in_signal_handler == 0) { - scoped_ptr_malloc trace_symbols(backtrace_symbols(trace, size)); - if (trace_symbols.get()) { - for (int i = 0; i < size; ++i) { - std::string trace_symbol = trace_symbols.get()[i]; - DemangleSymbols(&trace_symbol); - handler->HandleOutput(trace_symbol.c_str()); - handler->HandleOutput("\n"); - } - - printed = true; - } - } - - if (!printed) { - for (int i = 0; i < size; ++i) { - OutputPointer(trace[i], handler); - handler->HandleOutput("\n"); - } - } -#endif // defined(USE_SYMBOLIZE) -} - -void PrintToStderr(const char* output) { - // NOTE: This code MUST be async-signal safe (it's used by in-process - // stack dumping signal handler). NO malloc or stdio is allowed here. - ignore_result(HANDLE_EINTR(write(STDERR_FILENO, output, strlen(output)))); -} - -void StackDumpSignalHandler(int signal, siginfo_t* info, void* void_context) { - // NOTE: This code MUST be async-signal safe. - // NO malloc or stdio is allowed here. - - // Record the fact that we are in the signal handler now, so that the rest - // of StackTrace can behave in an async-signal-safe manner. - in_signal_handler = 1; - - if (BeingDebugged()) - BreakDebugger(); - - PrintToStderr("Received signal "); - char buf[1024] = { 0 }; - internal::itoa_r(signal, buf, sizeof(buf), 10, 0); - PrintToStderr(buf); - if (signal == SIGBUS) { - if (info->si_code == BUS_ADRALN) - PrintToStderr(" BUS_ADRALN "); - else if (info->si_code == BUS_ADRERR) - PrintToStderr(" BUS_ADRERR "); - else if (info->si_code == BUS_OBJERR) - PrintToStderr(" BUS_OBJERR "); - else - PrintToStderr(" "); - } else if (signal == SIGFPE) { - if (info->si_code == FPE_FLTDIV) - PrintToStderr(" FPE_FLTDIV "); - else if (info->si_code == FPE_FLTINV) - PrintToStderr(" FPE_FLTINV "); - else if (info->si_code == FPE_FLTOVF) - PrintToStderr(" FPE_FLTOVF "); - else if (info->si_code == FPE_FLTRES) - PrintToStderr(" FPE_FLTRES "); - else if (info->si_code == FPE_FLTSUB) - PrintToStderr(" FPE_FLTSUB "); - else if (info->si_code == FPE_FLTUND) - PrintToStderr(" FPE_FLTUND "); - else if (info->si_code == FPE_INTDIV) - PrintToStderr(" FPE_INTDIV "); - else if (info->si_code == FPE_INTOVF) - PrintToStderr(" FPE_INTOVF "); - else - PrintToStderr(" "); - } else if (signal == SIGILL) { - if (info->si_code == ILL_BADSTK) - PrintToStderr(" ILL_BADSTK "); - else if (info->si_code == ILL_COPROC) - PrintToStderr(" ILL_COPROC "); - else if (info->si_code == ILL_ILLOPN) - PrintToStderr(" ILL_ILLOPN "); - else if (info->si_code == ILL_ILLADR) - PrintToStderr(" ILL_ILLADR "); - else if (info->si_code == ILL_ILLTRP) - PrintToStderr(" ILL_ILLTRP "); - else if (info->si_code == ILL_PRVOPC) - PrintToStderr(" ILL_PRVOPC "); - else if (info->si_code == ILL_PRVREG) - PrintToStderr(" ILL_PRVREG "); - else - PrintToStderr(" "); - } else if (signal == SIGSEGV) { - if (info->si_code == SEGV_MAPERR) - PrintToStderr(" SEGV_MAPERR "); - else if (info->si_code == SEGV_ACCERR) - PrintToStderr(" SEGV_ACCERR "); - else - PrintToStderr(" "); - } - if (signal == SIGBUS || signal == SIGFPE || - signal == SIGILL || signal == SIGSEGV) { - internal::itoa_r(reinterpret_cast(info->si_addr), - buf, sizeof(buf), 16, 12); - PrintToStderr(buf); - } - PrintToStderr("\n"); - - debug::StackTrace().PrintBacktrace(); - -#if defined(OS_LINUX) -#if ARCH_CPU_X86_FAMILY - ucontext_t* context = reinterpret_cast(void_context); - const struct { - const char* label; - greg_t value; - } registers[] = { -#if ARCH_CPU_32_BITS - { " gs: ", context->uc_mcontext.gregs[REG_GS] }, - { " fs: ", context->uc_mcontext.gregs[REG_FS] }, - { " es: ", context->uc_mcontext.gregs[REG_ES] }, - { " ds: ", context->uc_mcontext.gregs[REG_DS] }, - { " edi: ", context->uc_mcontext.gregs[REG_EDI] }, - { " esi: ", context->uc_mcontext.gregs[REG_ESI] }, - { " ebp: ", context->uc_mcontext.gregs[REG_EBP] }, - { " esp: ", context->uc_mcontext.gregs[REG_ESP] }, - { " ebx: ", context->uc_mcontext.gregs[REG_EBX] }, - { " edx: ", context->uc_mcontext.gregs[REG_EDX] }, - { " ecx: ", context->uc_mcontext.gregs[REG_ECX] }, - { " eax: ", context->uc_mcontext.gregs[REG_EAX] }, - { " trp: ", context->uc_mcontext.gregs[REG_TRAPNO] }, - { " err: ", context->uc_mcontext.gregs[REG_ERR] }, - { " ip: ", context->uc_mcontext.gregs[REG_EIP] }, - { " cs: ", context->uc_mcontext.gregs[REG_CS] }, - { " efl: ", context->uc_mcontext.gregs[REG_EFL] }, - { " usp: ", context->uc_mcontext.gregs[REG_UESP] }, - { " ss: ", context->uc_mcontext.gregs[REG_SS] }, -#elif ARCH_CPU_64_BITS - { " r8: ", context->uc_mcontext.gregs[REG_R8] }, - { " r9: ", context->uc_mcontext.gregs[REG_R9] }, - { " r10: ", context->uc_mcontext.gregs[REG_R10] }, - { " r11: ", context->uc_mcontext.gregs[REG_R11] }, - { " r12: ", context->uc_mcontext.gregs[REG_R12] }, - { " r13: ", context->uc_mcontext.gregs[REG_R13] }, - { " r14: ", context->uc_mcontext.gregs[REG_R14] }, - { " r15: ", context->uc_mcontext.gregs[REG_R15] }, - { " di: ", context->uc_mcontext.gregs[REG_RDI] }, - { " si: ", context->uc_mcontext.gregs[REG_RSI] }, - { " bp: ", context->uc_mcontext.gregs[REG_RBP] }, - { " bx: ", context->uc_mcontext.gregs[REG_RBX] }, - { " dx: ", context->uc_mcontext.gregs[REG_RDX] }, - { " ax: ", context->uc_mcontext.gregs[REG_RAX] }, - { " cx: ", context->uc_mcontext.gregs[REG_RCX] }, - { " sp: ", context->uc_mcontext.gregs[REG_RSP] }, - { " ip: ", context->uc_mcontext.gregs[REG_RIP] }, - { " efl: ", context->uc_mcontext.gregs[REG_EFL] }, - { " cgf: ", context->uc_mcontext.gregs[REG_CSGSFS] }, - { " erf: ", context->uc_mcontext.gregs[REG_ERR] }, - { " trp: ", context->uc_mcontext.gregs[REG_TRAPNO] }, - { " msk: ", context->uc_mcontext.gregs[REG_OLDMASK] }, - { " cr2: ", context->uc_mcontext.gregs[REG_CR2] }, -#endif - }; - -#if ARCH_CPU_32_BITS - const int kRegisterPadding = 8; -#elif ARCH_CPU_64_BITS - const int kRegisterPadding = 16; -#endif - - for (size_t i = 0; i < ARRAYSIZE_UNSAFE(registers); i++) { - PrintToStderr(registers[i].label); - internal::itoa_r(registers[i].value, buf, sizeof(buf), - 16, kRegisterPadding); - PrintToStderr(buf); - - if ((i + 1) % 4 == 0) - PrintToStderr("\n"); - } - PrintToStderr("\n"); -#endif -#elif defined(OS_MACOSX) - // TODO(shess): Port to 64-bit. -#if ARCH_CPU_X86_FAMILY && ARCH_CPU_32_BITS - ucontext_t* context = reinterpret_cast(void_context); - size_t len; - - // NOTE: Even |snprintf()| is not on the approved list for signal - // handlers, but buffered I/O is definitely not on the list due to - // potential for |malloc()|. - len = static_cast( - snprintf(buf, sizeof(buf), - "ax: %x, bx: %x, cx: %x, dx: %x\n", - context->uc_mcontext->__ss.__eax, - context->uc_mcontext->__ss.__ebx, - context->uc_mcontext->__ss.__ecx, - context->uc_mcontext->__ss.__edx)); - write(STDERR_FILENO, buf, std::min(len, sizeof(buf) - 1)); - - len = static_cast( - snprintf(buf, sizeof(buf), - "di: %x, si: %x, bp: %x, sp: %x, ss: %x, flags: %x\n", - context->uc_mcontext->__ss.__edi, - context->uc_mcontext->__ss.__esi, - context->uc_mcontext->__ss.__ebp, - context->uc_mcontext->__ss.__esp, - context->uc_mcontext->__ss.__ss, - context->uc_mcontext->__ss.__eflags)); - write(STDERR_FILENO, buf, std::min(len, sizeof(buf) - 1)); - - len = static_cast( - snprintf(buf, sizeof(buf), - "ip: %x, cs: %x, ds: %x, es: %x, fs: %x, gs: %x\n", - context->uc_mcontext->__ss.__eip, - context->uc_mcontext->__ss.__cs, - context->uc_mcontext->__ss.__ds, - context->uc_mcontext->__ss.__es, - context->uc_mcontext->__ss.__fs, - context->uc_mcontext->__ss.__gs)); - write(STDERR_FILENO, buf, std::min(len, sizeof(buf) - 1)); -#endif // ARCH_CPU_32_BITS -#endif // defined(OS_MACOSX) - _exit(1); -} - -class PrintBacktraceOutputHandler : public BacktraceOutputHandler { - public: - PrintBacktraceOutputHandler() {} - - virtual void HandleOutput(const char* output) OVERRIDE { - // NOTE: This code MUST be async-signal safe (it's used by in-process - // stack dumping signal handler). NO malloc or stdio is allowed here. - PrintToStderr(output); - } - - private: - DISALLOW_COPY_AND_ASSIGN(PrintBacktraceOutputHandler); -}; - -class StreamBacktraceOutputHandler : public BacktraceOutputHandler { - public: - explicit StreamBacktraceOutputHandler(std::ostream* os) : os_(os) { - } - - virtual void HandleOutput(const char* output) OVERRIDE { - (*os_) << output; - } - - private: - std::ostream* os_; - - DISALLOW_COPY_AND_ASSIGN(StreamBacktraceOutputHandler); -}; - -void WarmUpBacktrace() { - // Warm up stack trace infrastructure. It turns out that on the first - // call glibc initializes some internal data structures using pthread_once, - // and even backtrace() can call malloc(), leading to hangs. - // - // Example stack trace snippet (with tcmalloc): - // - // #8 0x0000000000a173b5 in tc_malloc - // at ./third_party/tcmalloc/chromium/src/debugallocation.cc:1161 - // #9 0x00007ffff7de7900 in _dl_map_object_deps at dl-deps.c:517 - // #10 0x00007ffff7ded8a9 in dl_open_worker at dl-open.c:262 - // #11 0x00007ffff7de9176 in _dl_catch_error at dl-error.c:178 - // #12 0x00007ffff7ded31a in _dl_open (file=0x7ffff625e298 "libgcc_s.so.1") - // at dl-open.c:639 - // #13 0x00007ffff6215602 in do_dlopen at dl-libc.c:89 - // #14 0x00007ffff7de9176 in _dl_catch_error at dl-error.c:178 - // #15 0x00007ffff62156c4 in dlerror_run at dl-libc.c:48 - // #16 __GI___libc_dlopen_mode at dl-libc.c:165 - // #17 0x00007ffff61ef8f5 in init - // at ../sysdeps/x86_64/../ia64/backtrace.c:53 - // #18 0x00007ffff6aad400 in pthread_once - // at ../nptl/sysdeps/unix/sysv/linux/x86_64/pthread_once.S:104 - // #19 0x00007ffff61efa14 in __GI___backtrace - // at ../sysdeps/x86_64/../ia64/backtrace.c:104 - // #20 0x0000000000752a54 in base::debug::StackTrace::StackTrace - // at base/debug/stack_trace_posix.cc:175 - // #21 0x00000000007a4ae5 in - // base::(anonymous namespace)::StackDumpSignalHandler - // at base/process_util_posix.cc:172 - // #22 - StackTrace stack_trace; -} - -} // namespace - -#if !defined(OS_IOS) -bool EnableInProcessStackDumping() { - // When running in an application, our code typically expects SIGPIPE - // to be ignored. Therefore, when testing that same code, it should run - // with SIGPIPE ignored as well. - struct sigaction sigpipe_action; - memset(&sigpipe_action, 0, sizeof(sigpipe_action)); - sigpipe_action.sa_handler = SIG_IGN; - sigemptyset(&sigpipe_action.sa_mask); - bool success = (sigaction(SIGPIPE, &sigpipe_action, NULL) == 0); - - // Avoid hangs during backtrace initialization, see above. - WarmUpBacktrace(); - - struct sigaction action; - memset(&action, 0, sizeof(action)); - action.sa_flags = SA_RESETHAND | SA_SIGINFO; - action.sa_sigaction = &StackDumpSignalHandler; - sigemptyset(&action.sa_mask); - - success &= (sigaction(SIGILL, &action, NULL) == 0); - success &= (sigaction(SIGABRT, &action, NULL) == 0); - success &= (sigaction(SIGFPE, &action, NULL) == 0); - success &= (sigaction(SIGBUS, &action, NULL) == 0); - success &= (sigaction(SIGSEGV, &action, NULL) == 0); - success &= (sigaction(SIGSYS, &action, NULL) == 0); - - return success; -} -#endif // !defined(OS_IOS) - -StackTrace::StackTrace() { - // NOTE: This code MUST be async-signal safe (it's used by in-process - // stack dumping signal handler). NO malloc or stdio is allowed here. - - // Though the backtrace API man page does not list any possible negative - // return values, we take no chance. - count_ = std::max(backtrace(trace_, arraysize(trace_)), 0); -} - -void StackTrace::PrintBacktrace() const { - // NOTE: This code MUST be async-signal safe (it's used by in-process - // stack dumping signal handler). NO malloc or stdio is allowed here. - - PrintBacktraceOutputHandler handler; - ProcessBacktrace(trace_, count_, &handler); -} - -void StackTrace::OutputToStream(std::ostream* os) const { - StreamBacktraceOutputHandler handler(os); - ProcessBacktrace(trace_, count_, &handler); -} - -namespace internal { - -// NOTE: code from sandbox/linux/seccomp-bpf/demo.cc. -char *itoa_r(intptr_t i, char *buf, size_t sz, int base, size_t padding) { - // Make sure we can write at least one NUL byte. - size_t n = 1; - if (n > sz) - return NULL; - - if (base < 2 || base > 16) { - buf[0] = '\000'; - return NULL; - } - - char *start = buf; - - uintptr_t j = i; - - // Handle negative numbers (only for base 10). - if (i < 0 && base == 10) { - j = -i; - - // Make sure we can write the '-' character. - if (++n > sz) { - buf[0] = '\000'; - return NULL; - } - *start++ = '-'; - } - - // Loop until we have converted the entire number. Output at least one - // character (i.e. '0'). - char *ptr = start; - do { - // Make sure there is still enough space left in our output buffer. - if (++n > sz) { - buf[0] = '\000'; - return NULL; - } - - // Output the next digit. - *ptr++ = "0123456789abcdef"[j % base]; - j /= base; - - if (padding > 0) - padding--; - } while (j > 0 || padding > 0); - - // Terminate the output with a NUL character. - *ptr = '\000'; - - // Conversion to ASCII actually resulted in the digits being in reverse - // order. We can't easily generate them in forward order, as we can't tell - // the number of characters needed until we are done converting. - // So, now, we reverse the string (except for the possible "-" sign). - while (--ptr > start) { - char ch = *ptr; - *ptr = *start; - *start++ = ch; - } - return buf; -} - -} // namespace internal - -} // namespace debug -} // namespace base diff --git a/base/debug/stack_trace_unittest.cc b/base/debug/stack_trace_unittest.cc deleted file mode 100644 index b676327d7a..0000000000 --- a/base/debug/stack_trace_unittest.cc +++ /dev/null @@ -1,229 +0,0 @@ -// Copyright (c) 2011 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include -#include -#include - -#include "base/debug/stack_trace.h" -#include "base/logging.h" -#include "base/process/kill.h" -#include "base/process/process_handle.h" -#include "base/test/test_timeouts.h" -#include "testing/gtest/include/gtest/gtest.h" -#include "testing/multiprocess_func_list.h" - -#if defined(OS_POSIX) && !defined(OS_ANDROID) && !defined(OS_IOS) -#include "base/test/multiprocess_test.h" -#endif - -namespace base { -namespace debug { - -#if defined(OS_POSIX) && !defined(OS_ANDROID) && !defined(OS_IOS) -typedef MultiProcessTest StackTraceTest; -#else -typedef testing::Test StackTraceTest; -#endif - -// Note: On Linux, this test currently only fully works on Debug builds. -// See comments in the #ifdef soup if you intend to change this. -#if defined(OS_WIN) -// Always fails on Windows: crbug.com/32070 -#define MAYBE_OutputToStream DISABLED_OutputToStream -#else -#define MAYBE_OutputToStream OutputToStream -#endif -TEST_F(StackTraceTest, MAYBE_OutputToStream) { - StackTrace trace; - - // Dump the trace into a string. - std::ostringstream os; - trace.OutputToStream(&os); - std::string backtrace_message = os.str(); - - // ToString() should produce the same output. - EXPECT_EQ(backtrace_message, trace.ToString()); - -#if defined(OS_POSIX) && !defined(OS_MACOSX) && NDEBUG - // Stack traces require an extra data table that bloats our binaries, - // so they're turned off for release builds. We stop the test here, - // at least letting us verify that the calls don't crash. - return; -#endif // defined(OS_POSIX) && !defined(OS_MACOSX) && NDEBUG - - size_t frames_found = 0; - trace.Addresses(&frames_found); - ASSERT_GE(frames_found, 5u) << - "No stack frames found. Skipping rest of test."; - - // Check if the output has symbol initialization warning. If it does, fail. - ASSERT_EQ(backtrace_message.find("Dumping unresolved backtrace"), - std::string::npos) << - "Unable to resolve symbols. Skipping rest of test."; - -#if defined(OS_MACOSX) -#if 0 - // Disabled due to -fvisibility=hidden in build config. - - // Symbol resolution via the backtrace_symbol function does not work well - // in OS X. - // See this thread: - // - // http://lists.apple.com/archives/darwin-dev/2009/Mar/msg00111.html - // - // Just check instead that we find our way back to the "start" symbol - // which should be the first symbol in the trace. - // - // TODO(port): Find a more reliable way to resolve symbols. - - // Expect to at least find main. - EXPECT_TRUE(backtrace_message.find("start") != std::string::npos) - << "Expected to find start in backtrace:\n" - << backtrace_message; - -#endif -#elif defined(USE_SYMBOLIZE) - // This branch is for gcc-compiled code, but not Mac due to the - // above #if. - // Expect a demangled symbol. - EXPECT_TRUE(backtrace_message.find("testing::Test::Run()") != - std::string::npos) - << "Expected a demangled symbol in backtrace:\n" - << backtrace_message; - -#elif 0 - // This is the fall-through case; it used to cover Windows. - // But it's disabled because of varying buildbot configs; - // some lack symbols. - - // Expect to at least find main. - EXPECT_TRUE(backtrace_message.find("main") != std::string::npos) - << "Expected to find main in backtrace:\n" - << backtrace_message; - -#if defined(OS_WIN) -// MSVC doesn't allow the use of C99's __func__ within C++, so we fake it with -// MSVC's __FUNCTION__ macro. -#define __func__ __FUNCTION__ -#endif - - // Expect to find this function as well. - // Note: This will fail if not linked with -rdynamic (aka -export_dynamic) - EXPECT_TRUE(backtrace_message.find(__func__) != std::string::npos) - << "Expected to find " << __func__ << " in backtrace:\n" - << backtrace_message; - -#endif // define(OS_MACOSX) -} - -// The test is used for manual testing, e.g., to see the raw output. -TEST_F(StackTraceTest, DebugOutputToStream) { - StackTrace trace; - std::ostringstream os; - trace.OutputToStream(&os); - VLOG(1) << os.str(); -} - -// The test is used for manual testing, e.g., to see the raw output. -TEST_F(StackTraceTest, DebugPrintBacktrace) { - StackTrace().PrintBacktrace(); -} - -#if defined(OS_POSIX) && !defined(OS_ANDROID) -#if !defined(OS_IOS) -MULTIPROCESS_TEST_MAIN(MismatchedMallocChildProcess) { - char* pointer = new char[10]; - delete pointer; - return 2; -} - -// Regression test for StackDumpingSignalHandler async-signal unsafety. -// Combined with tcmalloc's debugallocation, that signal handler -// and e.g. mismatched new[]/delete would cause a hang because -// of re-entering malloc. -TEST_F(StackTraceTest, AsyncSignalUnsafeSignalHandlerHang) { - ProcessHandle child = this->SpawnChild("MismatchedMallocChildProcess", false); - ASSERT_NE(kNullProcessHandle, child); - ASSERT_TRUE(WaitForSingleProcess(child, TestTimeouts::action_timeout())); -} -#endif // !defined(OS_IOS) - -namespace { - -std::string itoa_r_wrapper(intptr_t i, size_t sz, int base, size_t padding) { - char buffer[1024]; - CHECK_LE(sz, sizeof(buffer)); - - char* result = internal::itoa_r(i, buffer, sz, base, padding); - EXPECT_TRUE(result); - return std::string(buffer); -} - -} // namespace - -TEST_F(StackTraceTest, itoa_r) { - EXPECT_EQ("0", itoa_r_wrapper(0, 128, 10, 0)); - EXPECT_EQ("-1", itoa_r_wrapper(-1, 128, 10, 0)); - - // Test edge cases. - if (sizeof(intptr_t) == 4) { - EXPECT_EQ("ffffffff", itoa_r_wrapper(-1, 128, 16, 0)); - EXPECT_EQ("-2147483648", - itoa_r_wrapper(std::numeric_limits::min(), 128, 10, 0)); - EXPECT_EQ("2147483647", - itoa_r_wrapper(std::numeric_limits::max(), 128, 10, 0)); - - EXPECT_EQ("80000000", - itoa_r_wrapper(std::numeric_limits::min(), 128, 16, 0)); - EXPECT_EQ("7fffffff", - itoa_r_wrapper(std::numeric_limits::max(), 128, 16, 0)); - } else if (sizeof(intptr_t) == 8) { - EXPECT_EQ("ffffffffffffffff", itoa_r_wrapper(-1, 128, 16, 0)); - EXPECT_EQ("-9223372036854775808", - itoa_r_wrapper(std::numeric_limits::min(), 128, 10, 0)); - EXPECT_EQ("9223372036854775807", - itoa_r_wrapper(std::numeric_limits::max(), 128, 10, 0)); - - EXPECT_EQ("8000000000000000", - itoa_r_wrapper(std::numeric_limits::min(), 128, 16, 0)); - EXPECT_EQ("7fffffffffffffff", - itoa_r_wrapper(std::numeric_limits::max(), 128, 16, 0)); - } else { - ADD_FAILURE() << "Missing test case for your size of intptr_t (" - << sizeof(intptr_t) << ")"; - } - - // Test hex output. - EXPECT_EQ("688", itoa_r_wrapper(0x688, 128, 16, 0)); - EXPECT_EQ("deadbeef", itoa_r_wrapper(0xdeadbeef, 128, 16, 0)); - - // Check that itoa_r respects passed buffer size limit. - char buffer[1024]; - EXPECT_TRUE(internal::itoa_r(0xdeadbeef, buffer, 10, 16, 0)); - EXPECT_TRUE(internal::itoa_r(0xdeadbeef, buffer, 9, 16, 0)); - EXPECT_FALSE(internal::itoa_r(0xdeadbeef, buffer, 8, 16, 0)); - EXPECT_FALSE(internal::itoa_r(0xdeadbeef, buffer, 7, 16, 0)); - EXPECT_TRUE(internal::itoa_r(0xbeef, buffer, 5, 16, 4)); - EXPECT_FALSE(internal::itoa_r(0xbeef, buffer, 5, 16, 5)); - EXPECT_FALSE(internal::itoa_r(0xbeef, buffer, 5, 16, 6)); - - // Test padding. - EXPECT_EQ("1", itoa_r_wrapper(1, 128, 10, 0)); - EXPECT_EQ("1", itoa_r_wrapper(1, 128, 10, 1)); - EXPECT_EQ("01", itoa_r_wrapper(1, 128, 10, 2)); - EXPECT_EQ("001", itoa_r_wrapper(1, 128, 10, 3)); - EXPECT_EQ("0001", itoa_r_wrapper(1, 128, 10, 4)); - EXPECT_EQ("00001", itoa_r_wrapper(1, 128, 10, 5)); - EXPECT_EQ("688", itoa_r_wrapper(0x688, 128, 16, 0)); - EXPECT_EQ("688", itoa_r_wrapper(0x688, 128, 16, 1)); - EXPECT_EQ("688", itoa_r_wrapper(0x688, 128, 16, 2)); - EXPECT_EQ("688", itoa_r_wrapper(0x688, 128, 16, 3)); - EXPECT_EQ("0688", itoa_r_wrapper(0x688, 128, 16, 4)); - EXPECT_EQ("00688", itoa_r_wrapper(0x688, 128, 16, 5)); -} -#endif // defined(OS_POSIX) && !defined(OS_ANDROID) - -} // namespace debug -} // namespace base diff --git a/base/debug/stack_trace_win.cc b/base/debug/stack_trace_win.cc deleted file mode 100644 index 986241b0a3..0000000000 --- a/base/debug/stack_trace_win.cc +++ /dev/null @@ -1,271 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "base/debug/stack_trace.h" - -#include -#include - -#include - -#include "base/basictypes.h" -#include "base/logging.h" -#include "base/memory/singleton.h" -#include "base/path_service.h" -#include "base/process/launch.h" -#include "base/strings/string_util.h" -#include "base/synchronization/lock.h" -#include "base/win/windows_version.h" - -namespace base { -namespace debug { - -namespace { - -// Previous unhandled filter. Will be called if not NULL when we intercept an -// exception. Only used in unit tests. -LPTOP_LEVEL_EXCEPTION_FILTER g_previous_filter = NULL; - -// Prints the exception call stack. -// This is the unit tests exception filter. -long WINAPI StackDumpExceptionFilter(EXCEPTION_POINTERS* info) { - debug::StackTrace(info).PrintBacktrace(); - if (g_previous_filter) - return g_previous_filter(info); - return EXCEPTION_CONTINUE_SEARCH; -} - -// SymbolContext is a threadsafe singleton that wraps the DbgHelp Sym* family -// of functions. The Sym* family of functions may only be invoked by one -// thread at a time. SymbolContext code may access a symbol server over the -// network while holding the lock for this singleton. In the case of high -// latency, this code will adversely affect performance. -// -// There is also a known issue where this backtrace code can interact -// badly with breakpad if breakpad is invoked in a separate thread while -// we are using the Sym* functions. This is because breakpad does now -// share a lock with this function. See this related bug: -// -// http://code.google.com/p/google-breakpad/issues/detail?id=311 -// -// This is a very unlikely edge case, and the current solution is to -// just ignore it. -class SymbolContext { - public: - static SymbolContext* GetInstance() { - // We use a leaky singleton because code may call this during process - // termination. - return - Singleton >::get(); - } - - // Returns the error code of a failed initialization. - DWORD init_error() const { - return init_error_; - } - - // For the given trace, attempts to resolve the symbols, and output a trace - // to the ostream os. The format for each line of the backtrace is: - // - // SymbolName[0xAddress+Offset] (FileName:LineNo) - // - // This function should only be called if Init() has been called. We do not - // LOG(FATAL) here because this code is called might be triggered by a - // LOG(FATAL) itself. - void OutputTraceToStream(const void* const* trace, - size_t count, - std::ostream* os) { - base::AutoLock lock(lock_); - - for (size_t i = 0; (i < count) && os->good(); ++i) { - const int kMaxNameLength = 256; - DWORD_PTR frame = reinterpret_cast(trace[i]); - - // Code adapted from MSDN example: - // http://msdn.microsoft.com/en-us/library/ms680578(VS.85).aspx - ULONG64 buffer[ - (sizeof(SYMBOL_INFO) + - kMaxNameLength * sizeof(wchar_t) + - sizeof(ULONG64) - 1) / - sizeof(ULONG64)]; - memset(buffer, 0, sizeof(buffer)); - - // Initialize symbol information retrieval structures. - DWORD64 sym_displacement = 0; - PSYMBOL_INFO symbol = reinterpret_cast(&buffer[0]); - symbol->SizeOfStruct = sizeof(SYMBOL_INFO); - symbol->MaxNameLen = kMaxNameLength - 1; - BOOL has_symbol = SymFromAddr(GetCurrentProcess(), frame, - &sym_displacement, symbol); - - // Attempt to retrieve line number information. - DWORD line_displacement = 0; - IMAGEHLP_LINE64 line = {}; - line.SizeOfStruct = sizeof(IMAGEHLP_LINE64); - BOOL has_line = SymGetLineFromAddr64(GetCurrentProcess(), frame, - &line_displacement, &line); - - // Output the backtrace line. - (*os) << "\t"; - if (has_symbol) { - (*os) << symbol->Name << " [0x" << trace[i] << "+" - << sym_displacement << "]"; - } else { - // If there is no symbol information, add a spacer. - (*os) << "(No symbol) [0x" << trace[i] << "]"; - } - if (has_line) { - (*os) << " (" << line.FileName << ":" << line.LineNumber << ")"; - } - (*os) << "\n"; - } - } - - private: - friend struct DefaultSingletonTraits; - - SymbolContext() : init_error_(ERROR_SUCCESS) { - // Initializes the symbols for the process. - // Defer symbol load until they're needed, use undecorated names, and - // get line numbers. - SymSetOptions(SYMOPT_DEFERRED_LOADS | - SYMOPT_UNDNAME | - SYMOPT_LOAD_LINES); - if (!SymInitialize(GetCurrentProcess(), NULL, TRUE)) { - init_error_ = GetLastError(); - // TODO(awong): Handle error: SymInitialize can fail with - // ERROR_INVALID_PARAMETER. - // When it fails, we should not call debugbreak since it kills the current - // process (prevents future tests from running or kills the browser - // process). - DLOG(ERROR) << "SymInitialize failed: " << init_error_; - return; - } - - init_error_ = ERROR_SUCCESS; - - // Work around a mysterious hang on Windows XP. - if (base::win::GetVersion() < base::win::VERSION_VISTA) - return; - - // When transferring the binaries e.g. between bots, path put - // into the executable will get off. To still retrieve symbols correctly, - // add the directory of the executable to symbol search path. - // All following errors are non-fatal. - wchar_t symbols_path[1024]; - - // Note: The below function takes buffer size as number of characters, - // not number of bytes! - if (!SymGetSearchPathW(GetCurrentProcess(), - symbols_path, - arraysize(symbols_path))) { - DLOG(WARNING) << "SymGetSearchPath failed: "; - return; - } - - FilePath module_path; - if (!PathService::Get(FILE_EXE, &module_path)) { - DLOG(WARNING) << "PathService::Get(FILE_EXE) failed."; - return; - } - - std::wstring new_path(std::wstring(symbols_path) + - L";" + module_path.DirName().value()); - if (!SymSetSearchPathW(GetCurrentProcess(), new_path.c_str())) { - DLOG(WARNING) << "SymSetSearchPath failed."; - return; - } - } - - DWORD init_error_; - base::Lock lock_; - DISALLOW_COPY_AND_ASSIGN(SymbolContext); -}; - -} // namespace - -bool EnableInProcessStackDumping() { - // Add stack dumping support on exception on windows. Similar to OS_POSIX - // signal() handling in process_util_posix.cc. - g_previous_filter = SetUnhandledExceptionFilter(&StackDumpExceptionFilter); - RouteStdioToConsole(); - return true; -} - -// Disable optimizations for the StackTrace::StackTrace function. It is -// important to disable at least frame pointer optimization ("y"), since -// that breaks CaptureStackBackTrace() and prevents StackTrace from working -// in Release builds (it may still be janky if other frames are using FPO, -// but at least it will make it further). -#if defined(COMPILER_MSVC) -#pragma optimize("", off) -#endif - -StackTrace::StackTrace() { - // When walking our own stack, use CaptureStackBackTrace(). - count_ = CaptureStackBackTrace(0, arraysize(trace_), trace_, NULL); -} - -#if defined(COMPILER_MSVC) -#pragma optimize("", on) -#endif - -StackTrace::StackTrace(EXCEPTION_POINTERS* exception_pointers) { - // When walking an exception stack, we need to use StackWalk64(). - count_ = 0; - // Initialize stack walking. - STACKFRAME64 stack_frame; - memset(&stack_frame, 0, sizeof(stack_frame)); -#if defined(_WIN64) - int machine_type = IMAGE_FILE_MACHINE_AMD64; - stack_frame.AddrPC.Offset = exception_pointers->ContextRecord->Rip; - stack_frame.AddrFrame.Offset = exception_pointers->ContextRecord->Rbp; - stack_frame.AddrStack.Offset = exception_pointers->ContextRecord->Rsp; -#else - int machine_type = IMAGE_FILE_MACHINE_I386; - stack_frame.AddrPC.Offset = exception_pointers->ContextRecord->Eip; - stack_frame.AddrFrame.Offset = exception_pointers->ContextRecord->Ebp; - stack_frame.AddrStack.Offset = exception_pointers->ContextRecord->Esp; -#endif - stack_frame.AddrPC.Mode = AddrModeFlat; - stack_frame.AddrFrame.Mode = AddrModeFlat; - stack_frame.AddrStack.Mode = AddrModeFlat; - while (StackWalk64(machine_type, - GetCurrentProcess(), - GetCurrentThread(), - &stack_frame, - exception_pointers->ContextRecord, - NULL, - &SymFunctionTableAccess64, - &SymGetModuleBase64, - NULL) && - count_ < arraysize(trace_)) { - trace_[count_++] = reinterpret_cast(stack_frame.AddrPC.Offset); - } - - for (size_t i = count_; i < arraysize(trace_); ++i) - trace_[i] = NULL; -} - -void StackTrace::PrintBacktrace() const { - OutputToStream(&std::cerr); -} - -void StackTrace::OutputToStream(std::ostream* os) const { - SymbolContext* context = SymbolContext::GetInstance(); - DWORD error = context->init_error(); - if (error != ERROR_SUCCESS) { - (*os) << "Error initializing symbols (" << error - << "). Dumping unresolved backtrace:\n"; - for (int i = 0; (i < count_) && os->good(); ++i) { - (*os) << "\t" << trace_[i] << "\n"; - } - } else { - (*os) << "Backtrace:\n"; - context->OutputTraceToStream(trace_, count_, os); - } -} - -} // namespace debug -} // namespace base diff --git a/base/debug/trace_event.h b/base/debug/trace_event.h deleted file mode 100644 index 6805513b66..0000000000 --- a/base/debug/trace_event.h +++ /dev/null @@ -1,1542 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -// This header file defines the set of trace_event macros without specifying -// how the events actually get collected and stored. If you need to expose trace -// events to some other universe, you can copy-and-paste this file as well as -// trace_event.h, modifying the macros contained there as necessary for the -// target platform. The end result is that multiple libraries can funnel events -// through to a shared trace event collector. - -// Trace events are for tracking application performance and resource usage. -// Macros are provided to track: -// Begin and end of function calls -// Counters -// -// Events are issued against categories. Whereas LOG's -// categories are statically defined, TRACE categories are created -// implicitly with a string. For example: -// TRACE_EVENT_INSTANT0("MY_SUBSYSTEM", "SomeImportantEvent", -// TRACE_EVENT_SCOPE_THREAD) -// -// It is often the case that one trace may belong in multiple categories at the -// same time. The first argument to the trace can be a comma-separated list of -// categories, forming a category group, like: -// -// TRACE_EVENT_INSTANT0("input,views", "OnMouseOver", TRACE_EVENT_SCOPE_THREAD) -// -// We can enable/disable tracing of OnMouseOver by enabling/disabling either -// category. -// -// Events can be INSTANT, or can be pairs of BEGIN and END in the same scope: -// TRACE_EVENT_BEGIN0("MY_SUBSYSTEM", "SomethingCostly") -// doSomethingCostly() -// TRACE_EVENT_END0("MY_SUBSYSTEM", "SomethingCostly") -// Note: our tools can't always determine the correct BEGIN/END pairs unless -// these are used in the same scope. Use ASYNC_BEGIN/ASYNC_END macros if you -// need them to be in separate scopes. -// -// A common use case is to trace entire function scopes. This -// issues a trace BEGIN and END automatically: -// void doSomethingCostly() { -// TRACE_EVENT0("MY_SUBSYSTEM", "doSomethingCostly"); -// ... -// } -// -// Additional parameters can be associated with an event: -// void doSomethingCostly2(int howMuch) { -// TRACE_EVENT1("MY_SUBSYSTEM", "doSomethingCostly", -// "howMuch", howMuch); -// ... -// } -// -// The trace system will automatically add to this information the -// current process id, thread id, and a timestamp in microseconds. -// -// To trace an asynchronous procedure such as an IPC send/receive, use -// ASYNC_BEGIN and ASYNC_END: -// [single threaded sender code] -// static int send_count = 0; -// ++send_count; -// TRACE_EVENT_ASYNC_BEGIN0("ipc", "message", send_count); -// Send(new MyMessage(send_count)); -// [receive code] -// void OnMyMessage(send_count) { -// TRACE_EVENT_ASYNC_END0("ipc", "message", send_count); -// } -// The third parameter is a unique ID to match ASYNC_BEGIN/ASYNC_END pairs. -// ASYNC_BEGIN and ASYNC_END can occur on any thread of any traced process. -// Pointers can be used for the ID parameter, and they will be mangled -// internally so that the same pointer on two different processes will not -// match. For example: -// class MyTracedClass { -// public: -// MyTracedClass() { -// TRACE_EVENT_ASYNC_BEGIN0("category", "MyTracedClass", this); -// } -// ~MyTracedClass() { -// TRACE_EVENT_ASYNC_END0("category", "MyTracedClass", this); -// } -// } -// -// Trace event also supports counters, which is a way to track a quantity -// as it varies over time. Counters are created with the following macro: -// TRACE_COUNTER1("MY_SUBSYSTEM", "myCounter", g_myCounterValue); -// -// Counters are process-specific. The macro itself can be issued from any -// thread, however. -// -// Sometimes, you want to track two counters at once. You can do this with two -// counter macros: -// TRACE_COUNTER1("MY_SUBSYSTEM", "myCounter0", g_myCounterValue[0]); -// TRACE_COUNTER1("MY_SUBSYSTEM", "myCounter1", g_myCounterValue[1]); -// Or you can do it with a combined macro: -// TRACE_COUNTER2("MY_SUBSYSTEM", "myCounter", -// "bytesPinned", g_myCounterValue[0], -// "bytesAllocated", g_myCounterValue[1]); -// This indicates to the tracing UI that these counters should be displayed -// in a single graph, as a summed area chart. -// -// Since counters are in a global namespace, you may want to disambiguate with a -// unique ID, by using the TRACE_COUNTER_ID* variations. -// -// By default, trace collection is compiled in, but turned off at runtime. -// Collecting trace data is the responsibility of the embedding -// application. In Chrome's case, navigating to about:tracing will turn on -// tracing and display data collected across all active processes. -// -// -// Memory scoping note: -// Tracing copies the pointers, not the string content, of the strings passed -// in for category_group, name, and arg_names. Thus, the following code will -// cause problems: -// char* str = strdup("importantName"); -// TRACE_EVENT_INSTANT0("SUBSYSTEM", str); // BAD! -// free(str); // Trace system now has dangling pointer -// -// To avoid this issue with the |name| and |arg_name| parameters, use the -// TRACE_EVENT_COPY_XXX overloads of the macros at additional runtime overhead. -// Notes: The category must always be in a long-lived char* (i.e. static const). -// The |arg_values|, when used, are always deep copied with the _COPY -// macros. -// -// When are string argument values copied: -// const char* arg_values are only referenced by default: -// TRACE_EVENT1("category", "name", -// "arg1", "literal string is only referenced"); -// Use TRACE_STR_COPY to force copying of a const char*: -// TRACE_EVENT1("category", "name", -// "arg1", TRACE_STR_COPY("string will be copied")); -// std::string arg_values are always copied: -// TRACE_EVENT1("category", "name", -// "arg1", std::string("string will be copied")); -// -// -// Convertible notes: -// Converting a large data type to a string can be costly. To help with this, -// the trace framework provides an interface ConvertableToTraceFormat. If you -// inherit from it and implement the AppendAsTraceFormat method the trace -// framework will call back to your object to convert a trace output time. This -// means, if the category for the event is disabled, the conversion will not -// happen. -// -// class MyData : public base::debug::ConvertableToTraceFormat { -// public: -// MyData() {} -// virtual ~MyData() {} -// virtual void AppendAsTraceFormat(std::string* out) const OVERRIDE { -// out->append("{\"foo\":1}"); -// } -// private: -// DISALLOW_COPY_AND_ASSIGN(MyData); -// }; -// -// scoped_ptr data(new MyData()); -// TRACE_EVENT1("foo", "bar", "data", -// data.PassAs()); -// -// The trace framework will take ownership if the passed pointer and it will -// be free'd when the trace buffer is flushed. -// -// Note, we only do the conversion when the buffer is flushed, so the provided -// data object should not be modified after it's passed to the trace framework. -// -// -// Thread Safety: -// A thread safe singleton and mutex are used for thread safety. Category -// enabled flags are used to limit the performance impact when the system -// is not enabled. -// -// TRACE_EVENT macros first cache a pointer to a category. The categories are -// statically allocated and safe at all times, even after exit. Fetching a -// category is protected by the TraceLog::lock_. Multiple threads initializing -// the static variable is safe, as they will be serialized by the lock and -// multiple calls will return the same pointer to the category. -// -// Then the category_group_enabled flag is checked. This is a unsigned char, and -// not intended to be multithread safe. It optimizes access to AddTraceEvent -// which is threadsafe internally via TraceLog::lock_. The enabled flag may -// cause some threads to incorrectly call or skip calling AddTraceEvent near -// the time of the system being enabled or disabled. This is acceptable as -// we tolerate some data loss while the system is being enabled/disabled and -// because AddTraceEvent is threadsafe internally and checks the enabled state -// again under lock. -// -// Without the use of these static category pointers and enabled flags all -// trace points would carry a significant performance cost of acquiring a lock -// and resolving the category. - -#ifndef BASE_DEBUG_TRACE_EVENT_H_ -#define BASE_DEBUG_TRACE_EVENT_H_ - -#include - -#include "base/atomicops.h" -#include "base/debug/trace_event_impl.h" -#include "base/debug/trace_event_memory.h" -#include "build/build_config.h" - -// By default, const char* argument values are assumed to have long-lived scope -// and will not be copied. Use this macro to force a const char* to be copied. -#define TRACE_STR_COPY(str) \ - trace_event_internal::TraceStringWithCopy(str) - -// This will mark the trace event as disabled by default. The user will need -// to explicitly enable the event. -#define TRACE_DISABLED_BY_DEFAULT(name) "disabled-by-default-" name - -// By default, uint64 ID argument values are not mangled with the Process ID in -// TRACE_EVENT_ASYNC macros. Use this macro to force Process ID mangling. -#define TRACE_ID_MANGLE(id) \ - trace_event_internal::TraceID::ForceMangle(id) - -// By default, pointers are mangled with the Process ID in TRACE_EVENT_ASYNC -// macros. Use this macro to prevent Process ID mangling. -#define TRACE_ID_DONT_MANGLE(id) \ - trace_event_internal::TraceID::DontMangle(id) - -// Records a pair of begin and end events called "name" for the current -// scope, with 0, 1 or 2 associated arguments. If the category is not -// enabled, then this does nothing. -// - category and name strings must have application lifetime (statics or -// literals). They may not include " chars. -#define TRACE_EVENT0(category_group, name) \ - INTERNAL_TRACE_MEMORY(category_group, name) \ - INTERNAL_TRACE_EVENT_ADD_SCOPED(category_group, name) -#define TRACE_EVENT1(category_group, name, arg1_name, arg1_val) \ - INTERNAL_TRACE_MEMORY(category_group, name) \ - INTERNAL_TRACE_EVENT_ADD_SCOPED(category_group, name, arg1_name, arg1_val) -#define TRACE_EVENT2( \ - category_group, name, arg1_name, arg1_val, arg2_name, arg2_val) \ - INTERNAL_TRACE_MEMORY(category_group, name) \ - INTERNAL_TRACE_EVENT_ADD_SCOPED( \ - category_group, name, arg1_name, arg1_val, arg2_name, arg2_val) - -// UNSHIPPED_TRACE_EVENT* are like TRACE_EVENT* except that they are not -// included in official builds. - -#if OFFICIAL_BUILD -#undef TRACING_IS_OFFICIAL_BUILD -#define TRACING_IS_OFFICIAL_BUILD 1 -#elif !defined(TRACING_IS_OFFICIAL_BUILD) -#define TRACING_IS_OFFICIAL_BUILD 0 -#endif - -#if TRACING_IS_OFFICIAL_BUILD -#define UNSHIPPED_TRACE_EVENT0(category_group, name) (void)0 -#define UNSHIPPED_TRACE_EVENT1(category_group, name, arg1_name, arg1_val) \ - (void)0 -#define UNSHIPPED_TRACE_EVENT2(category_group, name, arg1_name, arg1_val, \ - arg2_name, arg2_val) (void)0 -#define UNSHIPPED_TRACE_EVENT_INSTANT0(category_group, name, scope) (void)0 -#define UNSHIPPED_TRACE_EVENT_INSTANT1(category_group, name, scope, \ - arg1_name, arg1_val) (void)0 -#define UNSHIPPED_TRACE_EVENT_INSTANT2(category_group, name, scope, \ - arg1_name, arg1_val, \ - arg2_name, arg2_val) (void)0 -#else -#define UNSHIPPED_TRACE_EVENT0(category_group, name) \ - TRACE_EVENT0(category_group, name) -#define UNSHIPPED_TRACE_EVENT1(category_group, name, arg1_name, arg1_val) \ - TRACE_EVENT1(category_group, name, arg1_name, arg1_val) -#define UNSHIPPED_TRACE_EVENT2(category_group, name, arg1_name, arg1_val, \ - arg2_name, arg2_val) \ - TRACE_EVENT2(category_group, name, arg1_name, arg1_val, arg2_name, arg2_val) -#define UNSHIPPED_TRACE_EVENT_INSTANT0(category_group, name, scope) \ - TRACE_EVENT_INSTANT0(category_group, name, scope) -#define UNSHIPPED_TRACE_EVENT_INSTANT1(category_group, name, scope, \ - arg1_name, arg1_val) \ - TRACE_EVENT_INSTANT1(category_group, name, scope, arg1_name, arg1_val) -#define UNSHIPPED_TRACE_EVENT_INSTANT2(category_group, name, scope, \ - arg1_name, arg1_val, \ - arg2_name, arg2_val) \ - TRACE_EVENT_INSTANT2(category_group, name, scope, arg1_name, arg1_val, \ - arg2_name, arg2_val) -#endif - -// Records a single event called "name" immediately, with 0, 1 or 2 -// associated arguments. If the category is not enabled, then this -// does nothing. -// - category and name strings must have application lifetime (statics or -// literals). They may not include " chars. -#define TRACE_EVENT_INSTANT0(category_group, name, scope) \ - INTERNAL_TRACE_EVENT_ADD(TRACE_EVENT_PHASE_INSTANT, \ - category_group, name, TRACE_EVENT_FLAG_NONE | scope) -#define TRACE_EVENT_INSTANT1(category_group, name, scope, arg1_name, arg1_val) \ - INTERNAL_TRACE_EVENT_ADD(TRACE_EVENT_PHASE_INSTANT, \ - category_group, name, TRACE_EVENT_FLAG_NONE | scope, \ - arg1_name, arg1_val) -#define TRACE_EVENT_INSTANT2(category_group, name, scope, arg1_name, arg1_val, \ - arg2_name, arg2_val) \ - INTERNAL_TRACE_EVENT_ADD(TRACE_EVENT_PHASE_INSTANT, \ - category_group, name, TRACE_EVENT_FLAG_NONE | scope, \ - arg1_name, arg1_val, arg2_name, arg2_val) -#define TRACE_EVENT_COPY_INSTANT0(category_group, name, scope) \ - INTERNAL_TRACE_EVENT_ADD(TRACE_EVENT_PHASE_INSTANT, \ - category_group, name, TRACE_EVENT_FLAG_COPY | scope) -#define TRACE_EVENT_COPY_INSTANT1(category_group, name, scope, \ - arg1_name, arg1_val) \ - INTERNAL_TRACE_EVENT_ADD(TRACE_EVENT_PHASE_INSTANT, \ - category_group, name, TRACE_EVENT_FLAG_COPY | scope, arg1_name, \ - arg1_val) -#define TRACE_EVENT_COPY_INSTANT2(category_group, name, scope, \ - arg1_name, arg1_val, \ - arg2_name, arg2_val) \ - INTERNAL_TRACE_EVENT_ADD(TRACE_EVENT_PHASE_INSTANT, \ - category_group, name, TRACE_EVENT_FLAG_COPY | scope, \ - arg1_name, arg1_val, arg2_name, arg2_val) - -// Sets the current sample state to the given category and name (both must be -// constant strings). These states are intended for a sampling profiler. -// Implementation note: we store category and name together because we don't -// want the inconsistency/expense of storing two pointers. -// |thread_bucket| is [0..2] and is used to statically isolate samples in one -// thread from others. -#define TRACE_EVENT_SET_SAMPLING_STATE_FOR_BUCKET( \ - bucket_number, category, name) \ - trace_event_internal:: \ - TraceEventSamplingStateScope::Set(category "\0" name) - -// Returns a current sampling state of the given bucket. -#define TRACE_EVENT_GET_SAMPLING_STATE_FOR_BUCKET(bucket_number) \ - trace_event_internal::TraceEventSamplingStateScope::Current() - -// Creates a scope of a sampling state of the given bucket. -// -// { // The sampling state is set within this scope. -// TRACE_EVENT_SAMPLING_STATE_SCOPE_FOR_BUCKET(0, "category", "name"); -// ...; -// } -#define TRACE_EVENT_SCOPED_SAMPLING_STATE_FOR_BUCKET( \ - bucket_number, category, name) \ - trace_event_internal::TraceEventSamplingStateScope \ - traceEventSamplingScope(category "\0" name); - -// Syntactic sugars for the sampling tracing in the main thread. -#define TRACE_EVENT_SCOPED_SAMPLING_STATE(category, name) \ - TRACE_EVENT_SCOPED_SAMPLING_STATE_FOR_BUCKET(0, category, name) -#define TRACE_EVENT_GET_SAMPLING_STATE() \ - TRACE_EVENT_GET_SAMPLING_STATE_FOR_BUCKET(0) -#define TRACE_EVENT_SET_SAMPLING_STATE(category, name) \ - TRACE_EVENT_SET_SAMPLING_STATE_FOR_BUCKET(0, category, name) - - -// Records a single BEGIN event called "name" immediately, with 0, 1 or 2 -// associated arguments. If the category is not enabled, then this -// does nothing. -// - category and name strings must have application lifetime (statics or -// literals). They may not include " chars. -#define TRACE_EVENT_BEGIN0(category_group, name) \ - INTERNAL_TRACE_EVENT_ADD(TRACE_EVENT_PHASE_BEGIN, \ - category_group, name, TRACE_EVENT_FLAG_NONE) -#define TRACE_EVENT_BEGIN1(category_group, name, arg1_name, arg1_val) \ - INTERNAL_TRACE_EVENT_ADD(TRACE_EVENT_PHASE_BEGIN, \ - category_group, name, TRACE_EVENT_FLAG_NONE, arg1_name, arg1_val) -#define TRACE_EVENT_BEGIN2(category_group, name, arg1_name, arg1_val, \ - arg2_name, arg2_val) \ - INTERNAL_TRACE_EVENT_ADD(TRACE_EVENT_PHASE_BEGIN, \ - category_group, name, TRACE_EVENT_FLAG_NONE, arg1_name, arg1_val, \ - arg2_name, arg2_val) -#define TRACE_EVENT_COPY_BEGIN0(category_group, name) \ - INTERNAL_TRACE_EVENT_ADD(TRACE_EVENT_PHASE_BEGIN, \ - category_group, name, TRACE_EVENT_FLAG_COPY) -#define TRACE_EVENT_COPY_BEGIN1(category_group, name, arg1_name, arg1_val) \ - INTERNAL_TRACE_EVENT_ADD(TRACE_EVENT_PHASE_BEGIN, \ - category_group, name, TRACE_EVENT_FLAG_COPY, arg1_name, arg1_val) -#define TRACE_EVENT_COPY_BEGIN2(category_group, name, arg1_name, arg1_val, \ - arg2_name, arg2_val) \ - INTERNAL_TRACE_EVENT_ADD(TRACE_EVENT_PHASE_BEGIN, \ - category_group, name, TRACE_EVENT_FLAG_COPY, arg1_name, arg1_val, \ - arg2_name, arg2_val) - -// Similar to TRACE_EVENT_BEGINx but with a custom |at| timestamp provided. -// - |id| is used to match the _BEGIN event with the _END event. -// Events are considered to match if their category_group, name and id values -// all match. |id| must either be a pointer or an integer value up to 64 bits. -// If it's a pointer, the bits will be xored with a hash of the process ID so -// that the same pointer on two different processes will not collide. -#define TRACE_EVENT_BEGIN_WITH_ID_TID_AND_TIMESTAMP0(category_group, \ - name, id, thread_id, timestamp) \ - INTERNAL_TRACE_EVENT_ADD_WITH_ID_TID_AND_TIMESTAMP( \ - TRACE_EVENT_PHASE_ASYNC_BEGIN, category_group, name, id, thread_id, \ - timestamp, TRACE_EVENT_FLAG_NONE) -#define TRACE_EVENT_COPY_BEGIN_WITH_ID_TID_AND_TIMESTAMP0( \ - category_group, name, id, thread_id, timestamp) \ - INTERNAL_TRACE_EVENT_ADD_WITH_ID_TID_AND_TIMESTAMP( \ - TRACE_EVENT_PHASE_ASYNC_BEGIN, category_group, name, id, thread_id, \ - timestamp, TRACE_EVENT_FLAG_COPY) - -// Records a single END event for "name" immediately. If the category -// is not enabled, then this does nothing. -// - category and name strings must have application lifetime (statics or -// literals). They may not include " chars. -#define TRACE_EVENT_END0(category_group, name) \ - INTERNAL_TRACE_EVENT_ADD(TRACE_EVENT_PHASE_END, \ - category_group, name, TRACE_EVENT_FLAG_NONE) -#define TRACE_EVENT_END1(category_group, name, arg1_name, arg1_val) \ - INTERNAL_TRACE_EVENT_ADD(TRACE_EVENT_PHASE_END, \ - category_group, name, TRACE_EVENT_FLAG_NONE, arg1_name, arg1_val) -#define TRACE_EVENT_END2(category_group, name, arg1_name, arg1_val, \ - arg2_name, arg2_val) \ - INTERNAL_TRACE_EVENT_ADD(TRACE_EVENT_PHASE_END, \ - category_group, name, TRACE_EVENT_FLAG_NONE, arg1_name, arg1_val, \ - arg2_name, arg2_val) -#define TRACE_EVENT_COPY_END0(category_group, name) \ - INTERNAL_TRACE_EVENT_ADD(TRACE_EVENT_PHASE_END, \ - category_group, name, TRACE_EVENT_FLAG_COPY) -#define TRACE_EVENT_COPY_END1(category_group, name, arg1_name, arg1_val) \ - INTERNAL_TRACE_EVENT_ADD(TRACE_EVENT_PHASE_END, \ - category_group, name, TRACE_EVENT_FLAG_COPY, arg1_name, arg1_val) -#define TRACE_EVENT_COPY_END2(category_group, name, arg1_name, arg1_val, \ - arg2_name, arg2_val) \ - INTERNAL_TRACE_EVENT_ADD(TRACE_EVENT_PHASE_END, \ - category_group, name, TRACE_EVENT_FLAG_COPY, arg1_name, arg1_val, \ - arg2_name, arg2_val) - -// Similar to TRACE_EVENT_ENDx but with a custom |at| timestamp provided. -// - |id| is used to match the _BEGIN event with the _END event. -// Events are considered to match if their category_group, name and id values -// all match. |id| must either be a pointer or an integer value up to 64 bits. -// If it's a pointer, the bits will be xored with a hash of the process ID so -// that the same pointer on two different processes will not collide. -#define TRACE_EVENT_END_WITH_ID_TID_AND_TIMESTAMP0(category_group, \ - name, id, thread_id, timestamp) \ - INTERNAL_TRACE_EVENT_ADD_WITH_ID_TID_AND_TIMESTAMP( \ - TRACE_EVENT_PHASE_ASYNC_END, category_group, name, id, thread_id, \ - timestamp, TRACE_EVENT_FLAG_NONE) -#define TRACE_EVENT_COPY_END_WITH_ID_TID_AND_TIMESTAMP0( \ - category_group, name, id, thread_id, timestamp) \ - INTERNAL_TRACE_EVENT_ADD_WITH_ID_TID_AND_TIMESTAMP( \ - TRACE_EVENT_PHASE_ASYNC_END, category_group, name, id, thread_id, \ - timestamp, TRACE_EVENT_FLAG_COPY) - -// Records the value of a counter called "name" immediately. Value -// must be representable as a 32 bit integer. -// - category and name strings must have application lifetime (statics or -// literals). They may not include " chars. -#define TRACE_COUNTER1(category_group, name, value) \ - INTERNAL_TRACE_EVENT_ADD(TRACE_EVENT_PHASE_COUNTER, \ - category_group, name, TRACE_EVENT_FLAG_NONE, \ - "value", static_cast(value)) -#define TRACE_COPY_COUNTER1(category_group, name, value) \ - INTERNAL_TRACE_EVENT_ADD(TRACE_EVENT_PHASE_COUNTER, \ - category_group, name, TRACE_EVENT_FLAG_COPY, \ - "value", static_cast(value)) - -// Records the values of a multi-parted counter called "name" immediately. -// The UI will treat value1 and value2 as parts of a whole, displaying their -// values as a stacked-bar chart. -// - category and name strings must have application lifetime (statics or -// literals). They may not include " chars. -#define TRACE_COUNTER2(category_group, name, value1_name, value1_val, \ - value2_name, value2_val) \ - INTERNAL_TRACE_EVENT_ADD(TRACE_EVENT_PHASE_COUNTER, \ - category_group, name, TRACE_EVENT_FLAG_NONE, \ - value1_name, static_cast(value1_val), \ - value2_name, static_cast(value2_val)) -#define TRACE_COPY_COUNTER2(category_group, name, value1_name, value1_val, \ - value2_name, value2_val) \ - INTERNAL_TRACE_EVENT_ADD(TRACE_EVENT_PHASE_COUNTER, \ - category_group, name, TRACE_EVENT_FLAG_COPY, \ - value1_name, static_cast(value1_val), \ - value2_name, static_cast(value2_val)) - -// Records the value of a counter called "name" immediately. Value -// must be representable as a 32 bit integer. -// - category and name strings must have application lifetime (statics or -// literals). They may not include " chars. -// - |id| is used to disambiguate counters with the same name. It must either -// be a pointer or an integer value up to 64 bits. If it's a pointer, the bits -// will be xored with a hash of the process ID so that the same pointer on -// two different processes will not collide. -#define TRACE_COUNTER_ID1(category_group, name, id, value) \ - INTERNAL_TRACE_EVENT_ADD_WITH_ID(TRACE_EVENT_PHASE_COUNTER, \ - category_group, name, id, TRACE_EVENT_FLAG_NONE, \ - "value", static_cast(value)) -#define TRACE_COPY_COUNTER_ID1(category_group, name, id, value) \ - INTERNAL_TRACE_EVENT_ADD_WITH_ID(TRACE_EVENT_PHASE_COUNTER, \ - category_group, name, id, TRACE_EVENT_FLAG_COPY, \ - "value", static_cast(value)) - -// Records the values of a multi-parted counter called "name" immediately. -// The UI will treat value1 and value2 as parts of a whole, displaying their -// values as a stacked-bar chart. -// - category and name strings must have application lifetime (statics or -// literals). They may not include " chars. -// - |id| is used to disambiguate counters with the same name. It must either -// be a pointer or an integer value up to 64 bits. If it's a pointer, the bits -// will be xored with a hash of the process ID so that the same pointer on -// two different processes will not collide. -#define TRACE_COUNTER_ID2(category_group, name, id, value1_name, value1_val, \ - value2_name, value2_val) \ - INTERNAL_TRACE_EVENT_ADD_WITH_ID(TRACE_EVENT_PHASE_COUNTER, \ - category_group, name, id, TRACE_EVENT_FLAG_NONE, \ - value1_name, static_cast(value1_val), \ - value2_name, static_cast(value2_val)) -#define TRACE_COPY_COUNTER_ID2(category_group, name, id, value1_name, \ - value1_val, value2_name, value2_val) \ - INTERNAL_TRACE_EVENT_ADD_WITH_ID(TRACE_EVENT_PHASE_COUNTER, \ - category_group, name, id, TRACE_EVENT_FLAG_COPY, \ - value1_name, static_cast(value1_val), \ - value2_name, static_cast(value2_val)) - - -// Records a single ASYNC_BEGIN event called "name" immediately, with 0, 1 or 2 -// associated arguments. If the category is not enabled, then this -// does nothing. -// - category and name strings must have application lifetime (statics or -// literals). They may not include " chars. -// - |id| is used to match the ASYNC_BEGIN event with the ASYNC_END event. ASYNC -// events are considered to match if their category_group, name and id values -// all match. |id| must either be a pointer or an integer value up to 64 bits. -// If it's a pointer, the bits will be xored with a hash of the process ID so -// that the same pointer on two different processes will not collide. -// An asynchronous operation can consist of multiple phases. The first phase is -// defined by the ASYNC_BEGIN calls. Additional phases can be defined using the -// ASYNC_STEP macros. When the operation completes, call ASYNC_END. -// An ASYNC trace typically occur on a single thread (if not, they will only be -// drawn on the thread defined in the ASYNC_BEGIN event), but all events in that -// operation must use the same |name| and |id|. Each event can have its own -// args. -#define TRACE_EVENT_ASYNC_BEGIN0(category_group, name, id) \ - INTERNAL_TRACE_EVENT_ADD_WITH_ID(TRACE_EVENT_PHASE_ASYNC_BEGIN, \ - category_group, name, id, TRACE_EVENT_FLAG_NONE) -#define TRACE_EVENT_ASYNC_BEGIN1(category_group, name, id, arg1_name, \ - arg1_val) \ - INTERNAL_TRACE_EVENT_ADD_WITH_ID(TRACE_EVENT_PHASE_ASYNC_BEGIN, \ - category_group, name, id, TRACE_EVENT_FLAG_NONE, arg1_name, arg1_val) -#define TRACE_EVENT_ASYNC_BEGIN2(category_group, name, id, arg1_name, \ - arg1_val, arg2_name, arg2_val) \ - INTERNAL_TRACE_EVENT_ADD_WITH_ID(TRACE_EVENT_PHASE_ASYNC_BEGIN, \ - category_group, name, id, TRACE_EVENT_FLAG_NONE, \ - arg1_name, arg1_val, arg2_name, arg2_val) -#define TRACE_EVENT_COPY_ASYNC_BEGIN0(category_group, name, id) \ - INTERNAL_TRACE_EVENT_ADD_WITH_ID(TRACE_EVENT_PHASE_ASYNC_BEGIN, \ - category_group, name, id, TRACE_EVENT_FLAG_COPY) -#define TRACE_EVENT_COPY_ASYNC_BEGIN1(category_group, name, id, arg1_name, \ - arg1_val) \ - INTERNAL_TRACE_EVENT_ADD_WITH_ID(TRACE_EVENT_PHASE_ASYNC_BEGIN, \ - category_group, name, id, TRACE_EVENT_FLAG_COPY, \ - arg1_name, arg1_val) -#define TRACE_EVENT_COPY_ASYNC_BEGIN2(category_group, name, id, arg1_name, \ - arg1_val, arg2_name, arg2_val) \ - INTERNAL_TRACE_EVENT_ADD_WITH_ID(TRACE_EVENT_PHASE_ASYNC_BEGIN, \ - category_group, name, id, TRACE_EVENT_FLAG_COPY, \ - arg1_name, arg1_val, arg2_name, arg2_val) - -// Records a single ASYNC_STEP event for |step| immediately. If the category -// is not enabled, then this does nothing. The |name| and |id| must match the -// ASYNC_BEGIN event above. The |step| param identifies this step within the -// async event. This should be called at the beginning of the next phase of an -// asynchronous operation. -#define TRACE_EVENT_ASYNC_STEP0(category_group, name, id, step) \ - INTERNAL_TRACE_EVENT_ADD_WITH_ID(TRACE_EVENT_PHASE_ASYNC_STEP, \ - category_group, name, id, TRACE_EVENT_FLAG_NONE, "step", step) -#define TRACE_EVENT_ASYNC_STEP1(category_group, name, id, step, \ - arg1_name, arg1_val) \ - INTERNAL_TRACE_EVENT_ADD_WITH_ID(TRACE_EVENT_PHASE_ASYNC_STEP, \ - category_group, name, id, TRACE_EVENT_FLAG_NONE, "step", step, \ - arg1_name, arg1_val) - -#define TRACE_EVENT_COPY_ASYNC_STEP0(category_group, name, id, step) \ - INTERNAL_TRACE_EVENT_ADD_WITH_ID(TRACE_EVENT_PHASE_ASYNC_STEP, \ - category_group, name, id, TRACE_EVENT_FLAG_COPY, "step", step) -#define TRACE_EVENT_COPY_ASYNC_STEP1(category_group, name, id, step, \ - arg1_name, arg1_val) \ - INTERNAL_TRACE_EVENT_ADD_WITH_ID(TRACE_EVENT_PHASE_ASYNC_STEP, \ - category_group, name, id, TRACE_EVENT_FLAG_COPY, "step", step, \ - arg1_name, arg1_val) - -// Records a single ASYNC_END event for "name" immediately. If the category -// is not enabled, then this does nothing. -#define TRACE_EVENT_ASYNC_END0(category_group, name, id) \ - INTERNAL_TRACE_EVENT_ADD_WITH_ID(TRACE_EVENT_PHASE_ASYNC_END, \ - category_group, name, id, TRACE_EVENT_FLAG_NONE) -#define TRACE_EVENT_ASYNC_END1(category_group, name, id, arg1_name, arg1_val) \ - INTERNAL_TRACE_EVENT_ADD_WITH_ID(TRACE_EVENT_PHASE_ASYNC_END, \ - category_group, name, id, TRACE_EVENT_FLAG_NONE, arg1_name, arg1_val) -#define TRACE_EVENT_ASYNC_END2(category_group, name, id, arg1_name, arg1_val, \ - arg2_name, arg2_val) \ - INTERNAL_TRACE_EVENT_ADD_WITH_ID(TRACE_EVENT_PHASE_ASYNC_END, \ - category_group, name, id, TRACE_EVENT_FLAG_NONE, \ - arg1_name, arg1_val, arg2_name, arg2_val) -#define TRACE_EVENT_COPY_ASYNC_END0(category_group, name, id) \ - INTERNAL_TRACE_EVENT_ADD_WITH_ID(TRACE_EVENT_PHASE_ASYNC_END, \ - category_group, name, id, TRACE_EVENT_FLAG_COPY) -#define TRACE_EVENT_COPY_ASYNC_END1(category_group, name, id, arg1_name, \ - arg1_val) \ - INTERNAL_TRACE_EVENT_ADD_WITH_ID(TRACE_EVENT_PHASE_ASYNC_END, \ - category_group, name, id, TRACE_EVENT_FLAG_COPY, \ - arg1_name, arg1_val) -#define TRACE_EVENT_COPY_ASYNC_END2(category_group, name, id, arg1_name, \ - arg1_val, arg2_name, arg2_val) \ - INTERNAL_TRACE_EVENT_ADD_WITH_ID(TRACE_EVENT_PHASE_ASYNC_END, \ - category_group, name, id, TRACE_EVENT_FLAG_COPY, \ - arg1_name, arg1_val, arg2_name, arg2_val) - - -// Records a single FLOW_BEGIN event called "name" immediately, with 0, 1 or 2 -// associated arguments. If the category is not enabled, then this -// does nothing. -// - category and name strings must have application lifetime (statics or -// literals). They may not include " chars. -// - |id| is used to match the FLOW_BEGIN event with the FLOW_END event. FLOW -// events are considered to match if their category_group, name and id values -// all match. |id| must either be a pointer or an integer value up to 64 bits. -// If it's a pointer, the bits will be xored with a hash of the process ID so -// that the same pointer on two different processes will not collide. -// FLOW events are different from ASYNC events in how they are drawn by the -// tracing UI. A FLOW defines asynchronous data flow, such as posting a task -// (FLOW_BEGIN) and later executing that task (FLOW_END). Expect FLOWs to be -// drawn as lines or arrows from FLOW_BEGIN scopes to FLOW_END scopes. Similar -// to ASYNC, a FLOW can consist of multiple phases. The first phase is defined -// by the FLOW_BEGIN calls. Additional phases can be defined using the FLOW_STEP -// macros. When the operation completes, call FLOW_END. An async operation can -// span threads and processes, but all events in that operation must use the -// same |name| and |id|. Each event can have its own args. -#define TRACE_EVENT_FLOW_BEGIN0(category_group, name, id) \ - INTERNAL_TRACE_EVENT_ADD_WITH_ID(TRACE_EVENT_PHASE_FLOW_BEGIN, \ - category_group, name, id, TRACE_EVENT_FLAG_NONE) -#define TRACE_EVENT_FLOW_BEGIN1(category_group, name, id, arg1_name, arg1_val) \ - INTERNAL_TRACE_EVENT_ADD_WITH_ID(TRACE_EVENT_PHASE_FLOW_BEGIN, \ - category_group, name, id, TRACE_EVENT_FLAG_NONE, arg1_name, arg1_val) -#define TRACE_EVENT_FLOW_BEGIN2(category_group, name, id, arg1_name, arg1_val, \ - arg2_name, arg2_val) \ - INTERNAL_TRACE_EVENT_ADD_WITH_ID(TRACE_EVENT_PHASE_FLOW_BEGIN, \ - category_group, name, id, TRACE_EVENT_FLAG_NONE, \ - arg1_name, arg1_val, arg2_name, arg2_val) -#define TRACE_EVENT_COPY_FLOW_BEGIN0(category_group, name, id) \ - INTERNAL_TRACE_EVENT_ADD_WITH_ID(TRACE_EVENT_PHASE_FLOW_BEGIN, \ - category_group, name, id, TRACE_EVENT_FLAG_COPY) -#define TRACE_EVENT_COPY_FLOW_BEGIN1(category_group, name, id, arg1_name, \ - arg1_val) \ - INTERNAL_TRACE_EVENT_ADD_WITH_ID(TRACE_EVENT_PHASE_FLOW_BEGIN, \ - category_group, name, id, TRACE_EVENT_FLAG_COPY, \ - arg1_name, arg1_val) -#define TRACE_EVENT_COPY_FLOW_BEGIN2(category_group, name, id, arg1_name, \ - arg1_val, arg2_name, arg2_val) \ - INTERNAL_TRACE_EVENT_ADD_WITH_ID(TRACE_EVENT_PHASE_FLOW_BEGIN, \ - category_group, name, id, TRACE_EVENT_FLAG_COPY, \ - arg1_name, arg1_val, arg2_name, arg2_val) - -// Records a single FLOW_STEP event for |step| immediately. If the category -// is not enabled, then this does nothing. The |name| and |id| must match the -// FLOW_BEGIN event above. The |step| param identifies this step within the -// async event. This should be called at the beginning of the next phase of an -// asynchronous operation. -#define TRACE_EVENT_FLOW_STEP0(category_group, name, id, step) \ - INTERNAL_TRACE_EVENT_ADD_WITH_ID(TRACE_EVENT_PHASE_FLOW_STEP, \ - category_group, name, id, TRACE_EVENT_FLAG_NONE, "step", step) -#define TRACE_EVENT_FLOW_STEP1(category_group, name, id, step, \ - arg1_name, arg1_val) \ - INTERNAL_TRACE_EVENT_ADD_WITH_ID(TRACE_EVENT_PHASE_FLOW_STEP, \ - category_group, name, id, TRACE_EVENT_FLAG_NONE, "step", step, \ - arg1_name, arg1_val) -#define TRACE_EVENT_COPY_FLOW_STEP0(category_group, name, id, step) \ - INTERNAL_TRACE_EVENT_ADD_WITH_ID(TRACE_EVENT_PHASE_FLOW_STEP, \ - category_group, name, id, TRACE_EVENT_FLAG_COPY, "step", step) -#define TRACE_EVENT_COPY_FLOW_STEP1(category_group, name, id, step, \ - arg1_name, arg1_val) \ - INTERNAL_TRACE_EVENT_ADD_WITH_ID(TRACE_EVENT_PHASE_FLOW_STEP, \ - category_group, name, id, TRACE_EVENT_FLAG_COPY, "step", step, \ - arg1_name, arg1_val) - -// Records a single FLOW_END event for "name" immediately. If the category -// is not enabled, then this does nothing. -#define TRACE_EVENT_FLOW_END0(category_group, name, id) \ - INTERNAL_TRACE_EVENT_ADD_WITH_ID(TRACE_EVENT_PHASE_FLOW_END, \ - category_group, name, id, TRACE_EVENT_FLAG_NONE) -#define TRACE_EVENT_FLOW_END1(category_group, name, id, arg1_name, arg1_val) \ - INTERNAL_TRACE_EVENT_ADD_WITH_ID(TRACE_EVENT_PHASE_FLOW_END, \ - category_group, name, id, TRACE_EVENT_FLAG_NONE, arg1_name, arg1_val) -#define TRACE_EVENT_FLOW_END2(category_group, name, id, arg1_name, arg1_val, \ - arg2_name, arg2_val) \ - INTERNAL_TRACE_EVENT_ADD_WITH_ID(TRACE_EVENT_PHASE_FLOW_END, \ - category_group, name, id, TRACE_EVENT_FLAG_NONE, \ - arg1_name, arg1_val, arg2_name, arg2_val) -#define TRACE_EVENT_COPY_FLOW_END0(category_group, name, id) \ - INTERNAL_TRACE_EVENT_ADD_WITH_ID(TRACE_EVENT_PHASE_FLOW_END, \ - category_group, name, id, TRACE_EVENT_FLAG_COPY) -#define TRACE_EVENT_COPY_FLOW_END1(category_group, name, id, arg1_name, \ - arg1_val) \ - INTERNAL_TRACE_EVENT_ADD_WITH_ID(TRACE_EVENT_PHASE_FLOW_END, \ - category_group, name, id, TRACE_EVENT_FLAG_COPY, \ - arg1_name, arg1_val) -#define TRACE_EVENT_COPY_FLOW_END2(category_group, name, id, arg1_name, \ - arg1_val, arg2_name, arg2_val) \ - INTERNAL_TRACE_EVENT_ADD_WITH_ID(TRACE_EVENT_PHASE_FLOW_END, \ - category_group, name, id, TRACE_EVENT_FLAG_COPY, \ - arg1_name, arg1_val, arg2_name, arg2_val) - -// Macros to track the life time and value of arbitrary client objects. -// See also TraceTrackableObject. -#define TRACE_EVENT_OBJECT_CREATED_WITH_ID(category_group, name, id) \ - INTERNAL_TRACE_EVENT_ADD_WITH_ID(TRACE_EVENT_PHASE_CREATE_OBJECT, \ - category_group, name, TRACE_ID_DONT_MANGLE(id), TRACE_EVENT_FLAG_NONE) - -#define TRACE_EVENT_OBJECT_SNAPSHOT_WITH_ID(category_group, name, id, snapshot) \ - INTERNAL_TRACE_EVENT_ADD_WITH_ID(TRACE_EVENT_PHASE_SNAPSHOT_OBJECT, \ - category_group, name, TRACE_ID_DONT_MANGLE(id), TRACE_EVENT_FLAG_NONE,\ - "snapshot", snapshot) - -#define TRACE_EVENT_OBJECT_DELETED_WITH_ID(category_group, name, id) \ - INTERNAL_TRACE_EVENT_ADD_WITH_ID(TRACE_EVENT_PHASE_DELETE_OBJECT, \ - category_group, name, TRACE_ID_DONT_MANGLE(id), TRACE_EVENT_FLAG_NONE) - - -// Macro to efficiently determine if a given category group is enabled. -#define TRACE_EVENT_CATEGORY_GROUP_ENABLED(category_group, ret) \ - do { \ - INTERNAL_TRACE_EVENT_GET_CATEGORY_INFO(category_group); \ - if (*INTERNAL_TRACE_EVENT_UID(catstatic)) { \ - *ret = true; \ - } else { \ - *ret = false; \ - } \ - } while (0) - -// Macro to efficiently determine, through polling, if a new trace has begun. -#define TRACE_EVENT_IS_NEW_TRACE(ret) \ - do { \ - static int INTERNAL_TRACE_EVENT_UID(lastRecordingNumber) = 0; \ - int num_traces_recorded = TRACE_EVENT_API_GET_NUM_TRACES_RECORDED(); \ - if (num_traces_recorded != -1 && \ - num_traces_recorded != \ - INTERNAL_TRACE_EVENT_UID(lastRecordingNumber)) { \ - INTERNAL_TRACE_EVENT_UID(lastRecordingNumber) = \ - num_traces_recorded; \ - *ret = true; \ - } else { \ - *ret = false; \ - } \ - } while (0) - -//////////////////////////////////////////////////////////////////////////////// -// Implementation specific tracing API definitions. - -// Get a pointer to the enabled state of the given trace category. Only -// long-lived literal strings should be given as the category group. The -// returned pointer can be held permanently in a local static for example. If -// the unsigned char is non-zero, tracing is enabled. If tracing is enabled, -// TRACE_EVENT_API_ADD_TRACE_EVENT can be called. It's OK if tracing is disabled -// between the load of the tracing state and the call to -// TRACE_EVENT_API_ADD_TRACE_EVENT, because this flag only provides an early out -// for best performance when tracing is disabled. -// const unsigned char* -// TRACE_EVENT_API_GET_CATEGORY_GROUP_ENABLED(const char* category_group) -#define TRACE_EVENT_API_GET_CATEGORY_GROUP_ENABLED \ - base::debug::TraceLog::GetCategoryGroupEnabled - -// Get the number of times traces have been recorded. This is used to implement -// the TRACE_EVENT_IS_NEW_TRACE facility. -// unsigned int TRACE_EVENT_API_GET_NUM_TRACES_RECORDED() -#define TRACE_EVENT_API_GET_NUM_TRACES_RECORDED \ - base::debug::TraceLog::GetInstance()->GetNumTracesRecorded - -// Add a trace event to the platform tracing system. -// void TRACE_EVENT_API_ADD_TRACE_EVENT( -// char phase, -// const unsigned char* category_group_enabled, -// const char* name, -// unsigned long long id, -// int num_args, -// const char** arg_names, -// const unsigned char* arg_types, -// const unsigned long long* arg_values, -// unsigned char flags) -#define TRACE_EVENT_API_ADD_TRACE_EVENT \ - base::debug::TraceLog::GetInstance()->AddTraceEvent - -// Add a trace event to the platform tracing system. -// void TRACE_EVENT_API_ADD_TRACE_EVENT_WITH_TIMESTAMP( -// char phase, -// const unsigned char* category_group_enabled, -// const char* name, -// unsigned long long id, -// int thread_id, -// const TimeTicks& timestamp, -// int num_args, -// const char** arg_names, -// const unsigned char* arg_types, -// const unsigned long long* arg_values, -// unsigned char flags) -#define TRACE_EVENT_API_ADD_TRACE_EVENT_WITH_THREAD_ID_AND_TIMESTAMP \ - base::debug::TraceLog::GetInstance()->AddTraceEventWithThreadIdAndTimestamp - -// Defines atomic operations used internally by the tracing system. -#define TRACE_EVENT_API_ATOMIC_WORD base::subtle::AtomicWord -#define TRACE_EVENT_API_ATOMIC_LOAD(var) base::subtle::NoBarrier_Load(&(var)) -#define TRACE_EVENT_API_ATOMIC_STORE(var, value) \ - base::subtle::NoBarrier_Store(&(var), (value)) - -// Defines visibility for classes in trace_event.h -#define TRACE_EVENT_API_CLASS_EXPORT BASE_EXPORT - -// The thread buckets for the sampling profiler. -TRACE_EVENT_API_CLASS_EXPORT extern \ - TRACE_EVENT_API_ATOMIC_WORD g_trace_state[3]; - -#define TRACE_EVENT_API_THREAD_BUCKET(thread_bucket) \ - g_trace_state[thread_bucket] - -//////////////////////////////////////////////////////////////////////////////// - -// Implementation detail: trace event macros create temporary variables -// to keep instrumentation overhead low. These macros give each temporary -// variable a unique name based on the line number to prevent name collisions. -#define INTERNAL_TRACE_EVENT_UID3(a,b) \ - trace_event_unique_##a##b -#define INTERNAL_TRACE_EVENT_UID2(a,b) \ - INTERNAL_TRACE_EVENT_UID3(a,b) -#define INTERNAL_TRACE_EVENT_UID(name_prefix) \ - INTERNAL_TRACE_EVENT_UID2(name_prefix, __LINE__) - -// Implementation detail: internal macro to create static category. -// No barriers are needed, because this code is designed to operate safely -// even when the unsigned char* points to garbage data (which may be the case -// on processors without cache coherency). -#define INTERNAL_TRACE_EVENT_GET_CATEGORY_INFO(category_group) \ - static TRACE_EVENT_API_ATOMIC_WORD INTERNAL_TRACE_EVENT_UID(atomic) = 0; \ - const unsigned char* INTERNAL_TRACE_EVENT_UID(catstatic) = \ - reinterpret_cast(TRACE_EVENT_API_ATOMIC_LOAD( \ - INTERNAL_TRACE_EVENT_UID(atomic))); \ - if (!INTERNAL_TRACE_EVENT_UID(catstatic)) { \ - INTERNAL_TRACE_EVENT_UID(catstatic) = \ - TRACE_EVENT_API_GET_CATEGORY_GROUP_ENABLED(category_group); \ - TRACE_EVENT_API_ATOMIC_STORE(INTERNAL_TRACE_EVENT_UID(atomic), \ - reinterpret_cast( \ - INTERNAL_TRACE_EVENT_UID(catstatic))); \ - } - -// Implementation detail: internal macro to create static category and add -// event if the category is enabled. -#define INTERNAL_TRACE_EVENT_ADD(phase, category_group, name, flags, ...) \ - do { \ - INTERNAL_TRACE_EVENT_GET_CATEGORY_INFO(category_group); \ - if (*INTERNAL_TRACE_EVENT_UID(catstatic)) { \ - trace_event_internal::AddTraceEvent( \ - phase, INTERNAL_TRACE_EVENT_UID(catstatic), name, \ - trace_event_internal::kNoEventId, flags, ##__VA_ARGS__); \ - } \ - } while (0) - -// Implementation detail: internal macro to create static category and add begin -// event if the category is enabled. Also adds the end event when the scope -// ends. -#define INTERNAL_TRACE_EVENT_ADD_SCOPED(category_group, name, ...) \ - INTERNAL_TRACE_EVENT_GET_CATEGORY_INFO(category_group); \ - trace_event_internal::TraceEndOnScopeClose \ - INTERNAL_TRACE_EVENT_UID(profileScope); \ - if (*INTERNAL_TRACE_EVENT_UID(catstatic)) { \ - trace_event_internal::AddTraceEvent( \ - TRACE_EVENT_PHASE_BEGIN, \ - INTERNAL_TRACE_EVENT_UID(catstatic), \ - name, trace_event_internal::kNoEventId, \ - TRACE_EVENT_FLAG_NONE, ##__VA_ARGS__); \ - INTERNAL_TRACE_EVENT_UID(profileScope).Initialize( \ - INTERNAL_TRACE_EVENT_UID(catstatic), name); \ - } - -// Implementation detail: internal macro to create static category and add -// event if the category is enabled. -#define INTERNAL_TRACE_EVENT_ADD_WITH_ID(phase, category_group, name, id, \ - flags, ...) \ - do { \ - INTERNAL_TRACE_EVENT_GET_CATEGORY_INFO(category_group); \ - if (*INTERNAL_TRACE_EVENT_UID(catstatic)) { \ - unsigned char trace_event_flags = flags | TRACE_EVENT_FLAG_HAS_ID; \ - trace_event_internal::TraceID trace_event_trace_id( \ - id, &trace_event_flags); \ - trace_event_internal::AddTraceEvent( \ - phase, INTERNAL_TRACE_EVENT_UID(catstatic), \ - name, trace_event_trace_id.data(), trace_event_flags, \ - ##__VA_ARGS__); \ - } \ - } while (0) - -// Implementation detail: internal macro to create static category and add -// event if the category is enabled. -#define INTERNAL_TRACE_EVENT_ADD_WITH_ID_TID_AND_TIMESTAMP(phase, \ - category_group, name, id, thread_id, timestamp, flags, ...) \ - do { \ - INTERNAL_TRACE_EVENT_GET_CATEGORY_INFO(category_group); \ - if (*INTERNAL_TRACE_EVENT_UID(catstatic)) { \ - unsigned char trace_event_flags = flags | TRACE_EVENT_FLAG_HAS_ID; \ - trace_event_internal::TraceID trace_event_trace_id( \ - id, &trace_event_flags); \ - trace_event_internal::AddTraceEventWithThreadIdAndTimestamp( \ - phase, INTERNAL_TRACE_EVENT_UID(catstatic), \ - name, trace_event_trace_id.data(), \ - thread_id, base::TimeTicks::FromInternalValue(timestamp), \ - trace_event_flags, ##__VA_ARGS__); \ - } \ - } while (0) - -// Notes regarding the following definitions: -// New values can be added and propagated to third party libraries, but existing -// definitions must never be changed, because third party libraries may use old -// definitions. - -// Phase indicates the nature of an event entry. E.g. part of a begin/end pair. -#define TRACE_EVENT_PHASE_BEGIN ('B') -#define TRACE_EVENT_PHASE_END ('E') -#define TRACE_EVENT_PHASE_INSTANT ('i') -#define TRACE_EVENT_PHASE_ASYNC_BEGIN ('S') -#define TRACE_EVENT_PHASE_ASYNC_STEP ('T') -#define TRACE_EVENT_PHASE_ASYNC_END ('F') -#define TRACE_EVENT_PHASE_FLOW_BEGIN ('s') -#define TRACE_EVENT_PHASE_FLOW_STEP ('t') -#define TRACE_EVENT_PHASE_FLOW_END ('f') -#define TRACE_EVENT_PHASE_METADATA ('M') -#define TRACE_EVENT_PHASE_COUNTER ('C') -#define TRACE_EVENT_PHASE_SAMPLE ('P') -#define TRACE_EVENT_PHASE_CREATE_OBJECT ('N') -#define TRACE_EVENT_PHASE_SNAPSHOT_OBJECT ('O') -#define TRACE_EVENT_PHASE_DELETE_OBJECT ('D') - -// Flags for changing the behavior of TRACE_EVENT_API_ADD_TRACE_EVENT. -#define TRACE_EVENT_FLAG_NONE (static_cast(0)) -#define TRACE_EVENT_FLAG_COPY (static_cast(1 << 0)) -#define TRACE_EVENT_FLAG_HAS_ID (static_cast(1 << 1)) -#define TRACE_EVENT_FLAG_MANGLE_ID (static_cast(1 << 2)) -#define TRACE_EVENT_FLAG_SCOPE_OFFSET (static_cast(1 << 3)) - -#define TRACE_EVENT_FLAG_SCOPE_MASK (static_cast( \ - TRACE_EVENT_FLAG_SCOPE_OFFSET | (TRACE_EVENT_FLAG_SCOPE_OFFSET << 1))) - -// Type values for identifying types in the TraceValue union. -#define TRACE_VALUE_TYPE_BOOL (static_cast(1)) -#define TRACE_VALUE_TYPE_UINT (static_cast(2)) -#define TRACE_VALUE_TYPE_INT (static_cast(3)) -#define TRACE_VALUE_TYPE_DOUBLE (static_cast(4)) -#define TRACE_VALUE_TYPE_POINTER (static_cast(5)) -#define TRACE_VALUE_TYPE_STRING (static_cast(6)) -#define TRACE_VALUE_TYPE_COPY_STRING (static_cast(7)) -#define TRACE_VALUE_TYPE_CONVERTABLE (static_cast(8)) - -// Enum reflecting the scope of an INSTANT event. Must fit within -// TRACE_EVENT_FLAG_SCOPE_MASK. -#define TRACE_EVENT_SCOPE_GLOBAL (static_cast(0 << 3)) -#define TRACE_EVENT_SCOPE_PROCESS (static_cast(1 << 3)) -#define TRACE_EVENT_SCOPE_THREAD (static_cast(2 << 3)) - -#define TRACE_EVENT_SCOPE_NAME_GLOBAL ('g') -#define TRACE_EVENT_SCOPE_NAME_PROCESS ('p') -#define TRACE_EVENT_SCOPE_NAME_THREAD ('t') - -namespace trace_event_internal { - -// Specify these values when the corresponding argument of AddTraceEvent is not -// used. -const int kZeroNumArgs = 0; -const unsigned long long kNoEventId = 0; - -// TraceID encapsulates an ID that can either be an integer or pointer. Pointers -// are by default mangled with the Process ID so that they are unlikely to -// collide when the same pointer is used on different processes. -class TraceID { - public: - class DontMangle { - public: - explicit DontMangle(void* id) - : data_(static_cast( - reinterpret_cast(id))) {} - explicit DontMangle(unsigned long long id) : data_(id) {} - explicit DontMangle(unsigned long id) : data_(id) {} - explicit DontMangle(unsigned int id) : data_(id) {} - explicit DontMangle(unsigned short id) : data_(id) {} - explicit DontMangle(unsigned char id) : data_(id) {} - explicit DontMangle(long long id) - : data_(static_cast(id)) {} - explicit DontMangle(long id) - : data_(static_cast(id)) {} - explicit DontMangle(int id) - : data_(static_cast(id)) {} - explicit DontMangle(short id) - : data_(static_cast(id)) {} - explicit DontMangle(signed char id) - : data_(static_cast(id)) {} - unsigned long long data() const { return data_; } - private: - unsigned long long data_; - }; - - class ForceMangle { - public: - explicit ForceMangle(unsigned long long id) : data_(id) {} - explicit ForceMangle(unsigned long id) : data_(id) {} - explicit ForceMangle(unsigned int id) : data_(id) {} - explicit ForceMangle(unsigned short id) : data_(id) {} - explicit ForceMangle(unsigned char id) : data_(id) {} - explicit ForceMangle(long long id) - : data_(static_cast(id)) {} - explicit ForceMangle(long id) - : data_(static_cast(id)) {} - explicit ForceMangle(int id) - : data_(static_cast(id)) {} - explicit ForceMangle(short id) - : data_(static_cast(id)) {} - explicit ForceMangle(signed char id) - : data_(static_cast(id)) {} - unsigned long long data() const { return data_; } - private: - unsigned long long data_; - }; - - TraceID(const void* id, unsigned char* flags) - : data_(static_cast( - reinterpret_cast(id))) { - *flags |= TRACE_EVENT_FLAG_MANGLE_ID; - } - TraceID(ForceMangle id, unsigned char* flags) : data_(id.data()) { - *flags |= TRACE_EVENT_FLAG_MANGLE_ID; - } - TraceID(DontMangle id, unsigned char* flags) : data_(id.data()) { - } - TraceID(unsigned long long id, unsigned char* flags) - : data_(id) { (void)flags; } - TraceID(unsigned long id, unsigned char* flags) - : data_(id) { (void)flags; } - TraceID(unsigned int id, unsigned char* flags) - : data_(id) { (void)flags; } - TraceID(unsigned short id, unsigned char* flags) - : data_(id) { (void)flags; } - TraceID(unsigned char id, unsigned char* flags) - : data_(id) { (void)flags; } - TraceID(long long id, unsigned char* flags) - : data_(static_cast(id)) { (void)flags; } - TraceID(long id, unsigned char* flags) - : data_(static_cast(id)) { (void)flags; } - TraceID(int id, unsigned char* flags) - : data_(static_cast(id)) { (void)flags; } - TraceID(short id, unsigned char* flags) - : data_(static_cast(id)) { (void)flags; } - TraceID(signed char id, unsigned char* flags) - : data_(static_cast(id)) { (void)flags; } - - unsigned long long data() const { return data_; } - - private: - unsigned long long data_; -}; - -// Simple union to store various types as unsigned long long. -union TraceValueUnion { - bool as_bool; - unsigned long long as_uint; - long long as_int; - double as_double; - const void* as_pointer; - const char* as_string; -}; - -// Simple container for const char* that should be copied instead of retained. -class TraceStringWithCopy { - public: - explicit TraceStringWithCopy(const char* str) : str_(str) {} - operator const char* () const { return str_; } - private: - const char* str_; -}; - -// Define SetTraceValue for each allowed type. It stores the type and -// value in the return arguments. This allows this API to avoid declaring any -// structures so that it is portable to third_party libraries. -#define INTERNAL_DECLARE_SET_TRACE_VALUE(actual_type, \ - union_member, \ - value_type_id) \ - static inline void SetTraceValue( \ - actual_type arg, \ - unsigned char* type, \ - unsigned long long* value) { \ - TraceValueUnion type_value; \ - type_value.union_member = arg; \ - *type = value_type_id; \ - *value = type_value.as_uint; \ - } -// Simpler form for int types that can be safely casted. -#define INTERNAL_DECLARE_SET_TRACE_VALUE_INT(actual_type, \ - value_type_id) \ - static inline void SetTraceValue( \ - actual_type arg, \ - unsigned char* type, \ - unsigned long long* value) { \ - *type = value_type_id; \ - *value = static_cast(arg); \ - } - -INTERNAL_DECLARE_SET_TRACE_VALUE_INT(unsigned long long, TRACE_VALUE_TYPE_UINT) -INTERNAL_DECLARE_SET_TRACE_VALUE_INT(unsigned long, TRACE_VALUE_TYPE_UINT) -INTERNAL_DECLARE_SET_TRACE_VALUE_INT(unsigned int, TRACE_VALUE_TYPE_UINT) -INTERNAL_DECLARE_SET_TRACE_VALUE_INT(unsigned short, TRACE_VALUE_TYPE_UINT) -INTERNAL_DECLARE_SET_TRACE_VALUE_INT(unsigned char, TRACE_VALUE_TYPE_UINT) -INTERNAL_DECLARE_SET_TRACE_VALUE_INT(long long, TRACE_VALUE_TYPE_INT) -INTERNAL_DECLARE_SET_TRACE_VALUE_INT(long, TRACE_VALUE_TYPE_INT) -INTERNAL_DECLARE_SET_TRACE_VALUE_INT(int, TRACE_VALUE_TYPE_INT) -INTERNAL_DECLARE_SET_TRACE_VALUE_INT(short, TRACE_VALUE_TYPE_INT) -INTERNAL_DECLARE_SET_TRACE_VALUE_INT(signed char, TRACE_VALUE_TYPE_INT) -INTERNAL_DECLARE_SET_TRACE_VALUE(bool, as_bool, TRACE_VALUE_TYPE_BOOL) -INTERNAL_DECLARE_SET_TRACE_VALUE(double, as_double, TRACE_VALUE_TYPE_DOUBLE) -INTERNAL_DECLARE_SET_TRACE_VALUE(const void*, as_pointer, - TRACE_VALUE_TYPE_POINTER) -INTERNAL_DECLARE_SET_TRACE_VALUE(const char*, as_string, - TRACE_VALUE_TYPE_STRING) -INTERNAL_DECLARE_SET_TRACE_VALUE(const TraceStringWithCopy&, as_string, - TRACE_VALUE_TYPE_COPY_STRING) - -#undef INTERNAL_DECLARE_SET_TRACE_VALUE -#undef INTERNAL_DECLARE_SET_TRACE_VALUE_INT - -// std::string version of SetTraceValue so that trace arguments can be strings. -static inline void SetTraceValue(const std::string& arg, - unsigned char* type, - unsigned long long* value) { - TraceValueUnion type_value; - type_value.as_string = arg.c_str(); - *type = TRACE_VALUE_TYPE_COPY_STRING; - *value = type_value.as_uint; -} - -// These AddTraceEvent and AddTraceEventWithThreadIdAndTimestamp template -// functions are defined here instead of in the macro, because the arg_values -// could be temporary objects, such as std::string. In order to store -// pointers to the internal c_str and pass through to the tracing API, -// the arg_values must live throughout these procedures. - -static inline void AddTraceEventWithThreadIdAndTimestamp( - char phase, - const unsigned char* category_group_enabled, - const char* name, - unsigned long long id, - int thread_id, - const base::TimeTicks& timestamp, - unsigned char flags, - const char* arg1_name, - scoped_ptr arg1_val) { - const int num_args = 1; - unsigned char arg_types[1] = { TRACE_VALUE_TYPE_CONVERTABLE }; - scoped_ptr convertable_values[1]; - convertable_values[0].reset(arg1_val.release()); - - TRACE_EVENT_API_ADD_TRACE_EVENT_WITH_THREAD_ID_AND_TIMESTAMP( - phase, category_group_enabled, name, id, thread_id, timestamp, - num_args, &arg1_name, arg_types, NULL, convertable_values, flags); -} - -static inline void AddTraceEvent( - char phase, - const unsigned char* category_group_enabled, - const char* name, - unsigned long long id, - unsigned char flags, - const char* arg1_name, - scoped_ptr arg1_val) { - int thread_id = static_cast(base::PlatformThread::CurrentId()); - base::TimeTicks now = base::TimeTicks::NowFromSystemTraceTime(); - AddTraceEventWithThreadIdAndTimestamp(phase, category_group_enabled, name, id, - thread_id, now, flags, arg1_name, - arg1_val.Pass()); -} - -template -static inline void AddTraceEventWithThreadIdAndTimestamp( - char phase, - const unsigned char* category_group_enabled, - const char* name, - unsigned long long id, - int thread_id, - const base::TimeTicks& timestamp, - unsigned char flags, - const char* arg1_name, - ARG1_TYPE arg1_val, - const char* arg2_name, - scoped_ptr arg2_val) { - const int num_args = 2; - const char* arg_names[2] = { arg1_name, arg2_name }; - - unsigned char arg_types[2]; - unsigned long long arg_values[2]; - SetTraceValue(arg1_val, &arg_types[0], &arg_values[0]); - arg_types[1] = TRACE_VALUE_TYPE_CONVERTABLE; - - scoped_ptr convertable_values[2]; - convertable_values[1].reset(arg2_val.release()); - - TRACE_EVENT_API_ADD_TRACE_EVENT_WITH_THREAD_ID_AND_TIMESTAMP( - phase, category_group_enabled, name, id, thread_id, timestamp, - num_args, arg_names, arg_types, arg_values, convertable_values, flags); -} - -template -static inline void AddTraceEvent( - char phase, - const unsigned char* category_group_enabled, - const char* name, - unsigned long long id, - unsigned char flags, - const char* arg1_name, - ARG1_TYPE arg1_val, - const char* arg2_name, - scoped_ptr arg2_val) { - int thread_id = static_cast(base::PlatformThread::CurrentId()); - base::TimeTicks now = base::TimeTicks::NowFromSystemTraceTime(); - AddTraceEventWithThreadIdAndTimestamp(phase, category_group_enabled, name, id, - thread_id, now, flags, - arg1_name, arg1_val, - arg2_name, arg2_val.Pass()); -} - -template -static inline void AddTraceEventWithThreadIdAndTimestamp( - char phase, - const unsigned char* category_group_enabled, - const char* name, - unsigned long long id, - int thread_id, - const base::TimeTicks& timestamp, - unsigned char flags, - const char* arg1_name, - scoped_ptr arg1_val, - const char* arg2_name, - ARG2_TYPE arg2_val) { - const int num_args = 2; - const char* arg_names[2] = { arg1_name, arg2_name }; - - unsigned char arg_types[2]; - unsigned long long arg_values[2]; - arg_types[0] = TRACE_VALUE_TYPE_CONVERTABLE; - arg_values[0] = 0; - SetTraceValue(arg2_val, &arg_types[1], &arg_values[1]); - - scoped_ptr convertable_values[2]; - convertable_values[0].reset(arg1_val.release()); - - TRACE_EVENT_API_ADD_TRACE_EVENT_WITH_THREAD_ID_AND_TIMESTAMP( - phase, category_group_enabled, name, id, thread_id, timestamp, - num_args, arg_names, arg_types, arg_values, convertable_values, flags); -} - -template -static inline void AddTraceEvent( - char phase, - const unsigned char* category_group_enabled, - const char* name, - unsigned long long id, - unsigned char flags, - const char* arg1_name, - scoped_ptr arg1_val, - const char* arg2_name, - ARG2_TYPE arg2_val) { - int thread_id = static_cast(base::PlatformThread::CurrentId()); - base::TimeTicks now = base::TimeTicks::NowFromSystemTraceTime(); - AddTraceEventWithThreadIdAndTimestamp(phase, category_group_enabled, name, id, - thread_id, now, flags, - arg1_name, arg1_val.Pass(), - arg2_name, arg2_val); -} - -static inline void AddTraceEventWithThreadIdAndTimestamp( - char phase, - const unsigned char* category_group_enabled, - const char* name, - unsigned long long id, - int thread_id, - const base::TimeTicks& timestamp, - unsigned char flags, - const char* arg1_name, - scoped_ptr arg1_val, - const char* arg2_name, - scoped_ptr arg2_val) { - const int num_args = 2; - const char* arg_names[2] = { arg1_name, arg2_name }; - unsigned char arg_types[2] = - { TRACE_VALUE_TYPE_CONVERTABLE, TRACE_VALUE_TYPE_CONVERTABLE }; - scoped_ptr convertable_values[2]; - convertable_values[0].reset(arg1_val.release()); - convertable_values[1].reset(arg2_val.release()); - - TRACE_EVENT_API_ADD_TRACE_EVENT_WITH_THREAD_ID_AND_TIMESTAMP( - phase, category_group_enabled, name, id, thread_id, timestamp, - num_args, arg_names, arg_types, NULL, convertable_values, flags); -} - -static inline void AddTraceEvent( - char phase, - const unsigned char* category_group_enabled, - const char* name, - unsigned long long id, - unsigned char flags, - const char* arg1_name, - scoped_ptr arg1_val, - const char* arg2_name, - scoped_ptr arg2_val) { - int thread_id = static_cast(base::PlatformThread::CurrentId()); - base::TimeTicks now = base::TimeTicks::NowFromSystemTraceTime(); - AddTraceEventWithThreadIdAndTimestamp(phase, category_group_enabled, name, id, - thread_id, now, flags, - arg1_name, arg1_val.Pass(), - arg2_name, arg2_val.Pass()); -} - -static inline void AddTraceEventWithThreadIdAndTimestamp( - char phase, - const unsigned char* category_group_enabled, - const char* name, - unsigned long long id, - int thread_id, - const base::TimeTicks& timestamp, - unsigned char flags) { - TRACE_EVENT_API_ADD_TRACE_EVENT_WITH_THREAD_ID_AND_TIMESTAMP( - phase, category_group_enabled, name, id, thread_id, timestamp, - kZeroNumArgs, NULL, NULL, NULL, NULL, flags); -} - -static inline void AddTraceEvent(char phase, - const unsigned char* category_group_enabled, - const char* name, - unsigned long long id, - unsigned char flags) { - int thread_id = static_cast(base::PlatformThread::CurrentId()); - base::TimeTicks now = base::TimeTicks::NowFromSystemTraceTime(); - AddTraceEventWithThreadIdAndTimestamp(phase, category_group_enabled, name, id, - thread_id, now, flags); -} - -template -static inline void AddTraceEventWithThreadIdAndTimestamp( - char phase, - const unsigned char* category_group_enabled, - const char* name, - unsigned long long id, - int thread_id, - const base::TimeTicks& timestamp, - unsigned char flags, - const char* arg1_name, - const ARG1_TYPE& arg1_val) { - const int num_args = 1; - unsigned char arg_types[1]; - unsigned long long arg_values[1]; - SetTraceValue(arg1_val, &arg_types[0], &arg_values[0]); - TRACE_EVENT_API_ADD_TRACE_EVENT_WITH_THREAD_ID_AND_TIMESTAMP( - phase, category_group_enabled, name, id, thread_id, timestamp, - num_args, &arg1_name, arg_types, arg_values, NULL, flags); -} - -template -static inline void AddTraceEvent(char phase, - const unsigned char* category_group_enabled, - const char* name, - unsigned long long id, - unsigned char flags, - const char* arg1_name, - const ARG1_TYPE& arg1_val) { - int thread_id = static_cast(base::PlatformThread::CurrentId()); - base::TimeTicks now = base::TimeTicks::NowFromSystemTraceTime(); - AddTraceEventWithThreadIdAndTimestamp(phase, category_group_enabled, name, id, - thread_id, now, flags, arg1_name, - arg1_val); -} - -template -static inline void AddTraceEventWithThreadIdAndTimestamp( - char phase, - const unsigned char* category_group_enabled, - const char* name, - unsigned long long id, - int thread_id, - const base::TimeTicks& timestamp, - unsigned char flags, - const char* arg1_name, - const ARG1_TYPE& arg1_val, - const char* arg2_name, - const ARG2_TYPE& arg2_val) { - const int num_args = 2; - const char* arg_names[2] = { arg1_name, arg2_name }; - unsigned char arg_types[2]; - unsigned long long arg_values[2]; - SetTraceValue(arg1_val, &arg_types[0], &arg_values[0]); - SetTraceValue(arg2_val, &arg_types[1], &arg_values[1]); - TRACE_EVENT_API_ADD_TRACE_EVENT_WITH_THREAD_ID_AND_TIMESTAMP( - phase, category_group_enabled, name, id, thread_id, timestamp, - num_args, arg_names, arg_types, arg_values, NULL, flags); -} - -template -static inline void AddTraceEvent(char phase, - const unsigned char* category_group_enabled, - const char* name, - unsigned long long id, - unsigned char flags, - const char* arg1_name, - const ARG1_TYPE& arg1_val, - const char* arg2_name, - const ARG2_TYPE& arg2_val) { - int thread_id = static_cast(base::PlatformThread::CurrentId()); - base::TimeTicks now = base::TimeTicks::NowFromSystemTraceTime(); - AddTraceEventWithThreadIdAndTimestamp(phase, category_group_enabled, name, id, - thread_id, now, flags, arg1_name, - arg1_val, arg2_name, arg2_val); -} - -// Used by TRACE_EVENTx macro. Do not use directly. -class TRACE_EVENT_API_CLASS_EXPORT TraceEndOnScopeClose { - public: - // Note: members of data_ intentionally left uninitialized. See Initialize. - TraceEndOnScopeClose() : p_data_(NULL) {} - ~TraceEndOnScopeClose() { - if (p_data_) - AddEventIfEnabled(); - } - - void Initialize(const unsigned char* category_group_enabled, - const char* name) { - data_.category_group_enabled = category_group_enabled; - data_.name = name; - p_data_ = &data_; - } - - private: - // Add the end event if the category is still enabled. - void AddEventIfEnabled() { - // Only called when p_data_ is non-null. - if (*p_data_->category_group_enabled) { - TRACE_EVENT_API_ADD_TRACE_EVENT( - TRACE_EVENT_PHASE_END, // phase - p_data_->category_group_enabled, // category enabled - p_data_->name, // name - kNoEventId, // id - kZeroNumArgs, // num_args - NULL, // arg_names - NULL, // arg_types - NULL, // arg_values - NULL, // convertable_values - TRACE_EVENT_FLAG_NONE); // flags - } - } - - // This Data struct workaround is to avoid initializing all the members - // in Data during construction of this object, since this object is always - // constructed, even when tracing is disabled. If the members of Data were - // members of this class instead, compiler warnings occur about potential - // uninitialized accesses. - struct Data { - const unsigned char* category_group_enabled; - const char* name; - }; - Data* p_data_; - Data data_; -}; - -// Used by TRACE_EVENT_BINARY_EFFICIENTx macro. Do not use directly. -class TRACE_EVENT_API_CLASS_EXPORT ScopedTrace { - public: - ScopedTrace(TRACE_EVENT_API_ATOMIC_WORD* event_uid, const char* name); - ~ScopedTrace(); - - private: - const unsigned char* category_group_enabled_; - const char* name_; -}; - -// A support macro for TRACE_EVENT_BINARY_EFFICIENTx -#define INTERNAL_TRACE_EVENT_BINARY_EFFICIENT_ADD_SCOPED( \ - category_group, name, ...) \ - static TRACE_EVENT_API_ATOMIC_WORD INTERNAL_TRACE_EVENT_UID(atomic) = 0; \ - trace_event_internal::ScopedTrace \ - INTERNAL_TRACE_EVENT_UID(profileScope)( \ - &INTERNAL_TRACE_EVENT_UID(atomic), name); \ - -// This macro generates less code then TRACE_EVENT0 but is also -// slower to execute when tracing is off. It should generally only be -// used with code that is seldom executed or conditionally executed -// when debugging. -#define TRACE_EVENT_BINARY_EFFICIENT0(category_group, name) \ - INTERNAL_TRACE_EVENT_BINARY_EFFICIENT_ADD_SCOPED(category_group, name) - -// TraceEventSamplingStateScope records the current sampling state -// and sets a new sampling state. When the scope exists, it restores -// the sampling state having recorded. -template -class TraceEventSamplingStateScope { - public: - TraceEventSamplingStateScope(const char* category_and_name) { - previous_state_ = TraceEventSamplingStateScope::Current(); - TraceEventSamplingStateScope::Set(category_and_name); - } - - ~TraceEventSamplingStateScope() { - TraceEventSamplingStateScope::Set(previous_state_); - } - - static inline const char* Current() { - return reinterpret_cast(TRACE_EVENT_API_ATOMIC_LOAD( - g_trace_state[BucketNumber])); - } - - static inline void Set(const char* category_and_name) { - TRACE_EVENT_API_ATOMIC_STORE( - g_trace_state[BucketNumber], - reinterpret_cast( - const_cast(category_and_name))); - } - - private: - const char* previous_state_; -}; - -} // namespace trace_event_internal - -namespace base { -namespace debug { - -template class TraceScopedTrackableObject { - public: - TraceScopedTrackableObject(const char* category_group, const char* name, - IDType id) - : category_group_(category_group), - name_(name), - id_(id) { - TRACE_EVENT_OBJECT_CREATED_WITH_ID(category_group_, name_, id_); - } - - template void snapshot(ArgType snapshot) { - TRACE_EVENT_OBJECT_SNAPSHOT_WITH_ID(category_group_, name_, id_, snapshot); - } - - ~TraceScopedTrackableObject() { - TRACE_EVENT_OBJECT_DELETED_WITH_ID(category_group_, name_, id_); - } - - private: - const char* category_group_; - const char* name_; - IDType id_; - - DISALLOW_COPY_AND_ASSIGN(TraceScopedTrackableObject); -}; - -} // namespace debug -} // namespace base - -#endif /* BASE_DEBUG_TRACE_EVENT_H_ */ diff --git a/base/debug/trace_event_android.cc b/base/debug/trace_event_android.cc deleted file mode 100644 index 78d9de6674..0000000000 --- a/base/debug/trace_event_android.cc +++ /dev/null @@ -1,158 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "base/debug/trace_event_impl.h" - -#include - -#include "base/debug/trace_event.h" -#include "base/format_macros.h" -#include "base/logging.h" -#include "base/strings/stringprintf.h" - -namespace { - -int g_atrace_fd = -1; -const char* kATraceMarkerFile = "/sys/kernel/debug/tracing/trace_marker"; - -void WriteEvent( - char phase, - const char* category_group, - const char* name, - unsigned long long id, - int num_args, - const char** arg_names, - const unsigned char* arg_types, - const unsigned long long* arg_values, - scoped_ptr convertable_values[], - unsigned char flags) { - std::string out = base::StringPrintf("%c|%d|%s", phase, getpid(), name); - if (flags & TRACE_EVENT_FLAG_HAS_ID) - base::StringAppendF(&out, "-%" PRIx64, static_cast(id)); - out += '|'; - - for (int i = 0; i < num_args; ++i) { - if (i) - out += ';'; - out += arg_names[i]; - out += '='; - std::string::size_type value_start = out.length(); - if (arg_types[i] == TRACE_VALUE_TYPE_CONVERTABLE) { - convertable_values[i]->AppendAsTraceFormat(&out); - } else { - base::debug::TraceEvent::TraceValue value; - value.as_uint = arg_values[i]; - base::debug::TraceEvent::AppendValueAsJSON(arg_types[i], value, &out); - } - // Remove the quotes which may confuse the atrace script. - ReplaceSubstringsAfterOffset(&out, value_start, "\\\"", "'"); - ReplaceSubstringsAfterOffset(&out, value_start, "\"", ""); - // Replace chars used for separators with similar chars in the value. - std::replace(out.begin() + value_start, out.end(), ';', ','); - std::replace(out.begin() + value_start, out.end(), '|', '!'); - } - - out += '|'; - out += category_group; - write(g_atrace_fd, out.c_str(), out.size()); -} - -} // namespace - -namespace base { -namespace debug { - -void TraceLog::StartATrace() { - AutoLock lock(lock_); - if (g_atrace_fd == -1) { - g_atrace_fd = open(kATraceMarkerFile, O_WRONLY); - if (g_atrace_fd == -1) { - LOG(WARNING) << "Couldn't open " << kATraceMarkerFile; - } else { - UpdateCategoryGroupEnabledFlags(); - } - } -} - -void TraceLog::StopATrace() { - AutoLock lock(lock_); - if (g_atrace_fd != -1) { - close(g_atrace_fd); - g_atrace_fd = -1; - UpdateCategoryGroupEnabledFlags(); - } -} - -void TraceLog::SendToATrace( - char phase, - const char* category_group, - const char* name, - unsigned long long id, - int num_args, - const char** arg_names, - const unsigned char* arg_types, - const unsigned long long* arg_values, - scoped_ptr convertable_values[], - unsigned char flags) { - if (g_atrace_fd == -1) - return; - - switch (phase) { - case TRACE_EVENT_PHASE_BEGIN: - WriteEvent('B', category_group, name, id, - num_args, arg_names, arg_types, arg_values, convertable_values, - flags); - break; - - case TRACE_EVENT_PHASE_END: - // Though a single 'E' is enough, here append pid, name and - // category_group etc. So that unpaired events can be found easily. - WriteEvent('E', category_group, name, id, - num_args, arg_names, arg_types, arg_values, convertable_values, - flags); - break; - - case TRACE_EVENT_PHASE_INSTANT: - // Simulate an instance event with a pair of begin/end events. - WriteEvent('B', category_group, name, id, - num_args, arg_names, arg_types, arg_values, convertable_values, - flags); - write(g_atrace_fd, "E", 1); - break; - - case TRACE_EVENT_PHASE_COUNTER: - for (int i = 0; i < num_args; ++i) { - DCHECK(arg_types[i] == TRACE_VALUE_TYPE_INT); - std::string out = base::StringPrintf("C|%d|%s-%s", - getpid(), name, arg_names[i]); - if (flags & TRACE_EVENT_FLAG_HAS_ID) - StringAppendF(&out, "-%" PRIx64, static_cast(id)); - StringAppendF(&out, "|%d|%s", - static_cast(arg_values[i]), category_group); - write(g_atrace_fd, out.c_str(), out.size()); - } - break; - - default: - // Do nothing. - break; - } -} - -// Must be called with lock_ locked. -void TraceLog::ApplyATraceEnabledFlag(unsigned char* category_group_enabled) { - if (g_atrace_fd == -1) - return; - - // Don't enable disabled-by-default categories for atrace. - const char* category_group = GetCategoryGroupName(category_group_enabled); - if (strncmp(category_group, TRACE_DISABLED_BY_DEFAULT(""), - strlen(TRACE_DISABLED_BY_DEFAULT(""))) == 0) - return; - - *category_group_enabled |= ATRACE_ENABLED; -} - -} // namespace debug -} // namespace base diff --git a/base/debug/trace_event_impl.cc b/base/debug/trace_event_impl.cc deleted file mode 100644 index cc22424f15..0000000000 --- a/base/debug/trace_event_impl.cc +++ /dev/null @@ -1,1692 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "base/debug/trace_event_impl.h" - -#include - -#include "base/base_switches.h" -#include "base/bind.h" -#include "base/command_line.h" -#include "base/debug/leak_annotations.h" -#include "base/debug/trace_event.h" -#include "base/format_macros.h" -#include "base/lazy_instance.h" -#include "base/memory/singleton.h" -#include "base/process/process_metrics.h" -#include "base/stl_util.h" -#include "base/strings/string_split.h" -#include "base/strings/string_tokenizer.h" -#include "base/strings/string_util.h" -#include "base/strings/stringprintf.h" -#include "base/strings/utf_string_conversions.h" -#include "base/synchronization/cancellation_flag.h" -#include "base/synchronization/waitable_event.h" -#include "base/sys_info.h" -#include "base/third_party/dynamic_annotations/dynamic_annotations.h" -#include "base/threading/platform_thread.h" -#include "base/threading/thread_id_name_manager.h" -#include "base/threading/thread_local.h" -#include "base/time/time.h" - -#if defined(OS_WIN) -#include "base/debug/trace_event_win.h" -#endif - -class DeleteTraceLogForTesting { - public: - static void Delete() { - Singleton >::OnExit(0); - } -}; - -// The thread buckets for the sampling profiler. -BASE_EXPORT TRACE_EVENT_API_ATOMIC_WORD g_trace_state[3]; - -namespace base { -namespace debug { - -// Controls the number of trace events we will buffer in-memory -// before throwing them away. -const size_t kTraceEventBufferSize = 500000; -const size_t kTraceEventBatchSize = 1000; -const size_t kTraceEventInitialBufferSize = 1024; - -#define MAX_CATEGORY_GROUPS 100 - -namespace { - -// Parallel arrays g_category_groups and g_category_group_enabled are separate -// so that a pointer to a member of g_category_group_enabled can be easily -// converted to an index into g_category_groups. This allows macros to deal -// only with char enabled pointers from g_category_group_enabled, and we can -// convert internally to determine the category name from the char enabled -// pointer. -const char* g_category_groups[MAX_CATEGORY_GROUPS] = { - "tracing already shutdown", - "tracing categories exhausted; must increase MAX_CATEGORY_GROUPS", - "__metadata", -}; - -// The enabled flag is char instead of bool so that the API can be used from C. -unsigned char g_category_group_enabled[MAX_CATEGORY_GROUPS] = { 0 }; -const int g_category_already_shutdown = 0; -const int g_category_categories_exhausted = 1; -const int g_category_metadata = 2; -const int g_num_builtin_categories = 3; -int g_category_index = g_num_builtin_categories; // Skip default categories. - -// The name of the current thread. This is used to decide if the current -// thread name has changed. We combine all the seen thread names into the -// output name for the thread. -LazyInstance >::Leaky - g_current_thread_name = LAZY_INSTANCE_INITIALIZER; - -const char kRecordUntilFull[] = "record-until-full"; -const char kRecordContinuously[] = "record-continuously"; -const char kEnableSampling[] = "enable-sampling"; - -size_t NextIndex(size_t index) { - index++; - if (index >= kTraceEventBufferSize) - index = 0; - return index; -} - -} // namespace - -class TraceBufferRingBuffer : public TraceBuffer { - public: - TraceBufferRingBuffer() - : unused_event_index_(0), - oldest_event_index_(0) { - logged_events_.reserve(kTraceEventInitialBufferSize); - } - - virtual ~TraceBufferRingBuffer() {} - - virtual void AddEvent(const TraceEvent& event) OVERRIDE { - if (unused_event_index_ < Size()) - logged_events_[unused_event_index_] = event; - else - logged_events_.push_back(event); - - unused_event_index_ = NextIndex(unused_event_index_); - if (unused_event_index_ == oldest_event_index_) { - oldest_event_index_ = NextIndex(oldest_event_index_); - } - } - - virtual bool HasMoreEvents() const OVERRIDE { - return oldest_event_index_ != unused_event_index_; - } - - virtual const TraceEvent& NextEvent() OVERRIDE { - DCHECK(HasMoreEvents()); - - size_t next = oldest_event_index_; - oldest_event_index_ = NextIndex(oldest_event_index_); - return GetEventAt(next); - } - - virtual bool IsFull() const OVERRIDE { - return false; - } - - virtual size_t CountEnabledByName( - const unsigned char* category, - const std::string& event_name) const OVERRIDE { - size_t notify_count = 0; - size_t index = oldest_event_index_; - while (index != unused_event_index_) { - const TraceEvent& event = GetEventAt(index); - if (category == event.category_group_enabled() && - strcmp(event_name.c_str(), event.name()) == 0) { - ++notify_count; - } - index = NextIndex(index); - } - return notify_count; - } - - virtual const TraceEvent& GetEventAt(size_t index) const OVERRIDE { - DCHECK(index < logged_events_.size()); - return logged_events_[index]; - } - - virtual size_t Size() const OVERRIDE { - return logged_events_.size(); - } - - private: - size_t unused_event_index_; - size_t oldest_event_index_; - std::vector logged_events_; - - DISALLOW_COPY_AND_ASSIGN(TraceBufferRingBuffer); -}; - -class TraceBufferVector : public TraceBuffer { - public: - TraceBufferVector() : current_iteration_index_(0) { - logged_events_.reserve(kTraceEventInitialBufferSize); - } - - virtual ~TraceBufferVector() { - } - - virtual void AddEvent(const TraceEvent& event) OVERRIDE { - // Note, we have two callers which need to be handled. The first is - // AddTraceEventWithThreadIdAndTimestamp() which checks Size() and does an - // early exit if full. The second is AddThreadNameMetadataEvents(). - // We can not DECHECK(!IsFull()) because we have to add the metadata - // events even if the buffer is full. - logged_events_.push_back(event); - } - - virtual bool HasMoreEvents() const OVERRIDE { - return current_iteration_index_ < Size(); - } - - virtual const TraceEvent& NextEvent() OVERRIDE { - DCHECK(HasMoreEvents()); - return GetEventAt(current_iteration_index_++); - } - - virtual bool IsFull() const OVERRIDE { - return Size() >= kTraceEventBufferSize; - } - - virtual size_t CountEnabledByName( - const unsigned char* category, - const std::string& event_name) const OVERRIDE { - size_t notify_count = 0; - for (size_t i = 0; i < Size(); i++) { - const TraceEvent& event = GetEventAt(i); - if (category == event.category_group_enabled() && - strcmp(event_name.c_str(), event.name()) == 0) { - ++notify_count; - } - } - return notify_count; - } - - virtual const TraceEvent& GetEventAt(size_t index) const OVERRIDE { - DCHECK(index < logged_events_.size()); - return logged_events_[index]; - } - - virtual size_t Size() const OVERRIDE { - return logged_events_.size(); - } - - private: - size_t current_iteration_index_; - std::vector logged_events_; - - DISALLOW_COPY_AND_ASSIGN(TraceBufferVector); -}; - -class TraceBufferDiscardsEvents : public TraceBuffer { - public: - virtual ~TraceBufferDiscardsEvents() { } - - virtual void AddEvent(const TraceEvent& event) OVERRIDE {} - virtual bool HasMoreEvents() const OVERRIDE { return false; } - - virtual const TraceEvent& NextEvent() OVERRIDE { - NOTREACHED(); - return *static_cast(NULL); - } - - virtual bool IsFull() const OVERRIDE { return false; } - - virtual size_t CountEnabledByName( - const unsigned char* category, - const std::string& event_name) const OVERRIDE { - return 0; - } - - virtual size_t Size() const OVERRIDE { return 0; } - - virtual const TraceEvent& GetEventAt(size_t index) const OVERRIDE { - NOTREACHED(); - return *static_cast(NULL); - } -}; - -//////////////////////////////////////////////////////////////////////////////// -// -// TraceEvent -// -//////////////////////////////////////////////////////////////////////////////// - -namespace { - -size_t GetAllocLength(const char* str) { return str ? strlen(str) + 1 : 0; } - -// Copies |*member| into |*buffer|, sets |*member| to point to this new -// location, and then advances |*buffer| by the amount written. -void CopyTraceEventParameter(char** buffer, - const char** member, - const char* end) { - if (*member) { - size_t written = strlcpy(*buffer, *member, end - *buffer) + 1; - DCHECK_LE(static_cast(written), end - *buffer); - *member = *buffer; - *buffer += written; - } -} - -} // namespace - -TraceEvent::TraceEvent() - : id_(0u), - category_group_enabled_(NULL), - name_(NULL), - thread_id_(0), - phase_(TRACE_EVENT_PHASE_BEGIN), - flags_(0) { - arg_names_[0] = NULL; - arg_names_[1] = NULL; - memset(arg_values_, 0, sizeof(arg_values_)); -} - -TraceEvent::TraceEvent( - int thread_id, - TimeTicks timestamp, - char phase, - const unsigned char* category_group_enabled, - const char* name, - unsigned long long id, - int num_args, - const char** arg_names, - const unsigned char* arg_types, - const unsigned long long* arg_values, - scoped_ptr convertable_values[], - unsigned char flags) - : timestamp_(timestamp), - id_(id), - category_group_enabled_(category_group_enabled), - name_(name), - thread_id_(thread_id), - phase_(phase), - flags_(flags) { - // Clamp num_args since it may have been set by a third_party library. - num_args = (num_args > kTraceMaxNumArgs) ? kTraceMaxNumArgs : num_args; - int i = 0; - for (; i < num_args; ++i) { - arg_names_[i] = arg_names[i]; - arg_types_[i] = arg_types[i]; - - if (arg_types[i] == TRACE_VALUE_TYPE_CONVERTABLE) - convertable_values_[i].reset(convertable_values[i].release()); - else - arg_values_[i].as_uint = arg_values[i]; - } - for (; i < kTraceMaxNumArgs; ++i) { - arg_names_[i] = NULL; - arg_values_[i].as_uint = 0u; - convertable_values_[i].reset(); - arg_types_[i] = TRACE_VALUE_TYPE_UINT; - } - - bool copy = !!(flags & TRACE_EVENT_FLAG_COPY); - size_t alloc_size = 0; - if (copy) { - alloc_size += GetAllocLength(name); - for (i = 0; i < num_args; ++i) { - alloc_size += GetAllocLength(arg_names_[i]); - if (arg_types_[i] == TRACE_VALUE_TYPE_STRING) - arg_types_[i] = TRACE_VALUE_TYPE_COPY_STRING; - } - } - - bool arg_is_copy[kTraceMaxNumArgs]; - for (i = 0; i < num_args; ++i) { - // No copying of convertable types, we retain ownership. - if (arg_types_[i] == TRACE_VALUE_TYPE_CONVERTABLE) - continue; - - // We only take a copy of arg_vals if they are of type COPY_STRING. - arg_is_copy[i] = (arg_types_[i] == TRACE_VALUE_TYPE_COPY_STRING); - if (arg_is_copy[i]) - alloc_size += GetAllocLength(arg_values_[i].as_string); - } - - if (alloc_size) { - parameter_copy_storage_ = new RefCountedString; - parameter_copy_storage_->data().resize(alloc_size); - char* ptr = string_as_array(¶meter_copy_storage_->data()); - const char* end = ptr + alloc_size; - if (copy) { - CopyTraceEventParameter(&ptr, &name_, end); - for (i = 0; i < num_args; ++i) { - CopyTraceEventParameter(&ptr, &arg_names_[i], end); - } - } - for (i = 0; i < num_args; ++i) { - if (arg_types_[i] == TRACE_VALUE_TYPE_CONVERTABLE) - continue; - if (arg_is_copy[i]) - CopyTraceEventParameter(&ptr, &arg_values_[i].as_string, end); - } - DCHECK_EQ(end, ptr) << "Overrun by " << ptr - end; - } -} - -TraceEvent::TraceEvent(const TraceEvent& other) - : timestamp_(other.timestamp_), - id_(other.id_), - category_group_enabled_(other.category_group_enabled_), - name_(other.name_), - thread_id_(other.thread_id_), - phase_(other.phase_), - flags_(other.flags_) { - parameter_copy_storage_ = other.parameter_copy_storage_; - - for (int i = 0; i < kTraceMaxNumArgs; ++i) { - arg_values_[i] = other.arg_values_[i]; - arg_names_[i] = other.arg_names_[i]; - arg_types_[i] = other.arg_types_[i]; - - if (arg_types_[i] == TRACE_VALUE_TYPE_CONVERTABLE) { - convertable_values_[i].reset( - const_cast(&other)->convertable_values_[i].release()); - } else { - convertable_values_[i].reset(); - } - } -} - -TraceEvent& TraceEvent::operator=(const TraceEvent& other) { - if (this == &other) - return *this; - - timestamp_ = other.timestamp_; - id_ = other.id_; - category_group_enabled_ = other.category_group_enabled_; - name_ = other.name_; - parameter_copy_storage_ = other.parameter_copy_storage_; - thread_id_ = other.thread_id_; - phase_ = other.phase_; - flags_ = other.flags_; - - for (int i = 0; i < kTraceMaxNumArgs; ++i) { - arg_values_[i] = other.arg_values_[i]; - arg_names_[i] = other.arg_names_[i]; - arg_types_[i] = other.arg_types_[i]; - - if (arg_types_[i] == TRACE_VALUE_TYPE_CONVERTABLE) { - convertable_values_[i].reset( - const_cast(&other)->convertable_values_[i].release()); - } else { - convertable_values_[i].reset(); - } - } - return *this; -} - -TraceEvent::~TraceEvent() { -} - -// static -void TraceEvent::AppendValueAsJSON(unsigned char type, - TraceEvent::TraceValue value, - std::string* out) { - std::string::size_type start_pos; - switch (type) { - case TRACE_VALUE_TYPE_BOOL: - *out += value.as_bool ? "true" : "false"; - break; - case TRACE_VALUE_TYPE_UINT: - StringAppendF(out, "%" PRIu64, static_cast(value.as_uint)); - break; - case TRACE_VALUE_TYPE_INT: - StringAppendF(out, "%" PRId64, static_cast(value.as_int)); - break; - case TRACE_VALUE_TYPE_DOUBLE: - StringAppendF(out, "%f", value.as_double); - break; - case TRACE_VALUE_TYPE_POINTER: - // JSON only supports double and int numbers. - // So as not to lose bits from a 64-bit pointer, output as a hex string. - StringAppendF(out, "\"0x%" PRIx64 "\"", static_cast( - reinterpret_cast( - value.as_pointer))); - break; - case TRACE_VALUE_TYPE_STRING: - case TRACE_VALUE_TYPE_COPY_STRING: - *out += "\""; - start_pos = out->size(); - *out += value.as_string ? value.as_string : "NULL"; - // insert backslash before special characters for proper json format. - while ((start_pos = out->find_first_of("\\\"", start_pos)) != - std::string::npos) { - out->insert(start_pos, 1, '\\'); - // skip inserted escape character and following character. - start_pos += 2; - } - *out += "\""; - break; - default: - NOTREACHED() << "Don't know how to print this value"; - break; - } -} - -void TraceEvent::AppendAsJSON(std::string* out) const { - int64 time_int64 = timestamp_.ToInternalValue(); - int process_id = TraceLog::GetInstance()->process_id(); - // Category group checked at category creation time. - DCHECK(!strchr(name_, '"')); - StringAppendF(out, - "{\"cat\":\"%s\",\"pid\":%i,\"tid\":%i,\"ts\":%" PRId64 "," - "\"ph\":\"%c\",\"name\":\"%s\",\"args\":{", - TraceLog::GetCategoryGroupName(category_group_enabled_), - process_id, - thread_id_, - time_int64, - phase_, - name_); - - // Output argument names and values, stop at first NULL argument name. - for (int i = 0; i < kTraceMaxNumArgs && arg_names_[i]; ++i) { - if (i > 0) - *out += ","; - *out += "\""; - *out += arg_names_[i]; - *out += "\":"; - - if (arg_types_[i] == TRACE_VALUE_TYPE_CONVERTABLE) - convertable_values_[i]->AppendAsTraceFormat(out); - else - AppendValueAsJSON(arg_types_[i], arg_values_[i], out); - } - *out += "}"; - - // If id_ is set, print it out as a hex string so we don't loose any - // bits (it might be a 64-bit pointer). - if (flags_ & TRACE_EVENT_FLAG_HAS_ID) - StringAppendF(out, ",\"id\":\"0x%" PRIx64 "\"", static_cast(id_)); - - // Instant events also output their scope. - if (phase_ == TRACE_EVENT_PHASE_INSTANT) { - char scope = '?'; - switch (flags_ & TRACE_EVENT_FLAG_SCOPE_MASK) { - case TRACE_EVENT_SCOPE_GLOBAL: - scope = TRACE_EVENT_SCOPE_NAME_GLOBAL; - break; - - case TRACE_EVENT_SCOPE_PROCESS: - scope = TRACE_EVENT_SCOPE_NAME_PROCESS; - break; - - case TRACE_EVENT_SCOPE_THREAD: - scope = TRACE_EVENT_SCOPE_NAME_THREAD; - break; - } - StringAppendF(out, ",\"s\":\"%c\"", scope); - } - - *out += "}"; -} - -void TraceEvent::AppendPrettyPrinted(std::ostringstream* out) const { - *out << name_ << "["; - *out << TraceLog::GetCategoryGroupName(category_group_enabled_); - *out << "]"; - if (arg_names_[0]) { - *out << ", {"; - for (int i = 0; i < kTraceMaxNumArgs && arg_names_[i]; ++i) { - if (i > 0) - *out << ", "; - *out << arg_names_[i] << ":"; - std::string value_as_text; - - if (arg_types_[i] == TRACE_VALUE_TYPE_CONVERTABLE) - convertable_values_[i]->AppendAsTraceFormat(&value_as_text); - else - AppendValueAsJSON(arg_types_[i], arg_values_[i], &value_as_text); - - *out << value_as_text; - } - *out << "}"; - } -} - -//////////////////////////////////////////////////////////////////////////////// -// -// TraceResultBuffer -// -//////////////////////////////////////////////////////////////////////////////// - -TraceResultBuffer::OutputCallback - TraceResultBuffer::SimpleOutput::GetCallback() { - return Bind(&SimpleOutput::Append, Unretained(this)); -} - -void TraceResultBuffer::SimpleOutput::Append( - const std::string& json_trace_output) { - json_output += json_trace_output; -} - -TraceResultBuffer::TraceResultBuffer() : append_comma_(false) { -} - -TraceResultBuffer::~TraceResultBuffer() { -} - -void TraceResultBuffer::SetOutputCallback( - const OutputCallback& json_chunk_callback) { - output_callback_ = json_chunk_callback; -} - -void TraceResultBuffer::Start() { - append_comma_ = false; - output_callback_.Run("["); -} - -void TraceResultBuffer::AddFragment(const std::string& trace_fragment) { - if (append_comma_) - output_callback_.Run(","); - append_comma_ = true; - output_callback_.Run(trace_fragment); -} - -void TraceResultBuffer::Finish() { - output_callback_.Run("]"); -} - -//////////////////////////////////////////////////////////////////////////////// -// -// TraceSamplingThread -// -//////////////////////////////////////////////////////////////////////////////// -class TraceBucketData; -typedef base::Callback TraceSampleCallback; - -class TraceBucketData { - public: - TraceBucketData(base::subtle::AtomicWord* bucket, - const char* name, - TraceSampleCallback callback); - ~TraceBucketData(); - - TRACE_EVENT_API_ATOMIC_WORD* bucket; - const char* bucket_name; - TraceSampleCallback callback; -}; - -// This object must be created on the IO thread. -class TraceSamplingThread : public PlatformThread::Delegate { - public: - TraceSamplingThread(); - virtual ~TraceSamplingThread(); - - // Implementation of PlatformThread::Delegate: - virtual void ThreadMain() OVERRIDE; - - static void DefaultSampleCallback(TraceBucketData* bucekt_data); - - void Stop(); - void InstallWaitableEventForSamplingTesting(WaitableEvent* waitable_event); - - private: - friend class TraceLog; - - void GetSamples(); - // Not thread-safe. Once the ThreadMain has been called, this can no longer - // be called. - void RegisterSampleBucket(TRACE_EVENT_API_ATOMIC_WORD* bucket, - const char* const name, - TraceSampleCallback callback); - // Splits a combined "category\0name" into the two component parts. - static void ExtractCategoryAndName(const char* combined, - const char** category, - const char** name); - std::vector sample_buckets_; - bool thread_running_; - scoped_ptr cancellation_flag_; - scoped_ptr waitable_event_for_testing_; -}; - - -TraceSamplingThread::TraceSamplingThread() - : thread_running_(false) { - cancellation_flag_.reset(new CancellationFlag); -} - -TraceSamplingThread::~TraceSamplingThread() { -} - -void TraceSamplingThread::ThreadMain() { - PlatformThread::SetName("Sampling Thread"); - thread_running_ = true; - const int kSamplingFrequencyMicroseconds = 1000; - while (!cancellation_flag_->IsSet()) { - PlatformThread::Sleep( - TimeDelta::FromMicroseconds(kSamplingFrequencyMicroseconds)); - GetSamples(); - if (waitable_event_for_testing_.get()) - waitable_event_for_testing_->Signal(); - } -} - -// static -void TraceSamplingThread::DefaultSampleCallback(TraceBucketData* bucket_data) { - TRACE_EVENT_API_ATOMIC_WORD category_and_name = - TRACE_EVENT_API_ATOMIC_LOAD(*bucket_data->bucket); - if (!category_and_name) - return; - const char* const combined = - reinterpret_cast(category_and_name); - const char* category_group; - const char* name; - ExtractCategoryAndName(combined, &category_group, &name); - TRACE_EVENT_API_ADD_TRACE_EVENT(TRACE_EVENT_PHASE_SAMPLE, - TraceLog::GetCategoryGroupEnabled(category_group), - name, 0, 0, NULL, NULL, NULL, NULL, 0); -} - -void TraceSamplingThread::GetSamples() { - for (size_t i = 0; i < sample_buckets_.size(); ++i) { - TraceBucketData* bucket_data = &sample_buckets_[i]; - bucket_data->callback.Run(bucket_data); - } -} - -void TraceSamplingThread::RegisterSampleBucket( - TRACE_EVENT_API_ATOMIC_WORD* bucket, - const char* const name, - TraceSampleCallback callback) { - DCHECK(!thread_running_); - sample_buckets_.push_back(TraceBucketData(bucket, name, callback)); -} - -// static -void TraceSamplingThread::ExtractCategoryAndName(const char* combined, - const char** category, - const char** name) { - *category = combined; - *name = &combined[strlen(combined) + 1]; -} - -void TraceSamplingThread::Stop() { - cancellation_flag_->Set(); -} - -void TraceSamplingThread::InstallWaitableEventForSamplingTesting( - WaitableEvent* waitable_event) { - waitable_event_for_testing_.reset(waitable_event); -} - - -TraceBucketData::TraceBucketData(base::subtle::AtomicWord* bucket, - const char* name, - TraceSampleCallback callback) - : bucket(bucket), - bucket_name(name), - callback(callback) { -} - -TraceBucketData::~TraceBucketData() { -} - -//////////////////////////////////////////////////////////////////////////////// -// -// TraceLog -// -//////////////////////////////////////////////////////////////////////////////// - -TraceLog::NotificationHelper::NotificationHelper(TraceLog* trace_log) - : trace_log_(trace_log), - notification_(0) { -} - -TraceLog::NotificationHelper::~NotificationHelper() { -} - -void TraceLog::NotificationHelper::AddNotificationWhileLocked( - int notification) { - if (trace_log_->notification_callback_.is_null()) - return; - if (notification_ == 0) - callback_copy_ = trace_log_->notification_callback_; - notification_ |= notification; -} - -void TraceLog::NotificationHelper::SendNotificationIfAny() { - if (notification_) - callback_copy_.Run(notification_); -} - -// static -TraceLog* TraceLog::GetInstance() { - return Singleton >::get(); -} - -// static -// Note, if you add more options here you also need to update: -// content/browser/devtools/devtools_tracing_handler:TraceOptionsFromString -TraceLog::Options TraceLog::TraceOptionsFromString(const std::string& options) { - std::vector split; - base::SplitString(options, ',', &split); - int ret = 0; - for (std::vector::iterator iter = split.begin(); - iter != split.end(); - ++iter) { - if (*iter == kRecordUntilFull) { - ret |= RECORD_UNTIL_FULL; - } else if (*iter == kRecordContinuously) { - ret |= RECORD_CONTINUOUSLY; - } else if (*iter == kEnableSampling) { - ret |= ENABLE_SAMPLING; - } else { - NOTREACHED(); // Unknown option provided. - } - } - if (!(ret & RECORD_UNTIL_FULL) && !(ret & RECORD_CONTINUOUSLY)) - ret |= RECORD_UNTIL_FULL; // Default when no options are specified. - - return static_cast(ret); -} - -TraceLog::TraceLog() - : enable_count_(0), - num_traces_recorded_(0), - event_callback_(NULL), - dispatching_to_observer_list_(false), - process_sort_index_(0), - watch_category_(NULL), - trace_options_(RECORD_UNTIL_FULL), - sampling_thread_handle_(0), - category_filter_(CategoryFilter::kDefaultCategoryFilterString) { - // Trace is enabled or disabled on one thread while other threads are - // accessing the enabled flag. We don't care whether edge-case events are - // traced or not, so we allow races on the enabled flag to keep the trace - // macros fast. - // TODO(jbates): ANNOTATE_BENIGN_RACE_SIZED crashes windows TSAN bots: - // ANNOTATE_BENIGN_RACE_SIZED(g_category_group_enabled, - // sizeof(g_category_group_enabled), - // "trace_event category enabled"); - for (int i = 0; i < MAX_CATEGORY_GROUPS; ++i) { - ANNOTATE_BENIGN_RACE(&g_category_group_enabled[i], - "trace_event category enabled"); - } -#if defined(OS_NACL) // NaCl shouldn't expose the process id. - SetProcessID(0); -#else - SetProcessID(static_cast(GetCurrentProcId())); - - // NaCl also shouldn't access the command line. - if (CommandLine::InitializedForCurrentProcess() && - CommandLine::ForCurrentProcess()->HasSwitch(switches::kTraceToConsole)) { - std::string category_string = - CommandLine::ForCurrentProcess()->GetSwitchValueASCII( - switches::kTraceToConsole); - - if (category_string.empty()) - category_string = "*"; - - SetEnabled(CategoryFilter(category_string), ECHO_TO_CONSOLE); - } -#endif - - logged_events_.reset(GetTraceBuffer()); -} - -TraceLog::~TraceLog() { -} - -const unsigned char* TraceLog::GetCategoryGroupEnabled( - const char* category_group) { - TraceLog* tracelog = GetInstance(); - if (!tracelog) { - DCHECK(!g_category_group_enabled[g_category_already_shutdown]); - return &g_category_group_enabled[g_category_already_shutdown]; - } - return tracelog->GetCategoryGroupEnabledInternal(category_group); -} - -const char* TraceLog::GetCategoryGroupName( - const unsigned char* category_group_enabled) { - // Calculate the index of the category group by finding - // category_group_enabled in g_category_group_enabled array. - uintptr_t category_begin = - reinterpret_cast(g_category_group_enabled); - uintptr_t category_ptr = reinterpret_cast(category_group_enabled); - DCHECK(category_ptr >= category_begin && - category_ptr < reinterpret_cast( - g_category_group_enabled + MAX_CATEGORY_GROUPS)) << - "out of bounds category pointer"; - uintptr_t category_index = - (category_ptr - category_begin) / sizeof(g_category_group_enabled[0]); - return g_category_groups[category_index]; -} - -void TraceLog::UpdateCategoryGroupEnabledFlag(int category_index) { - bool is_enabled = enable_count_ && category_filter_.IsCategoryGroupEnabled( - g_category_groups[category_index]); - SetCategoryGroupEnabled(category_index, is_enabled); -} - -void TraceLog::UpdateCategoryGroupEnabledFlags() { - for (int i = 0; i < g_category_index; i++) - UpdateCategoryGroupEnabledFlag(i); -} - -void TraceLog::SetCategoryGroupEnabled(int category_index, bool is_enabled) { - g_category_group_enabled[category_index] = - is_enabled ? CATEGORY_GROUP_ENABLED : 0; - -#if defined(OS_ANDROID) - ApplyATraceEnabledFlag(&g_category_group_enabled[category_index]); -#endif -} - -bool TraceLog::IsCategoryGroupEnabled( - const unsigned char* category_group_enabled) { - // On Android, ATrace and normal trace can be enabled independently. - // This function checks if the normal trace is enabled. - return *category_group_enabled & CATEGORY_GROUP_ENABLED; -} - -const unsigned char* TraceLog::GetCategoryGroupEnabledInternal( - const char* category_group) { - DCHECK(!strchr(category_group, '"')) << - "Category groups may not contain double quote"; - AutoLock lock(lock_); - - unsigned char* category_group_enabled = NULL; - // Search for pre-existing category group. - for (int i = 0; i < g_category_index; i++) { - if (strcmp(g_category_groups[i], category_group) == 0) { - category_group_enabled = &g_category_group_enabled[i]; - break; - } - } - - if (!category_group_enabled) { - // Create a new category group - DCHECK(g_category_index < MAX_CATEGORY_GROUPS) << - "must increase MAX_CATEGORY_GROUPS"; - if (g_category_index < MAX_CATEGORY_GROUPS) { - int new_index = g_category_index++; - // Don't hold on to the category_group pointer, so that we can create - // category groups with strings not known at compile time (this is - // required by SetWatchEvent). - const char* new_group = strdup(category_group); - ANNOTATE_LEAKING_OBJECT_PTR(new_group); - g_category_groups[new_index] = new_group; - DCHECK(!g_category_group_enabled[new_index]); - // Note that if both included and excluded patterns in the - // CategoryFilter are empty, we exclude nothing, - // thereby enabling this category group. - UpdateCategoryGroupEnabledFlag(new_index); - category_group_enabled = &g_category_group_enabled[new_index]; - } else { - category_group_enabled = - &g_category_group_enabled[g_category_categories_exhausted]; - } - } - return category_group_enabled; -} - -void TraceLog::GetKnownCategoryGroups( - std::vector* category_groups) { - AutoLock lock(lock_); - for (int i = g_num_builtin_categories; i < g_category_index; i++) - category_groups->push_back(g_category_groups[i]); -} - -void TraceLog::SetEnabled(const CategoryFilter& category_filter, - Options options) { - std::vector observer_list; - { - AutoLock lock(lock_); - - if (enable_count_++ > 0) { - if (options != trace_options_) { - DLOG(ERROR) << "Attemting to re-enable tracing with a different " - << "set of options."; - } - - category_filter_.Merge(category_filter); - UpdateCategoryGroupEnabledFlags(); - return; - } - - if (options != trace_options_) { - trace_options_ = options; - logged_events_.reset(GetTraceBuffer()); - } - - if (dispatching_to_observer_list_) { - DLOG(ERROR) << - "Cannot manipulate TraceLog::Enabled state from an observer."; - return; - } - - num_traces_recorded_++; - - category_filter_ = CategoryFilter(category_filter); - UpdateCategoryGroupEnabledFlags(); - - if (options & ENABLE_SAMPLING) { - sampling_thread_.reset(new TraceSamplingThread); - sampling_thread_->RegisterSampleBucket( - &g_trace_state[0], - "bucket0", - Bind(&TraceSamplingThread::DefaultSampleCallback)); - sampling_thread_->RegisterSampleBucket( - &g_trace_state[1], - "bucket1", - Bind(&TraceSamplingThread::DefaultSampleCallback)); - sampling_thread_->RegisterSampleBucket( - &g_trace_state[2], - "bucket2", - Bind(&TraceSamplingThread::DefaultSampleCallback)); - if (!PlatformThread::Create( - 0, sampling_thread_.get(), &sampling_thread_handle_)) { - DCHECK(false) << "failed to create thread"; - } - } - - dispatching_to_observer_list_ = true; - observer_list = enabled_state_observer_list_; - } - // Notify observers outside the lock in case they trigger trace events. - for (size_t i = 0; i < observer_list.size(); ++i) - observer_list[i]->OnTraceLogEnabled(); - - { - AutoLock lock(lock_); - dispatching_to_observer_list_ = false; - } -} - -const CategoryFilter& TraceLog::GetCurrentCategoryFilter() { - AutoLock lock(lock_); - DCHECK(enable_count_ > 0); - return category_filter_; -} - -void TraceLog::SetDisabled() { - std::vector observer_list; - { - AutoLock lock(lock_); - DCHECK(enable_count_ > 0); - if (--enable_count_ != 0) - return; - - if (dispatching_to_observer_list_) { - DLOG(ERROR) - << "Cannot manipulate TraceLog::Enabled state from an observer."; - return; - } - - if (sampling_thread_.get()) { - // Stop the sampling thread. - sampling_thread_->Stop(); - lock_.Release(); - PlatformThread::Join(sampling_thread_handle_); - lock_.Acquire(); - sampling_thread_handle_ = PlatformThreadHandle(); - sampling_thread_.reset(); - } - - category_filter_.Clear(); - watch_category_ = NULL; - watch_event_name_ = ""; - UpdateCategoryGroupEnabledFlags(); - AddMetadataEvents(); - - dispatching_to_observer_list_ = true; - observer_list = enabled_state_observer_list_; - } - - // Dispatch to observers outside the lock in case the observer triggers a - // trace event. - for (size_t i = 0; i < observer_list.size(); ++i) - observer_list[i]->OnTraceLogDisabled(); - - { - AutoLock lock(lock_); - dispatching_to_observer_list_ = false; - } -} - -int TraceLog::GetNumTracesRecorded() { - AutoLock lock(lock_); - if (enable_count_ == 0) - return -1; - return num_traces_recorded_; -} - -void TraceLog::AddEnabledStateObserver(EnabledStateObserver* listener) { - enabled_state_observer_list_.push_back(listener); -} - -void TraceLog::RemoveEnabledStateObserver(EnabledStateObserver* listener) { - std::vector::iterator it = - std::find(enabled_state_observer_list_.begin(), - enabled_state_observer_list_.end(), - listener); - if (it != enabled_state_observer_list_.end()) - enabled_state_observer_list_.erase(it); -} - -bool TraceLog::HasEnabledStateObserver(EnabledStateObserver* listener) const { - std::vector::const_iterator it = - std::find(enabled_state_observer_list_.begin(), - enabled_state_observer_list_.end(), - listener); - return it != enabled_state_observer_list_.end(); -} - -float TraceLog::GetBufferPercentFull() const { - return (float)((double)logged_events_->Size()/(double)kTraceEventBufferSize); -} - -void TraceLog::SetNotificationCallback( - const TraceLog::NotificationCallback& cb) { - AutoLock lock(lock_); - notification_callback_ = cb; -} - -TraceBuffer* TraceLog::GetTraceBuffer() { - if (trace_options_ & RECORD_CONTINUOUSLY) - return new TraceBufferRingBuffer(); - else if (trace_options_ & ECHO_TO_CONSOLE) - return new TraceBufferDiscardsEvents(); - return new TraceBufferVector(); -} - -void TraceLog::SetEventCallback(EventCallback cb) { - AutoLock lock(lock_); - event_callback_ = cb; -}; - -void TraceLog::Flush(const TraceLog::OutputCallback& cb) { - // Ignore memory allocations from here down. - INTERNAL_TRACE_MEMORY(TRACE_DISABLED_BY_DEFAULT("memory"), - TRACE_MEMORY_IGNORE); - scoped_ptr previous_logged_events; - { - AutoLock lock(lock_); - previous_logged_events.swap(logged_events_); - logged_events_.reset(GetTraceBuffer()); - } // release lock - - while (previous_logged_events->HasMoreEvents()) { - scoped_refptr json_events_str_ptr = - new RefCountedString(); - - for (size_t i = 0; i < kTraceEventBatchSize; ++i) { - if (i > 0) - *(&(json_events_str_ptr->data())) += ","; - - previous_logged_events->NextEvent().AppendAsJSON( - &(json_events_str_ptr->data())); - - if (!previous_logged_events->HasMoreEvents()) - break; - } - - cb.Run(json_events_str_ptr); - } -} - -void TraceLog::AddTraceEvent( - char phase, - const unsigned char* category_group_enabled, - const char* name, - unsigned long long id, - int num_args, - const char** arg_names, - const unsigned char* arg_types, - const unsigned long long* arg_values, - scoped_ptr convertable_values[], - unsigned char flags) { - int thread_id = static_cast(base::PlatformThread::CurrentId()); - base::TimeTicks now = base::TimeTicks::NowFromSystemTraceTime(); - AddTraceEventWithThreadIdAndTimestamp(phase, category_group_enabled, name, id, - thread_id, now, num_args, arg_names, - arg_types, arg_values, - convertable_values, flags); -} - -void TraceLog::AddTraceEventWithThreadIdAndTimestamp( - char phase, - const unsigned char* category_group_enabled, - const char* name, - unsigned long long id, - int thread_id, - const TimeTicks& timestamp, - int num_args, - const char** arg_names, - const unsigned char* arg_types, - const unsigned long long* arg_values, - scoped_ptr convertable_values[], - unsigned char flags) { - DCHECK(name); - - if (flags & TRACE_EVENT_FLAG_MANGLE_ID) - id ^= process_id_hash_; - -#if defined(OS_ANDROID) - SendToATrace(phase, GetCategoryGroupName(category_group_enabled), name, id, - num_args, arg_names, arg_types, arg_values, convertable_values, - flags); -#endif - - if (!IsCategoryGroupEnabled(category_group_enabled)) - return; - - TimeTicks now = timestamp - time_offset_; - EventCallback event_callback_copy; - - NotificationHelper notifier(this); - - // Check and update the current thread name only if the event is for the - // current thread to avoid locks in most cases. - if (thread_id == static_cast(PlatformThread::CurrentId())) { - const char* new_name = ThreadIdNameManager::GetInstance()-> - GetName(thread_id); - // Check if the thread name has been set or changed since the previous - // call (if any), but don't bother if the new name is empty. Note this will - // not detect a thread name change within the same char* buffer address: we - // favor common case performance over corner case correctness. - if (new_name != g_current_thread_name.Get().Get() && - new_name && *new_name) { - g_current_thread_name.Get().Set(new_name); - - AutoLock lock(lock_); - hash_map::iterator existing_name = - thread_names_.find(thread_id); - if (existing_name == thread_names_.end()) { - // This is a new thread id, and a new name. - thread_names_[thread_id] = new_name; - } else { - // This is a thread id that we've seen before, but potentially with a - // new name. - std::vector existing_names; - Tokenize(existing_name->second, ",", &existing_names); - bool found = std::find(existing_names.begin(), - existing_names.end(), - new_name) != existing_names.end(); - if (!found) { - existing_name->second.push_back(','); - existing_name->second.append(new_name); - } - } - } - } - - TraceEvent trace_event(thread_id, - now, phase, category_group_enabled, name, id, - num_args, arg_names, arg_types, arg_values, - convertable_values, flags); - - do { - AutoLock lock(lock_); - - event_callback_copy = event_callback_; - if (logged_events_->IsFull()) - break; - - logged_events_->AddEvent(trace_event); - - if (trace_options_ & ECHO_TO_CONSOLE) { - TimeDelta duration; - if (phase == TRACE_EVENT_PHASE_END) { - duration = timestamp - thread_event_start_times_[thread_id].top(); - thread_event_start_times_[thread_id].pop(); - } - - std::string thread_name = thread_names_[thread_id]; - if (thread_colors_.find(thread_name) == thread_colors_.end()) - thread_colors_[thread_name] = (thread_colors_.size() % 6) + 1; - - std::ostringstream log; - log << base::StringPrintf("%s: \x1b[0;3%dm", - thread_name.c_str(), - thread_colors_[thread_name]); - - size_t depth = 0; - if (thread_event_start_times_.find(thread_id) != - thread_event_start_times_.end()) - depth = thread_event_start_times_[thread_id].size(); - - for (size_t i = 0; i < depth; ++i) - log << "| "; - - trace_event.AppendPrettyPrinted(&log); - if (phase == TRACE_EVENT_PHASE_END) - log << base::StringPrintf(" (%.3f ms)", duration.InMillisecondsF()); - - LOG(ERROR) << log.str() << "\x1b[0;m"; - - if (phase == TRACE_EVENT_PHASE_BEGIN) - thread_event_start_times_[thread_id].push(timestamp); - } - - if (logged_events_->IsFull()) - notifier.AddNotificationWhileLocked(TRACE_BUFFER_FULL); - - if (watch_category_ == category_group_enabled && watch_event_name_ == name) - notifier.AddNotificationWhileLocked(EVENT_WATCH_NOTIFICATION); - } while (0); // release lock - - notifier.SendNotificationIfAny(); - if (event_callback_copy != NULL) { - event_callback_copy(phase, category_group_enabled, name, id, - num_args, arg_names, arg_types, arg_values, - flags); - } -} - -void TraceLog::AddTraceEventEtw(char phase, - const char* name, - const void* id, - const char* extra) { -#if defined(OS_WIN) - TraceEventETWProvider::Trace(name, phase, id, extra); -#endif - INTERNAL_TRACE_EVENT_ADD(phase, "ETW Trace Event", name, - TRACE_EVENT_FLAG_COPY, "id", id, "extra", extra); -} - -void TraceLog::AddTraceEventEtw(char phase, - const char* name, - const void* id, - const std::string& extra) -{ -#if defined(OS_WIN) - TraceEventETWProvider::Trace(name, phase, id, extra); -#endif - INTERNAL_TRACE_EVENT_ADD(phase, "ETW Trace Event", name, - TRACE_EVENT_FLAG_COPY, "id", id, "extra", extra); -} - -void TraceLog::SetWatchEvent(const std::string& category_name, - const std::string& event_name) { - const unsigned char* category = GetCategoryGroupEnabled( - category_name.c_str()); - size_t notify_count = 0; - { - AutoLock lock(lock_); - watch_category_ = category; - watch_event_name_ = event_name; - - // First, search existing events for watch event because we want to catch - // it even if it has already occurred. - notify_count = logged_events_->CountEnabledByName(category, event_name); - } // release lock - - // Send notification for each event found. - for (size_t i = 0; i < notify_count; ++i) { - NotificationHelper notifier(this); - lock_.Acquire(); - notifier.AddNotificationWhileLocked(EVENT_WATCH_NOTIFICATION); - lock_.Release(); - notifier.SendNotificationIfAny(); - } -} - -void TraceLog::CancelWatchEvent() { - AutoLock lock(lock_); - watch_category_ = NULL; - watch_event_name_ = ""; -} - -namespace { - -template -void AddMetadataEventToBuffer( - TraceBuffer* logged_events, - int thread_id, - const char* metadata_name, const char* arg_name, - const T& value) { - int num_args = 1; - unsigned char arg_type; - unsigned long long arg_value; - trace_event_internal::SetTraceValue(value, &arg_type, &arg_value); - logged_events->AddEvent(TraceEvent( - thread_id, - TimeTicks(), TRACE_EVENT_PHASE_METADATA, - &g_category_group_enabled[g_category_metadata], - metadata_name, trace_event_internal::kNoEventId, - num_args, &arg_name, &arg_type, &arg_value, NULL, - TRACE_EVENT_FLAG_NONE)); -} - -} - -void TraceLog::AddMetadataEvents() { - lock_.AssertAcquired(); - - int current_thread_id = static_cast(base::PlatformThread::CurrentId()); - if (process_sort_index_ != 0) { - AddMetadataEventToBuffer(logged_events_.get(), - current_thread_id, - "process_sort_index", "sort_index", - process_sort_index_); - } - - if (process_name_.size()) { - AddMetadataEventToBuffer(logged_events_.get(), - current_thread_id, - "process_name", "name", - process_name_); - } - - if (process_labels_.size() > 0) { - std::vector labels; - for(base::hash_map::iterator it = process_labels_.begin(); - it != process_labels_.end(); - it++) { - labels.push_back(it->second); - } - AddMetadataEventToBuffer(logged_events_.get(), - current_thread_id, - "process_labels", "labels", - JoinString(labels, ',')); - } - - // Thread sort indices. - for(hash_map::iterator it = thread_sort_indices_.begin(); - it != thread_sort_indices_.end(); - it++) { - if (it->second == 0) - continue; - AddMetadataEventToBuffer(logged_events_.get(), - it->first, - "thread_sort_index", "sort_index", - it->second); - } - - // Thread names. - for(hash_map::iterator it = thread_names_.begin(); - it != thread_names_.end(); - it++) { - if (it->second.empty()) - continue; - AddMetadataEventToBuffer(logged_events_.get(), - it->first, - "thread_name", "name", - it->second); - } -} - -void TraceLog::InstallWaitableEventForSamplingTesting( - WaitableEvent* waitable_event) { - sampling_thread_->InstallWaitableEventForSamplingTesting(waitable_event); -} - -void TraceLog::DeleteForTesting() { - DeleteTraceLogForTesting::Delete(); -} - -void TraceLog::SetProcessID(int process_id) { - process_id_ = process_id; - // Create a FNV hash from the process ID for XORing. - // See http://isthe.com/chongo/tech/comp/fnv/ for algorithm details. - unsigned long long offset_basis = 14695981039346656037ull; - unsigned long long fnv_prime = 1099511628211ull; - unsigned long long pid = static_cast(process_id_); - process_id_hash_ = (offset_basis ^ pid) * fnv_prime; -} - -void TraceLog::SetProcessSortIndex(int sort_index) { - AutoLock lock(lock_); - process_sort_index_ = sort_index; -} - -void TraceLog::SetProcessName(const std::string& process_name) { - AutoLock lock(lock_); - process_name_ = process_name; -} - -void TraceLog::UpdateProcessLabel( - int label_id, const std::string& current_label) { - if(!current_label.length()) - return RemoveProcessLabel(label_id); - - AutoLock lock(lock_); - process_labels_[label_id] = current_label; -} - -void TraceLog::RemoveProcessLabel(int label_id) { - AutoLock lock(lock_); - base::hash_map::iterator it = process_labels_.find( - label_id); - if (it == process_labels_.end()) - return; - - process_labels_.erase(it); -} - -void TraceLog::SetThreadSortIndex(PlatformThreadId thread_id, int sort_index) { - AutoLock lock(lock_); - thread_sort_indices_[static_cast(thread_id)] = sort_index; -} - -void TraceLog::SetTimeOffset(TimeDelta offset) { - time_offset_ = offset; -} - -size_t TraceLog::GetObserverCountForTest() const { - return enabled_state_observer_list_.size(); -} - -bool CategoryFilter::IsEmptyOrContainsLeadingOrTrailingWhitespace( - const std::string& str) { - return str.empty() || - str.at(0) == ' ' || - str.at(str.length() - 1) == ' '; -} - -bool CategoryFilter::DoesCategoryGroupContainCategory( - const char* category_group, - const char* category) const { - DCHECK(category); - CStringTokenizer category_group_tokens(category_group, - category_group + strlen(category_group), ","); - while (category_group_tokens.GetNext()) { - std::string category_group_token = category_group_tokens.token(); - // Don't allow empty tokens, nor tokens with leading or trailing space. - DCHECK(!CategoryFilter::IsEmptyOrContainsLeadingOrTrailingWhitespace( - category_group_token)) - << "Disallowed category string"; - if (MatchPattern(category_group_token.c_str(), category)) - return true; - } - return false; -} - -CategoryFilter::CategoryFilter(const std::string& filter_string) { - if (!filter_string.empty()) - Initialize(filter_string); - else - Initialize(CategoryFilter::kDefaultCategoryFilterString); -} - -CategoryFilter::CategoryFilter(const CategoryFilter& cf) - : included_(cf.included_), - disabled_(cf.disabled_), - excluded_(cf.excluded_) { -} - -CategoryFilter::~CategoryFilter() { -} - -CategoryFilter& CategoryFilter::operator=(const CategoryFilter& rhs) { - if (this == &rhs) - return *this; - - included_ = rhs.included_; - disabled_ = rhs.disabled_; - excluded_ = rhs.excluded_; - return *this; -} - -void CategoryFilter::Initialize(const std::string& filter_string) { - // Tokenize list of categories, delimited by ','. - StringTokenizer tokens(filter_string, ","); - // Add each token to the appropriate list (included_,excluded_). - while (tokens.GetNext()) { - std::string category = tokens.token(); - // Ignore empty categories. - if (category.empty()) - continue; - // Excluded categories start with '-'. - if (category.at(0) == '-') { - // Remove '-' from category string. - category = category.substr(1); - excluded_.push_back(category); - } else if (category.compare(0, strlen(TRACE_DISABLED_BY_DEFAULT("")), - TRACE_DISABLED_BY_DEFAULT("")) == 0) { - disabled_.push_back(category); - } else { - included_.push_back(category); - } - } -} - -void CategoryFilter::WriteString(const StringList& values, - std::string* out, - bool included) const { - bool prepend_comma = !out->empty(); - int token_cnt = 0; - for (StringList::const_iterator ci = values.begin(); - ci != values.end(); ++ci) { - if (token_cnt > 0 || prepend_comma) - StringAppendF(out, ","); - StringAppendF(out, "%s%s", (included ? "" : "-"), ci->c_str()); - ++token_cnt; - } -} - -std::string CategoryFilter::ToString() const { - std::string filter_string; - WriteString(included_, &filter_string, true); - WriteString(disabled_, &filter_string, true); - WriteString(excluded_, &filter_string, false); - return filter_string; -} - -bool CategoryFilter::IsCategoryGroupEnabled( - const char* category_group_name) const { - // TraceLog should call this method only as part of enabling/disabling - // categories. - StringList::const_iterator ci; - - // Check the disabled- filters and the disabled-* wildcard first so that a - // "*" filter does not include the disabled. - for (ci = disabled_.begin(); ci != disabled_.end(); ++ci) { - if (DoesCategoryGroupContainCategory(category_group_name, ci->c_str())) - return true; - } - if (DoesCategoryGroupContainCategory(category_group_name, - TRACE_DISABLED_BY_DEFAULT("*"))) - return false; - - for (ci = included_.begin(); ci != included_.end(); ++ci) { - if (DoesCategoryGroupContainCategory(category_group_name, ci->c_str())) - return true; - } - - for (ci = excluded_.begin(); ci != excluded_.end(); ++ci) { - if (DoesCategoryGroupContainCategory(category_group_name, ci->c_str())) - return false; - } - // If the category group is not excluded, and there are no included patterns - // we consider this pattern enabled. - return included_.empty(); -} - -bool CategoryFilter::HasIncludedPatterns() const { - return !included_.empty(); -} - -void CategoryFilter::Merge(const CategoryFilter& nested_filter) { - // Keep included patterns only if both filters have an included entry. - // Otherwise, one of the filter was specifying "*" and we want to honour the - // broadest filter. - if (HasIncludedPatterns() && nested_filter.HasIncludedPatterns()) { - included_.insert(included_.end(), - nested_filter.included_.begin(), - nested_filter.included_.end()); - } else { - included_.clear(); - } - - disabled_.insert(disabled_.end(), - nested_filter.disabled_.begin(), - nested_filter.disabled_.end()); - excluded_.insert(excluded_.end(), - nested_filter.excluded_.begin(), - nested_filter.excluded_.end()); -} - -void CategoryFilter::Clear() { - included_.clear(); - disabled_.clear(); - excluded_.clear(); -} - -} // namespace debug -} // namespace base - -namespace trace_event_internal { - -ScopedTrace::ScopedTrace( - TRACE_EVENT_API_ATOMIC_WORD* event_uid, const char* name) { - category_group_enabled_ = - reinterpret_cast(TRACE_EVENT_API_ATOMIC_LOAD( - *event_uid)); - if (!category_group_enabled_) { - category_group_enabled_ = TRACE_EVENT_API_GET_CATEGORY_GROUP_ENABLED("gpu"); - TRACE_EVENT_API_ATOMIC_STORE( - *event_uid, - reinterpret_cast(category_group_enabled_)); - } - if (*category_group_enabled_) { - name_ = name; - TRACE_EVENT_API_ADD_TRACE_EVENT( - TRACE_EVENT_PHASE_BEGIN, // phase - category_group_enabled_, // category enabled - name, // name - 0, // id - 0, // num_args - NULL, // arg_names - NULL, // arg_types - NULL, // arg_values - NULL, // convertable_values - TRACE_EVENT_FLAG_NONE); // flags - } else { - category_group_enabled_ = NULL; - } -} - -ScopedTrace::~ScopedTrace() { - if (category_group_enabled_ && *category_group_enabled_) { - TRACE_EVENT_API_ADD_TRACE_EVENT( - TRACE_EVENT_PHASE_END, // phase - category_group_enabled_, // category enabled - name_, // name - 0, // id - 0, // num_args - NULL, // arg_names - NULL, // arg_types - NULL, // arg_values - NULL, // convertable values - TRACE_EVENT_FLAG_NONE); // flags - } -} - -} // namespace trace_event_internal diff --git a/base/debug/trace_event_impl.h b/base/debug/trace_event_impl.h deleted file mode 100644 index be1a104937..0000000000 --- a/base/debug/trace_event_impl.h +++ /dev/null @@ -1,595 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - - -#ifndef BASE_DEBUG_TRACE_EVENT_IMPL_H_ -#define BASE_DEBUG_TRACE_EVENT_IMPL_H_ - -#include -#include -#include - -#include "base/callback.h" -#include "base/containers/hash_tables.h" -#include "base/gtest_prod_util.h" -#include "base/memory/ref_counted_memory.h" -#include "base/memory/scoped_vector.h" -#include "base/observer_list.h" -#include "base/strings/string_util.h" -#include "base/synchronization/condition_variable.h" -#include "base/synchronization/lock.h" -#include "base/threading/thread.h" -#include "base/timer/timer.h" - -// Older style trace macros with explicit id and extra data -// Only these macros result in publishing data to ETW as currently implemented. -#define TRACE_EVENT_BEGIN_ETW(name, id, extra) \ - base::debug::TraceLog::AddTraceEventEtw( \ - TRACE_EVENT_PHASE_BEGIN, \ - name, reinterpret_cast(id), extra) - -#define TRACE_EVENT_END_ETW(name, id, extra) \ - base::debug::TraceLog::AddTraceEventEtw( \ - TRACE_EVENT_PHASE_END, \ - name, reinterpret_cast(id), extra) - -#define TRACE_EVENT_INSTANT_ETW(name, id, extra) \ - base::debug::TraceLog::AddTraceEventEtw( \ - TRACE_EVENT_PHASE_INSTANT, \ - name, reinterpret_cast(id), extra) - -template -struct DefaultSingletonTraits; - -namespace base { - -class WaitableEvent; - -namespace debug { - -// For any argument of type TRACE_VALUE_TYPE_CONVERTABLE the provided -// class must implement this interface. -class ConvertableToTraceFormat { - public: - virtual ~ConvertableToTraceFormat() {} - - // Append the class info to the provided |out| string. The appended - // data must be a valid JSON object. Strings must be properly quoted, and - // escaped. There is no processing applied to the content after it is - // appended. - virtual void AppendAsTraceFormat(std::string* out) const = 0; -}; - -const int kTraceMaxNumArgs = 2; - -// Output records are "Events" and can be obtained via the -// OutputCallback whenever the tracing system decides to flush. This -// can happen at any time, on any thread, or you can programmatically -// force it to happen. -class BASE_EXPORT TraceEvent { - public: - union TraceValue { - bool as_bool; - unsigned long long as_uint; - long long as_int; - double as_double; - const void* as_pointer; - const char* as_string; - }; - - TraceEvent(); - TraceEvent(int thread_id, - TimeTicks timestamp, - char phase, - const unsigned char* category_group_enabled, - const char* name, - unsigned long long id, - int num_args, - const char** arg_names, - const unsigned char* arg_types, - const unsigned long long* arg_values, - scoped_ptr convertable_values[], - unsigned char flags); - TraceEvent(const TraceEvent& other); - TraceEvent& operator=(const TraceEvent& other); - ~TraceEvent(); - - // Serialize event data to JSON - static void AppendEventsAsJSON(const std::vector& events, - size_t start, - size_t count, - std::string* out); - void AppendAsJSON(std::string* out) const; - void AppendPrettyPrinted(std::ostringstream* out) const; - - static void AppendValueAsJSON(unsigned char type, - TraceValue value, - std::string* out); - - TimeTicks timestamp() const { return timestamp_; } - - // Exposed for unittesting: - - const base::RefCountedString* parameter_copy_storage() const { - return parameter_copy_storage_.get(); - } - - const unsigned char* category_group_enabled() const { - return category_group_enabled_; - } - - const char* name() const { return name_; } - - private: - // Note: these are ordered by size (largest first) for optimal packing. - TimeTicks timestamp_; - // id_ can be used to store phase-specific data. - unsigned long long id_; - TraceValue arg_values_[kTraceMaxNumArgs]; - const char* arg_names_[kTraceMaxNumArgs]; - scoped_ptr convertable_values_[kTraceMaxNumArgs]; - const unsigned char* category_group_enabled_; - const char* name_; - scoped_refptr parameter_copy_storage_; - int thread_id_; - char phase_; - unsigned char flags_; - unsigned char arg_types_[kTraceMaxNumArgs]; -}; - -// TraceBuffer holds the events as they are collected. -class BASE_EXPORT TraceBuffer { - public: - virtual ~TraceBuffer() {} - - virtual void AddEvent(const TraceEvent& event) = 0; - virtual bool HasMoreEvents() const = 0; - virtual const TraceEvent& NextEvent() = 0; - virtual bool IsFull() const = 0; - virtual size_t CountEnabledByName(const unsigned char* category, - const std::string& event_name) const = 0; - virtual size_t Size() const = 0; - virtual const TraceEvent& GetEventAt(size_t index) const = 0; -}; - -// TraceResultBuffer collects and converts trace fragments returned by TraceLog -// to JSON output. -class BASE_EXPORT TraceResultBuffer { - public: - typedef base::Callback OutputCallback; - - // If you don't need to stream JSON chunks out efficiently, and just want to - // get a complete JSON string after calling Finish, use this struct to collect - // JSON trace output. - struct BASE_EXPORT SimpleOutput { - OutputCallback GetCallback(); - void Append(const std::string& json_string); - - // Do what you want with the json_output_ string after calling - // TraceResultBuffer::Finish. - std::string json_output; - }; - - TraceResultBuffer(); - ~TraceResultBuffer(); - - // Set callback. The callback will be called during Start with the initial - // JSON output and during AddFragment and Finish with following JSON output - // chunks. The callback target must live past the last calls to - // TraceResultBuffer::Start/AddFragment/Finish. - void SetOutputCallback(const OutputCallback& json_chunk_callback); - - // Start JSON output. This resets all internal state, so you can reuse - // the TraceResultBuffer by calling Start. - void Start(); - - // Call AddFragment 0 or more times to add trace fragments from TraceLog. - void AddFragment(const std::string& trace_fragment); - - // When all fragments have been added, call Finish to complete the JSON - // formatted output. - void Finish(); - - private: - OutputCallback output_callback_; - bool append_comma_; -}; - -class BASE_EXPORT CategoryFilter { - public: - // The default category filter, used when none is provided. - // Allows all categories through, except if they end in the suffix 'Debug' or - // 'Test'. - static const char* kDefaultCategoryFilterString; - - // |filter_string| is a comma-delimited list of category wildcards. - // A category can have an optional '-' prefix to make it an excluded category. - // All the same rules apply above, so for example, having both included and - // excluded categories in the same list would not be supported. - // - // Example: CategoryFilter"test_MyTest*"); - // Example: CategoryFilter("test_MyTest*,test_OtherStuff"); - // Example: CategoryFilter("-excluded_category1,-excluded_category2"); - // Example: CategoryFilter("-*,webkit"); would disable everything but webkit. - // Example: CategoryFilter("-webkit"); would enable everything but webkit. - explicit CategoryFilter(const std::string& filter_string); - - CategoryFilter(const CategoryFilter& cf); - - ~CategoryFilter(); - - CategoryFilter& operator=(const CategoryFilter& rhs); - - // Writes the string representation of the CategoryFilter. This is a comma - // separated string, similar in nature to the one used to determine - // enabled/disabled category patterns, except here there is an arbitrary - // order, included categories go first, then excluded categories. Excluded - // categories are distinguished from included categories by the prefix '-'. - std::string ToString() const; - - // Determines whether category group would be enabled or - // disabled by this category filter. - bool IsCategoryGroupEnabled(const char* category_group) const; - - // Merges nested_filter with the current CategoryFilter - void Merge(const CategoryFilter& nested_filter); - - // Clears both included/excluded pattern lists. This would be equivalent to - // creating a CategoryFilter with an empty string, through the constructor. - // i.e: CategoryFilter(""). - // - // When using an empty filter, all categories are considered included as we - // are not excluding anything. - void Clear(); - - private: - FRIEND_TEST_ALL_PREFIXES(TraceEventTestFixture, CategoryFilter); - - static bool IsEmptyOrContainsLeadingOrTrailingWhitespace( - const std::string& str); - - typedef std::vector StringList; - - void Initialize(const std::string& filter_string); - void WriteString(const StringList& values, - std::string* out, - bool included) const; - bool HasIncludedPatterns() const; - - bool DoesCategoryGroupContainCategory(const char* category_group, - const char* category) const; - - StringList included_; - StringList disabled_; - StringList excluded_; -}; - -class TraceSamplingThread; - -class BASE_EXPORT TraceLog { - public: - // Notification is a mask of one or more of the following events. - enum Notification { - // The trace buffer does not flush dynamically, so when it fills up, - // subsequent trace events will be dropped. This callback is generated when - // the trace buffer is full. The callback must be thread safe. - TRACE_BUFFER_FULL = 1 << 0, - // A subscribed trace-event occurred. - EVENT_WATCH_NOTIFICATION = 1 << 1 - }; - - // Options determines how the trace buffer stores data. - enum Options { - // Record until the trace buffer is full. - RECORD_UNTIL_FULL = 1 << 0, - - // Record until the user ends the trace. The trace buffer is a fixed size - // and we use it as a ring buffer during recording. - RECORD_CONTINUOUSLY = 1 << 1, - - // Enable the sampling profiler. - ENABLE_SAMPLING = 1 << 2, - - // Echo to console. Events are discarded. - ECHO_TO_CONSOLE = 1 << 3 - }; - - static TraceLog* GetInstance(); - - // Convert the given string to trace options. Defaults to RECORD_UNTIL_FULL if - // the string does not provide valid options. - static Options TraceOptionsFromString(const std::string& str); - - // Get set of known category groups. This can change as new code paths are - // reached. The known category groups are inserted into |category_groups|. - void GetKnownCategoryGroups(std::vector* category_groups); - - // Retrieves the current CategoryFilter. - const CategoryFilter& GetCurrentCategoryFilter(); - - Options trace_options() const { return trace_options_; } - - // Enables tracing. See CategoryFilter comments for details - // on how to control what categories will be traced. - void SetEnabled(const CategoryFilter& category_filter, Options options); - - // Disable tracing for all categories. - void SetDisabled(); - bool IsEnabled() { return !!enable_count_; } - - // The number of times we have begun recording traces. If tracing is off, - // returns -1. If tracing is on, then it returns the number of times we have - // recorded a trace. By watching for this number to increment, you can - // passively discover when a new trace has begun. This is then used to - // implement the TRACE_EVENT_IS_NEW_TRACE() primitive. - int GetNumTracesRecorded(); - -#if defined(OS_ANDROID) - void StartATrace(); - void StopATrace(); -#endif - - // Enabled state listeners give a callback when tracing is enabled or - // disabled. This can be used to tie into other library's tracing systems - // on-demand. - class EnabledStateObserver { - public: - // Called just after the tracing system becomes enabled, outside of the - // |lock_|. TraceLog::IsEnabled() is true at this point. - virtual void OnTraceLogEnabled() = 0; - - // Called just after the tracing system disables, outside of the |lock_|. - // TraceLog::IsEnabled() is false at this point. - virtual void OnTraceLogDisabled() = 0; - }; - void AddEnabledStateObserver(EnabledStateObserver* listener); - void RemoveEnabledStateObserver(EnabledStateObserver* listener); - bool HasEnabledStateObserver(EnabledStateObserver* listener) const; - - float GetBufferPercentFull() const; - - // Set the thread-safe notification callback. The callback can occur at any - // time and from any thread. WARNING: It is possible for the previously set - // callback to be called during OR AFTER a call to SetNotificationCallback. - // Therefore, the target of the callback must either be a global function, - // ref-counted object or a LazyInstance with Leaky traits (or equivalent). - typedef base::Callback NotificationCallback; - void SetNotificationCallback(const NotificationCallback& cb); - - // Not using base::Callback because of its limited by 7 parameters. - // Also, using primitive type allows directly passing callback from WebCore. - // WARNING: It is possible for the previously set callback to be called - // after a call to SetEventCallback() that replaces or clears the callback. - // This callback may be invoked on any thread. - typedef void (*EventCallback)(char phase, - const unsigned char* category_group_enabled, - const char* name, - unsigned long long id, - int num_args, - const char* const arg_names[], - const unsigned char arg_types[], - const unsigned long long arg_values[], - unsigned char flags); - void SetEventCallback(EventCallback cb); - - // Flush all collected events to the given output callback. The callback will - // be called one or more times with IPC-bite-size chunks. The string format is - // undefined. Use TraceResultBuffer to convert one or more trace strings to - // JSON. - typedef base::Callback&)> - OutputCallback; - void Flush(const OutputCallback& cb); - - // Called by TRACE_EVENT* macros, don't call this directly. - // The name parameter is a category group for example: - // TRACE_EVENT0("renderer,webkit", "WebViewImpl::HandleInputEvent") - static const unsigned char* GetCategoryGroupEnabled(const char* name); - static const char* GetCategoryGroupName( - const unsigned char* category_group_enabled); - - // Called by TRACE_EVENT* macros, don't call this directly. - // If |copy| is set, |name|, |arg_name1| and |arg_name2| will be deep copied - // into the event; see "Memory scoping note" and TRACE_EVENT_COPY_XXX above. - void AddTraceEvent(char phase, - const unsigned char* category_group_enabled, - const char* name, - unsigned long long id, - int num_args, - const char** arg_names, - const unsigned char* arg_types, - const unsigned long long* arg_values, - scoped_ptr convertable_values[], - unsigned char flags); - void AddTraceEventWithThreadIdAndTimestamp( - char phase, - const unsigned char* category_group_enabled, - const char* name, - unsigned long long id, - int thread_id, - const TimeTicks& timestamp, - int num_args, - const char** arg_names, - const unsigned char* arg_types, - const unsigned long long* arg_values, - scoped_ptr convertable_values[], - unsigned char flags); - static void AddTraceEventEtw(char phase, - const char* category_group, - const void* id, - const char* extra); - static void AddTraceEventEtw(char phase, - const char* category_group, - const void* id, - const std::string& extra); - - // For every matching event, a notification will be fired. NOTE: the - // notification will fire for each matching event that has already occurred - // since tracing was started (including before tracing if the process was - // started with tracing turned on). - void SetWatchEvent(const std::string& category_name, - const std::string& event_name); - // Cancel the watch event. If tracing is enabled, this may race with the - // watch event notification firing. - void CancelWatchEvent(); - - int process_id() const { return process_id_; } - - // Exposed for unittesting: - - void InstallWaitableEventForSamplingTesting(WaitableEvent* waitable_event); - - // Allows deleting our singleton instance. - static void DeleteForTesting(); - - // Allow tests to inspect TraceEvents. - size_t GetEventsSize() const { return logged_events_->Size(); } - const TraceEvent& GetEventAt(size_t index) const { - return logged_events_->GetEventAt(index); - } - - void SetProcessID(int process_id); - - // Process sort indices, if set, override the order of a process will appear - // relative to other processes in the trace viewer. Processes are sorted first - // on their sort index, ascending, then by their name, and then tid. - void SetProcessSortIndex(int sort_index); - - // Sets the name of the process. - void SetProcessName(const std::string& process_name); - - // Processes can have labels in addition to their names. Use labels, for - // instance, to list out the web page titles that a process is handling. - void UpdateProcessLabel(int label_id, const std::string& current_label); - void RemoveProcessLabel(int label_id); - - // Thread sort indices, if set, override the order of a thread will appear - // within its process in the trace viewer. Threads are sorted first on their - // sort index, ascending, then by their name, and then tid. - void SetThreadSortIndex(PlatformThreadId , int sort_index); - - // Allow setting an offset between the current TimeTicks time and the time - // that should be reported. - void SetTimeOffset(TimeDelta offset); - - size_t GetObserverCountForTest() const; - - private: - // This allows constructor and destructor to be private and usable only - // by the Singleton class. - friend struct DefaultSingletonTraits; - - // Enable/disable each category group based on the current enable_count_ - // and category_filter_. Disable the category group if enabled_count_ is 0, or - // if the category group contains a category that matches an included category - // pattern, that category group will be enabled. - // On Android, ATRACE_ENABLED flag will be applied if atrace is started. - void UpdateCategoryGroupEnabledFlags(); - void UpdateCategoryGroupEnabledFlag(int category_index); - - static void SetCategoryGroupEnabled(int category_index, bool enabled); - static bool IsCategoryGroupEnabled( - const unsigned char* category_group_enabled); - - // The pointer returned from GetCategoryGroupEnabledInternal() points to a - // value with zero or more of the following bits. Used in this class only. - // The TRACE_EVENT macros should only use the value as a bool. - enum CategoryGroupEnabledFlags { - // Normal enabled flag for category groups enabled with Enable(). - CATEGORY_GROUP_ENABLED = 1 << 0, - // On Android if ATrace is enabled, all categories will have this bit. - // Not used on other platforms. - ATRACE_ENABLED = 1 << 1 - }; - - // Helper class for managing notification_thread_count_ and running - // notification callbacks. This is very similar to a reader-writer lock, but - // shares the lock with TraceLog and manages the notification flags. - class NotificationHelper { - public: - inline explicit NotificationHelper(TraceLog* trace_log); - inline ~NotificationHelper(); - - // Called only while TraceLog::lock_ is held. This ORs the given - // notification with any existing notifications. - inline void AddNotificationWhileLocked(int notification); - - // Called only while TraceLog::lock_ is NOT held. If there are any pending - // notifications from previous calls to AddNotificationWhileLocked, this - // will call the NotificationCallback. - inline void SendNotificationIfAny(); - - private: - TraceLog* trace_log_; - NotificationCallback callback_copy_; - int notification_; - }; - - TraceLog(); - ~TraceLog(); - const unsigned char* GetCategoryGroupEnabledInternal(const char* name); - void AddMetadataEvents(); - -#if defined(OS_ANDROID) - void SendToATrace(char phase, - const char* category_group, - const char* name, - unsigned long long id, - int num_args, - const char** arg_names, - const unsigned char* arg_types, - const unsigned long long* arg_values, - scoped_ptr convertable_values[], - unsigned char flags); - static void ApplyATraceEnabledFlag(unsigned char* category_group_enabled); -#endif - - TraceBuffer* GetTraceBuffer(); - - // TODO(nduca): switch to per-thread trace buffers to reduce thread - // synchronization. - // This lock protects TraceLog member accesses from arbitrary threads. - Lock lock_; - int enable_count_; - int num_traces_recorded_; - NotificationCallback notification_callback_; - scoped_ptr logged_events_; - EventCallback event_callback_; - bool dispatching_to_observer_list_; - std::vector enabled_state_observer_list_; - - std::string process_name_; - base::hash_map process_labels_; - int process_sort_index_; - base::hash_map thread_sort_indices_; - - base::hash_map thread_names_; - base::hash_map > thread_event_start_times_; - base::hash_map thread_colors_; - - // XORed with TraceID to make it unlikely to collide with other processes. - unsigned long long process_id_hash_; - - int process_id_; - - TimeDelta time_offset_; - - // Allow tests to wake up when certain events occur. - const unsigned char* watch_category_; - std::string watch_event_name_; - - Options trace_options_; - - // Sampling thread handles. - scoped_ptr sampling_thread_; - PlatformThreadHandle sampling_thread_handle_; - - CategoryFilter category_filter_; - - DISALLOW_COPY_AND_ASSIGN(TraceLog); -}; - -} // namespace debug -} // namespace base - -#endif // BASE_DEBUG_TRACE_EVENT_IMPL_H_ diff --git a/base/debug/trace_event_impl_constants.cc b/base/debug/trace_event_impl_constants.cc deleted file mode 100644 index 71e9e08db7..0000000000 --- a/base/debug/trace_event_impl_constants.cc +++ /dev/null @@ -1,14 +0,0 @@ -// Copyright (c) 2013 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "base/debug/trace_event_impl.h" - -namespace base { -namespace debug { - -// Enable everything but debug and test categories by default. -const char* CategoryFilter::kDefaultCategoryFilterString = "-*Debug,-*Test"; - -} // namespace debug -} // namespace base diff --git a/base/debug/trace_event_memory.cc b/base/debug/trace_event_memory.cc deleted file mode 100644 index fb5f65bbc1..0000000000 --- a/base/debug/trace_event_memory.cc +++ /dev/null @@ -1,414 +0,0 @@ -// Copyright 2013 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "base/debug/trace_event_memory.h" - -#include "base/debug/leak_annotations.h" -#include "base/debug/trace_event.h" -#include "base/lazy_instance.h" -#include "base/logging.h" -#include "base/memory/scoped_ptr.h" -#include "base/message_loop/message_loop.h" -#include "base/strings/string_number_conversions.h" -#include "base/strings/string_util.h" -#include "base/threading/thread_local_storage.h" - -namespace base { -namespace debug { - -namespace { - -// Maximum number of nested TRACE_MEMORY scopes to record. Must be greater than -// or equal to HeapProfileTable::kMaxStackDepth. -const size_t kMaxStackSize = 32; - -///////////////////////////////////////////////////////////////////////////// -// Holds a memory dump until the tracing system needs to serialize it. -class MemoryDumpHolder : public base::debug::ConvertableToTraceFormat { - public: - // Takes ownership of dump, which must be a JSON string, allocated with - // malloc() and NULL terminated. - explicit MemoryDumpHolder(char* dump) : dump_(dump) {} - virtual ~MemoryDumpHolder() { free(dump_); } - - // base::debug::ConvertableToTraceFormat overrides: - virtual void AppendAsTraceFormat(std::string* out) const OVERRIDE { - AppendHeapProfileAsTraceFormat(dump_, out); - } - - private: - char* dump_; - - DISALLOW_COPY_AND_ASSIGN(MemoryDumpHolder); -}; - -///////////////////////////////////////////////////////////////////////////// -// Records a stack of TRACE_MEMORY events. One per thread is required. -struct TraceMemoryStack { - TraceMemoryStack() : index_(0) { - memset(category_stack_, 0, kMaxStackSize * sizeof(category_stack_[0])); - } - - // Points to the next free entry. - size_t index_; - const char* category_stack_[kMaxStackSize]; -}; - -// Pointer to a TraceMemoryStack per thread. -base::ThreadLocalStorage::StaticSlot tls_trace_memory_stack = TLS_INITIALIZER; - -// Clean up memory pointed to by our thread-local storage. -void DeleteStackOnThreadCleanup(void* value) { - TraceMemoryStack* stack = static_cast(value); - delete stack; -} - -// Initializes the thread-local TraceMemoryStack pointer. Returns true on -// success or if it is already initialized. -bool InitThreadLocalStorage() { - if (tls_trace_memory_stack.initialized()) - return true; - // Initialize the thread-local storage key, returning true on success. - return tls_trace_memory_stack.Initialize(&DeleteStackOnThreadCleanup); -} - -// Clean up thread-local-storage in the main thread. -void CleanupThreadLocalStorage() { - if (!tls_trace_memory_stack.initialized()) - return; - TraceMemoryStack* stack = - static_cast(tls_trace_memory_stack.Get()); - delete stack; - tls_trace_memory_stack.Set(NULL); - // Intentionally do not release the thread-local-storage key here, that is, - // do not call tls_trace_memory_stack.Free(). Other threads have lazily - // created pointers in thread-local-storage via GetTraceMemoryStack() below. - // Those threads need to run the DeleteStack() destructor function when they - // exit. If we release the key the destructor will not be called and those - // threads will not clean up their memory. -} - -// Returns the thread-local trace memory stack for the current thread, creating -// one if needed. Returns NULL if the thread-local storage key isn't -// initialized, which indicates that heap profiling isn't running. -TraceMemoryStack* GetTraceMemoryStack() { - TraceMemoryStack* stack = - static_cast(tls_trace_memory_stack.Get()); - // Lazily initialize TraceMemoryStack objects for new threads. - if (!stack) { - stack = new TraceMemoryStack; - tls_trace_memory_stack.Set(stack); - } - return stack; -} - -// Returns a "pseudo-stack" of pointers to trace events. -// TODO(jamescook): Record both category and name, perhaps in a pair for speed. -int GetPseudoStack(int skip_count_ignored, void** stack_out) { - // If the tracing system isn't fully initialized, just skip this allocation. - // Attempting to initialize will allocate memory, causing this function to - // be called recursively from inside the allocator. - if (!tls_trace_memory_stack.initialized() || !tls_trace_memory_stack.Get()) - return 0; - TraceMemoryStack* stack = - static_cast(tls_trace_memory_stack.Get()); - // Copy at most kMaxStackSize stack entries. - const size_t count = std::min(stack->index_, kMaxStackSize); - // Notes that memcpy() works for zero bytes. - memcpy(stack_out, - stack->category_stack_, - count * sizeof(stack->category_stack_[0])); - // Function must return an int to match the signature required by tcmalloc. - return static_cast(count); -} - -} // namespace - -////////////////////////////////////////////////////////////////////////////// - -TraceMemoryController::TraceMemoryController( - scoped_refptr message_loop_proxy, - HeapProfilerStartFunction heap_profiler_start_function, - HeapProfilerStopFunction heap_profiler_stop_function, - GetHeapProfileFunction get_heap_profile_function) - : message_loop_proxy_(message_loop_proxy), - heap_profiler_start_function_(heap_profiler_start_function), - heap_profiler_stop_function_(heap_profiler_stop_function), - get_heap_profile_function_(get_heap_profile_function), - weak_factory_(this) { - // Force the "memory" category to show up in the trace viewer. - TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("memory"), "init"); - // Watch for the tracing system being enabled. - TraceLog::GetInstance()->AddEnabledStateObserver(this); -} - -TraceMemoryController::~TraceMemoryController() { - if (dump_timer_.IsRunning()) - StopProfiling(); - TraceLog::GetInstance()->RemoveEnabledStateObserver(this); -} - - // base::debug::TraceLog::EnabledStateChangedObserver overrides: -void TraceMemoryController::OnTraceLogEnabled() { - // Check to see if tracing is enabled for the memory category. - bool enabled; - TRACE_EVENT_CATEGORY_GROUP_ENABLED(TRACE_DISABLED_BY_DEFAULT("memory"), - &enabled); - if (!enabled) - return; - DVLOG(1) << "OnTraceLogEnabled"; - message_loop_proxy_->PostTask( - FROM_HERE, - base::Bind(&TraceMemoryController::StartProfiling, - weak_factory_.GetWeakPtr())); -} - -void TraceMemoryController::OnTraceLogDisabled() { - // The memory category is always disabled before OnTraceLogDisabled() is - // called, so we cannot tell if it was enabled before. Always try to turn - // off profiling. - DVLOG(1) << "OnTraceLogDisabled"; - message_loop_proxy_->PostTask( - FROM_HERE, - base::Bind(&TraceMemoryController::StopProfiling, - weak_factory_.GetWeakPtr())); -} - -void TraceMemoryController::StartProfiling() { - // Watch for the tracing framework sending enabling more than once. - if (dump_timer_.IsRunning()) - return; - DVLOG(1) << "Starting trace memory"; - if (!InitThreadLocalStorage()) - return; - ScopedTraceMemory::set_enabled(true); - // Call ::HeapProfilerWithPseudoStackStart(). - heap_profiler_start_function_(&GetPseudoStack); - const int kDumpIntervalSeconds = 5; - dump_timer_.Start(FROM_HERE, - TimeDelta::FromSeconds(kDumpIntervalSeconds), - base::Bind(&TraceMemoryController::DumpMemoryProfile, - weak_factory_.GetWeakPtr())); -} - -void TraceMemoryController::DumpMemoryProfile() { - // Don't trace allocations here in the memory tracing system. - INTERNAL_TRACE_MEMORY(TRACE_DISABLED_BY_DEFAULT("memory"), - TRACE_MEMORY_IGNORE); - - DVLOG(1) << "DumpMemoryProfile"; - // MemoryDumpHolder takes ownership of this string. See GetHeapProfile() in - // tcmalloc for details. - char* dump = get_heap_profile_function_(); - scoped_ptr dump_holder(new MemoryDumpHolder(dump)); - const int kSnapshotId = 1; - TRACE_EVENT_OBJECT_SNAPSHOT_WITH_ID( - TRACE_DISABLED_BY_DEFAULT("memory"), - "memory::Heap", - kSnapshotId, - dump_holder.PassAs()); -} - -void TraceMemoryController::StopProfiling() { - // Watch for the tracing framework sending disabled more than once. - if (!dump_timer_.IsRunning()) - return; - DVLOG(1) << "Stopping trace memory"; - dump_timer_.Stop(); - ScopedTraceMemory::set_enabled(false); - CleanupThreadLocalStorage(); - // Call ::HeapProfilerStop(). - heap_profiler_stop_function_(); -} - -bool TraceMemoryController::IsTimerRunningForTest() const { - return dump_timer_.IsRunning(); -} - -///////////////////////////////////////////////////////////////////////////// - -// static -bool ScopedTraceMemory::enabled_ = false; - -ScopedTraceMemory::ScopedTraceMemory(const char* category) { - // Not enabled indicates that the trace system isn't running, so don't - // record anything. - if (!enabled_) - return; - // Get our thread's copy of the stack. - TraceMemoryStack* trace_memory_stack = GetTraceMemoryStack(); - const size_t index = trace_memory_stack->index_; - // Allow deep nesting of stacks (needed for tests), but only record - // |kMaxStackSize| entries. - if (index < kMaxStackSize) - trace_memory_stack->category_stack_[index] = category; - trace_memory_stack->index_++; -} - -ScopedTraceMemory::~ScopedTraceMemory() { - // Not enabled indicates that the trace system isn't running, so don't - // record anything. - if (!enabled_) - return; - // Get our thread's copy of the stack. - TraceMemoryStack* trace_memory_stack = GetTraceMemoryStack(); - // The tracing system can be turned on with ScopedTraceMemory objects - // allocated on the stack, so avoid potential underflow as they are destroyed. - if (trace_memory_stack->index_ > 0) - trace_memory_stack->index_--; -} - -// static -void ScopedTraceMemory::InitForTest() { - InitThreadLocalStorage(); - enabled_ = true; -} - -// static -void ScopedTraceMemory::CleanupForTest() { - enabled_ = false; - CleanupThreadLocalStorage(); -} - -// static -int ScopedTraceMemory::GetStackIndexForTest() { - TraceMemoryStack* stack = GetTraceMemoryStack(); - return static_cast(stack->index_); -} - -// static -const char* ScopedTraceMemory::GetItemForTest(int index) { - TraceMemoryStack* stack = GetTraceMemoryStack(); - return stack->category_stack_[index]; -} - -///////////////////////////////////////////////////////////////////////////// - -void AppendHeapProfileAsTraceFormat(const char* input, std::string* output) { - // Heap profile output has a header total line, then a list of stacks with - // memory totals, like this: - // - // heap profile: 357: 55227 [ 14653: 2624014] @ heapprofile - // 95: 40940 [ 649: 114260] @ 0x7fa7f4b3be13 - // 77: 32546 [ 742: 106234] @ - // 68: 4195 [ 1087: 98009] @ 0x7fa7fa9b9ba0 0x7fa7f4b3be13 - // - // MAPPED_LIBRARIES: - // 1be411fc1000-1be4139e4000 rw-p 00000000 00:00 0 - // 1be4139e4000-1be4139e5000 ---p 00000000 00:00 0 - // ... - // - // Skip input after MAPPED_LIBRARIES. - std::string input_string; - const char* mapped_libraries = strstr(input, "MAPPED_LIBRARIES"); - if (mapped_libraries) { - input_string.assign(input, mapped_libraries - input); - } else { - input_string.assign(input); - } - - std::vector lines; - size_t line_count = Tokenize(input_string, "\n", &lines); - if (line_count == 0) { - DLOG(WARNING) << "No lines found"; - return; - } - - // Handle the initial summary line. - output->append("["); - AppendHeapProfileTotalsAsTraceFormat(lines[0], output); - - // Handle the following stack trace lines. - for (size_t i = 1; i < line_count; ++i) { - const std::string& line = lines[i]; - AppendHeapProfileLineAsTraceFormat(line, output); - } - output->append("]\n"); -} - -void AppendHeapProfileTotalsAsTraceFormat(const std::string& line, - std::string* output) { - // This is what a line looks like: - // heap profile: 357: 55227 [ 14653: 2624014] @ heapprofile - // - // The numbers represent total allocations since profiling was enabled. - // From the example above: - // 357 = Outstanding allocations (mallocs - frees) - // 55227 = Outstanding bytes (malloc bytes - free bytes) - // 14653 = Total allocations (mallocs) - // 2624014 = Total bytes (malloc bytes) - std::vector tokens; - Tokenize(line, " :[]@", &tokens); - if (tokens.size() < 4) { - DLOG(WARNING) << "Invalid totals line " << line; - return; - } - DCHECK_EQ(tokens[0], "heap"); - DCHECK_EQ(tokens[1], "profile"); - output->append("{\"current_allocs\": "); - output->append(tokens[2]); - output->append(", \"current_bytes\": "); - output->append(tokens[3]); - output->append(", \"trace\": \"\"}"); -} - -bool AppendHeapProfileLineAsTraceFormat(const std::string& line, - std::string* output) { - // This is what a line looks like: - // 68: 4195 [ 1087: 98009] @ 0x7fa7fa9b9ba0 0x7fa7f4b3be13 - // - // The numbers represent allocations for a particular stack trace since - // profiling was enabled. From the example above: - // 68 = Outstanding allocations (mallocs - frees) - // 4195 = Outstanding bytes (malloc bytes - free bytes) - // 1087 = Total allocations (mallocs) - // 98009 = Total bytes (malloc bytes) - // - // 0x7fa7fa9b9ba0 0x7fa7f4b3be13 = Stack trace represented as pointers to - // static strings from trace event names. - std::vector tokens; - Tokenize(line, " :[]@", &tokens); - // It's valid to have no stack addresses, so only require 4 tokens. - if (tokens.size() < 4) { - DLOG(WARNING) << "Invalid line " << line; - return false; - } - // Don't bother with stacks that have no current allocations. - if (tokens[0] == "0") - return false; - output->append(",\n"); - output->append("{\"current_allocs\": "); - output->append(tokens[0]); - output->append(", \"current_bytes\": "); - output->append(tokens[1]); - output->append(", \"trace\": \""); - - // Convert the "stack addresses" into strings. - const std::string kSingleQuote = "'"; - for (size_t t = 4; t < tokens.size(); ++t) { - // Each stack address is a pointer to a constant trace name string. - uint64 address = 0; - if (!base::HexStringToUInt64(tokens[t], &address)) - break; - // This is ugly but otherwise tcmalloc would need to gain a special output - // serializer for pseudo-stacks. Note that this cast also handles 64-bit to - // 32-bit conversion if necessary. Tests use a null address. - const char* trace_name = - address ? reinterpret_cast(address) : "null"; - - // Some trace name strings have double quotes, convert them to single. - std::string trace_name_string(trace_name); - ReplaceChars(trace_name_string, "\"", kSingleQuote, &trace_name_string); - - output->append(trace_name_string); - - // Trace viewer expects a trailing space. - output->append(" "); - } - output->append("\"}"); - return true; -} - -} // namespace debug -} // namespace base diff --git a/base/debug/trace_event_memory.h b/base/debug/trace_event_memory.h deleted file mode 100644 index 0d82198988..0000000000 --- a/base/debug/trace_event_memory.h +++ /dev/null @@ -1,152 +0,0 @@ -// Copyright 2013 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef BASE_DEBUG_TRACE_EVENT_MEMORY_H_ -#define BASE_DEBUG_TRACE_EVENT_MEMORY_H_ - -#include "base/base_export.h" -#include "base/debug/trace_event_impl.h" -#include "base/gtest_prod_util.h" -#include "base/memory/ref_counted.h" -#include "base/memory/weak_ptr.h" -#include "base/timer/timer.h" - -// TODO(jamescook): Windows support for memory tracing. -#if !defined(NO_TCMALLOC) && !defined(OS_NACL) && \ - (defined(OS_LINUX) || defined(OS_ANDROID)) -#define TCMALLOC_TRACE_MEMORY_SUPPORTED 1 -#endif - -namespace base { - -class MessageLoopProxy; - -namespace debug { - -// Watches for chrome://tracing to be enabled or disabled. When tracing is -// enabled, also enables tcmalloc heap profiling. This class is the preferred -// way to turn trace-base heap memory profiling on and off. -class BASE_EXPORT TraceMemoryController - : public TraceLog::EnabledStateObserver { - public: - typedef int (*StackGeneratorFunction)(int skip_count, void** stack); - typedef void (*HeapProfilerStartFunction)(StackGeneratorFunction callback); - typedef void (*HeapProfilerStopFunction)(); - typedef char* (*GetHeapProfileFunction)(); - - // |message_loop_proxy| must be a proxy to the primary thread for the client - // process, e.g. the UI thread in a browser. The function pointers must be - // pointers to tcmalloc heap profiling functions; by avoiding direct calls to - // these functions we avoid a dependency on third_party/tcmalloc from base. - TraceMemoryController( - scoped_refptr message_loop_proxy, - HeapProfilerStartFunction heap_profiler_start_function, - HeapProfilerStopFunction heap_profiler_stop_function, - GetHeapProfileFunction get_heap_profile_function); - virtual ~TraceMemoryController(); - - // base::debug::TraceLog::EnabledStateChangedObserver overrides: - virtual void OnTraceLogEnabled() OVERRIDE; - virtual void OnTraceLogDisabled() OVERRIDE; - - // Starts heap memory profiling. - void StartProfiling(); - - // Captures a heap profile. - void DumpMemoryProfile(); - - // If memory tracing is enabled, dumps a memory profile to the tracing system. - void StopProfiling(); - - private: - FRIEND_TEST_ALL_PREFIXES(TraceMemoryTest, TraceMemoryController); - - bool IsTimerRunningForTest() const; - - // Ensures the observer starts and stops tracing on the primary thread. - scoped_refptr message_loop_proxy_; - - // Pointers to tcmalloc heap profiling functions. Allows this class to use - // tcmalloc functions without introducing a dependency from base to tcmalloc. - HeapProfilerStartFunction heap_profiler_start_function_; - HeapProfilerStopFunction heap_profiler_stop_function_; - GetHeapProfileFunction get_heap_profile_function_; - - // Timer to schedule memory profile dumps. - RepeatingTimer dump_timer_; - - WeakPtrFactory weak_factory_; - - DISALLOW_COPY_AND_ASSIGN(TraceMemoryController); -}; - -////////////////////////////////////////////////////////////////////////////// - -// A scoped context for memory tracing. Pushes the name onto a stack for -// recording by tcmalloc heap profiling. -class BASE_EXPORT ScopedTraceMemory { - public: - // Memory for |name| must be static, for example, a literal string in - // a TRACE_EVENT macro. - explicit ScopedTraceMemory(const char* name); - ~ScopedTraceMemory(); - - // Enables the storing of trace names on a per-thread stack. - static void set_enabled(bool enabled) { enabled_ = enabled; } - - // Testing interface: - static void InitForTest(); - static void CleanupForTest(); - static int GetStackIndexForTest(); - static const char* GetItemForTest(int index); - - private: - static bool enabled_; - DISALLOW_COPY_AND_ASSIGN(ScopedTraceMemory); -}; - -////////////////////////////////////////////////////////////////////////////// - -// Converts tcmalloc's heap profiler data with pseudo-stacks in |input| to -// trace event compatible JSON and appends to |output|. Visible for testing. -BASE_EXPORT void AppendHeapProfileAsTraceFormat(const char* input, - std::string* output); - -// Converts the first |line| of heap profiler data, which contains totals for -// all allocations in a special format, into trace event compatible JSON and -// appends to |output|. Visible for testing. -BASE_EXPORT void AppendHeapProfileTotalsAsTraceFormat(const std::string& line, - std::string* output); - -// Converts a single |line| of heap profiler data into trace event compatible -// JSON and appends to |output|. Returns true if the line was valid and has a -// non-zero number of current allocations. Visible for testing. -BASE_EXPORT bool AppendHeapProfileLineAsTraceFormat(const std::string& line, - std::string* output); - -} // namespace debug -} // namespace base - -// Make local variables with unique names based on the line number. Note that -// the extra level of redirection is needed. -#define INTERNAL_TRACE_MEMORY_ID3(line) trace_memory_unique_##line -#define INTERNAL_TRACE_MEMORY_ID2(line) INTERNAL_TRACE_MEMORY_ID3(line) -#define INTERNAL_TRACE_MEMORY_ID INTERNAL_TRACE_MEMORY_ID2(__LINE__) - -// This is the core macro that adds a scope to each TRACE_EVENT location. -// It generates a unique local variable name using the macros above. -// TODO(jamescook): Make it record both category and name. -#if defined(TCMALLOC_TRACE_MEMORY_SUPPORTED) -#define INTERNAL_TRACE_MEMORY(category, name) \ - base::debug::ScopedTraceMemory INTERNAL_TRACE_MEMORY_ID(name); -#else -#define INTERNAL_TRACE_MEMORY(category, name) -#endif // defined(TRACE_MEMORY_SUPPORTED) - -// A special trace name that allows us to ignore memory allocations inside -// the memory dump system itself. The allocations are recorded, but the -// visualizer skips them. Must match the value in heap.js. -#define TRACE_MEMORY_IGNORE "trace-memory-ignore" - -#endif // BASE_DEBUG_TRACE_EVENT_MEMORY_H_ diff --git a/base/debug/trace_event_memory_unittest.cc b/base/debug/trace_event_memory_unittest.cc deleted file mode 100644 index 7c4eae6bb4..0000000000 --- a/base/debug/trace_event_memory_unittest.cc +++ /dev/null @@ -1,211 +0,0 @@ -// Copyright 2013 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "base/debug/trace_event_memory.h" - -#include -#include - -#include "base/debug/trace_event_impl.h" -#include "base/message_loop/message_loop.h" -#include "testing/gtest/include/gtest/gtest.h" - -#if defined(TCMALLOC_TRACE_MEMORY_SUPPORTED) -#include "third_party/tcmalloc/chromium/src/gperftools/heap-profiler.h" -#endif - -namespace base { -namespace debug { - -// Tests for the trace event memory tracking system. Exists as a class so it -// can be a friend of TraceMemoryController. -class TraceMemoryTest : public testing::Test { - public: - TraceMemoryTest() {} - virtual ~TraceMemoryTest() {} - - private: - DISALLOW_COPY_AND_ASSIGN(TraceMemoryTest); -}; - -////////////////////////////////////////////////////////////////////////////// - -#if defined(TCMALLOC_TRACE_MEMORY_SUPPORTED) - -TEST_F(TraceMemoryTest, TraceMemoryController) { - MessageLoop message_loop; - - // Start with no observers of the TraceLog. - EXPECT_EQ(0u, TraceLog::GetInstance()->GetObserverCountForTest()); - - // Creating a controller adds it to the TraceLog observer list. - scoped_ptr controller( - new TraceMemoryController( - message_loop.message_loop_proxy(), - ::HeapProfilerWithPseudoStackStart, - ::HeapProfilerStop, - ::GetHeapProfile)); - EXPECT_EQ(1u, TraceLog::GetInstance()->GetObserverCountForTest()); - EXPECT_TRUE( - TraceLog::GetInstance()->HasEnabledStateObserver(controller.get())); - - // By default the observer isn't dumping memory profiles. - EXPECT_FALSE(controller->IsTimerRunningForTest()); - - // Simulate enabling tracing. - controller->StartProfiling(); - message_loop.RunUntilIdle(); - EXPECT_TRUE(controller->IsTimerRunningForTest()); - - // Simulate disabling tracing. - controller->StopProfiling(); - message_loop.RunUntilIdle(); - EXPECT_FALSE(controller->IsTimerRunningForTest()); - - // Deleting the observer removes it from the TraceLog observer list. - controller.reset(); - EXPECT_EQ(0u, TraceLog::GetInstance()->GetObserverCountForTest()); -} - -TEST_F(TraceMemoryTest, ScopedTraceMemory) { - ScopedTraceMemory::InitForTest(); - - // Start with an empty stack. - EXPECT_EQ(0, ScopedTraceMemory::GetStackIndexForTest()); - - { - // Push an item. - const char kScope1[] = "scope1"; - ScopedTraceMemory scope1(kScope1); - EXPECT_EQ(1, ScopedTraceMemory::GetStackIndexForTest()); - EXPECT_EQ(kScope1, ScopedTraceMemory::GetItemForTest(0)); - - { - // One more item. - const char kScope2[] = "scope2"; - ScopedTraceMemory scope2(kScope2); - EXPECT_EQ(2, ScopedTraceMemory::GetStackIndexForTest()); - EXPECT_EQ(kScope2, ScopedTraceMemory::GetItemForTest(1)); - } - - // Ended scope 2. - EXPECT_EQ(1, ScopedTraceMemory::GetStackIndexForTest()); - } - - // Ended scope 1. - EXPECT_EQ(0, ScopedTraceMemory::GetStackIndexForTest()); - - ScopedTraceMemory::CleanupForTest(); -} - -void TestDeepScopeNesting(int current, int depth) { - EXPECT_EQ(current, ScopedTraceMemory::GetStackIndexForTest()); - const char kCategory[] = "foo"; - ScopedTraceMemory scope(kCategory); - if (current < depth) - TestDeepScopeNesting(current + 1, depth); - EXPECT_EQ(current + 1, ScopedTraceMemory::GetStackIndexForTest()); -} - -TEST_F(TraceMemoryTest, DeepScopeNesting) { - ScopedTraceMemory::InitForTest(); - - // Ensure really deep scopes don't crash. - TestDeepScopeNesting(0, 100); - - ScopedTraceMemory::CleanupForTest(); -} - -#endif // defined(TRACE_MEMORY_SUPPORTED) - -///////////////////////////////////////////////////////////////////////////// - -TEST_F(TraceMemoryTest, AppendHeapProfileTotalsAsTraceFormat) { - // Empty input gives empty output. - std::string empty_output; - AppendHeapProfileTotalsAsTraceFormat("", &empty_output); - EXPECT_EQ("", empty_output); - - // Typical case. - const char input[] = - "heap profile: 357: 55227 [ 14653: 2624014] @ heapprofile"; - const std::string kExpectedOutput = - "{\"current_allocs\": 357, \"current_bytes\": 55227, \"trace\": \"\"}"; - std::string output; - AppendHeapProfileTotalsAsTraceFormat(input, &output); - EXPECT_EQ(kExpectedOutput, output); -} - -TEST_F(TraceMemoryTest, AppendHeapProfileLineAsTraceFormat) { - // Empty input gives empty output. - std::string empty_output; - EXPECT_FALSE(AppendHeapProfileLineAsTraceFormat("", &empty_output)); - EXPECT_EQ("", empty_output); - - // Invalid input returns false. - std::string junk_output; - EXPECT_FALSE(AppendHeapProfileLineAsTraceFormat("junk", &junk_output)); - - // Input with the addresses of name1 and name2. - const char kName1[] = "name1"; - const char kName2[] = "name2"; - std::ostringstream input; - input << " 68: 4195 [ 1087: 98009] @ " << &kName1 << " " << &kName2; - const std::string kExpectedOutput = - ",\n" - "{" - "\"current_allocs\": 68, " - "\"current_bytes\": 4195, " - "\"trace\": \"name1 name2 \"" - "}"; - std::string output; - EXPECT_TRUE( - AppendHeapProfileLineAsTraceFormat(input.str().c_str(), &output)); - EXPECT_EQ(kExpectedOutput, output); - - // Zero current allocations is skipped. - std::ostringstream zero_input; - zero_input << " 0: 0 [ 1087: 98009] @ " << &kName1 << " " - << &kName2; - std::string zero_output; - EXPECT_FALSE(AppendHeapProfileLineAsTraceFormat(zero_input.str().c_str(), - &zero_output)); - EXPECT_EQ("", zero_output); -} - -TEST_F(TraceMemoryTest, AppendHeapProfileAsTraceFormat) { - // Empty input gives empty output. - std::string empty_output; - AppendHeapProfileAsTraceFormat("", &empty_output); - EXPECT_EQ("", empty_output); - - // Typical case. - const char input[] = - "heap profile: 357: 55227 [ 14653: 2624014] @ heapprofile\n" - " 95: 40940 [ 649: 114260] @\n" - " 77: 32546 [ 742: 106234] @ 0x0 0x0\n" - " 0: 0 [ 132: 4236] @ 0x0\n" - "\n" - "MAPPED_LIBRARIES:\n" - "1be411fc1000-1be4139e4000 rw-p 00000000 00:00 0\n" - "1be4139e4000-1be4139e5000 ---p 00000000 00:00 0\n"; - const std::string kExpectedOutput = - "[{" - "\"current_allocs\": 357, " - "\"current_bytes\": 55227, " - "\"trace\": \"\"},\n" - "{\"current_allocs\": 95, " - "\"current_bytes\": 40940, " - "\"trace\": \"\"},\n" - "{\"current_allocs\": 77, " - "\"current_bytes\": 32546, " - "\"trace\": \"null null \"" - "}]\n"; - std::string output; - AppendHeapProfileAsTraceFormat(input, &output); - EXPECT_EQ(kExpectedOutput, output); -} - -} // namespace debug -} // namespace base diff --git a/base/debug/trace_event_unittest.cc b/base/debug/trace_event_unittest.cc deleted file mode 100644 index b5909845f2..0000000000 --- a/base/debug/trace_event_unittest.cc +++ /dev/null @@ -1,2024 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "base/debug/trace_event_unittest.h" - -#include - -#include "base/bind.h" -#include "base/command_line.h" -#include "base/debug/trace_event.h" -#include "base/json/json_reader.h" -#include "base/json/json_writer.h" -#include "base/memory/ref_counted_memory.h" -#include "base/memory/scoped_ptr.h" -#include "base/memory/singleton.h" -#include "base/process/process_handle.h" -#include "base/strings/stringprintf.h" -#include "base/synchronization/waitable_event.h" -#include "base/threading/platform_thread.h" -#include "base/threading/thread.h" -#include "base/values.h" -#include "testing/gmock/include/gmock/gmock.h" -#include "testing/gtest/include/gtest/gtest.h" - -using base::debug::HighResSleepForTraceTest; - -namespace base { -namespace debug { - -namespace { - -enum CompareOp { - IS_EQUAL, - IS_NOT_EQUAL, -}; - -struct JsonKeyValue { - const char* key; - const char* value; - CompareOp op; -}; - -const int kThreadId = 42; -const int kAsyncId = 5; -const char kAsyncIdStr[] = "0x5"; -const int kAsyncId2 = 6; -const char kAsyncId2Str[] = "0x6"; - -class TraceEventTestFixture : public testing::Test { - public: - void OnTraceDataCollected( - const scoped_refptr& events_str); - void OnTraceNotification(int notification) { - if (notification & TraceLog::EVENT_WATCH_NOTIFICATION) - ++event_watch_notification_; - notifications_received_ |= notification; - } - DictionaryValue* FindMatchingTraceEntry(const JsonKeyValue* key_values); - DictionaryValue* FindNamePhase(const char* name, const char* phase); - DictionaryValue* FindNamePhaseKeyValue(const char* name, - const char* phase, - const char* key, - const char* value); - bool FindMatchingValue(const char* key, - const char* value); - bool FindNonMatchingValue(const char* key, - const char* value); - void Clear() { - trace_parsed_.Clear(); - json_output_.json_output.clear(); - } - - void BeginTrace() { - BeginSpecificTrace("*"); - } - - void BeginSpecificTrace(const std::string& filter) { - event_watch_notification_ = 0; - notifications_received_ = 0; - TraceLog::GetInstance()->SetEnabled(CategoryFilter(filter), - TraceLog::RECORD_UNTIL_FULL); - } - - void EndTraceAndFlush() { - while (TraceLog::GetInstance()->IsEnabled()) - TraceLog::GetInstance()->SetDisabled(); - TraceLog::GetInstance()->Flush( - base::Bind(&TraceEventTestFixture::OnTraceDataCollected, - base::Unretained(this))); - } - - virtual void SetUp() OVERRIDE { - const char* name = PlatformThread::GetName(); - old_thread_name_ = name ? strdup(name) : NULL; - notifications_received_ = 0; - - TraceLog::DeleteForTesting(); - TraceLog* tracelog = TraceLog::GetInstance(); - ASSERT_TRUE(tracelog); - ASSERT_FALSE(tracelog->IsEnabled()); - tracelog->SetNotificationCallback( - base::Bind(&TraceEventTestFixture::OnTraceNotification, - base::Unretained(this))); - trace_buffer_.SetOutputCallback(json_output_.GetCallback()); - } - virtual void TearDown() OVERRIDE { - if (TraceLog::GetInstance()) - EXPECT_FALSE(TraceLog::GetInstance()->IsEnabled()); - PlatformThread::SetName(old_thread_name_ ? old_thread_name_ : ""); - free(old_thread_name_); - old_thread_name_ = NULL; - // We want our singleton torn down after each test. - TraceLog::DeleteForTesting(); - } - - char* old_thread_name_; - ListValue trace_parsed_; - base::debug::TraceResultBuffer trace_buffer_; - base::debug::TraceResultBuffer::SimpleOutput json_output_; - int event_watch_notification_; - int notifications_received_; - - private: - // We want our singleton torn down after each test. - ShadowingAtExitManager at_exit_manager_; - Lock lock_; -}; - -void TraceEventTestFixture::OnTraceDataCollected( - const scoped_refptr& events_str) { - AutoLock lock(lock_); - json_output_.json_output.clear(); - trace_buffer_.Start(); - trace_buffer_.AddFragment(events_str->data()); - trace_buffer_.Finish(); - - scoped_ptr root; - root.reset(base::JSONReader::Read(json_output_.json_output, - JSON_PARSE_RFC | JSON_DETACHABLE_CHILDREN)); - - if (!root.get()) { - LOG(ERROR) << json_output_.json_output; - } - - ListValue* root_list = NULL; - ASSERT_TRUE(root.get()); - ASSERT_TRUE(root->GetAsList(&root_list)); - - // Move items into our aggregate collection - while (root_list->GetSize()) { - scoped_ptr item; - root_list->Remove(0, &item); - trace_parsed_.Append(item.release()); - } -} - -static bool CompareJsonValues(const std::string& lhs, - const std::string& rhs, - CompareOp op) { - switch (op) { - case IS_EQUAL: - return lhs == rhs; - case IS_NOT_EQUAL: - return lhs != rhs; - default: - CHECK(0); - } - return false; -} - -static bool IsKeyValueInDict(const JsonKeyValue* key_value, - DictionaryValue* dict) { - Value* value = NULL; - std::string value_str; - if (dict->Get(key_value->key, &value) && - value->GetAsString(&value_str) && - CompareJsonValues(value_str, key_value->value, key_value->op)) - return true; - - // Recurse to test arguments - DictionaryValue* args_dict = NULL; - dict->GetDictionary("args", &args_dict); - if (args_dict) - return IsKeyValueInDict(key_value, args_dict); - - return false; -} - -static bool IsAllKeyValueInDict(const JsonKeyValue* key_values, - DictionaryValue* dict) { - // Scan all key_values, they must all be present and equal. - while (key_values && key_values->key) { - if (!IsKeyValueInDict(key_values, dict)) - return false; - ++key_values; - } - return true; -} - -DictionaryValue* TraceEventTestFixture::FindMatchingTraceEntry( - const JsonKeyValue* key_values) { - // Scan all items - size_t trace_parsed_count = trace_parsed_.GetSize(); - for (size_t i = 0; i < trace_parsed_count; i++) { - Value* value = NULL; - trace_parsed_.Get(i, &value); - if (!value || value->GetType() != Value::TYPE_DICTIONARY) - continue; - DictionaryValue* dict = static_cast(value); - - if (IsAllKeyValueInDict(key_values, dict)) - return dict; - } - return NULL; -} - -DictionaryValue* TraceEventTestFixture::FindNamePhase(const char* name, - const char* phase) { - JsonKeyValue key_values[] = { - {"name", name, IS_EQUAL}, - {"ph", phase, IS_EQUAL}, - {0, 0, IS_EQUAL} - }; - return FindMatchingTraceEntry(key_values); -} - -DictionaryValue* TraceEventTestFixture::FindNamePhaseKeyValue( - const char* name, - const char* phase, - const char* key, - const char* value) { - JsonKeyValue key_values[] = { - {"name", name, IS_EQUAL}, - {"ph", phase, IS_EQUAL}, - {key, value, IS_EQUAL}, - {0, 0, IS_EQUAL} - }; - return FindMatchingTraceEntry(key_values); -} - -bool TraceEventTestFixture::FindMatchingValue(const char* key, - const char* value) { - JsonKeyValue key_values[] = { - {key, value, IS_EQUAL}, - {0, 0, IS_EQUAL} - }; - return FindMatchingTraceEntry(key_values); -} - -bool TraceEventTestFixture::FindNonMatchingValue(const char* key, - const char* value) { - JsonKeyValue key_values[] = { - {key, value, IS_NOT_EQUAL}, - {0, 0, IS_EQUAL} - }; - return FindMatchingTraceEntry(key_values); -} - -bool IsStringInDict(const char* string_to_match, const DictionaryValue* dict) { - for (DictionaryValue::Iterator it(*dict); !it.IsAtEnd(); it.Advance()) { - if (it.key().find(string_to_match) != std::string::npos) - return true; - - std::string value_str; - it.value().GetAsString(&value_str); - if (value_str.find(string_to_match) != std::string::npos) - return true; - } - - // Recurse to test arguments - const DictionaryValue* args_dict = NULL; - dict->GetDictionary("args", &args_dict); - if (args_dict) - return IsStringInDict(string_to_match, args_dict); - - return false; -} - -const DictionaryValue* FindTraceEntry( - const ListValue& trace_parsed, - const char* string_to_match, - const DictionaryValue* match_after_this_item = NULL) { - // Scan all items - size_t trace_parsed_count = trace_parsed.GetSize(); - for (size_t i = 0; i < trace_parsed_count; i++) { - const Value* value = NULL; - trace_parsed.Get(i, &value); - if (match_after_this_item) { - if (value == match_after_this_item) - match_after_this_item = NULL; - continue; - } - if (!value || value->GetType() != Value::TYPE_DICTIONARY) - continue; - const DictionaryValue* dict = static_cast(value); - - if (IsStringInDict(string_to_match, dict)) - return dict; - } - return NULL; -} - -std::vector FindTraceEntries( - const ListValue& trace_parsed, - const char* string_to_match) { - std::vector hits; - size_t trace_parsed_count = trace_parsed.GetSize(); - for (size_t i = 0; i < trace_parsed_count; i++) { - const Value* value = NULL; - trace_parsed.Get(i, &value); - if (!value || value->GetType() != Value::TYPE_DICTIONARY) - continue; - const DictionaryValue* dict = static_cast(value); - - if (IsStringInDict(string_to_match, dict)) - hits.push_back(dict); - } - return hits; -} - -void TraceWithAllMacroVariants(WaitableEvent* task_complete_event) { - { - TRACE_EVENT_BEGIN_ETW("TRACE_EVENT_BEGIN_ETW call", 0x1122, "extrastring1"); - TRACE_EVENT_END_ETW("TRACE_EVENT_END_ETW call", 0x3344, "extrastring2"); - TRACE_EVENT_INSTANT_ETW("TRACE_EVENT_INSTANT_ETW call", - 0x5566, "extrastring3"); - - TRACE_EVENT0("all", "TRACE_EVENT0 call"); - TRACE_EVENT1("all", "TRACE_EVENT1 call", "name1", "value1"); - TRACE_EVENT2("all", "TRACE_EVENT2 call", - "name1", "\"value1\"", - "name2", "value\\2"); - - TRACE_EVENT_INSTANT0("all", "TRACE_EVENT_INSTANT0 call", - TRACE_EVENT_SCOPE_GLOBAL); - TRACE_EVENT_INSTANT1("all", "TRACE_EVENT_INSTANT1 call", - TRACE_EVENT_SCOPE_PROCESS, "name1", "value1"); - TRACE_EVENT_INSTANT2("all", "TRACE_EVENT_INSTANT2 call", - TRACE_EVENT_SCOPE_THREAD, - "name1", "value1", - "name2", "value2"); - - TRACE_EVENT_BEGIN0("all", "TRACE_EVENT_BEGIN0 call"); - TRACE_EVENT_BEGIN1("all", "TRACE_EVENT_BEGIN1 call", "name1", "value1"); - TRACE_EVENT_BEGIN2("all", "TRACE_EVENT_BEGIN2 call", - "name1", "value1", - "name2", "value2"); - - TRACE_EVENT_END0("all", "TRACE_EVENT_END0 call"); - TRACE_EVENT_END1("all", "TRACE_EVENT_END1 call", "name1", "value1"); - TRACE_EVENT_END2("all", "TRACE_EVENT_END2 call", - "name1", "value1", - "name2", "value2"); - - TRACE_EVENT_ASYNC_BEGIN0("all", "TRACE_EVENT_ASYNC_BEGIN0 call", kAsyncId); - TRACE_EVENT_ASYNC_BEGIN1("all", "TRACE_EVENT_ASYNC_BEGIN1 call", kAsyncId, - "name1", "value1"); - TRACE_EVENT_ASYNC_BEGIN2("all", "TRACE_EVENT_ASYNC_BEGIN2 call", kAsyncId, - "name1", "value1", - "name2", "value2"); - - TRACE_EVENT_ASYNC_STEP0("all", "TRACE_EVENT_ASYNC_STEP0 call", - 5, "step1"); - TRACE_EVENT_ASYNC_STEP1("all", "TRACE_EVENT_ASYNC_STEP1 call", - 5, "step2", "name1", "value1"); - - TRACE_EVENT_ASYNC_END0("all", "TRACE_EVENT_ASYNC_END0 call", kAsyncId); - TRACE_EVENT_ASYNC_END1("all", "TRACE_EVENT_ASYNC_END1 call", kAsyncId, - "name1", "value1"); - TRACE_EVENT_ASYNC_END2("all", "TRACE_EVENT_ASYNC_END2 call", kAsyncId, - "name1", "value1", - "name2", "value2"); - - TRACE_EVENT_BEGIN_ETW("TRACE_EVENT_BEGIN_ETW0 call", kAsyncId, NULL); - TRACE_EVENT_BEGIN_ETW("TRACE_EVENT_BEGIN_ETW1 call", kAsyncId, "value"); - TRACE_EVENT_END_ETW("TRACE_EVENT_END_ETW0 call", kAsyncId, NULL); - TRACE_EVENT_END_ETW("TRACE_EVENT_END_ETW1 call", kAsyncId, "value"); - TRACE_EVENT_INSTANT_ETW("TRACE_EVENT_INSTANT_ETW0 call", kAsyncId, NULL); - TRACE_EVENT_INSTANT_ETW("TRACE_EVENT_INSTANT_ETW1 call", kAsyncId, "value"); - - TRACE_COUNTER1("all", "TRACE_COUNTER1 call", 31415); - TRACE_COUNTER2("all", "TRACE_COUNTER2 call", - "a", 30000, - "b", 1415); - - TRACE_COUNTER_ID1("all", "TRACE_COUNTER_ID1 call", 0x319009, 31415); - TRACE_COUNTER_ID2("all", "TRACE_COUNTER_ID2 call", 0x319009, - "a", 30000, "b", 1415); - - TRACE_EVENT_COPY_BEGIN_WITH_ID_TID_AND_TIMESTAMP0("all", - "TRACE_EVENT_COPY_BEGIN_WITH_ID_TID_AND_TIMESTAMP0 call", - kAsyncId, kThreadId, 12345); - TRACE_EVENT_COPY_END_WITH_ID_TID_AND_TIMESTAMP0("all", - "TRACE_EVENT_COPY_END_WITH_ID_TID_AND_TIMESTAMP0 call", - kAsyncId, kThreadId, 23456); - - TRACE_EVENT_BEGIN_WITH_ID_TID_AND_TIMESTAMP0("all", - "TRACE_EVENT_BEGIN_WITH_ID_TID_AND_TIMESTAMP0 call", - kAsyncId2, kThreadId, 34567); - TRACE_EVENT_END_WITH_ID_TID_AND_TIMESTAMP0("all", - "TRACE_EVENT_END_WITH_ID_TID_AND_TIMESTAMP0 call", - kAsyncId2, kThreadId, 45678); - - TRACE_EVENT_OBJECT_CREATED_WITH_ID("all", "tracked object 1", 0x42); - TRACE_EVENT_OBJECT_SNAPSHOT_WITH_ID( - "all", "tracked object 1", 0x42, "hello"); - TRACE_EVENT_OBJECT_DELETED_WITH_ID("all", "tracked object 1", 0x42); - - TraceScopedTrackableObject trackable("all", "tracked object 2", - 0x2128506); - trackable.snapshot("world"); - } // Scope close causes TRACE_EVENT0 etc to send their END events. - - if (task_complete_event) - task_complete_event->Signal(); -} - -void ValidateAllTraceMacrosCreatedData(const ListValue& trace_parsed) { - const DictionaryValue* item = NULL; - -#define EXPECT_FIND_(string) \ - EXPECT_TRUE((item = FindTraceEntry(trace_parsed, string))); -#define EXPECT_NOT_FIND_(string) \ - EXPECT_FALSE((item = FindTraceEntry(trace_parsed, string))); -#define EXPECT_SUB_FIND_(string) \ - if (item) EXPECT_TRUE((IsStringInDict(string, item))); - - EXPECT_FIND_("ETW Trace Event"); - EXPECT_FIND_("all"); - EXPECT_FIND_("TRACE_EVENT_BEGIN_ETW call"); - { - std::string str_val; - EXPECT_TRUE(item && item->GetString("args.id", &str_val)); - EXPECT_STREQ("0x1122", str_val.c_str()); - } - EXPECT_SUB_FIND_("extrastring1"); - EXPECT_FIND_("TRACE_EVENT_END_ETW call"); - EXPECT_FIND_("TRACE_EVENT_INSTANT_ETW call"); - EXPECT_FIND_("TRACE_EVENT0 call"); - { - std::string ph_begin; - std::string ph_end; - EXPECT_TRUE((item = FindTraceEntry(trace_parsed, "TRACE_EVENT0 call"))); - EXPECT_TRUE((item && item->GetString("ph", &ph_begin))); - EXPECT_TRUE((item = FindTraceEntry(trace_parsed, "TRACE_EVENT0 call", - item))); - EXPECT_TRUE((item && item->GetString("ph", &ph_end))); - EXPECT_EQ("B", ph_begin); - EXPECT_EQ("E", ph_end); - } - EXPECT_FIND_("TRACE_EVENT1 call"); - EXPECT_SUB_FIND_("name1"); - EXPECT_SUB_FIND_("value1"); - EXPECT_FIND_("TRACE_EVENT2 call"); - EXPECT_SUB_FIND_("name1"); - EXPECT_SUB_FIND_("\"value1\""); - EXPECT_SUB_FIND_("name2"); - EXPECT_SUB_FIND_("value\\2"); - - EXPECT_FIND_("TRACE_EVENT_INSTANT0 call"); - { - std::string scope; - EXPECT_TRUE((item && item->GetString("s", &scope))); - EXPECT_EQ("g", scope); - } - EXPECT_FIND_("TRACE_EVENT_INSTANT1 call"); - { - std::string scope; - EXPECT_TRUE((item && item->GetString("s", &scope))); - EXPECT_EQ("p", scope); - } - EXPECT_SUB_FIND_("name1"); - EXPECT_SUB_FIND_("value1"); - EXPECT_FIND_("TRACE_EVENT_INSTANT2 call"); - { - std::string scope; - EXPECT_TRUE((item && item->GetString("s", &scope))); - EXPECT_EQ("t", scope); - } - EXPECT_SUB_FIND_("name1"); - EXPECT_SUB_FIND_("value1"); - EXPECT_SUB_FIND_("name2"); - EXPECT_SUB_FIND_("value2"); - - EXPECT_FIND_("TRACE_EVENT_BEGIN0 call"); - EXPECT_FIND_("TRACE_EVENT_BEGIN1 call"); - EXPECT_SUB_FIND_("name1"); - EXPECT_SUB_FIND_("value1"); - EXPECT_FIND_("TRACE_EVENT_BEGIN2 call"); - EXPECT_SUB_FIND_("name1"); - EXPECT_SUB_FIND_("value1"); - EXPECT_SUB_FIND_("name2"); - EXPECT_SUB_FIND_("value2"); - - EXPECT_FIND_("TRACE_EVENT_END0 call"); - EXPECT_FIND_("TRACE_EVENT_END1 call"); - EXPECT_SUB_FIND_("name1"); - EXPECT_SUB_FIND_("value1"); - EXPECT_FIND_("TRACE_EVENT_END2 call"); - EXPECT_SUB_FIND_("name1"); - EXPECT_SUB_FIND_("value1"); - EXPECT_SUB_FIND_("name2"); - EXPECT_SUB_FIND_("value2"); - - EXPECT_FIND_("TRACE_EVENT_ASYNC_BEGIN0 call"); - EXPECT_SUB_FIND_("id"); - EXPECT_SUB_FIND_(kAsyncIdStr); - EXPECT_FIND_("TRACE_EVENT_ASYNC_BEGIN1 call"); - EXPECT_SUB_FIND_("id"); - EXPECT_SUB_FIND_(kAsyncIdStr); - EXPECT_SUB_FIND_("name1"); - EXPECT_SUB_FIND_("value1"); - EXPECT_FIND_("TRACE_EVENT_ASYNC_BEGIN2 call"); - EXPECT_SUB_FIND_("id"); - EXPECT_SUB_FIND_(kAsyncIdStr); - EXPECT_SUB_FIND_("name1"); - EXPECT_SUB_FIND_("value1"); - EXPECT_SUB_FIND_("name2"); - EXPECT_SUB_FIND_("value2"); - - EXPECT_FIND_("TRACE_EVENT_ASYNC_STEP0 call"); - EXPECT_SUB_FIND_("id"); - EXPECT_SUB_FIND_(kAsyncIdStr); - EXPECT_SUB_FIND_("step1"); - EXPECT_FIND_("TRACE_EVENT_ASYNC_STEP1 call"); - EXPECT_SUB_FIND_("id"); - EXPECT_SUB_FIND_(kAsyncIdStr); - EXPECT_SUB_FIND_("step2"); - EXPECT_SUB_FIND_("name1"); - EXPECT_SUB_FIND_("value1"); - - EXPECT_FIND_("TRACE_EVENT_ASYNC_END0 call"); - EXPECT_SUB_FIND_("id"); - EXPECT_SUB_FIND_(kAsyncIdStr); - EXPECT_FIND_("TRACE_EVENT_ASYNC_END1 call"); - EXPECT_SUB_FIND_("id"); - EXPECT_SUB_FIND_(kAsyncIdStr); - EXPECT_SUB_FIND_("name1"); - EXPECT_SUB_FIND_("value1"); - EXPECT_FIND_("TRACE_EVENT_ASYNC_END2 call"); - EXPECT_SUB_FIND_("id"); - EXPECT_SUB_FIND_(kAsyncIdStr); - EXPECT_SUB_FIND_("name1"); - EXPECT_SUB_FIND_("value1"); - EXPECT_SUB_FIND_("name2"); - EXPECT_SUB_FIND_("value2"); - - EXPECT_FIND_("TRACE_EVENT_BEGIN_ETW0 call"); - EXPECT_SUB_FIND_("id"); - EXPECT_SUB_FIND_(kAsyncIdStr); - EXPECT_SUB_FIND_("extra"); - EXPECT_SUB_FIND_("NULL"); - EXPECT_FIND_("TRACE_EVENT_BEGIN_ETW1 call"); - EXPECT_SUB_FIND_("id"); - EXPECT_SUB_FIND_(kAsyncIdStr); - EXPECT_SUB_FIND_("extra"); - EXPECT_SUB_FIND_("value"); - EXPECT_FIND_("TRACE_EVENT_END_ETW0 call"); - EXPECT_SUB_FIND_("id"); - EXPECT_SUB_FIND_(kAsyncIdStr); - EXPECT_SUB_FIND_("extra"); - EXPECT_SUB_FIND_("NULL"); - EXPECT_FIND_("TRACE_EVENT_END_ETW1 call"); - EXPECT_SUB_FIND_("id"); - EXPECT_SUB_FIND_(kAsyncIdStr); - EXPECT_SUB_FIND_("extra"); - EXPECT_SUB_FIND_("value"); - EXPECT_FIND_("TRACE_EVENT_INSTANT_ETW0 call"); - EXPECT_SUB_FIND_("id"); - EXPECT_SUB_FIND_(kAsyncIdStr); - EXPECT_SUB_FIND_("extra"); - EXPECT_SUB_FIND_("NULL"); - EXPECT_FIND_("TRACE_EVENT_INSTANT_ETW1 call"); - EXPECT_SUB_FIND_("id"); - EXPECT_SUB_FIND_(kAsyncIdStr); - EXPECT_SUB_FIND_("extra"); - EXPECT_SUB_FIND_("value"); - - EXPECT_FIND_("TRACE_COUNTER1 call"); - { - std::string ph; - EXPECT_TRUE((item && item->GetString("ph", &ph))); - EXPECT_EQ("C", ph); - - int value; - EXPECT_TRUE((item && item->GetInteger("args.value", &value))); - EXPECT_EQ(31415, value); - } - - EXPECT_FIND_("TRACE_COUNTER2 call"); - { - std::string ph; - EXPECT_TRUE((item && item->GetString("ph", &ph))); - EXPECT_EQ("C", ph); - - int value; - EXPECT_TRUE((item && item->GetInteger("args.a", &value))); - EXPECT_EQ(30000, value); - - EXPECT_TRUE((item && item->GetInteger("args.b", &value))); - EXPECT_EQ(1415, value); - } - - EXPECT_FIND_("TRACE_COUNTER_ID1 call"); - { - std::string id; - EXPECT_TRUE((item && item->GetString("id", &id))); - EXPECT_EQ("0x319009", id); - - std::string ph; - EXPECT_TRUE((item && item->GetString("ph", &ph))); - EXPECT_EQ("C", ph); - - int value; - EXPECT_TRUE((item && item->GetInteger("args.value", &value))); - EXPECT_EQ(31415, value); - } - - EXPECT_FIND_("TRACE_COUNTER_ID2 call"); - { - std::string id; - EXPECT_TRUE((item && item->GetString("id", &id))); - EXPECT_EQ("0x319009", id); - - std::string ph; - EXPECT_TRUE((item && item->GetString("ph", &ph))); - EXPECT_EQ("C", ph); - - int value; - EXPECT_TRUE((item && item->GetInteger("args.a", &value))); - EXPECT_EQ(30000, value); - - EXPECT_TRUE((item && item->GetInteger("args.b", &value))); - EXPECT_EQ(1415, value); - } - - EXPECT_FIND_("TRACE_EVENT_COPY_BEGIN_WITH_ID_TID_AND_TIMESTAMP0 call"); - { - int val; - EXPECT_TRUE((item && item->GetInteger("ts", &val))); - EXPECT_EQ(12345, val); - EXPECT_TRUE((item && item->GetInteger("tid", &val))); - EXPECT_EQ(kThreadId, val); - std::string id; - EXPECT_TRUE((item && item->GetString("id", &id))); - EXPECT_EQ(kAsyncIdStr, id); - } - - EXPECT_FIND_("TRACE_EVENT_COPY_END_WITH_ID_TID_AND_TIMESTAMP0 call"); - { - int val; - EXPECT_TRUE((item && item->GetInteger("ts", &val))); - EXPECT_EQ(23456, val); - EXPECT_TRUE((item && item->GetInteger("tid", &val))); - EXPECT_EQ(kThreadId, val); - std::string id; - EXPECT_TRUE((item && item->GetString("id", &id))); - EXPECT_EQ(kAsyncIdStr, id); - } - - EXPECT_FIND_("TRACE_EVENT_BEGIN_WITH_ID_TID_AND_TIMESTAMP0 call"); - { - int val; - EXPECT_TRUE((item && item->GetInteger("ts", &val))); - EXPECT_EQ(34567, val); - EXPECT_TRUE((item && item->GetInteger("tid", &val))); - EXPECT_EQ(kThreadId, val); - std::string id; - EXPECT_TRUE((item && item->GetString("id", &id))); - EXPECT_EQ(kAsyncId2Str, id); - } - - EXPECT_FIND_("TRACE_EVENT_END_WITH_ID_TID_AND_TIMESTAMP0 call"); - { - int val; - EXPECT_TRUE((item && item->GetInteger("ts", &val))); - EXPECT_EQ(45678, val); - EXPECT_TRUE((item && item->GetInteger("tid", &val))); - EXPECT_EQ(kThreadId, val); - std::string id; - EXPECT_TRUE((item && item->GetString("id", &id))); - EXPECT_EQ(kAsyncId2Str, id); - } - - EXPECT_FIND_("tracked object 1"); - { - std::string phase; - std::string id; - std::string snapshot; - - EXPECT_TRUE((item && item->GetString("ph", &phase))); - EXPECT_EQ("N", phase); - EXPECT_TRUE((item && item->GetString("id", &id))); - EXPECT_EQ("0x42", id); - - item = FindTraceEntry(trace_parsed, "tracked object 1", item); - EXPECT_TRUE(item); - EXPECT_TRUE(item && item->GetString("ph", &phase)); - EXPECT_EQ("O", phase); - EXPECT_TRUE(item && item->GetString("id", &id)); - EXPECT_EQ("0x42", id); - EXPECT_TRUE(item && item->GetString("args.snapshot", &snapshot)); - EXPECT_EQ("hello", snapshot); - - item = FindTraceEntry(trace_parsed, "tracked object 1", item); - EXPECT_TRUE(item); - EXPECT_TRUE(item && item->GetString("ph", &phase)); - EXPECT_EQ("D", phase); - EXPECT_TRUE(item && item->GetString("id", &id)); - EXPECT_EQ("0x42", id); - } - - EXPECT_FIND_("tracked object 2"); - { - std::string phase; - std::string id; - std::string snapshot; - - EXPECT_TRUE(item && item->GetString("ph", &phase)); - EXPECT_EQ("N", phase); - EXPECT_TRUE(item && item->GetString("id", &id)); - EXPECT_EQ("0x2128506", id); - - item = FindTraceEntry(trace_parsed, "tracked object 2", item); - EXPECT_TRUE(item); - EXPECT_TRUE(item && item->GetString("ph", &phase)); - EXPECT_EQ("O", phase); - EXPECT_TRUE(item && item->GetString("id", &id)); - EXPECT_EQ("0x2128506", id); - EXPECT_TRUE(item && item->GetString("args.snapshot", &snapshot)); - EXPECT_EQ("world", snapshot); - - item = FindTraceEntry(trace_parsed, "tracked object 2", item); - EXPECT_TRUE(item); - EXPECT_TRUE(item && item->GetString("ph", &phase)); - EXPECT_EQ("D", phase); - EXPECT_TRUE(item && item->GetString("id", &id)); - EXPECT_EQ("0x2128506", id); - } -} - -void TraceManyInstantEvents(int thread_id, int num_events, - WaitableEvent* task_complete_event) { - for (int i = 0; i < num_events; i++) { - TRACE_EVENT_INSTANT2("all", "multi thread event", - TRACE_EVENT_SCOPE_THREAD, - "thread", thread_id, - "event", i); - } - - if (task_complete_event) - task_complete_event->Signal(); -} - -void ValidateInstantEventPresentOnEveryThread(const ListValue& trace_parsed, - int num_threads, - int num_events) { - std::map > results; - - size_t trace_parsed_count = trace_parsed.GetSize(); - for (size_t i = 0; i < trace_parsed_count; i++) { - const Value* value = NULL; - trace_parsed.Get(i, &value); - if (!value || value->GetType() != Value::TYPE_DICTIONARY) - continue; - const DictionaryValue* dict = static_cast(value); - std::string name; - dict->GetString("name", &name); - if (name != "multi thread event") - continue; - - int thread = 0; - int event = 0; - EXPECT_TRUE(dict->GetInteger("args.thread", &thread)); - EXPECT_TRUE(dict->GetInteger("args.event", &event)); - results[thread][event] = true; - } - - EXPECT_FALSE(results[-1][-1]); - for (int thread = 0; thread < num_threads; thread++) { - for (int event = 0; event < num_events; event++) { - EXPECT_TRUE(results[thread][event]); - } - } -} - -void TraceCallsWithCachedCategoryPointersPointers(const char* name_str) { - TRACE_EVENT0("category name1", name_str); - TRACE_EVENT_INSTANT0("category name2", name_str, TRACE_EVENT_SCOPE_THREAD); - TRACE_EVENT_BEGIN0("category name3", name_str); - TRACE_EVENT_END0("category name4", name_str); -} - -} // namespace - -void HighResSleepForTraceTest(base::TimeDelta elapsed) { - base::TimeTicks end_time = base::TimeTicks::HighResNow() + elapsed; - do { - base::PlatformThread::Sleep(base::TimeDelta::FromMilliseconds(1)); - } while (base::TimeTicks::HighResNow() < end_time); -} - -// Simple Test for emitting data and validating it was received. -TEST_F(TraceEventTestFixture, DataCaptured) { - TraceLog::GetInstance()->SetEnabled(CategoryFilter("*"), - TraceLog::RECORD_UNTIL_FULL); - - TraceWithAllMacroVariants(NULL); - - EndTraceAndFlush(); - - ValidateAllTraceMacrosCreatedData(trace_parsed_); -} - -class MockEnabledStateChangedObserver : - public base::debug::TraceLog::EnabledStateObserver { - public: - MOCK_METHOD0(OnTraceLogEnabled, void()); - MOCK_METHOD0(OnTraceLogDisabled, void()); -}; - -TEST_F(TraceEventTestFixture, EnabledObserverFiresOnEnable) { - MockEnabledStateChangedObserver observer; - TraceLog::GetInstance()->AddEnabledStateObserver(&observer); - - EXPECT_CALL(observer, OnTraceLogEnabled()) - .Times(1); - TraceLog::GetInstance()->SetEnabled(CategoryFilter("*"), - TraceLog::RECORD_UNTIL_FULL); - testing::Mock::VerifyAndClear(&observer); - EXPECT_TRUE(TraceLog::GetInstance()->IsEnabled()); - - // Cleanup. - TraceLog::GetInstance()->RemoveEnabledStateObserver(&observer); - TraceLog::GetInstance()->SetDisabled(); -} - -TEST_F(TraceEventTestFixture, EnabledObserverDoesntFireOnSecondEnable) { - TraceLog::GetInstance()->SetEnabled(CategoryFilter("*"), - TraceLog::RECORD_UNTIL_FULL); - - testing::StrictMock observer; - TraceLog::GetInstance()->AddEnabledStateObserver(&observer); - - EXPECT_CALL(observer, OnTraceLogEnabled()) - .Times(0); - EXPECT_CALL(observer, OnTraceLogDisabled()) - .Times(0); - TraceLog::GetInstance()->SetEnabled(CategoryFilter("*"), - TraceLog::RECORD_UNTIL_FULL); - testing::Mock::VerifyAndClear(&observer); - EXPECT_TRUE(TraceLog::GetInstance()->IsEnabled()); - - // Cleanup. - TraceLog::GetInstance()->RemoveEnabledStateObserver(&observer); - TraceLog::GetInstance()->SetDisabled(); - TraceLog::GetInstance()->SetDisabled(); -} - -TEST_F(TraceEventTestFixture, EnabledObserverDoesntFireOnNestedDisable) { - CategoryFilter cf_inc_all("*"); - TraceLog::GetInstance()->SetEnabled(cf_inc_all, TraceLog::RECORD_UNTIL_FULL); - TraceLog::GetInstance()->SetEnabled(cf_inc_all, TraceLog::RECORD_UNTIL_FULL); - - testing::StrictMock observer; - TraceLog::GetInstance()->AddEnabledStateObserver(&observer); - - EXPECT_CALL(observer, OnTraceLogEnabled()) - .Times(0); - EXPECT_CALL(observer, OnTraceLogDisabled()) - .Times(0); - TraceLog::GetInstance()->SetDisabled(); - testing::Mock::VerifyAndClear(&observer); - - // Cleanup. - TraceLog::GetInstance()->RemoveEnabledStateObserver(&observer); - TraceLog::GetInstance()->SetDisabled(); -} - -TEST_F(TraceEventTestFixture, EnabledObserverFiresOnDisable) { - TraceLog::GetInstance()->SetEnabled(CategoryFilter("*"), - TraceLog::RECORD_UNTIL_FULL); - - MockEnabledStateChangedObserver observer; - TraceLog::GetInstance()->AddEnabledStateObserver(&observer); - - EXPECT_CALL(observer, OnTraceLogDisabled()) - .Times(1); - TraceLog::GetInstance()->SetDisabled(); - testing::Mock::VerifyAndClear(&observer); - - // Cleanup. - TraceLog::GetInstance()->RemoveEnabledStateObserver(&observer); -} - -// Tests the IsEnabled() state of TraceLog changes before callbacks. -class AfterStateChangeEnabledStateObserver - : public base::debug::TraceLog::EnabledStateObserver { - public: - AfterStateChangeEnabledStateObserver() {} - virtual ~AfterStateChangeEnabledStateObserver() {} - - // base::debug::TraceLog::EnabledStateObserver overrides: - virtual void OnTraceLogEnabled() OVERRIDE { - EXPECT_TRUE(TraceLog::GetInstance()->IsEnabled()); - } - - virtual void OnTraceLogDisabled() OVERRIDE { - EXPECT_FALSE(TraceLog::GetInstance()->IsEnabled()); - } -}; - -TEST_F(TraceEventTestFixture, ObserversFireAfterStateChange) { - AfterStateChangeEnabledStateObserver observer; - TraceLog::GetInstance()->AddEnabledStateObserver(&observer); - - TraceLog::GetInstance()->SetEnabled(CategoryFilter("*"), - TraceLog::RECORD_UNTIL_FULL); - EXPECT_TRUE(TraceLog::GetInstance()->IsEnabled()); - - TraceLog::GetInstance()->SetDisabled(); - EXPECT_FALSE(TraceLog::GetInstance()->IsEnabled()); - - TraceLog::GetInstance()->RemoveEnabledStateObserver(&observer); -} - -// Tests that a state observer can remove itself during a callback. -class SelfRemovingEnabledStateObserver - : public base::debug::TraceLog::EnabledStateObserver { - public: - SelfRemovingEnabledStateObserver() {} - virtual ~SelfRemovingEnabledStateObserver() {} - - // base::debug::TraceLog::EnabledStateObserver overrides: - virtual void OnTraceLogEnabled() OVERRIDE {} - - virtual void OnTraceLogDisabled() OVERRIDE { - TraceLog::GetInstance()->RemoveEnabledStateObserver(this); - } -}; - -TEST_F(TraceEventTestFixture, SelfRemovingObserver) { - ASSERT_EQ(0u, TraceLog::GetInstance()->GetObserverCountForTest()); - - SelfRemovingEnabledStateObserver observer; - TraceLog::GetInstance()->AddEnabledStateObserver(&observer); - EXPECT_EQ(1u, TraceLog::GetInstance()->GetObserverCountForTest()); - - TraceLog::GetInstance()->SetEnabled(CategoryFilter("*"), - TraceLog::RECORD_UNTIL_FULL); - TraceLog::GetInstance()->SetDisabled(); - // The observer removed itself on disable. - EXPECT_EQ(0u, TraceLog::GetInstance()->GetObserverCountForTest()); -} - -bool IsNewTrace() { - bool is_new_trace; - TRACE_EVENT_IS_NEW_TRACE(&is_new_trace); - return is_new_trace; -} - -TEST_F(TraceEventTestFixture, NewTraceRecording) { - ASSERT_FALSE(IsNewTrace()); - TraceLog::GetInstance()->SetEnabled(CategoryFilter("*"), - TraceLog::RECORD_UNTIL_FULL); - // First call to IsNewTrace() should succeed. But, the second shouldn't. - ASSERT_TRUE(IsNewTrace()); - ASSERT_FALSE(IsNewTrace()); - EndTraceAndFlush(); - - // IsNewTrace() should definitely be false now. - ASSERT_FALSE(IsNewTrace()); - - // Start another trace. IsNewTrace() should become true again, briefly, as - // before. - TraceLog::GetInstance()->SetEnabled(CategoryFilter("*"), - TraceLog::RECORD_UNTIL_FULL); - ASSERT_TRUE(IsNewTrace()); - ASSERT_FALSE(IsNewTrace()); - - // Cleanup. - EndTraceAndFlush(); -} - - -// Test that categories work. -TEST_F(TraceEventTestFixture, Categories) { - // Test that categories that are used can be retrieved whether trace was - // enabled or disabled when the trace event was encountered. - TRACE_EVENT_INSTANT0("c1", "name", TRACE_EVENT_SCOPE_THREAD); - TRACE_EVENT_INSTANT0("c2", "name", TRACE_EVENT_SCOPE_THREAD); - BeginTrace(); - TRACE_EVENT_INSTANT0("c3", "name", TRACE_EVENT_SCOPE_THREAD); - TRACE_EVENT_INSTANT0("c4", "name", TRACE_EVENT_SCOPE_THREAD); - // Category groups containing more than one category. - TRACE_EVENT_INSTANT0("c5,c6", "name", TRACE_EVENT_SCOPE_THREAD); - TRACE_EVENT_INSTANT0("c7,c8", "name", TRACE_EVENT_SCOPE_THREAD); - TRACE_EVENT_INSTANT0(TRACE_DISABLED_BY_DEFAULT("c9"), "name", - TRACE_EVENT_SCOPE_THREAD); - - EndTraceAndFlush(); - std::vector cat_groups; - TraceLog::GetInstance()->GetKnownCategoryGroups(&cat_groups); - EXPECT_TRUE(std::find(cat_groups.begin(), - cat_groups.end(), "c1") != cat_groups.end()); - EXPECT_TRUE(std::find(cat_groups.begin(), - cat_groups.end(), "c2") != cat_groups.end()); - EXPECT_TRUE(std::find(cat_groups.begin(), - cat_groups.end(), "c3") != cat_groups.end()); - EXPECT_TRUE(std::find(cat_groups.begin(), - cat_groups.end(), "c4") != cat_groups.end()); - EXPECT_TRUE(std::find(cat_groups.begin(), - cat_groups.end(), "c5,c6") != cat_groups.end()); - EXPECT_TRUE(std::find(cat_groups.begin(), - cat_groups.end(), "c7,c8") != cat_groups.end()); - EXPECT_TRUE(std::find(cat_groups.begin(), - cat_groups.end(), - "disabled-by-default-c9") != cat_groups.end()); - // Make sure metadata isn't returned. - EXPECT_TRUE(std::find(cat_groups.begin(), - cat_groups.end(), "__metadata") == cat_groups.end()); - - const std::vector empty_categories; - std::vector included_categories; - std::vector excluded_categories; - - // Test that category filtering works. - - // Include nonexistent category -> no events - Clear(); - included_categories.clear(); - TraceLog::GetInstance()->SetEnabled(CategoryFilter("not_found823564786"), - TraceLog::RECORD_UNTIL_FULL); - TRACE_EVENT_INSTANT0("cat1", "name", TRACE_EVENT_SCOPE_THREAD); - TRACE_EVENT_INSTANT0("cat2", "name", TRACE_EVENT_SCOPE_THREAD); - EndTraceAndFlush(); - EXPECT_TRUE(trace_parsed_.empty()); - - // Include existent category -> only events of that category - Clear(); - included_categories.clear(); - TraceLog::GetInstance()->SetEnabled(CategoryFilter("inc"), - TraceLog::RECORD_UNTIL_FULL); - TRACE_EVENT_INSTANT0("inc", "name", TRACE_EVENT_SCOPE_THREAD); - TRACE_EVENT_INSTANT0("inc2", "name", TRACE_EVENT_SCOPE_THREAD); - EndTraceAndFlush(); - EXPECT_TRUE(FindMatchingValue("cat", "inc")); - EXPECT_FALSE(FindNonMatchingValue("cat", "inc")); - - // Include existent wildcard -> all categories matching wildcard - Clear(); - included_categories.clear(); - TraceLog::GetInstance()->SetEnabled( - CategoryFilter("inc_wildcard_*,inc_wildchar_?_end"), - TraceLog::RECORD_UNTIL_FULL); - TRACE_EVENT_INSTANT0("inc_wildcard_abc", "included", - TRACE_EVENT_SCOPE_THREAD); - TRACE_EVENT_INSTANT0("inc_wildcard_", "included", TRACE_EVENT_SCOPE_THREAD); - TRACE_EVENT_INSTANT0("inc_wildchar_x_end", "included", - TRACE_EVENT_SCOPE_THREAD); - TRACE_EVENT_INSTANT0("inc_wildchar_bla_end", "not_inc", - TRACE_EVENT_SCOPE_THREAD); - TRACE_EVENT_INSTANT0("cat1", "not_inc", TRACE_EVENT_SCOPE_THREAD); - TRACE_EVENT_INSTANT0("cat2", "not_inc", TRACE_EVENT_SCOPE_THREAD); - TRACE_EVENT_INSTANT0("inc_wildcard_category,other_category", "included", - TRACE_EVENT_SCOPE_THREAD); - TRACE_EVENT_INSTANT0( - "non_included_category,inc_wildcard_category", "included", - TRACE_EVENT_SCOPE_THREAD); - EndTraceAndFlush(); - EXPECT_TRUE(FindMatchingValue("cat", "inc_wildcard_abc")); - EXPECT_TRUE(FindMatchingValue("cat", "inc_wildcard_")); - EXPECT_TRUE(FindMatchingValue("cat", "inc_wildchar_x_end")); - EXPECT_FALSE(FindMatchingValue("name", "not_inc")); - EXPECT_TRUE(FindMatchingValue("cat", "inc_wildcard_category,other_category")); - EXPECT_TRUE(FindMatchingValue("cat", - "non_included_category,inc_wildcard_category")); - - included_categories.clear(); - - // Exclude nonexistent category -> all events - Clear(); - TraceLog::GetInstance()->SetEnabled(CategoryFilter("-not_found823564786"), - TraceLog::RECORD_UNTIL_FULL); - TRACE_EVENT_INSTANT0("cat1", "name", TRACE_EVENT_SCOPE_THREAD); - TRACE_EVENT_INSTANT0("cat2", "name", TRACE_EVENT_SCOPE_THREAD); - TRACE_EVENT_INSTANT0("category1,category2", "name", TRACE_EVENT_SCOPE_THREAD); - EndTraceAndFlush(); - EXPECT_TRUE(FindMatchingValue("cat", "cat1")); - EXPECT_TRUE(FindMatchingValue("cat", "cat2")); - EXPECT_TRUE(FindMatchingValue("cat", "category1,category2")); - - // Exclude existent category -> only events of other categories - Clear(); - TraceLog::GetInstance()->SetEnabled(CategoryFilter("-inc"), - TraceLog::RECORD_UNTIL_FULL); - TRACE_EVENT_INSTANT0("inc", "name", TRACE_EVENT_SCOPE_THREAD); - TRACE_EVENT_INSTANT0("inc2", "name", TRACE_EVENT_SCOPE_THREAD); - TRACE_EVENT_INSTANT0("inc2,inc", "name", TRACE_EVENT_SCOPE_THREAD); - TRACE_EVENT_INSTANT0("inc,inc2", "name", TRACE_EVENT_SCOPE_THREAD); - EndTraceAndFlush(); - EXPECT_TRUE(FindMatchingValue("cat", "inc2")); - EXPECT_FALSE(FindMatchingValue("cat", "inc")); - EXPECT_FALSE(FindMatchingValue("cat", "inc2,inc")); - EXPECT_FALSE(FindMatchingValue("cat", "inc,inc2")); - - // Exclude existent wildcard -> all categories not matching wildcard - Clear(); - TraceLog::GetInstance()->SetEnabled( - CategoryFilter("-inc_wildcard_*,-inc_wildchar_?_end"), - TraceLog::RECORD_UNTIL_FULL); - TRACE_EVENT_INSTANT0("inc_wildcard_abc", "not_inc", - TRACE_EVENT_SCOPE_THREAD); - TRACE_EVENT_INSTANT0("inc_wildcard_", "not_inc", - TRACE_EVENT_SCOPE_THREAD); - TRACE_EVENT_INSTANT0("inc_wildchar_x_end", "not_inc", - TRACE_EVENT_SCOPE_THREAD); - TRACE_EVENT_INSTANT0("inc_wildchar_bla_end", "included", - TRACE_EVENT_SCOPE_THREAD); - TRACE_EVENT_INSTANT0("cat1", "included", TRACE_EVENT_SCOPE_THREAD); - TRACE_EVENT_INSTANT0("cat2", "included", TRACE_EVENT_SCOPE_THREAD); - EndTraceAndFlush(); - EXPECT_TRUE(FindMatchingValue("cat", "inc_wildchar_bla_end")); - EXPECT_TRUE(FindMatchingValue("cat", "cat1")); - EXPECT_TRUE(FindMatchingValue("cat", "cat2")); - EXPECT_FALSE(FindMatchingValue("name", "not_inc")); -} - - -// Test EVENT_WATCH_NOTIFICATION -TEST_F(TraceEventTestFixture, EventWatchNotification) { - // Basic one occurrence. - BeginTrace(); - TraceLog::GetInstance()->SetWatchEvent("cat", "event"); - TRACE_EVENT_INSTANT0("cat", "event", TRACE_EVENT_SCOPE_THREAD); - EndTraceAndFlush(); - EXPECT_EQ(event_watch_notification_, 1); - - // Basic one occurrence before Set. - BeginTrace(); - TRACE_EVENT_INSTANT0("cat", "event", TRACE_EVENT_SCOPE_THREAD); - TraceLog::GetInstance()->SetWatchEvent("cat", "event"); - EndTraceAndFlush(); - EXPECT_EQ(event_watch_notification_, 1); - - // Auto-reset after end trace. - BeginTrace(); - TraceLog::GetInstance()->SetWatchEvent("cat", "event"); - EndTraceAndFlush(); - BeginTrace(); - TRACE_EVENT_INSTANT0("cat", "event", TRACE_EVENT_SCOPE_THREAD); - EndTraceAndFlush(); - EXPECT_EQ(event_watch_notification_, 0); - - // Multiple occurrence. - BeginTrace(); - int num_occurrences = 5; - TraceLog::GetInstance()->SetWatchEvent("cat", "event"); - for (int i = 0; i < num_occurrences; ++i) - TRACE_EVENT_INSTANT0("cat", "event", TRACE_EVENT_SCOPE_THREAD); - EndTraceAndFlush(); - EXPECT_EQ(event_watch_notification_, num_occurrences); - - // Wrong category. - BeginTrace(); - TraceLog::GetInstance()->SetWatchEvent("cat", "event"); - TRACE_EVENT_INSTANT0("wrong_cat", "event", TRACE_EVENT_SCOPE_THREAD); - EndTraceAndFlush(); - EXPECT_EQ(event_watch_notification_, 0); - - // Wrong name. - BeginTrace(); - TraceLog::GetInstance()->SetWatchEvent("cat", "event"); - TRACE_EVENT_INSTANT0("cat", "wrong_event", TRACE_EVENT_SCOPE_THREAD); - EndTraceAndFlush(); - EXPECT_EQ(event_watch_notification_, 0); - - // Canceled. - BeginTrace(); - TraceLog::GetInstance()->SetWatchEvent("cat", "event"); - TraceLog::GetInstance()->CancelWatchEvent(); - TRACE_EVENT_INSTANT0("cat", "event", TRACE_EVENT_SCOPE_THREAD); - EndTraceAndFlush(); - EXPECT_EQ(event_watch_notification_, 0); -} - -// Test ASYNC_BEGIN/END events -TEST_F(TraceEventTestFixture, AsyncBeginEndEvents) { - BeginTrace(); - - unsigned long long id = 0xfeedbeeffeedbeefull; - TRACE_EVENT_ASYNC_BEGIN0( "cat", "name1", id); - TRACE_EVENT_ASYNC_STEP0( "cat", "name1", id, "step1"); - TRACE_EVENT_ASYNC_END0("cat", "name1", id); - TRACE_EVENT_BEGIN0( "cat", "name2"); - TRACE_EVENT_ASYNC_BEGIN0( "cat", "name3", 0); - - EndTraceAndFlush(); - - EXPECT_TRUE(FindNamePhase("name1", "S")); - EXPECT_TRUE(FindNamePhase("name1", "T")); - EXPECT_TRUE(FindNamePhase("name1", "F")); - - std::string id_str; - StringAppendF(&id_str, "0x%llx", id); - - EXPECT_TRUE(FindNamePhaseKeyValue("name1", "S", "id", id_str.c_str())); - EXPECT_TRUE(FindNamePhaseKeyValue("name1", "T", "id", id_str.c_str())); - EXPECT_TRUE(FindNamePhaseKeyValue("name1", "F", "id", id_str.c_str())); - EXPECT_TRUE(FindNamePhaseKeyValue("name3", "S", "id", "0x0")); - - // BEGIN events should not have id - EXPECT_FALSE(FindNamePhaseKeyValue("name2", "B", "id", "0")); -} - -// Test ASYNC_BEGIN/END events -TEST_F(TraceEventTestFixture, AsyncBeginEndPointerMangling) { - void* ptr = this; - - TraceLog::GetInstance()->SetProcessID(100); - BeginTrace(); - TRACE_EVENT_ASYNC_BEGIN0( "cat", "name1", ptr); - TRACE_EVENT_ASYNC_BEGIN0( "cat", "name2", ptr); - EndTraceAndFlush(); - - TraceLog::GetInstance()->SetProcessID(200); - BeginTrace(); - TRACE_EVENT_ASYNC_END0( "cat", "name1", ptr); - EndTraceAndFlush(); - - DictionaryValue* async_begin = FindNamePhase("name1", "S"); - DictionaryValue* async_begin2 = FindNamePhase("name2", "S"); - DictionaryValue* async_end = FindNamePhase("name1", "F"); - EXPECT_TRUE(async_begin); - EXPECT_TRUE(async_begin2); - EXPECT_TRUE(async_end); - - Value* value = NULL; - std::string async_begin_id_str; - std::string async_begin2_id_str; - std::string async_end_id_str; - ASSERT_TRUE(async_begin->Get("id", &value)); - ASSERT_TRUE(value->GetAsString(&async_begin_id_str)); - ASSERT_TRUE(async_begin2->Get("id", &value)); - ASSERT_TRUE(value->GetAsString(&async_begin2_id_str)); - ASSERT_TRUE(async_end->Get("id", &value)); - ASSERT_TRUE(value->GetAsString(&async_end_id_str)); - - EXPECT_STREQ(async_begin_id_str.c_str(), async_begin2_id_str.c_str()); - EXPECT_STRNE(async_begin_id_str.c_str(), async_end_id_str.c_str()); -} - -// Test that static strings are not copied. -TEST_F(TraceEventTestFixture, StaticStringVsString) { - TraceLog* tracer = TraceLog::GetInstance(); - // Make sure old events are flushed: - EndTraceAndFlush(); - EXPECT_EQ(0u, tracer->GetEventsSize()); - - { - BeginTrace(); - // Test that string arguments are copied. - TRACE_EVENT2("cat", "name1", - "arg1", std::string("argval"), "arg2", std::string("argval")); - // Test that static TRACE_STR_COPY string arguments are copied. - TRACE_EVENT2("cat", "name2", - "arg1", TRACE_STR_COPY("argval"), - "arg2", TRACE_STR_COPY("argval")); - size_t num_events = tracer->GetEventsSize(); - EXPECT_GT(num_events, 1u); - const TraceEvent& event1 = tracer->GetEventAt(num_events - 2); - const TraceEvent& event2 = tracer->GetEventAt(num_events - 1); - EXPECT_STREQ("name1", event1.name()); - EXPECT_STREQ("name2", event2.name()); - EXPECT_TRUE(event1.parameter_copy_storage() != NULL); - EXPECT_TRUE(event2.parameter_copy_storage() != NULL); - EXPECT_GT(event1.parameter_copy_storage()->size(), 0u); - EXPECT_GT(event2.parameter_copy_storage()->size(), 0u); - EndTraceAndFlush(); - } - - { - BeginTrace(); - // Test that static literal string arguments are not copied. - TRACE_EVENT2("cat", "name1", - "arg1", "argval", "arg2", "argval"); - // Test that static TRACE_STR_COPY NULL string arguments are not copied. - const char* str1 = NULL; - const char* str2 = NULL; - TRACE_EVENT2("cat", "name2", - "arg1", TRACE_STR_COPY(str1), - "arg2", TRACE_STR_COPY(str2)); - size_t num_events = tracer->GetEventsSize(); - EXPECT_GT(num_events, 1u); - const TraceEvent& event1 = tracer->GetEventAt(num_events - 2); - const TraceEvent& event2 = tracer->GetEventAt(num_events - 1); - EXPECT_STREQ("name1", event1.name()); - EXPECT_STREQ("name2", event2.name()); - EXPECT_TRUE(event1.parameter_copy_storage() == NULL); - EXPECT_TRUE(event2.parameter_copy_storage() == NULL); - EndTraceAndFlush(); - } -} - -// Test that data sent from other threads is gathered -TEST_F(TraceEventTestFixture, DataCapturedOnThread) { - BeginTrace(); - - Thread thread("1"); - WaitableEvent task_complete_event(false, false); - thread.Start(); - - thread.message_loop()->PostTask( - FROM_HERE, base::Bind(&TraceWithAllMacroVariants, &task_complete_event)); - task_complete_event.Wait(); - thread.Stop(); - - EndTraceAndFlush(); - ValidateAllTraceMacrosCreatedData(trace_parsed_); -} - -// Test that data sent from multiple threads is gathered -TEST_F(TraceEventTestFixture, DataCapturedManyThreads) { - BeginTrace(); - - const int num_threads = 4; - const int num_events = 4000; - Thread* threads[num_threads]; - WaitableEvent* task_complete_events[num_threads]; - for (int i = 0; i < num_threads; i++) { - threads[i] = new Thread(StringPrintf("Thread %d", i).c_str()); - task_complete_events[i] = new WaitableEvent(false, false); - threads[i]->Start(); - threads[i]->message_loop()->PostTask( - FROM_HERE, base::Bind(&TraceManyInstantEvents, - i, num_events, task_complete_events[i])); - } - - for (int i = 0; i < num_threads; i++) { - task_complete_events[i]->Wait(); - } - - for (int i = 0; i < num_threads; i++) { - threads[i]->Stop(); - delete threads[i]; - delete task_complete_events[i]; - } - - EndTraceAndFlush(); - - ValidateInstantEventPresentOnEveryThread(trace_parsed_, - num_threads, num_events); -} - -// Test that thread and process names show up in the trace -TEST_F(TraceEventTestFixture, ThreadNames) { - // Create threads before we enable tracing to make sure - // that tracelog still captures them. - const int num_threads = 4; - const int num_events = 10; - Thread* threads[num_threads]; - PlatformThreadId thread_ids[num_threads]; - for (int i = 0; i < num_threads; i++) - threads[i] = new Thread(StringPrintf("Thread %d", i).c_str()); - - // Enable tracing. - BeginTrace(); - - // Now run some trace code on these threads. - WaitableEvent* task_complete_events[num_threads]; - for (int i = 0; i < num_threads; i++) { - task_complete_events[i] = new WaitableEvent(false, false); - threads[i]->Start(); - thread_ids[i] = threads[i]->thread_id(); - threads[i]->message_loop()->PostTask( - FROM_HERE, base::Bind(&TraceManyInstantEvents, - i, num_events, task_complete_events[i])); - } - for (int i = 0; i < num_threads; i++) { - task_complete_events[i]->Wait(); - } - - // Shut things down. - for (int i = 0; i < num_threads; i++) { - threads[i]->Stop(); - delete threads[i]; - delete task_complete_events[i]; - } - - EndTraceAndFlush(); - - std::string tmp; - int tmp_int; - const DictionaryValue* item; - - // Make sure we get thread name metadata. - // Note, the test suite may have created a ton of threads. - // So, we'll have thread names for threads we didn't create. - std::vector items = - FindTraceEntries(trace_parsed_, "thread_name"); - for (int i = 0; i < static_cast(items.size()); i++) { - item = items[i]; - ASSERT_TRUE(item); - EXPECT_TRUE(item->GetInteger("tid", &tmp_int)); - - // See if this thread name is one of the threads we just created - for (int j = 0; j < num_threads; j++) { - if(static_cast(thread_ids[j]) != tmp_int) - continue; - - std::string expected_name = StringPrintf("Thread %d", j); - EXPECT_TRUE(item->GetString("ph", &tmp) && tmp == "M"); - EXPECT_TRUE(item->GetInteger("pid", &tmp_int) && - tmp_int == static_cast(base::GetCurrentProcId())); - // If the thread name changes or the tid gets reused, the name will be - // a comma-separated list of thread names, so look for a substring. - EXPECT_TRUE(item->GetString("args.name", &tmp) && - tmp.find(expected_name) != std::string::npos); - } - } -} - -TEST_F(TraceEventTestFixture, ThreadNameChanges) { - BeginTrace(); - - PlatformThread::SetName(""); - TRACE_EVENT_INSTANT0("drink", "water", TRACE_EVENT_SCOPE_THREAD); - - PlatformThread::SetName("cafe"); - TRACE_EVENT_INSTANT0("drink", "coffee", TRACE_EVENT_SCOPE_THREAD); - - PlatformThread::SetName("shop"); - // No event here, so won't appear in combined name. - - PlatformThread::SetName("pub"); - TRACE_EVENT_INSTANT0("drink", "beer", TRACE_EVENT_SCOPE_THREAD); - TRACE_EVENT_INSTANT0("drink", "wine", TRACE_EVENT_SCOPE_THREAD); - - PlatformThread::SetName(" bar"); - TRACE_EVENT_INSTANT0("drink", "whisky", TRACE_EVENT_SCOPE_THREAD); - - EndTraceAndFlush(); - - std::vector items = - FindTraceEntries(trace_parsed_, "thread_name"); - EXPECT_EQ(1u, items.size()); - ASSERT_GT(items.size(), 0u); - const DictionaryValue* item = items[0]; - ASSERT_TRUE(item); - int tid; - EXPECT_TRUE(item->GetInteger("tid", &tid)); - EXPECT_EQ(PlatformThread::CurrentId(), static_cast(tid)); - - std::string expected_name = "cafe,pub, bar"; - std::string tmp; - EXPECT_TRUE(item->GetString("args.name", &tmp)); - EXPECT_EQ(expected_name, tmp); -} - -// Test that the disabled trace categories are included/excluded from the -// trace output correctly. -TEST_F(TraceEventTestFixture, DisabledCategories) { - BeginTrace(); - TRACE_EVENT_INSTANT0(TRACE_DISABLED_BY_DEFAULT("cc"), "first", - TRACE_EVENT_SCOPE_THREAD); - TRACE_EVENT_INSTANT0("included", "first", TRACE_EVENT_SCOPE_THREAD); - EndTraceAndFlush(); - { - const DictionaryValue* item = NULL; - ListValue& trace_parsed = trace_parsed_; - EXPECT_NOT_FIND_("disabled-by-default-cc"); - EXPECT_FIND_("included"); - } - Clear(); - - BeginSpecificTrace("disabled-by-default-cc"); - TRACE_EVENT_INSTANT0(TRACE_DISABLED_BY_DEFAULT("cc"), "second", - TRACE_EVENT_SCOPE_THREAD); - TRACE_EVENT_INSTANT0("other_included", "second", TRACE_EVENT_SCOPE_THREAD); - EndTraceAndFlush(); - - { - const DictionaryValue* item = NULL; - ListValue& trace_parsed = trace_parsed_; - EXPECT_FIND_("disabled-by-default-cc"); - EXPECT_FIND_("other_included"); - } -} - -TEST_F(TraceEventTestFixture, NormallyNoDeepCopy) { - // Test that the TRACE_EVENT macros do not deep-copy their string. If they - // do so it may indicate a performance regression, but more-over it would - // make the DEEP_COPY overloads redundant. - std::string name_string("event name"); - - BeginTrace(); - TRACE_EVENT_INSTANT0("category", name_string.c_str(), - TRACE_EVENT_SCOPE_THREAD); - - // Modify the string in place (a wholesale reassignment may leave the old - // string intact on the heap). - name_string[0] = '@'; - - EndTraceAndFlush(); - - EXPECT_FALSE(FindTraceEntry(trace_parsed_, "event name")); - EXPECT_TRUE(FindTraceEntry(trace_parsed_, name_string.c_str())); -} - -TEST_F(TraceEventTestFixture, DeepCopy) { - static const char kOriginalName1[] = "name1"; - static const char kOriginalName2[] = "name2"; - static const char kOriginalName3[] = "name3"; - std::string name1(kOriginalName1); - std::string name2(kOriginalName2); - std::string name3(kOriginalName3); - std::string arg1("arg1"); - std::string arg2("arg2"); - std::string val1("val1"); - std::string val2("val2"); - - BeginTrace(); - TRACE_EVENT_COPY_INSTANT0("category", name1.c_str(), - TRACE_EVENT_SCOPE_THREAD); - TRACE_EVENT_COPY_BEGIN1("category", name2.c_str(), - arg1.c_str(), 5); - TRACE_EVENT_COPY_END2("category", name3.c_str(), - arg1.c_str(), val1, - arg2.c_str(), val2); - - // As per NormallyNoDeepCopy, modify the strings in place. - name1[0] = name2[0] = name3[0] = arg1[0] = arg2[0] = val1[0] = val2[0] = '@'; - - EndTraceAndFlush(); - - EXPECT_FALSE(FindTraceEntry(trace_parsed_, name1.c_str())); - EXPECT_FALSE(FindTraceEntry(trace_parsed_, name2.c_str())); - EXPECT_FALSE(FindTraceEntry(trace_parsed_, name3.c_str())); - - const DictionaryValue* entry1 = FindTraceEntry(trace_parsed_, kOriginalName1); - const DictionaryValue* entry2 = FindTraceEntry(trace_parsed_, kOriginalName2); - const DictionaryValue* entry3 = FindTraceEntry(trace_parsed_, kOriginalName3); - ASSERT_TRUE(entry1); - ASSERT_TRUE(entry2); - ASSERT_TRUE(entry3); - - int i; - EXPECT_FALSE(entry2->GetInteger("args.@rg1", &i)); - EXPECT_TRUE(entry2->GetInteger("args.arg1", &i)); - EXPECT_EQ(5, i); - - std::string s; - EXPECT_TRUE(entry3->GetString("args.arg1", &s)); - EXPECT_EQ("val1", s); - EXPECT_TRUE(entry3->GetString("args.arg2", &s)); - EXPECT_EQ("val2", s); -} - -// Test that TraceResultBuffer outputs the correct result whether it is added -// in chunks or added all at once. -TEST_F(TraceEventTestFixture, TraceResultBuffer) { - Clear(); - - trace_buffer_.Start(); - trace_buffer_.AddFragment("bla1"); - trace_buffer_.AddFragment("bla2"); - trace_buffer_.AddFragment("bla3,bla4"); - trace_buffer_.Finish(); - EXPECT_STREQ(json_output_.json_output.c_str(), "[bla1,bla2,bla3,bla4]"); - - Clear(); - - trace_buffer_.Start(); - trace_buffer_.AddFragment("bla1,bla2,bla3,bla4"); - trace_buffer_.Finish(); - EXPECT_STREQ(json_output_.json_output.c_str(), "[bla1,bla2,bla3,bla4]"); -} - -// Test that trace_event parameters are not evaluated if the tracing -// system is disabled. -TEST_F(TraceEventTestFixture, TracingIsLazy) { - BeginTrace(); - - int a = 0; - TRACE_EVENT_INSTANT1("category", "test", TRACE_EVENT_SCOPE_THREAD, "a", a++); - EXPECT_EQ(1, a); - - TraceLog::GetInstance()->SetDisabled(); - - TRACE_EVENT_INSTANT1("category", "test", TRACE_EVENT_SCOPE_THREAD, "a", a++); - EXPECT_EQ(1, a); - - EndTraceAndFlush(); -} - -TEST_F(TraceEventTestFixture, TraceEnableDisable) { - TraceLog* trace_log = TraceLog::GetInstance(); - CategoryFilter cf_inc_all("*"); - trace_log->SetEnabled(cf_inc_all, TraceLog::RECORD_UNTIL_FULL); - EXPECT_TRUE(trace_log->IsEnabled()); - trace_log->SetDisabled(); - EXPECT_FALSE(trace_log->IsEnabled()); - - trace_log->SetEnabled(cf_inc_all, TraceLog::RECORD_UNTIL_FULL); - EXPECT_TRUE(trace_log->IsEnabled()); - const std::vector empty; - trace_log->SetEnabled(CategoryFilter(""), TraceLog::RECORD_UNTIL_FULL); - EXPECT_TRUE(trace_log->IsEnabled()); - trace_log->SetDisabled(); - EXPECT_TRUE(trace_log->IsEnabled()); - trace_log->SetDisabled(); - EXPECT_FALSE(trace_log->IsEnabled()); -} - -TEST_F(TraceEventTestFixture, TraceCategoriesAfterNestedEnable) { - TraceLog* trace_log = TraceLog::GetInstance(); - trace_log->SetEnabled(CategoryFilter("foo,bar"), TraceLog::RECORD_UNTIL_FULL); - EXPECT_TRUE(*trace_log->GetCategoryGroupEnabled("foo")); - EXPECT_TRUE(*trace_log->GetCategoryGroupEnabled("bar")); - EXPECT_FALSE(*trace_log->GetCategoryGroupEnabled("baz")); - trace_log->SetEnabled(CategoryFilter("foo2"), TraceLog::RECORD_UNTIL_FULL); - EXPECT_TRUE(*trace_log->GetCategoryGroupEnabled("foo2")); - EXPECT_FALSE(*trace_log->GetCategoryGroupEnabled("baz")); - // The "" becomes the default catergory set when applied. - trace_log->SetEnabled(CategoryFilter(""), TraceLog::RECORD_UNTIL_FULL); - EXPECT_TRUE(*trace_log->GetCategoryGroupEnabled("foo")); - EXPECT_TRUE(*trace_log->GetCategoryGroupEnabled("baz")); - EXPECT_STREQ("-*Debug,-*Test", - trace_log->GetCurrentCategoryFilter().ToString().c_str()); - trace_log->SetDisabled(); - trace_log->SetDisabled(); - trace_log->SetDisabled(); - EXPECT_FALSE(*trace_log->GetCategoryGroupEnabled("foo")); - EXPECT_FALSE(*trace_log->GetCategoryGroupEnabled("baz")); - - trace_log->SetEnabled(CategoryFilter("-foo,-bar"), - TraceLog::RECORD_UNTIL_FULL); - EXPECT_FALSE(*trace_log->GetCategoryGroupEnabled("foo")); - EXPECT_TRUE(*trace_log->GetCategoryGroupEnabled("baz")); - trace_log->SetEnabled(CategoryFilter("moo"), TraceLog::RECORD_UNTIL_FULL); - EXPECT_TRUE(*trace_log->GetCategoryGroupEnabled("baz")); - EXPECT_TRUE(*trace_log->GetCategoryGroupEnabled("moo")); - EXPECT_FALSE(*trace_log->GetCategoryGroupEnabled("foo")); - EXPECT_STREQ("-foo,-bar", - trace_log->GetCurrentCategoryFilter().ToString().c_str()); - trace_log->SetDisabled(); - trace_log->SetDisabled(); - - // Make sure disabled categories aren't cleared if we set in the second. - trace_log->SetEnabled(CategoryFilter("disabled-by-default-cc,foo"), - TraceLog::RECORD_UNTIL_FULL); - EXPECT_FALSE(*trace_log->GetCategoryGroupEnabled("bar")); - trace_log->SetEnabled(CategoryFilter("disabled-by-default-gpu"), - TraceLog::RECORD_UNTIL_FULL); - EXPECT_TRUE(*trace_log->GetCategoryGroupEnabled("disabled-by-default-cc")); - EXPECT_TRUE(*trace_log->GetCategoryGroupEnabled("disabled-by-default-gpu")); - EXPECT_TRUE(*trace_log->GetCategoryGroupEnabled("bar")); - EXPECT_STREQ("disabled-by-default-cc,disabled-by-default-gpu", - trace_log->GetCurrentCategoryFilter().ToString().c_str()); - trace_log->SetDisabled(); - trace_log->SetDisabled(); -} - -TEST_F(TraceEventTestFixture, TraceOptionsParsing) { - EXPECT_EQ(TraceLog::RECORD_UNTIL_FULL, - TraceLog::TraceOptionsFromString(std::string())); - - EXPECT_EQ(TraceLog::RECORD_UNTIL_FULL, - TraceLog::TraceOptionsFromString("record-until-full")); - EXPECT_EQ(TraceLog::RECORD_CONTINUOUSLY, - TraceLog::TraceOptionsFromString("record-continuously")); - EXPECT_EQ(TraceLog::RECORD_UNTIL_FULL | TraceLog::ENABLE_SAMPLING, - TraceLog::TraceOptionsFromString("enable-sampling")); - EXPECT_EQ(TraceLog::RECORD_CONTINUOUSLY | TraceLog::ENABLE_SAMPLING, - TraceLog::TraceOptionsFromString( - "record-continuously,enable-sampling")); -} - -TEST_F(TraceEventTestFixture, TraceSampling) { - event_watch_notification_ = 0; - TraceLog::GetInstance()->SetEnabled( - CategoryFilter("*"), - TraceLog::Options(TraceLog::RECORD_UNTIL_FULL | - TraceLog::ENABLE_SAMPLING)); - - WaitableEvent* sampled = new WaitableEvent(false, false); - TraceLog::GetInstance()->InstallWaitableEventForSamplingTesting(sampled); - - TRACE_EVENT_SET_SAMPLING_STATE_FOR_BUCKET(1, "cc", "Stuff"); - sampled->Wait(); - TRACE_EVENT_SET_SAMPLING_STATE_FOR_BUCKET(1, "cc", "Things"); - sampled->Wait(); - - EndTraceAndFlush(); - - // Make sure we hit at least once. - EXPECT_TRUE(FindNamePhase("Stuff", "P")); - EXPECT_TRUE(FindNamePhase("Things", "P")); -} - -TEST_F(TraceEventTestFixture, TraceSamplingScope) { - event_watch_notification_ = 0; - TraceLog::GetInstance()->SetEnabled( - CategoryFilter("*"), - TraceLog::Options(TraceLog::RECORD_UNTIL_FULL | - TraceLog::ENABLE_SAMPLING)); - - WaitableEvent* sampled = new WaitableEvent(false, false); - TraceLog::GetInstance()->InstallWaitableEventForSamplingTesting(sampled); - - TRACE_EVENT_SCOPED_SAMPLING_STATE("AAA", "name"); - sampled->Wait(); - { - EXPECT_STREQ(TRACE_EVENT_GET_SAMPLING_STATE(), "AAA"); - TRACE_EVENT_SCOPED_SAMPLING_STATE("BBB", "name"); - sampled->Wait(); - EXPECT_STREQ(TRACE_EVENT_GET_SAMPLING_STATE(), "BBB"); - } - sampled->Wait(); - { - EXPECT_STREQ(TRACE_EVENT_GET_SAMPLING_STATE(), "AAA"); - TRACE_EVENT_SCOPED_SAMPLING_STATE("CCC", "name"); - sampled->Wait(); - EXPECT_STREQ(TRACE_EVENT_GET_SAMPLING_STATE(), "CCC"); - } - sampled->Wait(); - { - EXPECT_STREQ(TRACE_EVENT_GET_SAMPLING_STATE(), "AAA"); - TRACE_EVENT_SET_SAMPLING_STATE("DDD", "name"); - sampled->Wait(); - EXPECT_STREQ(TRACE_EVENT_GET_SAMPLING_STATE(), "DDD"); - } - sampled->Wait(); - EXPECT_STREQ(TRACE_EVENT_GET_SAMPLING_STATE(), "DDD"); - - EndTraceAndFlush(); -} - -class MyData : public base::debug::ConvertableToTraceFormat { - public: - MyData() {} - virtual ~MyData() {} - - virtual void AppendAsTraceFormat(std::string* out) const OVERRIDE { - out->append("{\"foo\":1}"); - } - - private: - DISALLOW_COPY_AND_ASSIGN(MyData); -}; - -TEST_F(TraceEventTestFixture, ConvertableTypes) { - TraceLog::GetInstance()->SetEnabled(CategoryFilter("*"), - TraceLog::RECORD_UNTIL_FULL); - - scoped_ptr data(new MyData()); - scoped_ptr data1(new MyData()); - scoped_ptr data2(new MyData()); - TRACE_EVENT1("foo", "bar", "data", - data.PassAs()); - TRACE_EVENT2("foo", "baz", - "data1", data1.PassAs(), - "data2", data2.PassAs()); - - - scoped_ptr convertData1(new MyData()); - scoped_ptr convertData2(new MyData()); - TRACE_EVENT2( - "foo", - "string_first", - "str", - "string value 1", - "convert", - convertData1.PassAs()); - TRACE_EVENT2( - "foo", - "string_second", - "convert", - convertData2.PassAs(), - "str", - "string value 2"); - EndTraceAndFlush(); - - // One arg version. - DictionaryValue* dict = FindNamePhase("bar", "B"); - ASSERT_TRUE(dict); - - const DictionaryValue* args_dict = NULL; - dict->GetDictionary("args", &args_dict); - ASSERT_TRUE(args_dict); - - const Value* value = NULL; - const DictionaryValue* convertable_dict = NULL; - EXPECT_TRUE(args_dict->Get("data", &value)); - ASSERT_TRUE(value->GetAsDictionary(&convertable_dict)); - - int foo_val; - EXPECT_TRUE(convertable_dict->GetInteger("foo", &foo_val)); - EXPECT_EQ(1, foo_val); - - // Two arg version. - dict = FindNamePhase("baz", "B"); - ASSERT_TRUE(dict); - - args_dict = NULL; - dict->GetDictionary("args", &args_dict); - ASSERT_TRUE(args_dict); - - value = NULL; - convertable_dict = NULL; - EXPECT_TRUE(args_dict->Get("data1", &value)); - ASSERT_TRUE(value->GetAsDictionary(&convertable_dict)); - - value = NULL; - convertable_dict = NULL; - EXPECT_TRUE(args_dict->Get("data2", &value)); - ASSERT_TRUE(value->GetAsDictionary(&convertable_dict)); - - // Convertable with other types. - dict = FindNamePhase("string_first", "B"); - ASSERT_TRUE(dict); - - args_dict = NULL; - dict->GetDictionary("args", &args_dict); - ASSERT_TRUE(args_dict); - - std::string str_value; - EXPECT_TRUE(args_dict->GetString("str", &str_value)); - EXPECT_STREQ("string value 1", str_value.c_str()); - - value = NULL; - convertable_dict = NULL; - foo_val = 0; - EXPECT_TRUE(args_dict->Get("convert", &value)); - ASSERT_TRUE(value->GetAsDictionary(&convertable_dict)); - EXPECT_TRUE(convertable_dict->GetInteger("foo", &foo_val)); - EXPECT_EQ(1, foo_val); - - dict = FindNamePhase("string_second", "B"); - ASSERT_TRUE(dict); - - args_dict = NULL; - dict->GetDictionary("args", &args_dict); - ASSERT_TRUE(args_dict); - - EXPECT_TRUE(args_dict->GetString("str", &str_value)); - EXPECT_STREQ("string value 2", str_value.c_str()); - - value = NULL; - convertable_dict = NULL; - foo_val = 0; - EXPECT_TRUE(args_dict->Get("convert", &value)); - ASSERT_TRUE(value->GetAsDictionary(&convertable_dict)); - EXPECT_TRUE(convertable_dict->GetInteger("foo", &foo_val)); - EXPECT_EQ(1, foo_val); -} - -class TraceEventCallbackTest : public TraceEventTestFixture { - public: - virtual void SetUp() OVERRIDE { - TraceEventTestFixture::SetUp(); - ASSERT_EQ(NULL, s_instance); - s_instance = this; - } - virtual void TearDown() OVERRIDE { - while (TraceLog::GetInstance()->IsEnabled()) - TraceLog::GetInstance()->SetDisabled(); - ASSERT_TRUE(!!s_instance); - s_instance = NULL; - TraceEventTestFixture::TearDown(); - } - - protected: - std::vector collected_events_; - - static TraceEventCallbackTest* s_instance; - static void Callback(char phase, - const unsigned char* category_enabled, - const char* name, - unsigned long long id, - int num_args, - const char* const arg_names[], - const unsigned char arg_types[], - const unsigned long long arg_values[], - unsigned char flags) { - s_instance->collected_events_.push_back(name); - } -}; - -TraceEventCallbackTest* TraceEventCallbackTest::s_instance; - -TEST_F(TraceEventCallbackTest, TraceEventCallback) { - TRACE_EVENT_INSTANT0("all", "before enable", TRACE_EVENT_SCOPE_THREAD); - TraceLog::GetInstance()->SetEnabled(CategoryFilter("*"), - TraceLog::RECORD_UNTIL_FULL); - TRACE_EVENT_INSTANT0("all", "before callback set", TRACE_EVENT_SCOPE_THREAD); - TraceLog::GetInstance()->SetEventCallback(Callback); - TRACE_EVENT_INSTANT0("all", "event1", TRACE_EVENT_SCOPE_GLOBAL); - TRACE_EVENT_INSTANT0("all", "event2", TRACE_EVENT_SCOPE_GLOBAL); - TraceLog::GetInstance()->SetEventCallback(NULL); - TRACE_EVENT_INSTANT0("all", "after callback removed", - TRACE_EVENT_SCOPE_GLOBAL); - ASSERT_EQ(2u, collected_events_.size()); - EXPECT_EQ("event1", collected_events_[0]); - EXPECT_EQ("event2", collected_events_[1]); -} - -TEST_F(TraceEventCallbackTest, TraceEventCallbackWhileFull) { - TraceLog::GetInstance()->SetEnabled(CategoryFilter("*"), - TraceLog::RECORD_UNTIL_FULL); - do { - TRACE_EVENT_INSTANT0("all", "badger badger", TRACE_EVENT_SCOPE_GLOBAL); - } while ((notifications_received_ & TraceLog::TRACE_BUFFER_FULL) == 0); - TraceLog::GetInstance()->SetEventCallback(Callback); - TRACE_EVENT_INSTANT0("all", "a snake", TRACE_EVENT_SCOPE_GLOBAL); - TraceLog::GetInstance()->SetEventCallback(NULL); - ASSERT_EQ(1u, collected_events_.size()); - EXPECT_EQ("a snake", collected_events_[0]); -} - -// TODO(dsinclair): Continuous Tracing unit test. - -// Test the category filter. -TEST_F(TraceEventTestFixture, CategoryFilter) { - // Using the default filter. - CategoryFilter default_cf = CategoryFilter( - CategoryFilter::kDefaultCategoryFilterString); - std::string category_filter_str = default_cf.ToString(); - EXPECT_STREQ("-*Debug,-*Test", category_filter_str.c_str()); - EXPECT_TRUE(default_cf.IsCategoryGroupEnabled("not-excluded-category")); - EXPECT_FALSE( - default_cf.IsCategoryGroupEnabled("disabled-by-default-category")); - EXPECT_FALSE(default_cf.IsCategoryGroupEnabled("Category1,CategoryDebug")); - EXPECT_FALSE(default_cf.IsCategoryGroupEnabled("CategoryDebug,Category1")); - EXPECT_FALSE(default_cf.IsCategoryGroupEnabled("CategoryTest,Category2")); - - // Make sure that upon an empty string, we fall back to the default filter. - default_cf = CategoryFilter(""); - category_filter_str = default_cf.ToString(); - EXPECT_STREQ("-*Debug,-*Test", category_filter_str.c_str()); - EXPECT_TRUE(default_cf.IsCategoryGroupEnabled("not-excluded-category")); - EXPECT_FALSE(default_cf.IsCategoryGroupEnabled("Category1,CategoryDebug")); - EXPECT_FALSE(default_cf.IsCategoryGroupEnabled("CategoryDebug,Category1")); - EXPECT_FALSE(default_cf.IsCategoryGroupEnabled("CategoryTest,Category2")); - - // Using an arbitrary non-empty filter. - CategoryFilter cf("included,-excluded,inc_pattern*,-exc_pattern*"); - category_filter_str = cf.ToString(); - EXPECT_STREQ("included,inc_pattern*,-excluded,-exc_pattern*", - category_filter_str.c_str()); - EXPECT_TRUE(cf.IsCategoryGroupEnabled("included")); - EXPECT_TRUE(cf.IsCategoryGroupEnabled("inc_pattern_category")); - EXPECT_FALSE(cf.IsCategoryGroupEnabled("exc_pattern_category")); - EXPECT_FALSE(cf.IsCategoryGroupEnabled("excluded")); - EXPECT_FALSE(cf.IsCategoryGroupEnabled("not-excluded-nor-included")); - EXPECT_FALSE(cf.IsCategoryGroupEnabled("Category1,CategoryDebug")); - EXPECT_FALSE(cf.IsCategoryGroupEnabled("CategoryDebug,Category1")); - EXPECT_FALSE(cf.IsCategoryGroupEnabled("CategoryTest,Category2")); - - cf.Merge(default_cf); - category_filter_str = cf.ToString(); - EXPECT_STREQ("-excluded,-exc_pattern*,-*Debug,-*Test", - category_filter_str.c_str()); - cf.Clear(); - - CategoryFilter reconstructed_cf(category_filter_str); - category_filter_str = reconstructed_cf.ToString(); - EXPECT_STREQ("-excluded,-exc_pattern*,-*Debug,-*Test", - category_filter_str.c_str()); - - // One included category. - CategoryFilter one_inc_cf("only_inc_cat"); - category_filter_str = one_inc_cf.ToString(); - EXPECT_STREQ("only_inc_cat", category_filter_str.c_str()); - - // One excluded category. - CategoryFilter one_exc_cf("-only_exc_cat"); - category_filter_str = one_exc_cf.ToString(); - EXPECT_STREQ("-only_exc_cat", category_filter_str.c_str()); - - // Enabling a disabled- category does not require all categories to be traced - // to be included. - CategoryFilter disabled_cat("disabled-by-default-cc,-excluded"); - EXPECT_STREQ("disabled-by-default-cc,-excluded", - disabled_cat.ToString().c_str()); - EXPECT_TRUE(disabled_cat.IsCategoryGroupEnabled("disabled-by-default-cc")); - EXPECT_TRUE(disabled_cat.IsCategoryGroupEnabled("some_other_group")); - EXPECT_FALSE(disabled_cat.IsCategoryGroupEnabled("excluded")); - - // Enabled a disabled- category and also including makes all categories to - // be traced require including. - CategoryFilter disabled_inc_cat("disabled-by-default-cc,included"); - EXPECT_STREQ("included,disabled-by-default-cc", - disabled_inc_cat.ToString().c_str()); - EXPECT_TRUE( - disabled_inc_cat.IsCategoryGroupEnabled("disabled-by-default-cc")); - EXPECT_TRUE(disabled_inc_cat.IsCategoryGroupEnabled("included")); - EXPECT_FALSE(disabled_inc_cat.IsCategoryGroupEnabled("other_included")); - - // Test that IsEmptyOrContainsLeadingOrTrailingWhitespace actually catches - // categories that are explicitly forbiden. - // This method is called in a DCHECK to assert that we don't have these types - // of strings as categories. - EXPECT_TRUE(CategoryFilter::IsEmptyOrContainsLeadingOrTrailingWhitespace( - " bad_category ")); - EXPECT_TRUE(CategoryFilter::IsEmptyOrContainsLeadingOrTrailingWhitespace( - " bad_category")); - EXPECT_TRUE(CategoryFilter::IsEmptyOrContainsLeadingOrTrailingWhitespace( - "bad_category ")); - EXPECT_TRUE(CategoryFilter::IsEmptyOrContainsLeadingOrTrailingWhitespace( - " bad_category")); - EXPECT_TRUE(CategoryFilter::IsEmptyOrContainsLeadingOrTrailingWhitespace( - "bad_category ")); - EXPECT_TRUE(CategoryFilter::IsEmptyOrContainsLeadingOrTrailingWhitespace( - " bad_category ")); - EXPECT_TRUE(CategoryFilter::IsEmptyOrContainsLeadingOrTrailingWhitespace( - "")); - EXPECT_FALSE(CategoryFilter::IsEmptyOrContainsLeadingOrTrailingWhitespace( - "good_category")); -} - -} // namespace debug -} // namespace base diff --git a/base/debug/trace_event_unittest.h b/base/debug/trace_event_unittest.h deleted file mode 100644 index 599fec7dcd..0000000000 --- a/base/debug/trace_event_unittest.h +++ /dev/null @@ -1,14 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "base/time/time.h" - -namespace base { -namespace debug { - -// Sleep until HighResNow has advanced by at least |elapsed|. -void HighResSleepForTraceTest(base::TimeDelta elapsed); - -} // namespace debug -} // namespace base diff --git a/base/debug/trace_event_win.cc b/base/debug/trace_event_win.cc deleted file mode 100644 index d5a21f4926..0000000000 --- a/base/debug/trace_event_win.cc +++ /dev/null @@ -1,120 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. -#include "base/debug/trace_event_win.h" - -#include "base/logging.h" -#include "base/memory/singleton.h" -#include // NOLINT - -namespace base { -namespace debug { - -using base::win::EtwEventType; -using base::win::EtwMofEvent; - -// {3DADA31D-19EF-4dc1-B345-037927193422} -const GUID kChromeTraceProviderName = { - 0x3dada31d, 0x19ef, 0x4dc1, 0xb3, 0x45, 0x3, 0x79, 0x27, 0x19, 0x34, 0x22 }; - -// {B967AE67-BB22-49d7-9406-55D91EE1D560} -const GUID kTraceEventClass32 = { - 0xb967ae67, 0xbb22, 0x49d7, 0x94, 0x6, 0x55, 0xd9, 0x1e, 0xe1, 0xd5, 0x60 }; - -// {97BE602D-2930-4ac3-8046-B6763B631DFE} -const GUID kTraceEventClass64 = { - 0x97be602d, 0x2930, 0x4ac3, 0x80, 0x46, 0xb6, 0x76, 0x3b, 0x63, 0x1d, 0xfe}; - - -TraceEventETWProvider::TraceEventETWProvider() : - EtwTraceProvider(kChromeTraceProviderName) { - Register(); -} - -TraceEventETWProvider* TraceEventETWProvider::GetInstance() { - return Singleton >::get(); -} - -bool TraceEventETWProvider::StartTracing() { - return true; -} - -void TraceEventETWProvider::TraceEvent(const char* name, - size_t name_len, - char type, - const void* id, - const char* extra, - size_t extra_len) { - // Make sure we don't touch NULL. - if (name == NULL) - name = ""; - if (extra == NULL) - extra = ""; - - EtwEventType etw_type = 0; - switch (type) { - case TRACE_EVENT_PHASE_BEGIN: - etw_type = kTraceEventTypeBegin; - break; - case TRACE_EVENT_PHASE_END: - etw_type = kTraceEventTypeEnd; - break; - - case TRACE_EVENT_PHASE_INSTANT: - etw_type = kTraceEventTypeInstant; - break; - - default: - NOTREACHED() << "Unknown event type"; - etw_type = kTraceEventTypeInstant; - break; - } - - EtwMofEvent<5> event(kTraceEventClass32, - etw_type, - TRACE_LEVEL_INFORMATION); - event.SetField(0, name_len + 1, name); - event.SetField(1, sizeof(id), &id); - event.SetField(2, extra_len + 1, extra); - - // See whether we're to capture a backtrace. - void* backtrace[32]; - if (enable_flags() & CAPTURE_STACK_TRACE) { - DWORD hash = 0; - DWORD depth = CaptureStackBackTrace(0, - arraysize(backtrace), - backtrace, - &hash); - event.SetField(3, sizeof(depth), &depth); - event.SetField(4, sizeof(backtrace[0]) * depth, backtrace); - } - - // Trace the event. - Log(event.get()); -} - -void TraceEventETWProvider::Trace(const char* name, - size_t name_len, - char type, - const void* id, - const char* extra, - size_t extra_len) { - TraceEventETWProvider* provider = TraceEventETWProvider::GetInstance(); - if (provider && provider->IsTracing()) { - // Compute the name & extra lengths if not supplied already. - if (name_len == -1) - name_len = (name == NULL) ? 0 : strlen(name); - if (extra_len == -1) - extra_len = (extra == NULL) ? 0 : strlen(extra); - - provider->TraceEvent(name, name_len, type, id, extra, extra_len); - } -} - -void TraceEventETWProvider::Resurrect() { - StaticMemorySingletonTraits::Resurrect(); -} - -} // namespace debug -} // namespace base diff --git a/base/debug/trace_event_win.h b/base/debug/trace_event_win.h deleted file mode 100644 index 2a900bb431..0000000000 --- a/base/debug/trace_event_win.h +++ /dev/null @@ -1,123 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -// This file contains the Windows-specific declarations for trace_event.h. -#ifndef BASE_DEBUG_TRACE_EVENT_WIN_H_ -#define BASE_DEBUG_TRACE_EVENT_WIN_H_ - -#include - -#include "base/base_export.h" -#include "base/debug/trace_event.h" -#include "base/win/event_trace_provider.h" - -// Fwd. -template -struct StaticMemorySingletonTraits; - -namespace base { -namespace debug { - -// This EtwTraceProvider subclass implements ETW logging -// for the macros above on Windows. -class BASE_EXPORT TraceEventETWProvider : public base::win::EtwTraceProvider { - public: - // Start logging trace events. - // This is a noop in this implementation. - static bool StartTracing(); - - // Trace begin/end/instant events, this is the bottleneck implementation - // all the others defer to. - // Allowing the use of std::string for name or extra is a convenience, - // whereas passing name or extra as a const char* avoids the construction - // of temporary std::string instances. - // If -1 is passed for name_len or extra_len, the strlen of the string will - // be used for length. - static void Trace(const char* name, - size_t name_len, - char type, - const void* id, - const char* extra, - size_t extra_len); - - // Allows passing extra as a std::string for convenience. - static void Trace(const char* name, - char type, - const void* id, - const std::string& extra) { - return Trace(name, -1, type, id, extra.c_str(), extra.length()); - } - - // Allows passing extra as a const char* to avoid constructing temporary - // std::string instances where not needed. - static void Trace(const char* name, - char type, - const void* id, - const char* extra) { - return Trace(name, -1, type, id, extra, -1); - } - - // Retrieves the singleton. - // Note that this may return NULL post-AtExit processing. - static TraceEventETWProvider* GetInstance(); - - // Returns true iff tracing is turned on. - bool IsTracing() { - return enable_level() >= TRACE_LEVEL_INFORMATION; - } - - // Emit a trace of type |type| containing |name|, |id|, and |extra|. - // Note: |name| and |extra| must be NULL, or a zero-terminated string of - // length |name_len| or |extra_len| respectively. - // Note: if name_len or extra_len are -1, the length of the corresponding - // string will be used. - void TraceEvent(const char* name, - size_t name_len, - char type, - const void* id, - const char* extra, - size_t extra_len); - - // Exposed for unittesting only, allows resurrecting our - // singleton instance post-AtExit processing. - static void Resurrect(); - - private: - // Ensure only the provider can construct us. - friend struct StaticMemorySingletonTraits; - TraceEventETWProvider(); - - DISALLOW_COPY_AND_ASSIGN(TraceEventETWProvider); -}; - -// The ETW trace provider GUID. -BASE_EXPORT extern const GUID kChromeTraceProviderName; - -// The ETW event class GUID for 32 bit events. -BASE_EXPORT extern const GUID kTraceEventClass32; - -// The ETW event class GUID for 64 bit events. -BASE_EXPORT extern const GUID kTraceEventClass64; - -// The ETW event types, IDs 0x00-0x09 are reserved, so start at 0x10. -const base::win::EtwEventType kTraceEventTypeBegin = 0x10; -const base::win::EtwEventType kTraceEventTypeEnd = 0x11; -const base::win::EtwEventType kTraceEventTypeInstant = 0x12; - -// If this flag is set in enable flags -enum TraceEventETWFlags { - CAPTURE_STACK_TRACE = 0x0001, -}; - -// The event format consists of: -// The "name" string as a zero-terminated ASCII string. -// The id pointer in the machine bitness. -// The "extra" string as a zero-terminated ASCII string. -// Optionally the stack trace, consisting of a DWORD "depth", followed -// by an array of void* (machine bitness) of length "depth". - -} // namespace debug -} // namespace base - -#endif // BASE_DEBUG_TRACE_EVENT_WIN_H_ diff --git a/base/debug/trace_event_win_unittest.cc b/base/debug/trace_event_win_unittest.cc deleted file mode 100644 index 531c5f7d86..0000000000 --- a/base/debug/trace_event_win_unittest.cc +++ /dev/null @@ -1,319 +0,0 @@ -// Copyright (c) 2011 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "base/debug/trace_event.h" - -#include - -#include "base/at_exit.h" -#include "base/basictypes.h" -#include "base/file_util.h" -#include "base/debug/trace_event.h" -#include "base/debug/trace_event_win.h" -#include "base/win/event_trace_consumer.h" -#include "base/win/event_trace_controller.h" -#include "base/win/event_trace_provider.h" -#include "base/win/windows_version.h" -#include "testing/gmock/include/gmock/gmock.h" -#include "testing/gtest/include/gtest/gtest.h" -#include // NOLINT - must be last include. - -namespace base { -namespace debug { - -namespace { - -using testing::_; -using testing::AnyNumber; -using testing::InSequence; -using testing::Ge; -using testing::Le; -using testing::NotNull; - -using base::win::EtwEventType; -using base::win::EtwTraceConsumerBase; -using base::win::EtwTraceController; -using base::win::EtwTraceProperties; - -// Data for unittests traces. -const char kEmpty[] = ""; -const char kName[] = "unittest.trace_name"; -const char kExtra[] = "UnittestDummyExtraString"; -const void* kId = kName; - -const wchar_t kTestSessionName[] = L"TraceEvent unittest session"; - -MATCHER_P(BufferStartsWith, str, "Buffer starts with") { - return memcmp(arg, str.c_str(), str.length()) == 0; -} - -// Duplicated from to fix link problems. -DEFINE_GUID( /* 68fdd900-4a3e-11d1-84f4-0000f80464e3 */ - kEventTraceGuid, - 0x68fdd900, - 0x4a3e, - 0x11d1, - 0x84, 0xf4, 0x00, 0x00, 0xf8, 0x04, 0x64, 0xe3); - -class TestEventConsumer: public EtwTraceConsumerBase { - public: - TestEventConsumer() { - EXPECT_TRUE(current_ == NULL); - current_ = this; - } - - ~TestEventConsumer() { - EXPECT_TRUE(current_ == this); - current_ = NULL; - } - - MOCK_METHOD4(Event, void(REFGUID event_class, - EtwEventType event_type, - size_t buf_len, - const void* buf)); - - static void ProcessEvent(EVENT_TRACE* event) { - ASSERT_TRUE(current_ != NULL); - current_->Event(event->Header.Guid, - event->Header.Class.Type, - event->MofLength, - event->MofData); - } - - private: - static TestEventConsumer* current_; -}; - -TestEventConsumer* TestEventConsumer::current_ = NULL; - -class TraceEventWinTest: public testing::Test { - public: - TraceEventWinTest() { - } - - void SetUp() { - bool is_xp = win::GetVersion() < base::win::VERSION_VISTA; - - if (is_xp) { - // Tear down any dangling session from an earlier failing test. - EtwTraceProperties ignore; - EtwTraceController::Stop(kTestSessionName, &ignore); - } - - // Resurrect and initialize the TraceLog singleton instance. - // On Vista and better, we need the provider registered before we - // start the private, in-proc session, but on XP we need the global - // session created and the provider enabled before we register our - // provider. - TraceEventETWProvider* tracelog = NULL; - if (!is_xp) { - TraceEventETWProvider::Resurrect(); - tracelog = TraceEventETWProvider::GetInstance(); - ASSERT_TRUE(tracelog != NULL); - ASSERT_FALSE(tracelog->IsTracing()); - } - - // Create the log file. - ASSERT_TRUE(file_util::CreateTemporaryFile(&log_file_)); - - // Create a private log session on the file. - EtwTraceProperties prop; - ASSERT_HRESULT_SUCCEEDED(prop.SetLoggerFileName(log_file_.value().c_str())); - EVENT_TRACE_PROPERTIES& p = *prop.get(); - p.Wnode.ClientContext = 1; // QPC timer accuracy. - p.LogFileMode = EVENT_TRACE_FILE_MODE_SEQUENTIAL; // Sequential log. - - // On Vista and later, we create a private in-process log session, because - // otherwise we'd need administrator privileges. Unfortunately we can't - // do the same on XP and better, because the semantics of a private - // logger session are different, and the IN_PROC flag is not supported. - if (!is_xp) { - p.LogFileMode |= EVENT_TRACE_PRIVATE_IN_PROC | // In-proc for non-admin. - EVENT_TRACE_PRIVATE_LOGGER_MODE; // Process-private log. - } - - p.MaximumFileSize = 100; // 100M file size. - p.FlushTimer = 1; // 1 second flush lag. - ASSERT_HRESULT_SUCCEEDED(controller_.Start(kTestSessionName, &prop)); - - // Enable the TraceLog provider GUID. - ASSERT_HRESULT_SUCCEEDED( - controller_.EnableProvider(kChromeTraceProviderName, - TRACE_LEVEL_INFORMATION, - 0)); - - if (is_xp) { - TraceEventETWProvider::Resurrect(); - tracelog = TraceEventETWProvider::GetInstance(); - } - ASSERT_TRUE(tracelog != NULL); - EXPECT_TRUE(tracelog->IsTracing()); - } - - void TearDown() { - EtwTraceProperties prop; - if (controller_.session() != 0) - EXPECT_HRESULT_SUCCEEDED(controller_.Stop(&prop)); - - if (!log_file_.value().empty()) - base::DeleteFile(log_file_, false); - - // We want our singleton torn down after each test. - TraceLog::DeleteForTesting(); - } - - void ExpectEvent(REFGUID guid, - EtwEventType type, - const char* name, - size_t name_len, - const void* id, - const char* extra, - size_t extra_len) { - // Build the trace event buffer we expect will result from this. - std::stringbuf str; - str.sputn(name, name_len + 1); - str.sputn(reinterpret_cast(&id), sizeof(id)); - str.sputn(extra, extra_len + 1); - - // And set up the expectation for the event callback. - EXPECT_CALL(consumer_, Event(guid, - type, - testing::Ge(str.str().length()), - BufferStartsWith(str.str()))); - } - - void ExpectPlayLog() { - // Ignore EventTraceGuid events. - EXPECT_CALL(consumer_, Event(kEventTraceGuid, _, _, _)) - .Times(AnyNumber()); - } - - void PlayLog() { - EtwTraceProperties prop; - EXPECT_HRESULT_SUCCEEDED(controller_.Flush(&prop)); - EXPECT_HRESULT_SUCCEEDED(controller_.Stop(&prop)); - ASSERT_HRESULT_SUCCEEDED( - consumer_.OpenFileSession(log_file_.value().c_str())); - - ASSERT_HRESULT_SUCCEEDED(consumer_.Consume()); - } - - private: - // We want our singleton torn down after each test. - ShadowingAtExitManager at_exit_manager_; - EtwTraceController controller_; - FilePath log_file_; - TestEventConsumer consumer_; -}; - -} // namespace - - -TEST_F(TraceEventWinTest, TraceLog) { - ExpectPlayLog(); - - // The events should arrive in the same sequence as the expects. - InSequence in_sequence; - - // Full argument version, passing lengths explicitly. - TraceEventETWProvider::Trace(kName, - strlen(kName), - TRACE_EVENT_PHASE_BEGIN, - kId, - kExtra, - strlen(kExtra)); - - ExpectEvent(kTraceEventClass32, - kTraceEventTypeBegin, - kName, strlen(kName), - kId, - kExtra, strlen(kExtra)); - - // Const char* version. - TraceEventETWProvider::Trace(static_cast(kName), - TRACE_EVENT_PHASE_END, - kId, - static_cast(kExtra)); - - ExpectEvent(kTraceEventClass32, - kTraceEventTypeEnd, - kName, strlen(kName), - kId, - kExtra, strlen(kExtra)); - - // std::string extra version. - TraceEventETWProvider::Trace(static_cast(kName), - TRACE_EVENT_PHASE_INSTANT, - kId, - std::string(kExtra)); - - ExpectEvent(kTraceEventClass32, - kTraceEventTypeInstant, - kName, strlen(kName), - kId, - kExtra, strlen(kExtra)); - - - // Test for sanity on NULL inputs. - TraceEventETWProvider::Trace(NULL, - 0, - TRACE_EVENT_PHASE_BEGIN, - kId, - NULL, - 0); - - ExpectEvent(kTraceEventClass32, - kTraceEventTypeBegin, - kEmpty, 0, - kId, - kEmpty, 0); - - TraceEventETWProvider::Trace(NULL, - -1, - TRACE_EVENT_PHASE_END, - kId, - NULL, - -1); - - ExpectEvent(kTraceEventClass32, - kTraceEventTypeEnd, - kEmpty, 0, - kId, - kEmpty, 0); - - PlayLog(); -} - -TEST_F(TraceEventWinTest, Macros) { - ExpectPlayLog(); - - // The events should arrive in the same sequence as the expects. - InSequence in_sequence; - - TRACE_EVENT_BEGIN_ETW(kName, kId, kExtra); - ExpectEvent(kTraceEventClass32, - kTraceEventTypeBegin, - kName, strlen(kName), - kId, - kExtra, strlen(kExtra)); - - TRACE_EVENT_END_ETW(kName, kId, kExtra); - ExpectEvent(kTraceEventClass32, - kTraceEventTypeEnd, - kName, strlen(kName), - kId, - kExtra, strlen(kExtra)); - - TRACE_EVENT_INSTANT_ETW(kName, kId, kExtra); - ExpectEvent(kTraceEventClass32, - kTraceEventTypeInstant, - kName, strlen(kName), - kId, - kExtra, strlen(kExtra)); - - PlayLog(); -} - -} // namespace debug -} // namespace base diff --git a/base/debug_message.cc b/base/debug_message.cc deleted file mode 100644 index 10f441d315..0000000000 --- a/base/debug_message.cc +++ /dev/null @@ -1,17 +0,0 @@ -// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include - -// Display the command line. This program is designed to be called from -// another process to display assertions. Since the other process has -// complete control of our command line, we assume that it did *not* -// add the program name as the first parameter. This allows us to just -// show the command line directly as the message. -int APIENTRY WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, - LPSTR lpCmdLine, int nCmdShow) { - LPWSTR cmdline = GetCommandLineW(); - MessageBox(NULL, cmdline, L"Kr\x00d8m", MB_TOPMOST); - return 0; -} diff --git a/base/deferred_sequenced_task_runner.cc b/base/deferred_sequenced_task_runner.cc deleted file mode 100644 index c96704c54d..0000000000 --- a/base/deferred_sequenced_task_runner.cc +++ /dev/null @@ -1,99 +0,0 @@ -// Copyright (c) 2013 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "base/deferred_sequenced_task_runner.h" - -#include "base/bind.h" -#include "base/logging.h" - -namespace base { - -DeferredSequencedTaskRunner::DeferredTask::DeferredTask() { -} - -DeferredSequencedTaskRunner::DeferredTask::~DeferredTask() { -} - -DeferredSequencedTaskRunner::DeferredSequencedTaskRunner( - const scoped_refptr& target_task_runner) - : started_(false), - target_task_runner_(target_task_runner) { -} - -DeferredSequencedTaskRunner::~DeferredSequencedTaskRunner() { -} - -bool DeferredSequencedTaskRunner::PostDelayedTask( - const tracked_objects::Location& from_here, - const Closure& task, - TimeDelta delay) { - AutoLock lock(lock_); - if (started_) { - DCHECK(deferred_tasks_queue_.empty()); - return target_task_runner_->PostDelayedTask(from_here, task, delay); - } - - QueueDeferredTask(from_here, task, delay, false /* is_non_nestable */); - return true; -} - -bool DeferredSequencedTaskRunner::RunsTasksOnCurrentThread() const { - return target_task_runner_->RunsTasksOnCurrentThread(); -} - -bool DeferredSequencedTaskRunner::PostNonNestableDelayedTask( - const tracked_objects::Location& from_here, - const Closure& task, - TimeDelta delay) { - AutoLock lock(lock_); - if (started_) { - DCHECK(deferred_tasks_queue_.empty()); - return target_task_runner_->PostNonNestableDelayedTask(from_here, - task, - delay); - } - QueueDeferredTask(from_here, task, delay, true /* is_non_nestable */); - return true; -} - -void DeferredSequencedTaskRunner::QueueDeferredTask( - const tracked_objects::Location& from_here, - const Closure& task, - TimeDelta delay, - bool is_non_nestable) { - DeferredTask deferred_task; - deferred_task.posted_from = from_here; - deferred_task.task = task; - deferred_task.delay = delay; - deferred_task.is_non_nestable = is_non_nestable; - deferred_tasks_queue_.push_back(deferred_task); -} - - -void DeferredSequencedTaskRunner::Start() { - AutoLock lock(lock_); - DCHECK(!started_); - started_ = true; - for (std::vector::iterator i = deferred_tasks_queue_.begin(); - i != deferred_tasks_queue_.end(); - ++i) { - const DeferredTask& task = *i; - if (task.is_non_nestable) { - target_task_runner_->PostNonNestableDelayedTask(task.posted_from, - task.task, - task.delay); - } else { - target_task_runner_->PostDelayedTask(task.posted_from, - task.task, - task.delay); - } - // Replace the i-th element in the |deferred_tasks_queue_| with an empty - // |DelayedTask| to ensure that |task| is destroyed before the next task - // is posted. - *i = DeferredTask(); - } - deferred_tasks_queue_.clear(); -} - -} // namespace base diff --git a/base/deferred_sequenced_task_runner.h b/base/deferred_sequenced_task_runner.h deleted file mode 100644 index 00ab0507de..0000000000 --- a/base/deferred_sequenced_task_runner.h +++ /dev/null @@ -1,79 +0,0 @@ -// Copyright (c) 2013 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef BASE_DEFERRED_SEQUENCED_TASKRUNNER_H_ -#define BASE_DEFERRED_SEQUENCED_TASKRUNNER_H_ - -#include - -#include "base/base_export.h" -#include "base/basictypes.h" -#include "base/callback.h" -#include "base/compiler_specific.h" -#include "base/memory/ref_counted.h" -#include "base/sequenced_task_runner.h" -#include "base/synchronization/lock.h" -#include "base/time/time.h" -#include "base/tracked_objects.h" - -namespace base { - -// A DeferredSequencedTaskRunner is a subclass of SequencedTaskRunner that -// queues up all requests until the first call to Start() is issued. -class BASE_EXPORT DeferredSequencedTaskRunner : public SequencedTaskRunner { - public: - explicit DeferredSequencedTaskRunner( - const scoped_refptr& target_runner); - - // TaskRunner implementation - virtual bool PostDelayedTask(const tracked_objects::Location& from_here, - const Closure& task, - TimeDelta delay) OVERRIDE; - virtual bool RunsTasksOnCurrentThread() const OVERRIDE; - - // SequencedTaskRunner implementation - virtual bool PostNonNestableDelayedTask( - const tracked_objects::Location& from_here, - const Closure& task, - TimeDelta delay) OVERRIDE; - - // Start the execution - posts all queued tasks to the target executor. The - // deferred tasks are posted with their initial delay, meaning that the task - // execution delay is actually measured from Start. - // Fails when called a second time. - void Start(); - - private: - struct DeferredTask { - DeferredTask(); - ~DeferredTask(); - - tracked_objects::Location posted_from; - Closure task; - // The delay this task was initially posted with. - TimeDelta delay; - bool is_non_nestable; - }; - - virtual ~DeferredSequencedTaskRunner(); - - // Creates a |Task| object and adds it to |deferred_tasks_queue_|. - void QueueDeferredTask(const tracked_objects::Location& from_here, - const Closure& task, - TimeDelta delay, - bool is_non_nestable); - - // // Protects |started_| and |deferred_tasks_queue_|. - mutable Lock lock_; - - bool started_; - const scoped_refptr target_task_runner_; - std::vector deferred_tasks_queue_; - - DISALLOW_COPY_AND_ASSIGN(DeferredSequencedTaskRunner); -}; - -} // namespace base - -#endif // BASE_DEFERRED_SEQUENCED_TASKRUNNER_H_ diff --git a/base/deferred_sequenced_task_runner_unittest.cc b/base/deferred_sequenced_task_runner_unittest.cc deleted file mode 100644 index 81f2a0a00c..0000000000 --- a/base/deferred_sequenced_task_runner_unittest.cc +++ /dev/null @@ -1,184 +0,0 @@ -// Copyright (c) 2013 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "base/deferred_sequenced_task_runner.h" - -#include "base/basictypes.h" -#include "base/bind.h" -#include "base/bind_helpers.h" -#include "base/memory/ref_counted.h" -#include "base/message_loop/message_loop.h" -#include "base/message_loop/message_loop_proxy.h" -#include "base/threading/non_thread_safe.h" -#include "base/threading/thread.h" -#include "testing/gmock/include/gmock/gmock.h" -#include "testing/gtest/include/gtest/gtest.h" - -namespace { - -class DeferredSequencedTaskRunnerTest : public testing::Test, - public base::NonThreadSafe { - public: - class ExecuteTaskOnDestructor : - public base::RefCounted { - public: - ExecuteTaskOnDestructor( - DeferredSequencedTaskRunnerTest* executor, - int task_id) - : executor_(executor), - task_id_(task_id) { - } - private: - friend class base::RefCounted; - virtual ~ExecuteTaskOnDestructor() { - executor_->ExecuteTask(task_id_); - } - DeferredSequencedTaskRunnerTest* executor_; - int task_id_; - }; - - void ExecuteTask(int task_id) { - base::AutoLock lock(lock_); - executed_task_ids_.push_back(task_id); - } - - void PostExecuteTask(int task_id) { - runner_->PostTask(FROM_HERE, - base::Bind(&DeferredSequencedTaskRunnerTest::ExecuteTask, - base::Unretained(this), - task_id)); - } - - void StartRunner() { - runner_->Start(); - } - - void DoNothing(ExecuteTaskOnDestructor* object) { - } - - protected: - DeferredSequencedTaskRunnerTest() : - loop_(), - runner_( - new base::DeferredSequencedTaskRunner(loop_.message_loop_proxy())) { - } - - base::MessageLoop loop_; - scoped_refptr runner_; - mutable base::Lock lock_; - std::vector executed_task_ids_; -}; - -TEST_F(DeferredSequencedTaskRunnerTest, Stopped) { - PostExecuteTask(1); - loop_.RunUntilIdle(); - EXPECT_THAT(executed_task_ids_, testing::ElementsAre()); -} - -TEST_F(DeferredSequencedTaskRunnerTest, Start) { - StartRunner(); - PostExecuteTask(1); - loop_.RunUntilIdle(); - EXPECT_THAT(executed_task_ids_, testing::ElementsAre(1)); -} - -TEST_F(DeferredSequencedTaskRunnerTest, StartWithMultipleElements) { - StartRunner(); - for (int i = 1; i < 5; ++i) - PostExecuteTask(i); - - loop_.RunUntilIdle(); - EXPECT_THAT(executed_task_ids_, testing::ElementsAre(1, 2, 3, 4)); -} - -TEST_F(DeferredSequencedTaskRunnerTest, DeferredStart) { - PostExecuteTask(1); - loop_.RunUntilIdle(); - EXPECT_THAT(executed_task_ids_, testing::ElementsAre()); - - StartRunner(); - loop_.RunUntilIdle(); - EXPECT_THAT(executed_task_ids_, testing::ElementsAre(1)); - - PostExecuteTask(2); - loop_.RunUntilIdle(); - EXPECT_THAT(executed_task_ids_, testing::ElementsAre(1, 2)); -} - -TEST_F(DeferredSequencedTaskRunnerTest, DeferredStartWithMultipleElements) { - for (int i = 1; i < 5; ++i) - PostExecuteTask(i); - loop_.RunUntilIdle(); - EXPECT_THAT(executed_task_ids_, testing::ElementsAre()); - - StartRunner(); - for (int i = 5; i < 9; ++i) - PostExecuteTask(i); - loop_.RunUntilIdle(); - EXPECT_THAT(executed_task_ids_, testing::ElementsAre(1, 2, 3, 4, 5, 6, 7, 8)); -} - -TEST_F(DeferredSequencedTaskRunnerTest, DeferredStartWithMultipleThreads) { - { - base::Thread thread1("DeferredSequencedTaskRunnerTestThread1"); - base::Thread thread2("DeferredSequencedTaskRunnerTestThread2"); - thread1.Start(); - thread2.Start(); - for (int i = 0; i < 5; ++i) { - thread1.message_loop()->PostTask( - FROM_HERE, - base::Bind(&DeferredSequencedTaskRunnerTest::PostExecuteTask, - base::Unretained(this), - 2 * i)); - thread2.message_loop()->PostTask( - FROM_HERE, - base::Bind(&DeferredSequencedTaskRunnerTest::PostExecuteTask, - base::Unretained(this), - 2 * i + 1)); - if (i == 2) { - thread1.message_loop()->PostTask( - FROM_HERE, - base::Bind(&DeferredSequencedTaskRunnerTest::StartRunner, - base::Unretained(this))); - } - } - } - - loop_.RunUntilIdle(); - EXPECT_THAT(executed_task_ids_, - testing::WhenSorted(testing::ElementsAre(0, 1, 2, 3, 4, 5, 6, 7, 8, 9))); -} - -TEST_F(DeferredSequencedTaskRunnerTest, ObjectDestructionOrder) { - { - base::Thread thread("DeferredSequencedTaskRunnerTestThread"); - thread.Start(); - runner_ = - new base::DeferredSequencedTaskRunner(thread.message_loop_proxy()); - for (int i = 0; i < 5; ++i) { - { - // Use a block to ensure that no reference to |short_lived_object| - // is kept on the main thread after it is posted to |runner_|. - scoped_refptr short_lived_object = - new ExecuteTaskOnDestructor(this, 2 * i); - runner_->PostTask( - FROM_HERE, - base::Bind(&DeferredSequencedTaskRunnerTest::DoNothing, - base::Unretained(this), - short_lived_object)); - } - // |short_lived_object| with id |2 * i| should be destroyed before the - // task |2 * i + 1| is executed. - PostExecuteTask(2 * i + 1); - } - StartRunner(); - } - - // All |short_lived_object| with id |2 * i| are destroyed before the task - // |2 * i + 1| is executed. - EXPECT_THAT(executed_task_ids_, - testing::ElementsAre(0, 1, 2, 3, 4, 5, 6, 7, 8, 9)); -} - -} // namespace diff --git a/base/environment.cc b/base/environment.cc deleted file mode 100644 index c1f2008b4c..0000000000 --- a/base/environment.cc +++ /dev/null @@ -1,127 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "base/environment.h" - -#if defined(OS_POSIX) -#include -#elif defined(OS_WIN) -#include -#endif - -#include "base/strings/string_util.h" - -#if defined(OS_WIN) -#include "base/memory/scoped_ptr.h" -#include "base/strings/utf_string_conversions.h" -#endif - -namespace { - -class EnvironmentImpl : public base::Environment { - public: - virtual bool GetVar(const char* variable_name, - std::string* result) OVERRIDE { - if (GetVarImpl(variable_name, result)) - return true; - - // Some commonly used variable names are uppercase while others - // are lowercase, which is inconsistent. Let's try to be helpful - // and look for a variable name with the reverse case. - // I.e. HTTP_PROXY may be http_proxy for some users/systems. - char first_char = variable_name[0]; - std::string alternate_case_var; - if (first_char >= 'a' && first_char <= 'z') - alternate_case_var = StringToUpperASCII(std::string(variable_name)); - else if (first_char >= 'A' && first_char <= 'Z') - alternate_case_var = StringToLowerASCII(std::string(variable_name)); - else - return false; - return GetVarImpl(alternate_case_var.c_str(), result); - } - - virtual bool SetVar(const char* variable_name, - const std::string& new_value) OVERRIDE { - return SetVarImpl(variable_name, new_value); - } - - virtual bool UnSetVar(const char* variable_name) OVERRIDE { - return UnSetVarImpl(variable_name); - } - - private: - bool GetVarImpl(const char* variable_name, std::string* result) { -#if defined(OS_POSIX) - const char* env_value = getenv(variable_name); - if (!env_value) - return false; - // Note that the variable may be defined but empty. - if (result) - *result = env_value; - return true; -#elif defined(OS_WIN) - DWORD value_length = ::GetEnvironmentVariable( - UTF8ToWide(variable_name).c_str(), NULL, 0); - if (value_length == 0) - return false; - if (result) { - scoped_ptr value(new wchar_t[value_length]); - ::GetEnvironmentVariable(UTF8ToWide(variable_name).c_str(), value.get(), - value_length); - *result = WideToUTF8(value.get()); - } - return true; -#else -#error need to port -#endif - } - - bool SetVarImpl(const char* variable_name, const std::string& new_value) { -#if defined(OS_POSIX) - // On success, zero is returned. - return !setenv(variable_name, new_value.c_str(), 1); -#elif defined(OS_WIN) - // On success, a nonzero value is returned. - return !!SetEnvironmentVariable(UTF8ToWide(variable_name).c_str(), - UTF8ToWide(new_value).c_str()); -#endif - } - - bool UnSetVarImpl(const char* variable_name) { -#if defined(OS_POSIX) - // On success, zero is returned. - return !unsetenv(variable_name); -#elif defined(OS_WIN) - // On success, a nonzero value is returned. - return !!SetEnvironmentVariable(UTF8ToWide(variable_name).c_str(), NULL); -#endif - } -}; - -} // namespace - -namespace base { - -namespace env_vars { - -#if defined(OS_POSIX) -// On Posix systems, this variable contains the location of the user's home -// directory. (e.g, /home/username/). -const char kHome[] = "HOME"; -#endif - -} // namespace env_vars - -Environment::~Environment() {} - -// static -Environment* Environment::Create() { - return new EnvironmentImpl(); -} - -bool Environment::HasVar(const char* variable_name) { - return GetVar(variable_name, NULL); -} - -} // namespace base diff --git a/base/environment.h b/base/environment.h deleted file mode 100644 index 5160ff2469..0000000000 --- a/base/environment.h +++ /dev/null @@ -1,48 +0,0 @@ -// Copyright (c) 2011 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef BASE_ENVIRONMENT_H_ -#define BASE_ENVIRONMENT_H_ - -#include - -#include "base/base_export.h" -#include "build/build_config.h" - -namespace base { - -namespace env_vars { - -#if defined(OS_POSIX) -BASE_EXPORT extern const char kHome[]; -#endif - -} // namespace env_vars - -class BASE_EXPORT Environment { - public: - virtual ~Environment(); - - // Static factory method that returns the implementation that provide the - // appropriate platform-specific instance. - static Environment* Create(); - - // Gets an environment variable's value and stores it in |result|. - // Returns false if the key is unset. - virtual bool GetVar(const char* variable_name, std::string* result) = 0; - - // Syntactic sugar for GetVar(variable_name, NULL); - virtual bool HasVar(const char* variable_name); - - // Returns true on success, otherwise returns false. - virtual bool SetVar(const char* variable_name, - const std::string& new_value) = 0; - - // Returns true on success, otherwise returns false. - virtual bool UnSetVar(const char* variable_name) = 0; -}; - -} // namespace base - -#endif // BASE_ENVIRONMENT_H_ diff --git a/base/environment_unittest.cc b/base/environment_unittest.cc deleted file mode 100644 index b6654c99f4..0000000000 --- a/base/environment_unittest.cc +++ /dev/null @@ -1,85 +0,0 @@ -// Copyright (c) 2011 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "base/environment.h" -#include "base/memory/scoped_ptr.h" -#include "testing/gtest/include/gtest/gtest.h" -#include "testing/platform_test.h" - -typedef PlatformTest EnvironmentTest; - -TEST_F(EnvironmentTest, GetVar) { - // Every setup should have non-empty PATH... - scoped_ptr env(base::Environment::Create()); - std::string env_value; - EXPECT_TRUE(env->GetVar("PATH", &env_value)); - EXPECT_NE(env_value, ""); -} - -TEST_F(EnvironmentTest, GetVarReverse) { - scoped_ptr env(base::Environment::Create()); - const char* kFooUpper = "FOO"; - const char* kFooLower = "foo"; - - // Set a variable in UPPER case. - EXPECT_TRUE(env->SetVar(kFooUpper, kFooLower)); - - // And then try to get this variable passing the lower case. - std::string env_value; - EXPECT_TRUE(env->GetVar(kFooLower, &env_value)); - - EXPECT_STREQ(env_value.c_str(), kFooLower); - - EXPECT_TRUE(env->UnSetVar(kFooUpper)); - - const char* kBar = "bar"; - // Now do the opposite, set the variable in the lower case. - EXPECT_TRUE(env->SetVar(kFooLower, kBar)); - - // And then try to get this variable passing the UPPER case. - EXPECT_TRUE(env->GetVar(kFooUpper, &env_value)); - - EXPECT_STREQ(env_value.c_str(), kBar); - - EXPECT_TRUE(env->UnSetVar(kFooLower)); -} - -TEST_F(EnvironmentTest, HasVar) { - // Every setup should have PATH... - scoped_ptr env(base::Environment::Create()); - EXPECT_TRUE(env->HasVar("PATH")); -} - -TEST_F(EnvironmentTest, SetVar) { - scoped_ptr env(base::Environment::Create()); - - const char* kFooUpper = "FOO"; - const char* kFooLower = "foo"; - EXPECT_TRUE(env->SetVar(kFooUpper, kFooLower)); - - // Now verify that the environment has the new variable. - EXPECT_TRUE(env->HasVar(kFooUpper)); - - std::string var_value; - EXPECT_TRUE(env->GetVar(kFooUpper, &var_value)); - EXPECT_EQ(var_value, kFooLower); -} - -TEST_F(EnvironmentTest, UnSetVar) { - scoped_ptr env(base::Environment::Create()); - - const char* kFooUpper = "FOO"; - const char* kFooLower = "foo"; - // First set some environment variable. - EXPECT_TRUE(env->SetVar(kFooUpper, kFooLower)); - - // Now verify that the environment has the new variable. - EXPECT_TRUE(env->HasVar(kFooUpper)); - - // Finally verify that the environment variable was erased. - EXPECT_TRUE(env->UnSetVar(kFooUpper)); - - // And check that the variable has been unset. - EXPECT_FALSE(env->HasVar(kFooUpper)); -} diff --git a/base/event_recorder.h b/base/event_recorder.h deleted file mode 100644 index bff87ed494..0000000000 --- a/base/event_recorder.h +++ /dev/null @@ -1,109 +0,0 @@ -// Copyright (c) 2011 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef BASE_EVENT_RECORDER_H_ -#define BASE_EVENT_RECORDER_H_ - -#include "base/base_export.h" -#include "base/basictypes.h" -#include "build/build_config.h" - -#if defined(OS_WIN) -#include -#include -#include -#endif - -namespace base { - -class FilePath; - -// A class for recording and playing back keyboard and mouse input events. -// -// Note - if you record events, and the playback with the windows in -// different sizes or positions, the playback will fail. When -// recording and playing, you should move the relevant windows -// to constant sizes and locations. -// TODO(mbelshe) For now this is a singleton. I believe that this class -// could be easily modified to: -// support two simultaneous recorders -// be playing back events while already recording events. -// Why? Imagine if the product had a "record a macro" feature. -// You might be recording globally, while recording or playing back -// a macro. I don't think two playbacks make sense. -class BASE_EXPORT EventRecorder { - public: - // Get the singleton EventRecorder. - // We can only handle one recorder/player at a time. - static EventRecorder* current() { - if (!current_) - current_ = new EventRecorder(); - return current_; - } - - // Starts recording events. - // Will clobber the file if it already exists. - // Returns true on success, or false if an error occurred. - bool StartRecording(const FilePath& filename); - - // Stops recording. - void StopRecording(); - - // Is the EventRecorder currently recording. - bool is_recording() const { return is_recording_; } - - // Plays events previously recorded. - // Returns true on success, or false if an error occurred. - bool StartPlayback(const FilePath& filename); - - // Stops playback. - void StopPlayback(); - - // Is the EventRecorder currently playing. - bool is_playing() const { return is_playing_; } - -#if defined(OS_WIN) - // C-style callbacks for the EventRecorder. - // Used for internal purposes only. - LRESULT RecordWndProc(int nCode, WPARAM wParam, LPARAM lParam); - LRESULT PlaybackWndProc(int nCode, WPARAM wParam, LPARAM lParam); -#endif - - private: - // Create a new EventRecorder. Events are saved to the file filename. - // If the file already exists, it will be deleted before recording - // starts. - EventRecorder() - : is_recording_(false), - is_playing_(false), -#if defined(OS_WIN) - journal_hook_(NULL), - file_(NULL), -#endif - playback_first_msg_time_(0), - playback_start_time_(0) { -#if defined(OS_WIN) - memset(&playback_msg_, 0, sizeof(playback_msg_)); -#endif - } - ~EventRecorder(); - - static EventRecorder* current_; // Our singleton. - - bool is_recording_; - bool is_playing_; -#if defined(OS_WIN) - HHOOK journal_hook_; - FILE* file_; - EVENTMSG playback_msg_; -#endif - int playback_first_msg_time_; - int playback_start_time_; - - DISALLOW_COPY_AND_ASSIGN(EventRecorder); -}; - -} // namespace base - -#endif // BASE_EVENT_RECORDER_H_ diff --git a/base/event_recorder_stubs.cc b/base/event_recorder_stubs.cc deleted file mode 100644 index 91f2e072fc..0000000000 --- a/base/event_recorder_stubs.cc +++ /dev/null @@ -1,28 +0,0 @@ -// Copyright (c) 2009 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "base/event_recorder.h" - -// This file implements a link stub for EventRecorder that can be used on -// platforms that don't have a working EventRecorder implementation. - -namespace base { - -EventRecorder* EventRecorder::current_; // Our singleton. - -bool EventRecorder::StartRecording(const FilePath& filename) { - return true; -} - -void EventRecorder::StopRecording() { -} - -bool EventRecorder::StartPlayback(const FilePath& filename) { - return false; -} - -void EventRecorder::StopPlayback() { -} - -} // namespace diff --git a/base/event_recorder_win.cc b/base/event_recorder_win.cc deleted file mode 100644 index 11bf0f0cb1..0000000000 --- a/base/event_recorder_win.cc +++ /dev/null @@ -1,258 +0,0 @@ -// Copyright (c) 2011 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include -#include -#include - -#include "base/event_recorder.h" -#include "base/file_util.h" -#include "base/logging.h" - -// A note about time. -// For perfect playback of events, you'd like a very accurate timer -// so that events are played back at exactly the same time that -// they were recorded. However, windows has a clock which is only -// granular to ~15ms. We see more consistent event playback when -// using a higher resolution timer. To do this, we use the -// timeGetTime API instead of the default GetTickCount() API. - -namespace base { - -EventRecorder* EventRecorder::current_ = NULL; - -LRESULT CALLBACK StaticRecordWndProc(int nCode, WPARAM wParam, - LPARAM lParam) { - DCHECK(EventRecorder::current()); - return EventRecorder::current()->RecordWndProc(nCode, wParam, lParam); -} - -LRESULT CALLBACK StaticPlaybackWndProc(int nCode, WPARAM wParam, - LPARAM lParam) { - DCHECK(EventRecorder::current()); - return EventRecorder::current()->PlaybackWndProc(nCode, wParam, lParam); -} - -EventRecorder::~EventRecorder() { - // Try to assert early if the caller deletes the recorder - // while it is still in use. - DCHECK(!journal_hook_); - DCHECK(!is_recording_ && !is_playing_); -} - -bool EventRecorder::StartRecording(const FilePath& filename) { - if (journal_hook_ != NULL) - return false; - if (is_recording_ || is_playing_) - return false; - - // Open the recording file. - DCHECK(!file_); - file_ = file_util::OpenFile(filename, "wb+"); - if (!file_) { - DLOG(ERROR) << "EventRecorder could not open log file"; - return false; - } - - // Set the faster clock, if possible. - ::timeBeginPeriod(1); - - // Set the recording hook. JOURNALRECORD can only be used as a global hook. - journal_hook_ = ::SetWindowsHookEx(WH_JOURNALRECORD, StaticRecordWndProc, - GetModuleHandle(NULL), 0); - if (!journal_hook_) { - DLOG(ERROR) << "EventRecorder Record Hook failed"; - file_util::CloseFile(file_); - return false; - } - - is_recording_ = true; - return true; -} - -void EventRecorder::StopRecording() { - if (is_recording_) { - DCHECK(journal_hook_ != NULL); - - if (!::UnhookWindowsHookEx(journal_hook_)) { - DLOG(ERROR) << "EventRecorder Unhook failed"; - // Nothing else we can really do here. - return; - } - - ::timeEndPeriod(1); - - DCHECK(file_ != NULL); - file_util::CloseFile(file_); - file_ = NULL; - - journal_hook_ = NULL; - is_recording_ = false; - } -} - -bool EventRecorder::StartPlayback(const FilePath& filename) { - if (journal_hook_ != NULL) - return false; - if (is_recording_ || is_playing_) - return false; - - // Open the recording file. - DCHECK(!file_); - file_ = file_util::OpenFile(filename, "rb"); - if (!file_) { - DLOG(ERROR) << "EventRecorder Playback could not open log file"; - return false; - } - // Read the first event from the record. - if (fread(&playback_msg_, sizeof(EVENTMSG), 1, file_) != 1) { - DLOG(ERROR) << "EventRecorder Playback has no records!"; - file_util::CloseFile(file_); - return false; - } - - // Set the faster clock, if possible. - ::timeBeginPeriod(1); - - // Playback time is tricky. When playing back, we read a series of events, - // each with timeouts. Simply subtracting the delta between two timers will - // lead to fast playback (about 2x speed). The API has two events, one - // which advances to the next event (HC_SKIP), and another that requests the - // event (HC_GETNEXT). The same event will be requested multiple times. - // Each time the event is requested, we must calculate the new delay. - // To do this, we track the start time of the playback, and constantly - // re-compute the delay. I mention this only because I saw two examples - // of how to use this code on the net, and both were broken :-) - playback_start_time_ = timeGetTime(); - playback_first_msg_time_ = playback_msg_.time; - - // Set the hook. JOURNALPLAYBACK can only be used as a global hook. - journal_hook_ = ::SetWindowsHookEx(WH_JOURNALPLAYBACK, StaticPlaybackWndProc, - GetModuleHandle(NULL), 0); - if (!journal_hook_) { - DLOG(ERROR) << "EventRecorder Playback Hook failed"; - return false; - } - - is_playing_ = true; - - return true; -} - -void EventRecorder::StopPlayback() { - if (is_playing_) { - DCHECK(journal_hook_ != NULL); - - if (!::UnhookWindowsHookEx(journal_hook_)) { - DLOG(ERROR) << "EventRecorder Unhook failed"; - // Nothing else we can really do here. - } - - DCHECK(file_ != NULL); - file_util::CloseFile(file_); - file_ = NULL; - - ::timeEndPeriod(1); - - journal_hook_ = NULL; - is_playing_ = false; - } -} - -// Windows callback hook for the recorder. -LRESULT EventRecorder::RecordWndProc(int nCode, WPARAM wParam, LPARAM lParam) { - static bool recording_enabled = true; - EVENTMSG* msg_ptr = NULL; - - // The API says we have to do this. - // See http://msdn2.microsoft.com/en-us/library/ms644983(VS.85).aspx - if (nCode < 0) - return ::CallNextHookEx(journal_hook_, nCode, wParam, lParam); - - // Check for the break key being pressed and stop recording. - if (::GetKeyState(VK_CANCEL) & 0x8000) { - StopRecording(); - return ::CallNextHookEx(journal_hook_, nCode, wParam, lParam); - } - - // The Journal Recorder must stop recording events when system modal - // dialogs are present. (see msdn link above) - switch (nCode) { - case HC_SYSMODALON: - recording_enabled = false; - break; - case HC_SYSMODALOFF: - recording_enabled = true; - break; - } - - if (nCode == HC_ACTION && recording_enabled) { - // Aha - we have an event to record. - msg_ptr = reinterpret_cast(lParam); - msg_ptr->time = timeGetTime(); - fwrite(msg_ptr, sizeof(EVENTMSG), 1, file_); - fflush(file_); - } - - return CallNextHookEx(journal_hook_, nCode, wParam, lParam); -} - -// Windows callback for the playback mode. -LRESULT EventRecorder::PlaybackWndProc(int nCode, WPARAM wParam, - LPARAM lParam) { - static bool playback_enabled = true; - int delay = 0; - - switch (nCode) { - // A system modal dialog box is being displayed. Stop playing back - // messages. - case HC_SYSMODALON: - playback_enabled = false; - break; - - // A system modal dialog box is destroyed. We can start playing back - // messages again. - case HC_SYSMODALOFF: - playback_enabled = true; - break; - - // Prepare to copy the next mouse or keyboard event to playback. - case HC_SKIP: - if (!playback_enabled) - break; - - // Read the next event from the record. - if (fread(&playback_msg_, sizeof(EVENTMSG), 1, file_) != 1) - this->StopPlayback(); - break; - - // Copy the mouse or keyboard event to the EVENTMSG structure in lParam. - case HC_GETNEXT: - if (!playback_enabled) - break; - - memcpy(reinterpret_cast(lParam), &playback_msg_, - sizeof(playback_msg_)); - - // The return value is the amount of time (in milliseconds) to wait - // before playing back the next message in the playback queue. Each - // time this is called, we recalculate the delay relative to our current - // wall clock. - delay = (playback_msg_.time - playback_first_msg_time_) - - (timeGetTime() - playback_start_time_); - if (delay < 0) - delay = 0; - return delay; - - // An application has called PeekMessage with wRemoveMsg set to PM_NOREMOVE - // indicating that the message is not removed from the message queue after - // PeekMessage processing. - case HC_NOREMOVE: - break; - } - - return CallNextHookEx(journal_hook_, nCode, wParam, lParam); -} - -} // namespace base diff --git a/base/event_types.h b/base/event_types.h deleted file mode 100644 index af586e46ec..0000000000 --- a/base/event_types.h +++ /dev/null @@ -1,37 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef BASE_EVENT_TYPES_H -#define BASE_EVENT_TYPES_H - -#include "build/build_config.h" - -#if defined(OS_WIN) -#include -#elif defined(USE_X11) -typedef union _XEvent XEvent; -#elif defined(OS_MACOSX) -#if defined(__OBJC__) -@class NSEvent; -#else // __OBJC__ -class NSEvent; -#endif // __OBJC__ -#endif - -namespace base { - -// Cross platform typedefs for native event types. -#if defined(OS_WIN) -typedef MSG NativeEvent; -#elif defined(USE_X11) -typedef XEvent* NativeEvent; -#elif defined(OS_MACOSX) -typedef NSEvent* NativeEvent; -#else -typedef void* NativeEvent; -#endif - -} // namespace base - -#endif // BASE_EVENT_TYPES_H diff --git a/base/file_descriptor_posix.h b/base/file_descriptor_posix.h deleted file mode 100644 index abc07893fa..0000000000 --- a/base/file_descriptor_posix.h +++ /dev/null @@ -1,45 +0,0 @@ -// Copyright (c) 2006-2009 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef BASE_FILE_DESCRIPTOR_POSIX_H_ -#define BASE_FILE_DESCRIPTOR_POSIX_H_ - -namespace base { - -// ----------------------------------------------------------------------------- -// We introduct a special structure for file descriptors in order that we are -// able to use template specialisation to special-case their handling. -// -// WARNING: (Chromium only) There are subtleties to consider if serialising -// these objects over IPC. See comments in ipc/ipc_message_utils.h -// above the template specialisation for this structure. -// ----------------------------------------------------------------------------- -struct FileDescriptor { - FileDescriptor() - : fd(-1), - auto_close(false) { } - - FileDescriptor(int ifd, bool iauto_close) - : fd(ifd), - auto_close(iauto_close) { } - - bool operator==(const FileDescriptor& other) const { - return (fd == other.fd && auto_close == other.auto_close); - } - - // A comparison operator so that we can use these as keys in a std::map. - bool operator<(const FileDescriptor& other) const { - return other.fd < fd; - } - - int fd; - // If true, this file descriptor should be closed after it has been used. For - // example an IPC system might interpret this flag as indicating that the - // file descriptor it has been given should be closed after use. - bool auto_close; -}; - -} // namespace base - -#endif // BASE_FILE_DESCRIPTOR_POSIX_H_ diff --git a/base/file_util.cc b/base/file_util.cc deleted file mode 100644 index 2623b64391..0000000000 --- a/base/file_util.cc +++ /dev/null @@ -1,264 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "base/file_util.h" - -#if defined(OS_WIN) -#include -#endif -#include - -#include - -#include "base/files/file_enumerator.h" -#include "base/files/file_path.h" -#include "base/logging.h" -#include "base/strings/string_piece.h" -#include "base/strings/string_util.h" -#include "base/strings/stringprintf.h" -#include "base/strings/utf_string_conversions.h" - -namespace base { - -namespace { - -const FilePath::CharType kExtensionSeparator = FILE_PATH_LITERAL('.'); - -// The maximum number of 'uniquified' files we will try to create. -// This is used when the filename we're trying to download is already in use, -// so we create a new unique filename by appending " (nnn)" before the -// extension, where 1 <= nnn <= kMaxUniqueFiles. -// Also used by code that cleans up said files. -static const int kMaxUniqueFiles = 100; - -} // namespace - -bool g_bug108724_debug = false; - -int64 ComputeDirectorySize(const FilePath& root_path) { - int64 running_size = 0; - FileEnumerator file_iter(root_path, true, FileEnumerator::FILES); - while (!file_iter.Next().empty()) - running_size += file_iter.GetInfo().GetSize(); - return running_size; -} - -bool Move(const FilePath& from_path, const FilePath& to_path) { - if (from_path.ReferencesParent() || to_path.ReferencesParent()) - return false; - return internal::MoveUnsafe(from_path, to_path); -} - -bool CopyFile(const FilePath& from_path, const FilePath& to_path) { - if (from_path.ReferencesParent() || to_path.ReferencesParent()) - return false; - return internal::CopyFileUnsafe(from_path, to_path); -} - -bool ContentsEqual(const FilePath& filename1, const FilePath& filename2) { - // We open the file in binary format even if they are text files because - // we are just comparing that bytes are exactly same in both files and not - // doing anything smart with text formatting. - std::ifstream file1(filename1.value().c_str(), - std::ios::in | std::ios::binary); - std::ifstream file2(filename2.value().c_str(), - std::ios::in | std::ios::binary); - - // Even if both files aren't openable (and thus, in some sense, "equal"), - // any unusable file yields a result of "false". - if (!file1.is_open() || !file2.is_open()) - return false; - - const int BUFFER_SIZE = 2056; - char buffer1[BUFFER_SIZE], buffer2[BUFFER_SIZE]; - do { - file1.read(buffer1, BUFFER_SIZE); - file2.read(buffer2, BUFFER_SIZE); - - if ((file1.eof() != file2.eof()) || - (file1.gcount() != file2.gcount()) || - (memcmp(buffer1, buffer2, file1.gcount()))) { - file1.close(); - file2.close(); - return false; - } - } while (!file1.eof() || !file2.eof()); - - file1.close(); - file2.close(); - return true; -} - -bool TextContentsEqual(const FilePath& filename1, const FilePath& filename2) { - std::ifstream file1(filename1.value().c_str(), std::ios::in); - std::ifstream file2(filename2.value().c_str(), std::ios::in); - - // Even if both files aren't openable (and thus, in some sense, "equal"), - // any unusable file yields a result of "false". - if (!file1.is_open() || !file2.is_open()) - return false; - - do { - std::string line1, line2; - getline(file1, line1); - getline(file2, line2); - - // Check for mismatched EOF states, or any error state. - if ((file1.eof() != file2.eof()) || - file1.bad() || file2.bad()) { - return false; - } - - // Trim all '\r' and '\n' characters from the end of the line. - std::string::size_type end1 = line1.find_last_not_of("\r\n"); - if (end1 == std::string::npos) - line1.clear(); - else if (end1 + 1 < line1.length()) - line1.erase(end1 + 1); - - std::string::size_type end2 = line2.find_last_not_of("\r\n"); - if (end2 == std::string::npos) - line2.clear(); - else if (end2 + 1 < line2.length()) - line2.erase(end2 + 1); - - if (line1 != line2) - return false; - } while (!file1.eof() || !file2.eof()); - - return true; -} - -} // namespace base - -// ----------------------------------------------------------------------------- - -namespace file_util { - -using base::FileEnumerator; -using base::FilePath; -using base::kExtensionSeparator; -using base::kMaxUniqueFiles; - -bool ReadFileToString(const FilePath& path, std::string* contents) { - if (path.ReferencesParent()) - return false; - FILE* file = OpenFile(path, "rb"); - if (!file) { - return false; - } - - char buf[1 << 16]; - size_t len; - while ((len = fread(buf, 1, sizeof(buf), file)) > 0) { - if (contents) - contents->append(buf, len); - } - CloseFile(file); - - return true; -} - -bool IsDirectoryEmpty(const FilePath& dir_path) { - FileEnumerator files(dir_path, false, - FileEnumerator::FILES | FileEnumerator::DIRECTORIES); - if (files.Next().empty()) - return true; - return false; -} - -FILE* CreateAndOpenTemporaryFile(FilePath* path) { - FilePath directory; - if (!GetTempDir(&directory)) - return NULL; - - return CreateAndOpenTemporaryFileInDir(directory, path); -} - -bool CreateDirectory(const base::FilePath& full_path) { - return CreateDirectoryAndGetError(full_path, NULL); -} - -bool GetFileSize(const FilePath& file_path, int64* file_size) { - base::PlatformFileInfo info; - if (!GetFileInfo(file_path, &info)) - return false; - *file_size = info.size; - return true; -} - -bool TouchFile(const FilePath& path, - const base::Time& last_accessed, - const base::Time& last_modified) { - int flags = base::PLATFORM_FILE_OPEN | base::PLATFORM_FILE_WRITE_ATTRIBUTES; - -#if defined(OS_WIN) - // On Windows, FILE_FLAG_BACKUP_SEMANTICS is needed to open a directory. - if (DirectoryExists(path)) - flags |= base::PLATFORM_FILE_BACKUP_SEMANTICS; -#endif // OS_WIN - - const base::PlatformFile file = - base::CreatePlatformFile(path, flags, NULL, NULL); - if (file != base::kInvalidPlatformFileValue) { - bool result = base::TouchPlatformFile(file, last_accessed, last_modified); - base::ClosePlatformFile(file); - return result; - } - - return false; -} - -bool SetLastModifiedTime(const FilePath& path, - const base::Time& last_modified) { - return TouchFile(path, last_modified, last_modified); -} - -bool CloseFile(FILE* file) { - if (file == NULL) - return true; - return fclose(file) == 0; -} - -bool TruncateFile(FILE* file) { - if (file == NULL) - return false; - long current_offset = ftell(file); - if (current_offset == -1) - return false; -#if defined(OS_WIN) - int fd = _fileno(file); - if (_chsize(fd, current_offset) != 0) - return false; -#else - int fd = fileno(file); - if (ftruncate(fd, current_offset) != 0) - return false; -#endif - return true; -} - -int GetUniquePathNumber( - const FilePath& path, - const FilePath::StringType& suffix) { - bool have_suffix = !suffix.empty(); - if (!PathExists(path) && - (!have_suffix || !PathExists(FilePath(path.value() + suffix)))) { - return 0; - } - - FilePath new_path; - for (int count = 1; count <= kMaxUniqueFiles; ++count) { - new_path = - path.InsertBeforeExtensionASCII(base::StringPrintf(" (%d)", count)); - if (!PathExists(new_path) && - (!have_suffix || !PathExists(FilePath(new_path.value() + suffix)))) { - return count; - } - } - - return -1; -} - -} // namespace file_util diff --git a/base/file_util.h b/base/file_util.h deleted file mode 100644 index 9673a6111f..0000000000 --- a/base/file_util.h +++ /dev/null @@ -1,464 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -// This file contains utility functions for dealing with the local -// filesystem. - -#ifndef BASE_FILE_UTIL_H_ -#define BASE_FILE_UTIL_H_ - -#include "build/build_config.h" - -#if defined(OS_WIN) -#include -#elif defined(OS_POSIX) -#include -#include -#endif - -#include - -#include -#include -#include - -#include "base/base_export.h" -#include "base/basictypes.h" -#include "base/files/file_path.h" -#include "base/memory/scoped_ptr.h" -#include "base/platform_file.h" -#include "base/strings/string16.h" - -#if defined(OS_POSIX) -#include "base/file_descriptor_posix.h" -#include "base/logging.h" -#include "base/posix/eintr_wrapper.h" -#endif - -namespace base { - -class Time; - -extern bool g_bug108724_debug; - -//----------------------------------------------------------------------------- -// Functions that involve filesystem access or modification: - -// Returns an absolute version of a relative path. Returns an empty path on -// error. On POSIX, this function fails if the path does not exist. This -// function can result in I/O so it can be slow. -BASE_EXPORT FilePath MakeAbsoluteFilePath(const FilePath& input); - -// Returns the total number of bytes used by all the files under |root_path|. -// If the path does not exist the function returns 0. -// -// This function is implemented using the FileEnumerator class so it is not -// particularly speedy in any platform. -BASE_EXPORT int64 ComputeDirectorySize(const FilePath& root_path); - -// Deletes the given path, whether it's a file or a directory. -// If it's a directory, it's perfectly happy to delete all of the -// directory's contents. Passing true to recursive deletes -// subdirectories and their contents as well. -// Returns true if successful, false otherwise. It is considered successful -// to attempt to delete a file that does not exist. -// -// In posix environment and if |path| is a symbolic link, this deletes only -// the symlink. (even if the symlink points to a non-existent file) -// -// WARNING: USING THIS WITH recursive==true IS EQUIVALENT -// TO "rm -rf", SO USE WITH CAUTION. -BASE_EXPORT bool DeleteFile(const FilePath& path, bool recursive); - -#if defined(OS_WIN) -// Schedules to delete the given path, whether it's a file or a directory, until -// the operating system is restarted. -// Note: -// 1) The file/directory to be deleted should exist in a temp folder. -// 2) The directory to be deleted must be empty. -BASE_EXPORT bool DeleteFileAfterReboot(const FilePath& path); -#endif - -// Moves the given path, whether it's a file or a directory. -// If a simple rename is not possible, such as in the case where the paths are -// on different volumes, this will attempt to copy and delete. Returns -// true for success. -// This function fails if either path contains traversal components ('..'). -BASE_EXPORT bool Move(const FilePath& from_path, const FilePath& to_path); - -// Renames file |from_path| to |to_path|. Both paths must be on the same -// volume, or the function will fail. Destination file will be created -// if it doesn't exist. Prefer this function over Move when dealing with -// temporary files. On Windows it preserves attributes of the target file. -// Returns true on success, leaving *error unchanged. -// Returns false on failure and sets *error appropriately, if it is non-NULL. -BASE_EXPORT bool ReplaceFile(const FilePath& from_path, - const FilePath& to_path, - PlatformFileError* error); - -// Copies a single file. Use CopyDirectory to copy directories. -// This function fails if either path contains traversal components ('..'). -BASE_EXPORT bool CopyFile(const FilePath& from_path, const FilePath& to_path); - -// Copies the given path, and optionally all subdirectories and their contents -// as well. -// -// If there are files existing under to_path, always overwrite. Returns true -// if successful, false otherwise. Wildcards on the names are not supported. -// -// If you only need to copy a file use CopyFile, it's faster. -BASE_EXPORT bool CopyDirectory(const FilePath& from_path, - const FilePath& to_path, - bool recursive); - -// Returns true if the given path exists on the local filesystem, -// false otherwise. -BASE_EXPORT bool PathExists(const FilePath& path); - -// Returns true if the given path is writable by the user, false otherwise. -BASE_EXPORT bool PathIsWritable(const FilePath& path); - -// Returns true if the given path exists and is a directory, false otherwise. -BASE_EXPORT bool DirectoryExists(const FilePath& path); - -// Returns true if the contents of the two files given are equal, false -// otherwise. If either file can't be read, returns false. -BASE_EXPORT bool ContentsEqual(const FilePath& filename1, - const FilePath& filename2); - -// Returns true if the contents of the two text files given are equal, false -// otherwise. This routine treats "\r\n" and "\n" as equivalent. -BASE_EXPORT bool TextContentsEqual(const FilePath& filename1, - const FilePath& filename2); - -} // namespace base - -// ----------------------------------------------------------------------------- - -namespace file_util { - -// Read the file at |path| into |contents|, returning true on success. -// This function fails if the |path| contains path traversal components ('..'). -// |contents| may be NULL, in which case this function is useful for its -// side effect of priming the disk cache. -// Useful for unit tests. -BASE_EXPORT bool ReadFileToString(const base::FilePath& path, - std::string* contents); - -#if defined(OS_POSIX) -// Read exactly |bytes| bytes from file descriptor |fd|, storing the result -// in |buffer|. This function is protected against EINTR and partial reads. -// Returns true iff |bytes| bytes have been successfully read from |fd|. -BASE_EXPORT bool ReadFromFD(int fd, char* buffer, size_t bytes); - -// Creates a symbolic link at |symlink| pointing to |target|. Returns -// false on failure. -BASE_EXPORT bool CreateSymbolicLink(const base::FilePath& target, - const base::FilePath& symlink); - -// Reads the given |symlink| and returns where it points to in |target|. -// Returns false upon failure. -BASE_EXPORT bool ReadSymbolicLink(const base::FilePath& symlink, - base::FilePath* target); - -// Bits ans masks of the file permission. -enum FilePermissionBits { - FILE_PERMISSION_MASK = S_IRWXU | S_IRWXG | S_IRWXO, - FILE_PERMISSION_USER_MASK = S_IRWXU, - FILE_PERMISSION_GROUP_MASK = S_IRWXG, - FILE_PERMISSION_OTHERS_MASK = S_IRWXO, - - FILE_PERMISSION_READ_BY_USER = S_IRUSR, - FILE_PERMISSION_WRITE_BY_USER = S_IWUSR, - FILE_PERMISSION_EXECUTE_BY_USER = S_IXUSR, - FILE_PERMISSION_READ_BY_GROUP = S_IRGRP, - FILE_PERMISSION_WRITE_BY_GROUP = S_IWGRP, - FILE_PERMISSION_EXECUTE_BY_GROUP = S_IXGRP, - FILE_PERMISSION_READ_BY_OTHERS = S_IROTH, - FILE_PERMISSION_WRITE_BY_OTHERS = S_IWOTH, - FILE_PERMISSION_EXECUTE_BY_OTHERS = S_IXOTH, -}; - -// Reads the permission of the given |path|, storing the file permission -// bits in |mode|. If |path| is symbolic link, |mode| is the permission of -// a file which the symlink points to. -BASE_EXPORT bool GetPosixFilePermissions(const base::FilePath& path, - int* mode); -// Sets the permission of the given |path|. If |path| is symbolic link, sets -// the permission of a file which the symlink points to. -BASE_EXPORT bool SetPosixFilePermissions(const base::FilePath& path, - int mode); -#endif // defined(OS_POSIX) - -// Return true if the given directory is empty -BASE_EXPORT bool IsDirectoryEmpty(const base::FilePath& dir_path); - -// Get the temporary directory provided by the system. -// WARNING: DON'T USE THIS. If you want to create a temporary file, use one of -// the functions below. -BASE_EXPORT bool GetTempDir(base::FilePath* path); -// Get a temporary directory for shared memory files. -// Only useful on POSIX; redirects to GetTempDir() on Windows. -BASE_EXPORT bool GetShmemTempDir(base::FilePath* path, bool executable); - -// Get the home directory. This is more complicated than just getenv("HOME") -// as it knows to fall back on getpwent() etc. -BASE_EXPORT base::FilePath GetHomeDir(); - -// Creates a temporary file. The full path is placed in |path|, and the -// function returns true if was successful in creating the file. The file will -// be empty and all handles closed after this function returns. -BASE_EXPORT bool CreateTemporaryFile(base::FilePath* path); - -// Same as CreateTemporaryFile but the file is created in |dir|. -BASE_EXPORT bool CreateTemporaryFileInDir(const base::FilePath& dir, - base::FilePath* temp_file); - -// Create and open a temporary file. File is opened for read/write. -// The full path is placed in |path|. -// Returns a handle to the opened file or NULL if an error occurred. -BASE_EXPORT FILE* CreateAndOpenTemporaryFile(base::FilePath* path); -// Like above but for shmem files. Only useful for POSIX. -// The executable flag says the file needs to support using -// mprotect with PROT_EXEC after mapping. -BASE_EXPORT FILE* CreateAndOpenTemporaryShmemFile(base::FilePath* path, - bool executable); -// Similar to CreateAndOpenTemporaryFile, but the file is created in |dir|. -BASE_EXPORT FILE* CreateAndOpenTemporaryFileInDir(const base::FilePath& dir, - base::FilePath* path); - -// Create a new directory. If prefix is provided, the new directory name is in -// the format of prefixyyyy. -// NOTE: prefix is ignored in the POSIX implementation. -// If success, return true and output the full path of the directory created. -BASE_EXPORT bool CreateNewTempDirectory( - const base::FilePath::StringType& prefix, - base::FilePath* new_temp_path); - -// Create a directory within another directory. -// Extra characters will be appended to |prefix| to ensure that the -// new directory does not have the same name as an existing directory. -BASE_EXPORT bool CreateTemporaryDirInDir( - const base::FilePath& base_dir, - const base::FilePath::StringType& prefix, - base::FilePath* new_dir); - -// Creates a directory, as well as creating any parent directories, if they -// don't exist. Returns 'true' on successful creation, or if the directory -// already exists. The directory is only readable by the current user. -// Returns true on success, leaving *error unchanged. -// Returns false on failure and sets *error appropriately, if it is non-NULL. -BASE_EXPORT bool CreateDirectoryAndGetError(const base::FilePath& full_path, - base::PlatformFileError* error); - -// Backward-compatible convenience method for the above. -BASE_EXPORT bool CreateDirectory(const base::FilePath& full_path); - -// Returns the file size. Returns true on success. -BASE_EXPORT bool GetFileSize(const base::FilePath& file_path, int64* file_size); - -// Sets |real_path| to |path| with symbolic links and junctions expanded. -// On windows, make sure the path starts with a lettered drive. -// |path| must reference a file. Function will fail if |path| points to -// a directory or to a nonexistent path. On windows, this function will -// fail if |path| is a junction or symlink that points to an empty file, -// or if |real_path| would be longer than MAX_PATH characters. -BASE_EXPORT bool NormalizeFilePath(const base::FilePath& path, - base::FilePath* real_path); - -#if defined(OS_WIN) - -// Given a path in NT native form ("\Device\HarddiskVolumeXX\..."), -// return in |drive_letter_path| the equivalent path that starts with -// a drive letter ("C:\..."). Return false if no such path exists. -BASE_EXPORT bool DevicePathToDriveLetterPath(const base::FilePath& device_path, - base::FilePath* drive_letter_path); - -// Given an existing file in |path|, set |real_path| to the path -// in native NT format, of the form "\Device\HarddiskVolumeXX\..". -// Returns false if the path can not be found. Empty files cannot -// be resolved with this function. -BASE_EXPORT bool NormalizeToNativeFilePath(const base::FilePath& path, - base::FilePath* nt_path); -#endif - -// This function will return if the given file is a symlink or not. -BASE_EXPORT bool IsLink(const base::FilePath& file_path); - -// Returns information about the given file path. -BASE_EXPORT bool GetFileInfo(const base::FilePath& file_path, - base::PlatformFileInfo* info); - -// Sets the time of the last access and the time of the last modification. -BASE_EXPORT bool TouchFile(const base::FilePath& path, - const base::Time& last_accessed, - const base::Time& last_modified); - -// Set the time of the last modification. Useful for unit tests. -BASE_EXPORT bool SetLastModifiedTime(const base::FilePath& path, - const base::Time& last_modified); - -#if defined(OS_POSIX) -// Store inode number of |path| in |inode|. Return true on success. -BASE_EXPORT bool GetInode(const base::FilePath& path, ino_t* inode); -#endif - -// Wrapper for fopen-like calls. Returns non-NULL FILE* on success. -BASE_EXPORT FILE* OpenFile(const base::FilePath& filename, const char* mode); - -// Closes file opened by OpenFile. Returns true on success. -BASE_EXPORT bool CloseFile(FILE* file); - -// Truncates an open file to end at the location of the current file pointer. -// This is a cross-platform analog to Windows' SetEndOfFile() function. -BASE_EXPORT bool TruncateFile(FILE* file); - -// Reads the given number of bytes from the file into the buffer. Returns -// the number of read bytes, or -1 on error. -BASE_EXPORT int ReadFile(const base::FilePath& filename, char* data, int size); - -// Writes the given buffer into the file, overwriting any data that was -// previously there. Returns the number of bytes written, or -1 on error. -BASE_EXPORT int WriteFile(const base::FilePath& filename, const char* data, - int size); -#if defined(OS_POSIX) -// Append the data to |fd|. Does not close |fd| when done. -BASE_EXPORT int WriteFileDescriptor(const int fd, const char* data, int size); -#endif -// Append the given buffer into the file. Returns the number of bytes written, -// or -1 on error. -BASE_EXPORT int AppendToFile(const base::FilePath& filename, - const char* data, int size); - -// Gets the current working directory for the process. -BASE_EXPORT bool GetCurrentDirectory(base::FilePath* path); - -// Sets the current working directory for the process. -BASE_EXPORT bool SetCurrentDirectory(const base::FilePath& path); - -// Attempts to find a number that can be appended to the |path| to make it -// unique. If |path| does not exist, 0 is returned. If it fails to find such -// a number, -1 is returned. If |suffix| is not empty, also checks the -// existence of it with the given suffix. -BASE_EXPORT int GetUniquePathNumber(const base::FilePath& path, - const base::FilePath::StringType& suffix); - -#if defined(OS_POSIX) -// Creates a directory with a guaranteed unique name based on |path|, returning -// the pathname if successful, or an empty path if there was an error creating -// the directory. Does not create parent directories. -BASE_EXPORT base::FilePath MakeUniqueDirectory(const base::FilePath& path); -#endif - -#if defined(OS_POSIX) -// Test that |path| can only be changed by a given user and members of -// a given set of groups. -// Specifically, test that all parts of |path| under (and including) |base|: -// * Exist. -// * Are owned by a specific user. -// * Are not writable by all users. -// * Are owned by a member of a given set of groups, or are not writable by -// their group. -// * Are not symbolic links. -// This is useful for checking that a config file is administrator-controlled. -// |base| must contain |path|. -BASE_EXPORT bool VerifyPathControlledByUser(const base::FilePath& base, - const base::FilePath& path, - uid_t owner_uid, - const std::set& group_gids); -#endif // defined(OS_POSIX) - -#if defined(OS_MACOSX) && !defined(OS_IOS) -// Is |path| writable only by a user with administrator privileges? -// This function uses Mac OS conventions. The super user is assumed to have -// uid 0, and the administrator group is assumed to be named "admin". -// Testing that |path|, and every parent directory including the root of -// the filesystem, are owned by the superuser, controlled by the group -// "admin", are not writable by all users, and contain no symbolic links. -// Will return false if |path| does not exist. -BASE_EXPORT bool VerifyPathControlledByAdmin(const base::FilePath& path); -#endif // defined(OS_MACOSX) && !defined(OS_IOS) - -// Returns the maximum length of path component on the volume containing -// the directory |path|, in the number of FilePath::CharType, or -1 on failure. -BASE_EXPORT int GetMaximumPathComponentLength(const base::FilePath& path); - -// A class to handle auto-closing of FILE*'s. -class ScopedFILEClose { - public: - inline void operator()(FILE* x) const { - if (x) { - fclose(x); - } - } -}; - -typedef scoped_ptr_malloc ScopedFILE; - -#if defined(OS_POSIX) -// A class to handle auto-closing of FDs. -class ScopedFDClose { - public: - inline void operator()(int* x) const { - if (x && *x >= 0) { - if (HANDLE_EINTR(close(*x)) < 0) - DPLOG(ERROR) << "close"; - } - } -}; - -typedef scoped_ptr_malloc ScopedFD; -#endif // OS_POSIX - -#if defined(OS_LINUX) -// Broad categories of file systems as returned by statfs() on Linux. -enum FileSystemType { - FILE_SYSTEM_UNKNOWN, // statfs failed. - FILE_SYSTEM_0, // statfs.f_type == 0 means unknown, may indicate AFS. - FILE_SYSTEM_ORDINARY, // on-disk filesystem like ext2 - FILE_SYSTEM_NFS, - FILE_SYSTEM_SMB, - FILE_SYSTEM_CODA, - FILE_SYSTEM_MEMORY, // in-memory file system - FILE_SYSTEM_CGROUP, // cgroup control. - FILE_SYSTEM_OTHER, // any other value. - FILE_SYSTEM_TYPE_COUNT -}; - -// Attempts determine the FileSystemType for |path|. -// Returns false if |path| doesn't exist. -BASE_EXPORT bool GetFileSystemType(const base::FilePath& path, - FileSystemType* type); -#endif - -} // namespace file_util - -// Internal -------------------------------------------------------------------- - -namespace base { -namespace internal { - -// Same as Move but allows paths with traversal components. -// Use only with extreme care. -BASE_EXPORT bool MoveUnsafe(const FilePath& from_path, - const FilePath& to_path); - -// Same as CopyFile but allows paths with traversal components. -// Use only with extreme care. -BASE_EXPORT bool CopyFileUnsafe(const FilePath& from_path, - const FilePath& to_path); - -#if defined(OS_WIN) -// Copy from_path to to_path recursively and then delete from_path recursively. -// Returns true if all operations succeed. -// This function simulates Move(), but unlike Move() it works across volumes. -// This function is not transactional. -BASE_EXPORT bool CopyAndDeleteDirectory(const FilePath& from_path, - const FilePath& to_path); -#endif // defined(OS_WIN) - -} // namespace internal -} // namespace base - -#endif // BASE_FILE_UTIL_H_ diff --git a/base/file_util_android.cc b/base/file_util_android.cc deleted file mode 100644 index 6ac9def8c1..0000000000 --- a/base/file_util_android.cc +++ /dev/null @@ -1,16 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "base/file_util.h" - -#include "base/files/file_path.h" -#include "base/path_service.h" - -namespace file_util { - -bool GetShmemTempDir(base::FilePath* path, bool executable) { - return PathService::Get(base::DIR_CACHE, path); -} - -} // namespace file_util diff --git a/base/file_util_linux.cc b/base/file_util_linux.cc deleted file mode 100644 index e4f0e28b12..0000000000 --- a/base/file_util_linux.cc +++ /dev/null @@ -1,62 +0,0 @@ -// Copyright (c) 2011 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "base/file_util.h" - -#include "base/files/file_path.h" - -#include -#include - -namespace file_util { - -bool GetFileSystemType(const base::FilePath& path, FileSystemType* type) { - struct statfs statfs_buf; - if (statfs(path.value().c_str(), &statfs_buf) < 0) { - if (errno == ENOENT) - return false; - *type = FILE_SYSTEM_UNKNOWN; - return true; - } - - // While you would think the possible values of f_type would be available - // in a header somewhere, it appears that is not the case. These values - // are copied from the statfs man page. - switch (statfs_buf.f_type) { - case 0: - *type = FILE_SYSTEM_0; - break; - case 0xEF53: // ext2, ext3. - case 0x4D44: // dos - case 0x5346544E: // NFTS - case 0x52654973: // reiser - case 0x58465342: // XFS - case 0x9123683E: // btrfs - case 0x3153464A: // JFS - *type = FILE_SYSTEM_ORDINARY; - break; - case 0x6969: // NFS - *type = FILE_SYSTEM_NFS; - break; - case 0xFF534D42: // CIFS - case 0x517B: // SMB - *type = FILE_SYSTEM_SMB; - break; - case 0x73757245: // Coda - *type = FILE_SYSTEM_CODA; - break; - case 0x858458f6: // ramfs - case 0x01021994: // tmpfs - *type = FILE_SYSTEM_MEMORY; - break; - case 0x27e0eb: // CGROUP - *type = FILE_SYSTEM_CGROUP; - break; - default: - *type = FILE_SYSTEM_OTHER; - } - return true; -} - -} // namespace diff --git a/base/file_util_mac.mm b/base/file_util_mac.mm deleted file mode 100644 index 9d9ac3d99b..0000000000 --- a/base/file_util_mac.mm +++ /dev/null @@ -1,42 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "base/file_util.h" - -#import -#include - -#include "base/basictypes.h" -#include "base/files/file_path.h" -#include "base/mac/foundation_util.h" -#include "base/strings/string_util.h" -#include "base/threading/thread_restrictions.h" - -namespace base { -namespace internal { - -bool CopyFileUnsafe(const FilePath& from_path, const FilePath& to_path) { - ThreadRestrictions::AssertIOAllowed(); - return (copyfile(from_path.value().c_str(), - to_path.value().c_str(), NULL, COPYFILE_ALL) == 0); -} - -} // namespace internal -} // namepsace base - -namespace file_util { - -bool GetTempDir(base::FilePath* path) { - NSString* tmp = NSTemporaryDirectory(); - if (tmp == nil) - return false; - *path = base::mac::NSStringToFilePath(tmp); - return true; -} - -bool GetShmemTempDir(base::FilePath* path, bool executable) { - return GetTempDir(path); -} - -} // namespace diff --git a/base/file_util_posix.cc b/base/file_util_posix.cc deleted file mode 100644 index 762700ae42..0000000000 --- a/base/file_util_posix.cc +++ /dev/null @@ -1,958 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "base/file_util.h" - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#if defined(OS_MACOSX) -#include -#include "base/mac/foundation_util.h" -#elif !defined(OS_ANDROID) -#include -#endif - -#include - -#include "base/basictypes.h" -#include "base/files/file_enumerator.h" -#include "base/files/file_path.h" -#include "base/logging.h" -#include "base/memory/scoped_ptr.h" -#include "base/memory/singleton.h" -#include "base/path_service.h" -#include "base/posix/eintr_wrapper.h" -#include "base/stl_util.h" -#include "base/strings/string_util.h" -#include "base/strings/stringprintf.h" -#include "base/strings/sys_string_conversions.h" -#include "base/strings/utf_string_conversions.h" -#include "base/threading/thread_restrictions.h" -#include "base/time/time.h" - -#if defined(OS_ANDROID) -#include "base/os_compat_android.h" -#endif - -#if !defined(OS_IOS) -#include -#endif - -#if defined(OS_CHROMEOS) -#include "base/chromeos/chromeos_version.h" -#endif - -namespace base { - -namespace { - -#if defined(OS_BSD) || defined(OS_MACOSX) -typedef struct stat stat_wrapper_t; -static int CallStat(const char *path, stat_wrapper_t *sb) { - ThreadRestrictions::AssertIOAllowed(); - return stat(path, sb); -} -static int CallLstat(const char *path, stat_wrapper_t *sb) { - ThreadRestrictions::AssertIOAllowed(); - return lstat(path, sb); -} -#else -typedef struct stat64 stat_wrapper_t; -static int CallStat(const char *path, stat_wrapper_t *sb) { - ThreadRestrictions::AssertIOAllowed(); - return stat64(path, sb); -} -static int CallLstat(const char *path, stat_wrapper_t *sb) { - ThreadRestrictions::AssertIOAllowed(); - return lstat64(path, sb); -} -#endif - -// Helper for NormalizeFilePath(), defined below. -bool RealPath(const FilePath& path, FilePath* real_path) { - ThreadRestrictions::AssertIOAllowed(); // For realpath(). - FilePath::CharType buf[PATH_MAX]; - if (!realpath(path.value().c_str(), buf)) - return false; - - *real_path = FilePath(buf); - return true; -} - -// Helper for VerifyPathControlledByUser. -bool VerifySpecificPathControlledByUser(const FilePath& path, - uid_t owner_uid, - const std::set& group_gids) { - stat_wrapper_t stat_info; - if (CallLstat(path.value().c_str(), &stat_info) != 0) { - DPLOG(ERROR) << "Failed to get information on path " - << path.value(); - return false; - } - - if (S_ISLNK(stat_info.st_mode)) { - DLOG(ERROR) << "Path " << path.value() - << " is a symbolic link."; - return false; - } - - if (stat_info.st_uid != owner_uid) { - DLOG(ERROR) << "Path " << path.value() - << " is owned by the wrong user."; - return false; - } - - if ((stat_info.st_mode & S_IWGRP) && - !ContainsKey(group_gids, stat_info.st_gid)) { - DLOG(ERROR) << "Path " << path.value() - << " is writable by an unprivileged group."; - return false; - } - - if (stat_info.st_mode & S_IWOTH) { - DLOG(ERROR) << "Path " << path.value() - << " is writable by any user."; - return false; - } - - return true; -} - -std::string TempFileName() { -#if defined(OS_MACOSX) - return StringPrintf(".%s.XXXXXX", base::mac::BaseBundleID()); -#endif - -#if defined(GOOGLE_CHROME_BUILD) - return std::string(".com.google.Chrome.XXXXXX"); -#else - return std::string(".org.chromium.Chromium.XXXXXX"); -#endif -} - -} // namespace - -FilePath MakeAbsoluteFilePath(const FilePath& input) { - ThreadRestrictions::AssertIOAllowed(); - char full_path[PATH_MAX]; - if (realpath(input.value().c_str(), full_path) == NULL) - return FilePath(); - return FilePath(full_path); -} - -// TODO(erikkay): The Windows version of this accepts paths like "foo/bar/*" -// which works both with and without the recursive flag. I'm not sure we need -// that functionality. If not, remove from file_util_win.cc, otherwise add it -// here. -bool DeleteFile(const FilePath& path, bool recursive) { - ThreadRestrictions::AssertIOAllowed(); - const char* path_str = path.value().c_str(); - stat_wrapper_t file_info; - int test = CallLstat(path_str, &file_info); - if (test != 0) { - // The Windows version defines this condition as success. - bool ret = (errno == ENOENT || errno == ENOTDIR); - return ret; - } - if (!S_ISDIR(file_info.st_mode)) - return (unlink(path_str) == 0); - if (!recursive) - return (rmdir(path_str) == 0); - - bool success = true; - std::stack directories; - directories.push(path.value()); - FileEnumerator traversal(path, true, - FileEnumerator::FILES | FileEnumerator::DIRECTORIES | - FileEnumerator::SHOW_SYM_LINKS); - for (FilePath current = traversal.Next(); success && !current.empty(); - current = traversal.Next()) { - if (traversal.GetInfo().IsDirectory()) - directories.push(current.value()); - else - success = (unlink(current.value().c_str()) == 0); - } - - while (success && !directories.empty()) { - FilePath dir = FilePath(directories.top()); - directories.pop(); - success = (rmdir(dir.value().c_str()) == 0); - } - return success; -} - -bool ReplaceFile(const FilePath& from_path, - const FilePath& to_path, - PlatformFileError* error) { - ThreadRestrictions::AssertIOAllowed(); - if (rename(from_path.value().c_str(), to_path.value().c_str()) == 0) - return true; - if (error) - *error = ErrnoToPlatformFileError(errno); - return false; -} - -bool CopyDirectory(const FilePath& from_path, - const FilePath& to_path, - bool recursive) { - ThreadRestrictions::AssertIOAllowed(); - // Some old callers of CopyDirectory want it to support wildcards. - // After some discussion, we decided to fix those callers. - // Break loudly here if anyone tries to do this. - // TODO(evanm): remove this once we're sure it's ok. - DCHECK(to_path.value().find('*') == std::string::npos); - DCHECK(from_path.value().find('*') == std::string::npos); - - char top_dir[PATH_MAX]; - if (strlcpy(top_dir, from_path.value().c_str(), - arraysize(top_dir)) >= arraysize(top_dir)) { - return false; - } - - // This function does not properly handle destinations within the source - FilePath real_to_path = to_path; - if (PathExists(real_to_path)) { - real_to_path = MakeAbsoluteFilePath(real_to_path); - if (real_to_path.empty()) - return false; - } else { - real_to_path = MakeAbsoluteFilePath(real_to_path.DirName()); - if (real_to_path.empty()) - return false; - } - FilePath real_from_path = MakeAbsoluteFilePath(from_path); - if (real_from_path.empty()) - return false; - if (real_to_path.value().size() >= real_from_path.value().size() && - real_to_path.value().compare(0, real_from_path.value().size(), - real_from_path.value()) == 0) - return false; - - bool success = true; - int traverse_type = FileEnumerator::FILES | FileEnumerator::SHOW_SYM_LINKS; - if (recursive) - traverse_type |= FileEnumerator::DIRECTORIES; - FileEnumerator traversal(from_path, recursive, traverse_type); - - // We have to mimic windows behavior here. |to_path| may not exist yet, - // start the loop with |to_path|. - struct stat from_stat; - FilePath current = from_path; - if (stat(from_path.value().c_str(), &from_stat) < 0) { - DLOG(ERROR) << "CopyDirectory() couldn't stat source directory: " - << from_path.value() << " errno = " << errno; - success = false; - } - struct stat to_path_stat; - FilePath from_path_base = from_path; - if (recursive && stat(to_path.value().c_str(), &to_path_stat) == 0 && - S_ISDIR(to_path_stat.st_mode)) { - // If the destination already exists and is a directory, then the - // top level of source needs to be copied. - from_path_base = from_path.DirName(); - } - - // The Windows version of this function assumes that non-recursive calls - // will always have a directory for from_path. - DCHECK(recursive || S_ISDIR(from_stat.st_mode)); - - while (success && !current.empty()) { - // current is the source path, including from_path, so append - // the suffix after from_path to to_path to create the target_path. - FilePath target_path(to_path); - if (from_path_base != current) { - if (!from_path_base.AppendRelativePath(current, &target_path)) { - success = false; - break; - } - } - - if (S_ISDIR(from_stat.st_mode)) { - if (mkdir(target_path.value().c_str(), from_stat.st_mode & 01777) != 0 && - errno != EEXIST) { - DLOG(ERROR) << "CopyDirectory() couldn't create directory: " - << target_path.value() << " errno = " << errno; - success = false; - } - } else if (S_ISREG(from_stat.st_mode)) { - if (!CopyFile(current, target_path)) { - DLOG(ERROR) << "CopyDirectory() couldn't create file: " - << target_path.value(); - success = false; - } - } else { - DLOG(WARNING) << "CopyDirectory() skipping non-regular file: " - << current.value(); - } - - current = traversal.Next(); - if (!current.empty()) - from_stat = traversal.GetInfo().stat(); - } - - return success; -} - -bool PathExists(const FilePath& path) { - ThreadRestrictions::AssertIOAllowed(); - return access(path.value().c_str(), F_OK) == 0; -} - -bool PathIsWritable(const FilePath& path) { - ThreadRestrictions::AssertIOAllowed(); - return access(path.value().c_str(), W_OK) == 0; -} - -bool DirectoryExists(const FilePath& path) { - ThreadRestrictions::AssertIOAllowed(); - stat_wrapper_t file_info; - if (CallStat(path.value().c_str(), &file_info) == 0) - return S_ISDIR(file_info.st_mode); - return false; -} - -} // namespace base - -// ----------------------------------------------------------------------------- - -namespace file_util { - -using base::stat_wrapper_t; -using base::CallStat; -using base::CallLstat; -using base::DirectoryExists; -using base::FileEnumerator; -using base::FilePath; -using base::MakeAbsoluteFilePath; -using base::RealPath; -using base::VerifySpecificPathControlledByUser; - -bool ReadFromFD(int fd, char* buffer, size_t bytes) { - size_t total_read = 0; - while (total_read < bytes) { - ssize_t bytes_read = - HANDLE_EINTR(read(fd, buffer + total_read, bytes - total_read)); - if (bytes_read <= 0) - break; - total_read += bytes_read; - } - return total_read == bytes; -} - -bool CreateSymbolicLink(const FilePath& target_path, - const FilePath& symlink_path) { - DCHECK(!symlink_path.empty()); - DCHECK(!target_path.empty()); - return ::symlink(target_path.value().c_str(), - symlink_path.value().c_str()) != -1; -} - -bool ReadSymbolicLink(const FilePath& symlink_path, - FilePath* target_path) { - DCHECK(!symlink_path.empty()); - DCHECK(target_path); - char buf[PATH_MAX]; - ssize_t count = ::readlink(symlink_path.value().c_str(), buf, arraysize(buf)); - - if (count <= 0) { - target_path->clear(); - return false; - } - - *target_path = FilePath(FilePath::StringType(buf, count)); - return true; -} - -bool GetPosixFilePermissions(const FilePath& path, int* mode) { - base::ThreadRestrictions::AssertIOAllowed(); - DCHECK(mode); - - stat_wrapper_t file_info; - // Uses stat(), because on symbolic link, lstat() does not return valid - // permission bits in st_mode - if (CallStat(path.value().c_str(), &file_info) != 0) - return false; - - *mode = file_info.st_mode & FILE_PERMISSION_MASK; - return true; -} - -bool SetPosixFilePermissions(const FilePath& path, - int mode) { - base::ThreadRestrictions::AssertIOAllowed(); - DCHECK((mode & ~FILE_PERMISSION_MASK) == 0); - - // Calls stat() so that we can preserve the higher bits like S_ISGID. - stat_wrapper_t stat_buf; - if (CallStat(path.value().c_str(), &stat_buf) != 0) - return false; - - // Clears the existing permission bits, and adds the new ones. - mode_t updated_mode_bits = stat_buf.st_mode & ~FILE_PERMISSION_MASK; - updated_mode_bits |= mode & FILE_PERMISSION_MASK; - - if (HANDLE_EINTR(chmod(path.value().c_str(), updated_mode_bits)) != 0) - return false; - - return true; -} - -// Creates and opens a temporary file in |directory|, returning the -// file descriptor. |path| is set to the temporary file path. -// This function does NOT unlink() the file. -int CreateAndOpenFdForTemporaryFile(FilePath directory, FilePath* path) { - base::ThreadRestrictions::AssertIOAllowed(); // For call to mkstemp(). - *path = directory.Append(base::TempFileName()); - const std::string& tmpdir_string = path->value(); - // this should be OK since mkstemp just replaces characters in place - char* buffer = const_cast(tmpdir_string.c_str()); - - return HANDLE_EINTR(mkstemp(buffer)); -} - -bool CreateTemporaryFile(FilePath* path) { - base::ThreadRestrictions::AssertIOAllowed(); // For call to close(). - FilePath directory; - if (!GetTempDir(&directory)) - return false; - int fd = CreateAndOpenFdForTemporaryFile(directory, path); - if (fd < 0) - return false; - ignore_result(HANDLE_EINTR(close(fd))); - return true; -} - -FILE* CreateAndOpenTemporaryShmemFile(FilePath* path, bool executable) { - FilePath directory; - if (!GetShmemTempDir(&directory, executable)) - return NULL; - - return CreateAndOpenTemporaryFileInDir(directory, path); -} - -FILE* CreateAndOpenTemporaryFileInDir(const FilePath& dir, FilePath* path) { - int fd = CreateAndOpenFdForTemporaryFile(dir, path); - if (fd < 0) - return NULL; - - FILE* file = fdopen(fd, "a+"); - if (!file) - ignore_result(HANDLE_EINTR(close(fd))); - return file; -} - -bool CreateTemporaryFileInDir(const FilePath& dir, FilePath* temp_file) { - base::ThreadRestrictions::AssertIOAllowed(); // For call to close(). - int fd = CreateAndOpenFdForTemporaryFile(dir, temp_file); - return ((fd >= 0) && !HANDLE_EINTR(close(fd))); -} - -static bool CreateTemporaryDirInDirImpl(const FilePath& base_dir, - const FilePath::StringType& name_tmpl, - FilePath* new_dir) { - base::ThreadRestrictions::AssertIOAllowed(); // For call to mkdtemp(). - DCHECK(name_tmpl.find("XXXXXX") != FilePath::StringType::npos) - << "Directory name template must contain \"XXXXXX\"."; - - FilePath sub_dir = base_dir.Append(name_tmpl); - std::string sub_dir_string = sub_dir.value(); - - // this should be OK since mkdtemp just replaces characters in place - char* buffer = const_cast(sub_dir_string.c_str()); - char* dtemp = mkdtemp(buffer); - if (!dtemp) { - DPLOG(ERROR) << "mkdtemp"; - return false; - } - *new_dir = FilePath(dtemp); - return true; -} - -bool CreateTemporaryDirInDir(const FilePath& base_dir, - const FilePath::StringType& prefix, - FilePath* new_dir) { - FilePath::StringType mkdtemp_template = prefix; - mkdtemp_template.append(FILE_PATH_LITERAL("XXXXXX")); - return CreateTemporaryDirInDirImpl(base_dir, mkdtemp_template, new_dir); -} - -bool CreateNewTempDirectory(const FilePath::StringType& prefix, - FilePath* new_temp_path) { - FilePath tmpdir; - if (!GetTempDir(&tmpdir)) - return false; - - return CreateTemporaryDirInDirImpl(tmpdir, base::TempFileName(), - new_temp_path); -} - -bool CreateDirectoryAndGetError(const FilePath& full_path, - base::PlatformFileError* error) { - base::ThreadRestrictions::AssertIOAllowed(); // For call to mkdir(). - std::vector subpaths; - - // Collect a list of all parent directories. - FilePath last_path = full_path; - subpaths.push_back(full_path); - for (FilePath path = full_path.DirName(); - path.value() != last_path.value(); path = path.DirName()) { - subpaths.push_back(path); - last_path = path; - } - - // Iterate through the parents and create the missing ones. - for (std::vector::reverse_iterator i = subpaths.rbegin(); - i != subpaths.rend(); ++i) { - if (DirectoryExists(*i)) - continue; - if (mkdir(i->value().c_str(), 0700) == 0) - continue; - // Mkdir failed, but it might have failed with EEXIST, or some other error - // due to the the directory appearing out of thin air. This can occur if - // two processes are trying to create the same file system tree at the same - // time. Check to see if it exists and make sure it is a directory. - int saved_errno = errno; - if (!DirectoryExists(*i)) { - if (error) - *error = base::ErrnoToPlatformFileError(saved_errno); - return false; - } - } - return true; -} - -base::FilePath MakeUniqueDirectory(const base::FilePath& path) { - const int kMaxAttempts = 20; - for (int attempts = 0; attempts < kMaxAttempts; attempts++) { - int uniquifier = - GetUniquePathNumber(path, base::FilePath::StringType()); - if (uniquifier < 0) - break; - base::FilePath test_path = (uniquifier == 0) ? path : - path.InsertBeforeExtensionASCII( - base::StringPrintf(" (%d)", uniquifier)); - if (mkdir(test_path.value().c_str(), 0777) == 0) - return test_path; - else if (errno != EEXIST) - break; - } - return base::FilePath(); -} - -// TODO(rkc): Refactor GetFileInfo and FileEnumerator to handle symlinks -// correctly. http://code.google.com/p/chromium-os/issues/detail?id=15948 -bool IsLink(const FilePath& file_path) { - stat_wrapper_t st; - // If we can't lstat the file, it's safe to assume that the file won't at - // least be a 'followable' link. - if (CallLstat(file_path.value().c_str(), &st) != 0) - return false; - - if (S_ISLNK(st.st_mode)) - return true; - else - return false; -} - -bool GetFileInfo(const FilePath& file_path, base::PlatformFileInfo* results) { - stat_wrapper_t file_info; - if (CallStat(file_path.value().c_str(), &file_info) != 0) - return false; - results->is_directory = S_ISDIR(file_info.st_mode); - results->size = file_info.st_size; -#if defined(OS_MACOSX) - results->last_modified = base::Time::FromTimeSpec(file_info.st_mtimespec); - results->last_accessed = base::Time::FromTimeSpec(file_info.st_atimespec); - results->creation_time = base::Time::FromTimeSpec(file_info.st_ctimespec); -#elif defined(OS_ANDROID) - results->last_modified = base::Time::FromTimeT(file_info.st_mtime); - results->last_accessed = base::Time::FromTimeT(file_info.st_atime); - results->creation_time = base::Time::FromTimeT(file_info.st_ctime); -#else - results->last_modified = base::Time::FromTimeSpec(file_info.st_mtim); - results->last_accessed = base::Time::FromTimeSpec(file_info.st_atim); - results->creation_time = base::Time::FromTimeSpec(file_info.st_ctim); -#endif - return true; -} - -bool GetInode(const FilePath& path, ino_t* inode) { - base::ThreadRestrictions::AssertIOAllowed(); // For call to stat(). - struct stat buffer; - int result = stat(path.value().c_str(), &buffer); - if (result < 0) - return false; - - *inode = buffer.st_ino; - return true; -} - -FILE* OpenFile(const std::string& filename, const char* mode) { - return OpenFile(FilePath(filename), mode); -} - -FILE* OpenFile(const FilePath& filename, const char* mode) { - base::ThreadRestrictions::AssertIOAllowed(); - FILE* result = NULL; - do { - result = fopen(filename.value().c_str(), mode); - } while (!result && errno == EINTR); - return result; -} - -int ReadFile(const FilePath& filename, char* data, int size) { - base::ThreadRestrictions::AssertIOAllowed(); - int fd = HANDLE_EINTR(open(filename.value().c_str(), O_RDONLY)); - if (fd < 0) - return -1; - - ssize_t bytes_read = HANDLE_EINTR(read(fd, data, size)); - if (int ret = HANDLE_EINTR(close(fd)) < 0) - return ret; - return bytes_read; -} - -int WriteFile(const FilePath& filename, const char* data, int size) { - base::ThreadRestrictions::AssertIOAllowed(); - int fd = HANDLE_EINTR(creat(filename.value().c_str(), 0666)); - if (fd < 0) - return -1; - - int bytes_written = WriteFileDescriptor(fd, data, size); - if (int ret = HANDLE_EINTR(close(fd)) < 0) - return ret; - return bytes_written; -} - -int WriteFileDescriptor(const int fd, const char* data, int size) { - // Allow for partial writes. - ssize_t bytes_written_total = 0; - for (ssize_t bytes_written_partial = 0; bytes_written_total < size; - bytes_written_total += bytes_written_partial) { - bytes_written_partial = - HANDLE_EINTR(write(fd, data + bytes_written_total, - size - bytes_written_total)); - if (bytes_written_partial < 0) - return -1; - } - - return bytes_written_total; -} - -int AppendToFile(const FilePath& filename, const char* data, int size) { - base::ThreadRestrictions::AssertIOAllowed(); - int fd = HANDLE_EINTR(open(filename.value().c_str(), O_WRONLY | O_APPEND)); - if (fd < 0) - return -1; - - int bytes_written = WriteFileDescriptor(fd, data, size); - if (int ret = HANDLE_EINTR(close(fd)) < 0) - return ret; - return bytes_written; -} - -// Gets the current working directory for the process. -bool GetCurrentDirectory(FilePath* dir) { - // getcwd can return ENOENT, which implies it checks against the disk. - base::ThreadRestrictions::AssertIOAllowed(); - - char system_buffer[PATH_MAX] = ""; - if (!getcwd(system_buffer, sizeof(system_buffer))) { - NOTREACHED(); - return false; - } - *dir = FilePath(system_buffer); - return true; -} - -// Sets the current working directory for the process. -bool SetCurrentDirectory(const FilePath& path) { - base::ThreadRestrictions::AssertIOAllowed(); - int ret = chdir(path.value().c_str()); - return !ret; -} - -bool NormalizeFilePath(const FilePath& path, FilePath* normalized_path) { - FilePath real_path_result; - if (!RealPath(path, &real_path_result)) - return false; - - // To be consistant with windows, fail if |real_path_result| is a - // directory. - stat_wrapper_t file_info; - if (CallStat(real_path_result.value().c_str(), &file_info) != 0 || - S_ISDIR(file_info.st_mode)) - return false; - - *normalized_path = real_path_result; - return true; -} - -#if !defined(OS_MACOSX) -bool GetTempDir(FilePath* path) { - const char* tmp = getenv("TMPDIR"); - if (tmp) - *path = FilePath(tmp); - else -#if defined(OS_ANDROID) - return PathService::Get(base::DIR_CACHE, path); -#else - *path = FilePath("/tmp"); -#endif - return true; -} - -#if !defined(OS_ANDROID) - -#if defined(OS_LINUX) -// Determine if /dev/shm files can be mapped and then mprotect'd PROT_EXEC. -// This depends on the mount options used for /dev/shm, which vary among -// different Linux distributions and possibly local configuration. It also -// depends on details of kernel--ChromeOS uses the noexec option for /dev/shm -// but its kernel allows mprotect with PROT_EXEC anyway. - -namespace { - -bool DetermineDevShmExecutable() { - bool result = false; - FilePath path; - int fd = CreateAndOpenFdForTemporaryFile(FilePath("/dev/shm"), &path); - if (fd >= 0) { - ScopedFD shm_fd_closer(&fd); - DeleteFile(path, false); - long sysconf_result = sysconf(_SC_PAGESIZE); - CHECK_GE(sysconf_result, 0); - size_t pagesize = static_cast(sysconf_result); - CHECK_GE(sizeof(pagesize), sizeof(sysconf_result)); - void *mapping = mmap(NULL, pagesize, PROT_READ, MAP_SHARED, fd, 0); - if (mapping != MAP_FAILED) { - if (mprotect(mapping, pagesize, PROT_READ | PROT_EXEC) == 0) - result = true; - munmap(mapping, pagesize); - } - } - return result; -} - -}; // namespace -#endif // defined(OS_LINUX) - -bool GetShmemTempDir(FilePath* path, bool executable) { -#if defined(OS_LINUX) - bool use_dev_shm = true; - if (executable) { - static const bool s_dev_shm_executable = DetermineDevShmExecutable(); - use_dev_shm = s_dev_shm_executable; - } - if (use_dev_shm) { - *path = FilePath("/dev/shm"); - return true; - } -#endif - return GetTempDir(path); -} -#endif // !defined(OS_ANDROID) - -FilePath GetHomeDir() { -#if defined(OS_CHROMEOS) - if (base::chromeos::IsRunningOnChromeOS()) - return FilePath("/home/chronos/user"); -#endif - - const char* home_dir = getenv("HOME"); - if (home_dir && home_dir[0]) - return FilePath(home_dir); - -#if defined(OS_ANDROID) - DLOG(WARNING) << "OS_ANDROID: Home directory lookup not yet implemented."; -#else - // g_get_home_dir calls getpwent, which can fall through to LDAP calls. - base::ThreadRestrictions::AssertIOAllowed(); - - home_dir = g_get_home_dir(); - if (home_dir && home_dir[0]) - return FilePath(home_dir); -#endif - - FilePath rv; - if (file_util::GetTempDir(&rv)) - return rv; - - // Last resort. - return FilePath("/tmp"); -} -#endif // !defined(OS_MACOSX) - -bool VerifyPathControlledByUser(const FilePath& base, - const FilePath& path, - uid_t owner_uid, - const std::set& group_gids) { - if (base != path && !base.IsParent(path)) { - DLOG(ERROR) << "|base| must be a subdirectory of |path|. base = \"" - << base.value() << "\", path = \"" << path.value() << "\""; - return false; - } - - std::vector base_components; - std::vector path_components; - - base.GetComponents(&base_components); - path.GetComponents(&path_components); - - std::vector::const_iterator ib, ip; - for (ib = base_components.begin(), ip = path_components.begin(); - ib != base_components.end(); ++ib, ++ip) { - // |base| must be a subpath of |path|, so all components should match. - // If these CHECKs fail, look at the test that base is a parent of - // path at the top of this function. - DCHECK(ip != path_components.end()); - DCHECK(*ip == *ib); - } - - FilePath current_path = base; - if (!VerifySpecificPathControlledByUser(current_path, owner_uid, group_gids)) - return false; - - for (; ip != path_components.end(); ++ip) { - current_path = current_path.Append(*ip); - if (!VerifySpecificPathControlledByUser( - current_path, owner_uid, group_gids)) - return false; - } - return true; -} - -#if defined(OS_MACOSX) && !defined(OS_IOS) -bool VerifyPathControlledByAdmin(const FilePath& path) { - const unsigned kRootUid = 0; - const FilePath kFileSystemRoot("/"); - - // The name of the administrator group on mac os. - const char* const kAdminGroupNames[] = { - "admin", - "wheel" - }; - - // Reading the groups database may touch the file system. - base::ThreadRestrictions::AssertIOAllowed(); - - std::set allowed_group_ids; - for (int i = 0, ie = arraysize(kAdminGroupNames); i < ie; ++i) { - struct group *group_record = getgrnam(kAdminGroupNames[i]); - if (!group_record) { - DPLOG(ERROR) << "Could not get the group ID of group \"" - << kAdminGroupNames[i] << "\"."; - continue; - } - - allowed_group_ids.insert(group_record->gr_gid); - } - - return VerifyPathControlledByUser( - kFileSystemRoot, path, kRootUid, allowed_group_ids); -} -#endif // defined(OS_MACOSX) && !defined(OS_IOS) - -int GetMaximumPathComponentLength(const FilePath& path) { - base::ThreadRestrictions::AssertIOAllowed(); - return pathconf(path.value().c_str(), _PC_NAME_MAX); -} - -} // namespace file_util - -namespace base { -namespace internal { - -bool MoveUnsafe(const FilePath& from_path, const FilePath& to_path) { - ThreadRestrictions::AssertIOAllowed(); - // Windows compatibility: if to_path exists, from_path and to_path - // must be the same type, either both files, or both directories. - stat_wrapper_t to_file_info; - if (CallStat(to_path.value().c_str(), &to_file_info) == 0) { - stat_wrapper_t from_file_info; - if (CallStat(from_path.value().c_str(), &from_file_info) == 0) { - if (S_ISDIR(to_file_info.st_mode) != S_ISDIR(from_file_info.st_mode)) - return false; - } else { - return false; - } - } - - if (rename(from_path.value().c_str(), to_path.value().c_str()) == 0) - return true; - - if (!CopyDirectory(from_path, to_path, true)) - return false; - - DeleteFile(from_path, true); - return true; -} - -#if !defined(OS_MACOSX) -// Mac has its own implementation, this is for all other Posix systems. -bool CopyFileUnsafe(const FilePath& from_path, const FilePath& to_path) { - ThreadRestrictions::AssertIOAllowed(); - int infile = HANDLE_EINTR(open(from_path.value().c_str(), O_RDONLY)); - if (infile < 0) - return false; - - int outfile = HANDLE_EINTR(creat(to_path.value().c_str(), 0666)); - if (outfile < 0) { - ignore_result(HANDLE_EINTR(close(infile))); - return false; - } - - const size_t kBufferSize = 32768; - std::vector buffer(kBufferSize); - bool result = true; - - while (result) { - ssize_t bytes_read = HANDLE_EINTR(read(infile, &buffer[0], buffer.size())); - if (bytes_read < 0) { - result = false; - break; - } - if (bytes_read == 0) - break; - // Allow for partial writes - ssize_t bytes_written_per_read = 0; - do { - ssize_t bytes_written_partial = HANDLE_EINTR(write( - outfile, - &buffer[bytes_written_per_read], - bytes_read - bytes_written_per_read)); - if (bytes_written_partial < 0) { - result = false; - break; - } - bytes_written_per_read += bytes_written_partial; - } while (bytes_written_per_read < bytes_read); - } - - if (HANDLE_EINTR(close(infile)) < 0) - result = false; - if (HANDLE_EINTR(close(outfile)) < 0) - result = false; - - return result; -} -#endif // !defined(OS_MACOSX) - -} // namespace internal -} // namespace base diff --git a/base/file_util_unittest.cc b/base/file_util_unittest.cc deleted file mode 100644 index 787b6d50ba..0000000000 --- a/base/file_util_unittest.cc +++ /dev/null @@ -1,2426 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "build/build_config.h" - -#if defined(OS_WIN) -#include -#include -#include -#include -#include -#endif - -#include -#include -#include - -#include "base/base_paths.h" -#include "base/file_util.h" -#include "base/files/file_enumerator.h" -#include "base/files/file_path.h" -#include "base/files/scoped_temp_dir.h" -#include "base/path_service.h" -#include "base/strings/utf_string_conversions.h" -#include "base/test/test_file_util.h" -#include "base/threading/platform_thread.h" -#include "testing/gtest/include/gtest/gtest.h" -#include "testing/platform_test.h" - -#if defined(OS_WIN) -#include "base/win/scoped_handle.h" -#include "base/win/windows_version.h" -#endif - -// This macro helps avoid wrapped lines in the test structs. -#define FPL(x) FILE_PATH_LITERAL(x) - -using base::DirectoryExists; -using base::FileEnumerator; -using base::FilePath; -using base::PathIsWritable; -using base::TextContentsEqual; - -namespace { - -// To test that file_util::Normalize FilePath() deals with NTFS reparse points -// correctly, we need functions to create and delete reparse points. -#if defined(OS_WIN) -typedef struct _REPARSE_DATA_BUFFER { - ULONG ReparseTag; - USHORT ReparseDataLength; - USHORT Reserved; - union { - struct { - USHORT SubstituteNameOffset; - USHORT SubstituteNameLength; - USHORT PrintNameOffset; - USHORT PrintNameLength; - ULONG Flags; - WCHAR PathBuffer[1]; - } SymbolicLinkReparseBuffer; - struct { - USHORT SubstituteNameOffset; - USHORT SubstituteNameLength; - USHORT PrintNameOffset; - USHORT PrintNameLength; - WCHAR PathBuffer[1]; - } MountPointReparseBuffer; - struct { - UCHAR DataBuffer[1]; - } GenericReparseBuffer; - }; -} REPARSE_DATA_BUFFER, *PREPARSE_DATA_BUFFER; - -// Sets a reparse point. |source| will now point to |target|. Returns true if -// the call succeeds, false otherwise. -bool SetReparsePoint(HANDLE source, const FilePath& target_path) { - std::wstring kPathPrefix = L"\\??\\"; - std::wstring target_str; - // The juction will not work if the target path does not start with \??\ . - if (kPathPrefix != target_path.value().substr(0, kPathPrefix.size())) - target_str += kPathPrefix; - target_str += target_path.value(); - const wchar_t* target = target_str.c_str(); - USHORT size_target = static_cast(wcslen(target)) * sizeof(target[0]); - char buffer[2000] = {0}; - DWORD returned; - - REPARSE_DATA_BUFFER* data = reinterpret_cast(buffer); - - data->ReparseTag = 0xa0000003; - memcpy(data->MountPointReparseBuffer.PathBuffer, target, size_target + 2); - - data->MountPointReparseBuffer.SubstituteNameLength = size_target; - data->MountPointReparseBuffer.PrintNameOffset = size_target + 2; - data->ReparseDataLength = size_target + 4 + 8; - - int data_size = data->ReparseDataLength + 8; - - if (!DeviceIoControl(source, FSCTL_SET_REPARSE_POINT, &buffer, data_size, - NULL, 0, &returned, NULL)) { - return false; - } - return true; -} - -// Delete the reparse point referenced by |source|. Returns true if the call -// succeeds, false otherwise. -bool DeleteReparsePoint(HANDLE source) { - DWORD returned; - REPARSE_DATA_BUFFER data = {0}; - data.ReparseTag = 0xa0000003; - if (!DeviceIoControl(source, FSCTL_DELETE_REPARSE_POINT, &data, 8, NULL, 0, - &returned, NULL)) { - return false; - } - return true; -} - -// Manages a reparse point for a test. -class ReparsePoint { - public: - // Creates a reparse point from |source| (an empty directory) to |target|. - ReparsePoint(const FilePath& source, const FilePath& target) { - dir_.Set( - ::CreateFile(source.value().c_str(), - FILE_ALL_ACCESS, - FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, - NULL, - OPEN_EXISTING, - FILE_FLAG_BACKUP_SEMANTICS, // Needed to open a directory. - NULL)); - created_ = dir_.IsValid() && SetReparsePoint(dir_, target); - } - - ~ReparsePoint() { - if (created_) - DeleteReparsePoint(dir_); - } - - bool IsValid() { return created_; } - - private: - base::win::ScopedHandle dir_; - bool created_; - DISALLOW_COPY_AND_ASSIGN(ReparsePoint); -}; - -#endif - -#if defined(OS_POSIX) -// Provide a simple way to change the permissions bits on |path| in tests. -// ASSERT failures will return, but not stop the test. Caller should wrap -// calls to this function in ASSERT_NO_FATAL_FAILURE(). -void ChangePosixFilePermissions(const FilePath& path, - int mode_bits_to_set, - int mode_bits_to_clear) { - ASSERT_FALSE(mode_bits_to_set & mode_bits_to_clear) - << "Can't set and clear the same bits."; - - int mode = 0; - ASSERT_TRUE(file_util::GetPosixFilePermissions(path, &mode)); - mode |= mode_bits_to_set; - mode &= ~mode_bits_to_clear; - ASSERT_TRUE(file_util::SetPosixFilePermissions(path, mode)); -} -#endif // defined(OS_POSIX) - -const wchar_t bogus_content[] = L"I'm cannon fodder."; - -const int FILES_AND_DIRECTORIES = - FileEnumerator::FILES | FileEnumerator::DIRECTORIES; - -// file_util winds up using autoreleased objects on the Mac, so this needs -// to be a PlatformTest -class FileUtilTest : public PlatformTest { - protected: - virtual void SetUp() OVERRIDE { - PlatformTest::SetUp(); - ASSERT_TRUE(temp_dir_.CreateUniqueTempDir()); - } - - base::ScopedTempDir temp_dir_; -}; - -// Collects all the results from the given file enumerator, and provides an -// interface to query whether a given file is present. -class FindResultCollector { - public: - explicit FindResultCollector(FileEnumerator& enumerator) { - FilePath cur_file; - while (!(cur_file = enumerator.Next()).value().empty()) { - FilePath::StringType path = cur_file.value(); - // The file should not be returned twice. - EXPECT_TRUE(files_.end() == files_.find(path)) - << "Same file returned twice"; - - // Save for later. - files_.insert(path); - } - } - - // Returns true if the enumerator found the file. - bool HasFile(const FilePath& file) const { - return files_.find(file.value()) != files_.end(); - } - - int size() { - return static_cast(files_.size()); - } - - private: - std::set files_; -}; - -// Simple function to dump some text into a new file. -void CreateTextFile(const FilePath& filename, - const std::wstring& contents) { - std::wofstream file; - file.open(filename.value().c_str()); - ASSERT_TRUE(file.is_open()); - file << contents; - file.close(); -} - -// Simple function to take out some text from a file. -std::wstring ReadTextFile(const FilePath& filename) { - wchar_t contents[64]; - std::wifstream file; - file.open(filename.value().c_str()); - EXPECT_TRUE(file.is_open()); - file.getline(contents, arraysize(contents)); - file.close(); - return std::wstring(contents); -} - -#if defined(OS_WIN) -uint64 FileTimeAsUint64(const FILETIME& ft) { - ULARGE_INTEGER u; - u.LowPart = ft.dwLowDateTime; - u.HighPart = ft.dwHighDateTime; - return u.QuadPart; -} -#endif - -const struct append_case { - const wchar_t* path; - const wchar_t* ending; - const wchar_t* result; -} append_cases[] = { -#if defined(OS_WIN) - {L"c:\\colon\\backslash", L"path", L"c:\\colon\\backslash\\path"}, - {L"c:\\colon\\backslash\\", L"path", L"c:\\colon\\backslash\\path"}, - {L"c:\\colon\\backslash\\\\", L"path", L"c:\\colon\\backslash\\\\path"}, - {L"c:\\colon\\backslash\\", L"", L"c:\\colon\\backslash\\"}, - {L"c:\\colon\\backslash", L"", L"c:\\colon\\backslash\\"}, - {L"", L"path", L"\\path"}, - {L"", L"", L"\\"}, -#elif defined(OS_POSIX) - {L"/foo/bar", L"path", L"/foo/bar/path"}, - {L"/foo/bar/", L"path", L"/foo/bar/path"}, - {L"/foo/bar//", L"path", L"/foo/bar//path"}, - {L"/foo/bar/", L"", L"/foo/bar/"}, - {L"/foo/bar", L"", L"/foo/bar/"}, - {L"", L"path", L"/path"}, - {L"", L"", L"/"}, -#endif -}; - -static const struct filename_case { - const wchar_t* path; - const wchar_t* filename; -} filename_cases[] = { -#if defined(OS_WIN) - {L"c:\\colon\\backslash", L"backslash"}, - {L"c:\\colon\\backslash\\", L""}, - {L"\\\\filename.exe", L"filename.exe"}, - {L"filename.exe", L"filename.exe"}, - {L"", L""}, - {L"\\\\\\", L""}, - {L"c:/colon/backslash", L"backslash"}, - {L"c:/colon/backslash/", L""}, - {L"//////", L""}, - {L"///filename.exe", L"filename.exe"}, -#elif defined(OS_POSIX) - {L"/foo/bar", L"bar"}, - {L"/foo/bar/", L""}, - {L"/filename.exe", L"filename.exe"}, - {L"filename.exe", L"filename.exe"}, - {L"", L""}, - {L"/", L""}, -#endif -}; - -// Test finding the file type from a path name -static const struct extension_case { - const wchar_t* path; - const wchar_t* extension; -} extension_cases[] = { -#if defined(OS_WIN) - {L"C:\\colon\\backslash\\filename.extension", L"extension"}, - {L"C:\\colon\\backslash\\filename.", L""}, - {L"C:\\colon\\backslash\\filename", L""}, - {L"C:\\colon\\backslash\\", L""}, - {L"C:\\colon\\backslash.\\", L""}, - {L"C:\\colon\\backslash\filename.extension.extension2", L"extension2"}, -#elif defined(OS_POSIX) - {L"/foo/bar/filename.extension", L"extension"}, - {L"/foo/bar/filename.", L""}, - {L"/foo/bar/filename", L""}, - {L"/foo/bar/", L""}, - {L"/foo/bar./", L""}, - {L"/foo/bar/filename.extension.extension2", L"extension2"}, - {L".", L""}, - {L"..", L""}, - {L"./foo", L""}, - {L"./foo.extension", L"extension"}, - {L"/foo.extension1/bar.extension2", L"extension2"}, -#endif -}; - -// Test finding the directory component of a path -static const struct dir_case { - const wchar_t* full_path; - const wchar_t* directory; -} dir_cases[] = { -#if defined(OS_WIN) - {L"C:\\WINDOWS\\system32\\gdi32.dll", L"C:\\WINDOWS\\system32"}, - {L"C:\\WINDOWS\\system32\\not_exist_thx_1138", L"C:\\WINDOWS\\system32"}, - {L"C:\\WINDOWS\\system32\\", L"C:\\WINDOWS\\system32"}, - {L"C:\\WINDOWS\\system32\\\\", L"C:\\WINDOWS\\system32"}, - {L"C:\\WINDOWS\\system32", L"C:\\WINDOWS"}, - {L"C:\\WINDOWS\\system32.\\", L"C:\\WINDOWS\\system32."}, - {L"C:\\", L"C:\\"}, -#elif defined(OS_POSIX) - {L"/foo/bar/gdi32.dll", L"/foo/bar"}, - {L"/foo/bar/not_exist_thx_1138", L"/foo/bar"}, - {L"/foo/bar/", L"/foo/bar"}, - {L"/foo/bar//", L"/foo/bar"}, - {L"/foo/bar", L"/foo"}, - {L"/foo/bar./", L"/foo/bar."}, - {L"/", L"/"}, - {L".", L"."}, - {L"..", L"."}, // yes, ".." technically lives in "." -#endif -}; - -TEST_F(FileUtilTest, FileAndDirectorySize) { - // Create three files of 20, 30 and 3 chars (utf8). ComputeDirectorySize - // should return 53 bytes. - FilePath file_01 = temp_dir_.path().Append(FPL("The file 01.txt")); - CreateTextFile(file_01, L"12345678901234567890"); - int64 size_f1 = 0; - ASSERT_TRUE(file_util::GetFileSize(file_01, &size_f1)); - EXPECT_EQ(20ll, size_f1); - - FilePath subdir_path = temp_dir_.path().Append(FPL("Level2")); - file_util::CreateDirectory(subdir_path); - - FilePath file_02 = subdir_path.Append(FPL("The file 02.txt")); - CreateTextFile(file_02, L"123456789012345678901234567890"); - int64 size_f2 = 0; - ASSERT_TRUE(file_util::GetFileSize(file_02, &size_f2)); - EXPECT_EQ(30ll, size_f2); - - FilePath subsubdir_path = subdir_path.Append(FPL("Level3")); - file_util::CreateDirectory(subsubdir_path); - - FilePath file_03 = subsubdir_path.Append(FPL("The file 03.txt")); - CreateTextFile(file_03, L"123"); - - int64 computed_size = base::ComputeDirectorySize(temp_dir_.path()); - EXPECT_EQ(size_f1 + size_f2 + 3, computed_size); -} - -TEST_F(FileUtilTest, NormalizeFilePathBasic) { - // Create a directory under the test dir. Because we create it, - // we know it is not a link. - FilePath file_a_path = temp_dir_.path().Append(FPL("file_a")); - FilePath dir_path = temp_dir_.path().Append(FPL("dir")); - FilePath file_b_path = dir_path.Append(FPL("file_b")); - file_util::CreateDirectory(dir_path); - - FilePath normalized_file_a_path, normalized_file_b_path; - ASSERT_FALSE(base::PathExists(file_a_path)); - ASSERT_FALSE(file_util::NormalizeFilePath(file_a_path, - &normalized_file_a_path)) - << "NormalizeFilePath() should fail on nonexistent paths."; - - CreateTextFile(file_a_path, bogus_content); - ASSERT_TRUE(base::PathExists(file_a_path)); - ASSERT_TRUE(file_util::NormalizeFilePath(file_a_path, - &normalized_file_a_path)); - - CreateTextFile(file_b_path, bogus_content); - ASSERT_TRUE(base::PathExists(file_b_path)); - ASSERT_TRUE(file_util::NormalizeFilePath(file_b_path, - &normalized_file_b_path)); - - // Beacuse this test created |dir_path|, we know it is not a link - // or junction. So, the real path of the directory holding file a - // must be the parent of the path holding file b. - ASSERT_TRUE(normalized_file_a_path.DirName() - .IsParent(normalized_file_b_path.DirName())); -} - -#if defined(OS_WIN) - -TEST_F(FileUtilTest, NormalizeFilePathReparsePoints) { - // Build the following directory structure: - // - // temp_dir - // |-> base_a - // | |-> sub_a - // | |-> file.txt - // | |-> long_name___... (Very long name.) - // | |-> sub_long - // | |-> deep.txt - // |-> base_b - // |-> to_sub_a (reparse point to temp_dir\base_a\sub_a) - // |-> to_base_b (reparse point to temp_dir\base_b) - // |-> to_sub_long (reparse point to temp_dir\sub_a\long_name_\sub_long) - - FilePath base_a = temp_dir_.path().Append(FPL("base_a")); - ASSERT_TRUE(file_util::CreateDirectory(base_a)); - - FilePath sub_a = base_a.Append(FPL("sub_a")); - ASSERT_TRUE(file_util::CreateDirectory(sub_a)); - - FilePath file_txt = sub_a.Append(FPL("file.txt")); - CreateTextFile(file_txt, bogus_content); - - // Want a directory whose name is long enough to make the path to the file - // inside just under MAX_PATH chars. This will be used to test that when - // a junction expands to a path over MAX_PATH chars in length, - // NormalizeFilePath() fails without crashing. - FilePath sub_long_rel(FPL("sub_long")); - FilePath deep_txt(FPL("deep.txt")); - - int target_length = MAX_PATH; - target_length -= (sub_a.value().length() + 1); // +1 for the sepperator '\'. - target_length -= (sub_long_rel.Append(deep_txt).value().length() + 1); - // Without making the path a bit shorter, CreateDirectory() fails. - // the resulting path is still long enough to hit the failing case in - // NormalizePath(). - const int kCreateDirLimit = 4; - target_length -= kCreateDirLimit; - FilePath::StringType long_name_str = FPL("long_name_"); - long_name_str.resize(target_length, '_'); - - FilePath long_name = sub_a.Append(FilePath(long_name_str)); - FilePath deep_file = long_name.Append(sub_long_rel).Append(deep_txt); - ASSERT_EQ(MAX_PATH - kCreateDirLimit, deep_file.value().length()); - - FilePath sub_long = deep_file.DirName(); - ASSERT_TRUE(file_util::CreateDirectory(sub_long)); - CreateTextFile(deep_file, bogus_content); - - FilePath base_b = temp_dir_.path().Append(FPL("base_b")); - ASSERT_TRUE(file_util::CreateDirectory(base_b)); - - FilePath to_sub_a = base_b.Append(FPL("to_sub_a")); - ASSERT_TRUE(file_util::CreateDirectory(to_sub_a)); - FilePath normalized_path; - { - ReparsePoint reparse_to_sub_a(to_sub_a, sub_a); - ASSERT_TRUE(reparse_to_sub_a.IsValid()); - - FilePath to_base_b = base_b.Append(FPL("to_base_b")); - ASSERT_TRUE(file_util::CreateDirectory(to_base_b)); - ReparsePoint reparse_to_base_b(to_base_b, base_b); - ASSERT_TRUE(reparse_to_base_b.IsValid()); - - FilePath to_sub_long = base_b.Append(FPL("to_sub_long")); - ASSERT_TRUE(file_util::CreateDirectory(to_sub_long)); - ReparsePoint reparse_to_sub_long(to_sub_long, sub_long); - ASSERT_TRUE(reparse_to_sub_long.IsValid()); - - // Normalize a junction free path: base_a\sub_a\file.txt . - ASSERT_TRUE(file_util::NormalizeFilePath(file_txt, &normalized_path)); - ASSERT_STREQ(file_txt.value().c_str(), normalized_path.value().c_str()); - - // Check that the path base_b\to_sub_a\file.txt can be normalized to exclude - // the junction to_sub_a. - ASSERT_TRUE(file_util::NormalizeFilePath(to_sub_a.Append(FPL("file.txt")), - &normalized_path)); - ASSERT_STREQ(file_txt.value().c_str(), normalized_path.value().c_str()); - - // Check that the path base_b\to_base_b\to_base_b\to_sub_a\file.txt can be - // normalized to exclude junctions to_base_b and to_sub_a . - ASSERT_TRUE(file_util::NormalizeFilePath(base_b.Append(FPL("to_base_b")) - .Append(FPL("to_base_b")) - .Append(FPL("to_sub_a")) - .Append(FPL("file.txt")), - &normalized_path)); - ASSERT_STREQ(file_txt.value().c_str(), normalized_path.value().c_str()); - - // A long enough path will cause NormalizeFilePath() to fail. Make a long - // path using to_base_b many times, and check that paths long enough to fail - // do not cause a crash. - FilePath long_path = base_b; - const int kLengthLimit = MAX_PATH + 200; - while (long_path.value().length() <= kLengthLimit) { - long_path = long_path.Append(FPL("to_base_b")); - } - long_path = long_path.Append(FPL("to_sub_a")) - .Append(FPL("file.txt")); - - ASSERT_FALSE(file_util::NormalizeFilePath(long_path, &normalized_path)); - - // Normalizing the junction to deep.txt should fail, because the expanded - // path to deep.txt is longer than MAX_PATH. - ASSERT_FALSE(file_util::NormalizeFilePath(to_sub_long.Append(deep_txt), - &normalized_path)); - - // Delete the reparse points, and see that NormalizeFilePath() fails - // to traverse them. - } - - ASSERT_FALSE(file_util::NormalizeFilePath(to_sub_a.Append(FPL("file.txt")), - &normalized_path)); -} - -TEST_F(FileUtilTest, DevicePathToDriveLetter) { - // Get a drive letter. - std::wstring real_drive_letter = temp_dir_.path().value().substr(0, 2); - if (!isalpha(real_drive_letter[0]) || ':' != real_drive_letter[1]) { - LOG(ERROR) << "Can't get a drive letter to test with."; - return; - } - - // Get the NT style path to that drive. - wchar_t device_path[MAX_PATH] = {'\0'}; - ASSERT_TRUE( - ::QueryDosDevice(real_drive_letter.c_str(), device_path, MAX_PATH)); - FilePath actual_device_path(device_path); - FilePath win32_path; - - // Run DevicePathToDriveLetterPath() on the NT style path we got from - // QueryDosDevice(). Expect the drive letter we started with. - ASSERT_TRUE(file_util::DevicePathToDriveLetterPath(actual_device_path, - &win32_path)); - ASSERT_EQ(real_drive_letter, win32_path.value()); - - // Add some directories to the path. Expect those extra path componenets - // to be preserved. - FilePath kRelativePath(FPL("dir1\\dir2\\file.txt")); - ASSERT_TRUE(file_util::DevicePathToDriveLetterPath( - actual_device_path.Append(kRelativePath), - &win32_path)); - EXPECT_EQ(FilePath(real_drive_letter + L"\\").Append(kRelativePath).value(), - win32_path.value()); - - // Deform the real path so that it is invalid by removing the last four - // characters. The way windows names devices that are hard disks - // (\Device\HardDiskVolume${NUMBER}) guarantees that the string is longer - // than three characters. The only way the truncated string could be a - // real drive is if more than 10^3 disks are mounted: - // \Device\HardDiskVolume10000 would be truncated to \Device\HardDiskVolume1 - // Check that DevicePathToDriveLetterPath fails. - int path_length = actual_device_path.value().length(); - int new_length = path_length - 4; - ASSERT_LT(0, new_length); - FilePath prefix_of_real_device_path( - actual_device_path.value().substr(0, new_length)); - ASSERT_FALSE(file_util::DevicePathToDriveLetterPath( - prefix_of_real_device_path, - &win32_path)); - - ASSERT_FALSE(file_util::DevicePathToDriveLetterPath( - prefix_of_real_device_path.Append(kRelativePath), - &win32_path)); - - // Deform the real path so that it is invalid by adding some characters. For - // example, if C: maps to \Device\HardDiskVolume8, then we simulate a - // request for the drive letter whose native path is - // \Device\HardDiskVolume812345 . We assume such a device does not exist, - // because drives are numbered in order and mounting 112345 hard disks will - // never happen. - const FilePath::StringType kExtraChars = FPL("12345"); - - FilePath real_device_path_plus_numbers( - actual_device_path.value() + kExtraChars); - - ASSERT_FALSE(file_util::DevicePathToDriveLetterPath( - real_device_path_plus_numbers, - &win32_path)); - - ASSERT_FALSE(file_util::DevicePathToDriveLetterPath( - real_device_path_plus_numbers.Append(kRelativePath), - &win32_path)); -} - -TEST_F(FileUtilTest, GetPlatformFileInfoForDirectory) { - FilePath empty_dir = temp_dir_.path().Append(FPL("gpfi_test")); - ASSERT_TRUE(file_util::CreateDirectory(empty_dir)); - base::win::ScopedHandle dir( - ::CreateFile(empty_dir.value().c_str(), - FILE_ALL_ACCESS, - FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, - NULL, - OPEN_EXISTING, - FILE_FLAG_BACKUP_SEMANTICS, // Needed to open a directory. - NULL)); - ASSERT_TRUE(dir.IsValid()); - base::PlatformFileInfo info; - EXPECT_TRUE(base::GetPlatformFileInfo(dir.Get(), &info)); - EXPECT_TRUE(info.is_directory); - EXPECT_FALSE(info.is_symbolic_link); - EXPECT_EQ(0, info.size); -} - -TEST_F(FileUtilTest, CreateTemporaryFileInDirLongPathTest) { - // Test that CreateTemporaryFileInDir() creates a path and returns a long path - // if it is available. This test requires that: - // - the filesystem at |temp_dir_| supports long filenames. - // - the account has FILE_LIST_DIRECTORY permission for all ancestor - // directories of |temp_dir_|. - const FilePath::CharType kLongDirName[] = FPL("A long path"); - const FilePath::CharType kTestSubDirName[] = FPL("test"); - FilePath long_test_dir = temp_dir_.path().Append(kLongDirName); - ASSERT_TRUE(file_util::CreateDirectory(long_test_dir)); - - // kLongDirName is not a 8.3 component. So GetShortName() should give us a - // different short name. - WCHAR path_buffer[MAX_PATH]; - DWORD path_buffer_length = GetShortPathName(long_test_dir.value().c_str(), - path_buffer, MAX_PATH); - ASSERT_LT(path_buffer_length, DWORD(MAX_PATH)); - ASSERT_NE(DWORD(0), path_buffer_length); - FilePath short_test_dir(path_buffer); - ASSERT_STRNE(kLongDirName, short_test_dir.BaseName().value().c_str()); - - FilePath temp_file; - ASSERT_TRUE(file_util::CreateTemporaryFileInDir(short_test_dir, &temp_file)); - EXPECT_STREQ(kLongDirName, temp_file.DirName().BaseName().value().c_str()); - EXPECT_TRUE(base::PathExists(temp_file)); - - // Create a subdirectory of |long_test_dir| and make |long_test_dir| - // unreadable. We should still be able to create a temp file in the - // subdirectory, but we won't be able to determine the long path for it. This - // mimics the environment that some users run where their user profiles reside - // in a location where the don't have full access to the higher level - // directories. (Note that this assumption is true for NTFS, but not for some - // network file systems. E.g. AFS). - FilePath access_test_dir = long_test_dir.Append(kTestSubDirName); - ASSERT_TRUE(file_util::CreateDirectory(access_test_dir)); - file_util::PermissionRestorer long_test_dir_restorer(long_test_dir); - ASSERT_TRUE(file_util::MakeFileUnreadable(long_test_dir)); - - // Use the short form of the directory to create a temporary filename. - ASSERT_TRUE(file_util::CreateTemporaryFileInDir( - short_test_dir.Append(kTestSubDirName), &temp_file)); - EXPECT_TRUE(base::PathExists(temp_file)); - EXPECT_TRUE(short_test_dir.IsParent(temp_file.DirName())); - - // Check that the long path can't be determined for |temp_file|. - path_buffer_length = GetLongPathName(temp_file.value().c_str(), - path_buffer, MAX_PATH); - EXPECT_EQ(DWORD(0), path_buffer_length); -} - -#endif // defined(OS_WIN) - -#if defined(OS_POSIX) - -TEST_F(FileUtilTest, CreateAndReadSymlinks) { - FilePath link_from = temp_dir_.path().Append(FPL("from_file")); - FilePath link_to = temp_dir_.path().Append(FPL("to_file")); - CreateTextFile(link_to, bogus_content); - - ASSERT_TRUE(file_util::CreateSymbolicLink(link_to, link_from)) - << "Failed to create file symlink."; - - // If we created the link properly, we should be able to read the contents - // through it. - std::wstring contents = ReadTextFile(link_from); - EXPECT_EQ(bogus_content, contents); - - FilePath result; - ASSERT_TRUE(file_util::ReadSymbolicLink(link_from, &result)); - EXPECT_EQ(link_to.value(), result.value()); - - // Link to a directory. - link_from = temp_dir_.path().Append(FPL("from_dir")); - link_to = temp_dir_.path().Append(FPL("to_dir")); - ASSERT_TRUE(file_util::CreateDirectory(link_to)); - ASSERT_TRUE(file_util::CreateSymbolicLink(link_to, link_from)) - << "Failed to create directory symlink."; - - // Test failures. - EXPECT_FALSE(file_util::CreateSymbolicLink(link_to, link_to)); - EXPECT_FALSE(file_util::ReadSymbolicLink(link_to, &result)); - FilePath missing = temp_dir_.path().Append(FPL("missing")); - EXPECT_FALSE(file_util::ReadSymbolicLink(missing, &result)); -} - -// The following test of NormalizeFilePath() require that we create a symlink. -// This can not be done on Windows before Vista. On Vista, creating a symlink -// requires privilege "SeCreateSymbolicLinkPrivilege". -// TODO(skerner): Investigate the possibility of giving base_unittests the -// privileges required to create a symlink. -TEST_F(FileUtilTest, NormalizeFilePathSymlinks) { - // Link one file to another. - FilePath link_from = temp_dir_.path().Append(FPL("from_file")); - FilePath link_to = temp_dir_.path().Append(FPL("to_file")); - CreateTextFile(link_to, bogus_content); - - ASSERT_TRUE(file_util::CreateSymbolicLink(link_to, link_from)) - << "Failed to create file symlink."; - - // Check that NormalizeFilePath sees the link. - FilePath normalized_path; - ASSERT_TRUE(file_util::NormalizeFilePath(link_from, &normalized_path)); - EXPECT_NE(link_from, link_to); - EXPECT_EQ(link_to.BaseName().value(), normalized_path.BaseName().value()); - EXPECT_EQ(link_to.BaseName().value(), normalized_path.BaseName().value()); - - // Link to a directory. - link_from = temp_dir_.path().Append(FPL("from_dir")); - link_to = temp_dir_.path().Append(FPL("to_dir")); - ASSERT_TRUE(file_util::CreateDirectory(link_to)); - ASSERT_TRUE(file_util::CreateSymbolicLink(link_to, link_from)) - << "Failed to create directory symlink."; - - EXPECT_FALSE(file_util::NormalizeFilePath(link_from, &normalized_path)) - << "Links to directories should return false."; - - // Test that a loop in the links causes NormalizeFilePath() to return false. - link_from = temp_dir_.path().Append(FPL("link_a")); - link_to = temp_dir_.path().Append(FPL("link_b")); - ASSERT_TRUE(file_util::CreateSymbolicLink(link_to, link_from)) - << "Failed to create loop symlink a."; - ASSERT_TRUE(file_util::CreateSymbolicLink(link_from, link_to)) - << "Failed to create loop symlink b."; - - // Infinite loop! - EXPECT_FALSE(file_util::NormalizeFilePath(link_from, &normalized_path)); -} -#endif // defined(OS_POSIX) - -TEST_F(FileUtilTest, DeleteNonExistent) { - FilePath non_existent = temp_dir_.path().AppendASCII("bogus_file_dne.foobar"); - ASSERT_FALSE(base::PathExists(non_existent)); - - EXPECT_TRUE(base::DeleteFile(non_existent, false)); - ASSERT_FALSE(base::PathExists(non_existent)); - EXPECT_TRUE(base::DeleteFile(non_existent, true)); - ASSERT_FALSE(base::PathExists(non_existent)); -} - -TEST_F(FileUtilTest, DeleteFile) { - // Create a file - FilePath file_name = temp_dir_.path().Append(FPL("Test DeleteFile 1.txt")); - CreateTextFile(file_name, bogus_content); - ASSERT_TRUE(base::PathExists(file_name)); - - // Make sure it's deleted - EXPECT_TRUE(base::DeleteFile(file_name, false)); - EXPECT_FALSE(base::PathExists(file_name)); - - // Test recursive case, create a new file - file_name = temp_dir_.path().Append(FPL("Test DeleteFile 2.txt")); - CreateTextFile(file_name, bogus_content); - ASSERT_TRUE(base::PathExists(file_name)); - - // Make sure it's deleted - EXPECT_TRUE(base::DeleteFile(file_name, true)); - EXPECT_FALSE(base::PathExists(file_name)); -} - -#if defined(OS_POSIX) -TEST_F(FileUtilTest, DeleteSymlinkToExistentFile) { - // Create a file. - FilePath file_name = temp_dir_.path().Append(FPL("Test DeleteFile 2.txt")); - CreateTextFile(file_name, bogus_content); - ASSERT_TRUE(base::PathExists(file_name)); - - // Create a symlink to the file. - FilePath file_link = temp_dir_.path().Append("file_link_2"); - ASSERT_TRUE(file_util::CreateSymbolicLink(file_name, file_link)) - << "Failed to create symlink."; - - // Delete the symbolic link. - EXPECT_TRUE(base::DeleteFile(file_link, false)); - - // Make sure original file is not deleted. - EXPECT_FALSE(base::PathExists(file_link)); - EXPECT_TRUE(base::PathExists(file_name)); -} - -TEST_F(FileUtilTest, DeleteSymlinkToNonExistentFile) { - // Create a non-existent file path. - FilePath non_existent = temp_dir_.path().Append(FPL("Test DeleteFile 3.txt")); - EXPECT_FALSE(base::PathExists(non_existent)); - - // Create a symlink to the non-existent file. - FilePath file_link = temp_dir_.path().Append("file_link_3"); - ASSERT_TRUE(file_util::CreateSymbolicLink(non_existent, file_link)) - << "Failed to create symlink."; - - // Make sure the symbolic link is exist. - EXPECT_TRUE(file_util::IsLink(file_link)); - EXPECT_FALSE(base::PathExists(file_link)); - - // Delete the symbolic link. - EXPECT_TRUE(base::DeleteFile(file_link, false)); - - // Make sure the symbolic link is deleted. - EXPECT_FALSE(file_util::IsLink(file_link)); -} - -TEST_F(FileUtilTest, ChangeFilePermissionsAndRead) { - // Create a file path. - FilePath file_name = temp_dir_.path().Append(FPL("Test Readable File.txt")); - EXPECT_FALSE(base::PathExists(file_name)); - - const std::string kData("hello"); - - int buffer_size = kData.length(); - char* buffer = new char[buffer_size]; - - // Write file. - EXPECT_EQ(static_cast(kData.length()), - file_util::WriteFile(file_name, kData.data(), kData.length())); - EXPECT_TRUE(base::PathExists(file_name)); - - // Make sure the file is readable. - int32 mode = 0; - EXPECT_TRUE(file_util::GetPosixFilePermissions(file_name, &mode)); - EXPECT_TRUE(mode & file_util::FILE_PERMISSION_READ_BY_USER); - - // Get rid of the read permission. - EXPECT_TRUE(file_util::SetPosixFilePermissions(file_name, 0u)); - EXPECT_TRUE(file_util::GetPosixFilePermissions(file_name, &mode)); - EXPECT_FALSE(mode & file_util::FILE_PERMISSION_READ_BY_USER); - // Make sure the file can't be read. - EXPECT_EQ(-1, file_util::ReadFile(file_name, buffer, buffer_size)); - - // Give the read permission. - EXPECT_TRUE(file_util::SetPosixFilePermissions( - file_name, - file_util::FILE_PERMISSION_READ_BY_USER)); - EXPECT_TRUE(file_util::GetPosixFilePermissions(file_name, &mode)); - EXPECT_TRUE(mode & file_util::FILE_PERMISSION_READ_BY_USER); - // Make sure the file can be read. - EXPECT_EQ(static_cast(kData.length()), - file_util::ReadFile(file_name, buffer, buffer_size)); - - // Delete the file. - EXPECT_TRUE(base::DeleteFile(file_name, false)); - EXPECT_FALSE(base::PathExists(file_name)); - - delete[] buffer; -} - -TEST_F(FileUtilTest, ChangeFilePermissionsAndWrite) { - // Create a file path. - FilePath file_name = temp_dir_.path().Append(FPL("Test Readable File.txt")); - EXPECT_FALSE(base::PathExists(file_name)); - - const std::string kData("hello"); - - // Write file. - EXPECT_EQ(static_cast(kData.length()), - file_util::WriteFile(file_name, kData.data(), kData.length())); - EXPECT_TRUE(base::PathExists(file_name)); - - // Make sure the file is writable. - int mode = 0; - EXPECT_TRUE(file_util::GetPosixFilePermissions(file_name, &mode)); - EXPECT_TRUE(mode & file_util::FILE_PERMISSION_WRITE_BY_USER); - EXPECT_TRUE(PathIsWritable(file_name)); - - // Get rid of the write permission. - EXPECT_TRUE(file_util::SetPosixFilePermissions(file_name, 0u)); - EXPECT_TRUE(file_util::GetPosixFilePermissions(file_name, &mode)); - EXPECT_FALSE(mode & file_util::FILE_PERMISSION_WRITE_BY_USER); - // Make sure the file can't be write. - EXPECT_EQ(-1, - file_util::WriteFile(file_name, kData.data(), kData.length())); - EXPECT_FALSE(PathIsWritable(file_name)); - - // Give read permission. - EXPECT_TRUE(file_util::SetPosixFilePermissions( - file_name, - file_util::FILE_PERMISSION_WRITE_BY_USER)); - EXPECT_TRUE(file_util::GetPosixFilePermissions(file_name, &mode)); - EXPECT_TRUE(mode & file_util::FILE_PERMISSION_WRITE_BY_USER); - // Make sure the file can be write. - EXPECT_EQ(static_cast(kData.length()), - file_util::WriteFile(file_name, kData.data(), kData.length())); - EXPECT_TRUE(PathIsWritable(file_name)); - - // Delete the file. - EXPECT_TRUE(base::DeleteFile(file_name, false)); - EXPECT_FALSE(base::PathExists(file_name)); -} - -TEST_F(FileUtilTest, ChangeDirectoryPermissionsAndEnumerate) { - // Create a directory path. - FilePath subdir_path = - temp_dir_.path().Append(FPL("PermissionTest1")); - file_util::CreateDirectory(subdir_path); - ASSERT_TRUE(base::PathExists(subdir_path)); - - // Create a dummy file to enumerate. - FilePath file_name = subdir_path.Append(FPL("Test Readable File.txt")); - EXPECT_FALSE(base::PathExists(file_name)); - const std::string kData("hello"); - EXPECT_EQ(static_cast(kData.length()), - file_util::WriteFile(file_name, kData.data(), kData.length())); - EXPECT_TRUE(base::PathExists(file_name)); - - // Make sure the directory has the all permissions. - int mode = 0; - EXPECT_TRUE(file_util::GetPosixFilePermissions(subdir_path, &mode)); - EXPECT_EQ(file_util::FILE_PERMISSION_USER_MASK, - mode & file_util::FILE_PERMISSION_USER_MASK); - - // Get rid of the permissions from the directory. - EXPECT_TRUE(file_util::SetPosixFilePermissions(subdir_path, 0u)); - EXPECT_TRUE(file_util::GetPosixFilePermissions(subdir_path, &mode)); - EXPECT_FALSE(mode & file_util::FILE_PERMISSION_USER_MASK); - - // Make sure the file in the directory can't be enumerated. - FileEnumerator f1(subdir_path, true, FileEnumerator::FILES); - EXPECT_TRUE(base::PathExists(subdir_path)); - FindResultCollector c1(f1); - EXPECT_EQ(c1.size(), 0); - EXPECT_FALSE(file_util::GetPosixFilePermissions(file_name, &mode)); - - // Give the permissions to the directory. - EXPECT_TRUE(file_util::SetPosixFilePermissions( - subdir_path, - file_util::FILE_PERMISSION_USER_MASK)); - EXPECT_TRUE(file_util::GetPosixFilePermissions(subdir_path, &mode)); - EXPECT_EQ(file_util::FILE_PERMISSION_USER_MASK, - mode & file_util::FILE_PERMISSION_USER_MASK); - - // Make sure the file in the directory can be enumerated. - FileEnumerator f2(subdir_path, true, FileEnumerator::FILES); - FindResultCollector c2(f2); - EXPECT_TRUE(c2.HasFile(file_name)); - EXPECT_EQ(c2.size(), 1); - - // Delete the file. - EXPECT_TRUE(base::DeleteFile(subdir_path, true)); - EXPECT_FALSE(base::PathExists(subdir_path)); -} - -#endif // defined(OS_POSIX) - -#if defined(OS_WIN) -// Tests that the Delete function works for wild cards, especially -// with the recursion flag. Also coincidentally tests PathExists. -// TODO(erikkay): see if anyone's actually using this feature of the API -TEST_F(FileUtilTest, DeleteWildCard) { - // Create a file and a directory - FilePath file_name = temp_dir_.path().Append(FPL("Test DeleteWildCard.txt")); - CreateTextFile(file_name, bogus_content); - ASSERT_TRUE(base::PathExists(file_name)); - - FilePath subdir_path = temp_dir_.path().Append(FPL("DeleteWildCardDir")); - file_util::CreateDirectory(subdir_path); - ASSERT_TRUE(base::PathExists(subdir_path)); - - // Create the wildcard path - FilePath directory_contents = temp_dir_.path(); - directory_contents = directory_contents.Append(FPL("*")); - - // Delete non-recursively and check that only the file is deleted - EXPECT_TRUE(base::DeleteFile(directory_contents, false)); - EXPECT_FALSE(base::PathExists(file_name)); - EXPECT_TRUE(base::PathExists(subdir_path)); - - // Delete recursively and make sure all contents are deleted - EXPECT_TRUE(base::DeleteFile(directory_contents, true)); - EXPECT_FALSE(base::PathExists(file_name)); - EXPECT_FALSE(base::PathExists(subdir_path)); -} - -// TODO(erikkay): see if anyone's actually using this feature of the API -TEST_F(FileUtilTest, DeleteNonExistantWildCard) { - // Create a file and a directory - FilePath subdir_path = - temp_dir_.path().Append(FPL("DeleteNonExistantWildCard")); - file_util::CreateDirectory(subdir_path); - ASSERT_TRUE(base::PathExists(subdir_path)); - - // Create the wildcard path - FilePath directory_contents = subdir_path; - directory_contents = directory_contents.Append(FPL("*")); - - // Delete non-recursively and check nothing got deleted - EXPECT_TRUE(base::DeleteFile(directory_contents, false)); - EXPECT_TRUE(base::PathExists(subdir_path)); - - // Delete recursively and check nothing got deleted - EXPECT_TRUE(base::DeleteFile(directory_contents, true)); - EXPECT_TRUE(base::PathExists(subdir_path)); -} -#endif - -// Tests non-recursive Delete() for a directory. -TEST_F(FileUtilTest, DeleteDirNonRecursive) { - // Create a subdirectory and put a file and two directories inside. - FilePath test_subdir = temp_dir_.path().Append(FPL("DeleteDirNonRecursive")); - file_util::CreateDirectory(test_subdir); - ASSERT_TRUE(base::PathExists(test_subdir)); - - FilePath file_name = test_subdir.Append(FPL("Test DeleteDir.txt")); - CreateTextFile(file_name, bogus_content); - ASSERT_TRUE(base::PathExists(file_name)); - - FilePath subdir_path1 = test_subdir.Append(FPL("TestSubDir1")); - file_util::CreateDirectory(subdir_path1); - ASSERT_TRUE(base::PathExists(subdir_path1)); - - FilePath subdir_path2 = test_subdir.Append(FPL("TestSubDir2")); - file_util::CreateDirectory(subdir_path2); - ASSERT_TRUE(base::PathExists(subdir_path2)); - - // Delete non-recursively and check that the empty dir got deleted - EXPECT_TRUE(base::DeleteFile(subdir_path2, false)); - EXPECT_FALSE(base::PathExists(subdir_path2)); - - // Delete non-recursively and check that nothing got deleted - EXPECT_FALSE(base::DeleteFile(test_subdir, false)); - EXPECT_TRUE(base::PathExists(test_subdir)); - EXPECT_TRUE(base::PathExists(file_name)); - EXPECT_TRUE(base::PathExists(subdir_path1)); -} - -// Tests recursive Delete() for a directory. -TEST_F(FileUtilTest, DeleteDirRecursive) { - // Create a subdirectory and put a file and two directories inside. - FilePath test_subdir = temp_dir_.path().Append(FPL("DeleteDirRecursive")); - file_util::CreateDirectory(test_subdir); - ASSERT_TRUE(base::PathExists(test_subdir)); - - FilePath file_name = test_subdir.Append(FPL("Test DeleteDirRecursive.txt")); - CreateTextFile(file_name, bogus_content); - ASSERT_TRUE(base::PathExists(file_name)); - - FilePath subdir_path1 = test_subdir.Append(FPL("TestSubDir1")); - file_util::CreateDirectory(subdir_path1); - ASSERT_TRUE(base::PathExists(subdir_path1)); - - FilePath subdir_path2 = test_subdir.Append(FPL("TestSubDir2")); - file_util::CreateDirectory(subdir_path2); - ASSERT_TRUE(base::PathExists(subdir_path2)); - - // Delete recursively and check that the empty dir got deleted - EXPECT_TRUE(base::DeleteFile(subdir_path2, true)); - EXPECT_FALSE(base::PathExists(subdir_path2)); - - // Delete recursively and check that everything got deleted - EXPECT_TRUE(base::DeleteFile(test_subdir, true)); - EXPECT_FALSE(base::PathExists(file_name)); - EXPECT_FALSE(base::PathExists(subdir_path1)); - EXPECT_FALSE(base::PathExists(test_subdir)); -} - -TEST_F(FileUtilTest, MoveFileNew) { - // Create a file - FilePath file_name_from = - temp_dir_.path().Append(FILE_PATH_LITERAL("Move_Test_File.txt")); - CreateTextFile(file_name_from, L"Gooooooooooooooooooooogle"); - ASSERT_TRUE(base::PathExists(file_name_from)); - - // The destination. - FilePath file_name_to = temp_dir_.path().Append( - FILE_PATH_LITERAL("Move_Test_File_Destination.txt")); - ASSERT_FALSE(base::PathExists(file_name_to)); - - EXPECT_TRUE(base::Move(file_name_from, file_name_to)); - - // Check everything has been moved. - EXPECT_FALSE(base::PathExists(file_name_from)); - EXPECT_TRUE(base::PathExists(file_name_to)); -} - -TEST_F(FileUtilTest, MoveFileExists) { - // Create a file - FilePath file_name_from = - temp_dir_.path().Append(FILE_PATH_LITERAL("Move_Test_File.txt")); - CreateTextFile(file_name_from, L"Gooooooooooooooooooooogle"); - ASSERT_TRUE(base::PathExists(file_name_from)); - - // The destination name. - FilePath file_name_to = temp_dir_.path().Append( - FILE_PATH_LITERAL("Move_Test_File_Destination.txt")); - CreateTextFile(file_name_to, L"Old file content"); - ASSERT_TRUE(base::PathExists(file_name_to)); - - EXPECT_TRUE(base::Move(file_name_from, file_name_to)); - - // Check everything has been moved. - EXPECT_FALSE(base::PathExists(file_name_from)); - EXPECT_TRUE(base::PathExists(file_name_to)); - EXPECT_TRUE(L"Gooooooooooooooooooooogle" == ReadTextFile(file_name_to)); -} - -TEST_F(FileUtilTest, MoveFileDirExists) { - // Create a file - FilePath file_name_from = - temp_dir_.path().Append(FILE_PATH_LITERAL("Move_Test_File.txt")); - CreateTextFile(file_name_from, L"Gooooooooooooooooooooogle"); - ASSERT_TRUE(base::PathExists(file_name_from)); - - // The destination directory - FilePath dir_name_to = - temp_dir_.path().Append(FILE_PATH_LITERAL("Destination")); - file_util::CreateDirectory(dir_name_to); - ASSERT_TRUE(base::PathExists(dir_name_to)); - - EXPECT_FALSE(base::Move(file_name_from, dir_name_to)); -} - - -TEST_F(FileUtilTest, MoveNew) { - // Create a directory - FilePath dir_name_from = - temp_dir_.path().Append(FILE_PATH_LITERAL("Move_From_Subdir")); - file_util::CreateDirectory(dir_name_from); - ASSERT_TRUE(base::PathExists(dir_name_from)); - - // Create a file under the directory - FilePath txt_file_name(FILE_PATH_LITERAL("Move_Test_File.txt")); - FilePath file_name_from = dir_name_from.Append(txt_file_name); - CreateTextFile(file_name_from, L"Gooooooooooooooooooooogle"); - ASSERT_TRUE(base::PathExists(file_name_from)); - - // Move the directory. - FilePath dir_name_to = - temp_dir_.path().Append(FILE_PATH_LITERAL("Move_To_Subdir")); - FilePath file_name_to = - dir_name_to.Append(FILE_PATH_LITERAL("Move_Test_File.txt")); - - ASSERT_FALSE(base::PathExists(dir_name_to)); - - EXPECT_TRUE(base::Move(dir_name_from, dir_name_to)); - - // Check everything has been moved. - EXPECT_FALSE(base::PathExists(dir_name_from)); - EXPECT_FALSE(base::PathExists(file_name_from)); - EXPECT_TRUE(base::PathExists(dir_name_to)); - EXPECT_TRUE(base::PathExists(file_name_to)); - - // Test path traversal. - file_name_from = dir_name_to.Append(txt_file_name); - file_name_to = dir_name_to.Append(FILE_PATH_LITERAL("..")); - file_name_to = file_name_to.Append(txt_file_name); - EXPECT_FALSE(base::Move(file_name_from, file_name_to)); - EXPECT_TRUE(base::PathExists(file_name_from)); - EXPECT_FALSE(base::PathExists(file_name_to)); - EXPECT_TRUE(base::internal::MoveUnsafe(file_name_from, file_name_to)); - EXPECT_FALSE(base::PathExists(file_name_from)); - EXPECT_TRUE(base::PathExists(file_name_to)); -} - -TEST_F(FileUtilTest, MoveExist) { - // Create a directory - FilePath dir_name_from = - temp_dir_.path().Append(FILE_PATH_LITERAL("Move_From_Subdir")); - file_util::CreateDirectory(dir_name_from); - ASSERT_TRUE(base::PathExists(dir_name_from)); - - // Create a file under the directory - FilePath file_name_from = - dir_name_from.Append(FILE_PATH_LITERAL("Move_Test_File.txt")); - CreateTextFile(file_name_from, L"Gooooooooooooooooooooogle"); - ASSERT_TRUE(base::PathExists(file_name_from)); - - // Move the directory - FilePath dir_name_exists = - temp_dir_.path().Append(FILE_PATH_LITERAL("Destination")); - - FilePath dir_name_to = - dir_name_exists.Append(FILE_PATH_LITERAL("Move_To_Subdir")); - FilePath file_name_to = - dir_name_to.Append(FILE_PATH_LITERAL("Move_Test_File.txt")); - - // Create the destination directory. - file_util::CreateDirectory(dir_name_exists); - ASSERT_TRUE(base::PathExists(dir_name_exists)); - - EXPECT_TRUE(base::Move(dir_name_from, dir_name_to)); - - // Check everything has been moved. - EXPECT_FALSE(base::PathExists(dir_name_from)); - EXPECT_FALSE(base::PathExists(file_name_from)); - EXPECT_TRUE(base::PathExists(dir_name_to)); - EXPECT_TRUE(base::PathExists(file_name_to)); -} - -TEST_F(FileUtilTest, CopyDirectoryRecursivelyNew) { - // Create a directory. - FilePath dir_name_from = - temp_dir_.path().Append(FILE_PATH_LITERAL("Copy_From_Subdir")); - file_util::CreateDirectory(dir_name_from); - ASSERT_TRUE(base::PathExists(dir_name_from)); - - // Create a file under the directory. - FilePath file_name_from = - dir_name_from.Append(FILE_PATH_LITERAL("Copy_Test_File.txt")); - CreateTextFile(file_name_from, L"Gooooooooooooooooooooogle"); - ASSERT_TRUE(base::PathExists(file_name_from)); - - // Create a subdirectory. - FilePath subdir_name_from = - dir_name_from.Append(FILE_PATH_LITERAL("Subdir")); - file_util::CreateDirectory(subdir_name_from); - ASSERT_TRUE(base::PathExists(subdir_name_from)); - - // Create a file under the subdirectory. - FilePath file_name2_from = - subdir_name_from.Append(FILE_PATH_LITERAL("Copy_Test_File.txt")); - CreateTextFile(file_name2_from, L"Gooooooooooooooooooooogle"); - ASSERT_TRUE(base::PathExists(file_name2_from)); - - // Copy the directory recursively. - FilePath dir_name_to = - temp_dir_.path().Append(FILE_PATH_LITERAL("Copy_To_Subdir")); - FilePath file_name_to = - dir_name_to.Append(FILE_PATH_LITERAL("Copy_Test_File.txt")); - FilePath subdir_name_to = - dir_name_to.Append(FILE_PATH_LITERAL("Subdir")); - FilePath file_name2_to = - subdir_name_to.Append(FILE_PATH_LITERAL("Copy_Test_File.txt")); - - ASSERT_FALSE(base::PathExists(dir_name_to)); - - EXPECT_TRUE(base::CopyDirectory(dir_name_from, dir_name_to, true)); - - // Check everything has been copied. - EXPECT_TRUE(base::PathExists(dir_name_from)); - EXPECT_TRUE(base::PathExists(file_name_from)); - EXPECT_TRUE(base::PathExists(subdir_name_from)); - EXPECT_TRUE(base::PathExists(file_name2_from)); - EXPECT_TRUE(base::PathExists(dir_name_to)); - EXPECT_TRUE(base::PathExists(file_name_to)); - EXPECT_TRUE(base::PathExists(subdir_name_to)); - EXPECT_TRUE(base::PathExists(file_name2_to)); -} - -TEST_F(FileUtilTest, CopyDirectoryRecursivelyExists) { - // Create a directory. - FilePath dir_name_from = - temp_dir_.path().Append(FILE_PATH_LITERAL("Copy_From_Subdir")); - file_util::CreateDirectory(dir_name_from); - ASSERT_TRUE(base::PathExists(dir_name_from)); - - // Create a file under the directory. - FilePath file_name_from = - dir_name_from.Append(FILE_PATH_LITERAL("Copy_Test_File.txt")); - CreateTextFile(file_name_from, L"Gooooooooooooooooooooogle"); - ASSERT_TRUE(base::PathExists(file_name_from)); - - // Create a subdirectory. - FilePath subdir_name_from = - dir_name_from.Append(FILE_PATH_LITERAL("Subdir")); - file_util::CreateDirectory(subdir_name_from); - ASSERT_TRUE(base::PathExists(subdir_name_from)); - - // Create a file under the subdirectory. - FilePath file_name2_from = - subdir_name_from.Append(FILE_PATH_LITERAL("Copy_Test_File.txt")); - CreateTextFile(file_name2_from, L"Gooooooooooooooooooooogle"); - ASSERT_TRUE(base::PathExists(file_name2_from)); - - // Copy the directory recursively. - FilePath dir_name_exists = - temp_dir_.path().Append(FILE_PATH_LITERAL("Destination")); - - FilePath dir_name_to = - dir_name_exists.Append(FILE_PATH_LITERAL("Copy_From_Subdir")); - FilePath file_name_to = - dir_name_to.Append(FILE_PATH_LITERAL("Copy_Test_File.txt")); - FilePath subdir_name_to = - dir_name_to.Append(FILE_PATH_LITERAL("Subdir")); - FilePath file_name2_to = - subdir_name_to.Append(FILE_PATH_LITERAL("Copy_Test_File.txt")); - - // Create the destination directory. - file_util::CreateDirectory(dir_name_exists); - ASSERT_TRUE(base::PathExists(dir_name_exists)); - - EXPECT_TRUE(base::CopyDirectory(dir_name_from, dir_name_exists, true)); - - // Check everything has been copied. - EXPECT_TRUE(base::PathExists(dir_name_from)); - EXPECT_TRUE(base::PathExists(file_name_from)); - EXPECT_TRUE(base::PathExists(subdir_name_from)); - EXPECT_TRUE(base::PathExists(file_name2_from)); - EXPECT_TRUE(base::PathExists(dir_name_to)); - EXPECT_TRUE(base::PathExists(file_name_to)); - EXPECT_TRUE(base::PathExists(subdir_name_to)); - EXPECT_TRUE(base::PathExists(file_name2_to)); -} - -TEST_F(FileUtilTest, CopyDirectoryNew) { - // Create a directory. - FilePath dir_name_from = - temp_dir_.path().Append(FILE_PATH_LITERAL("Copy_From_Subdir")); - file_util::CreateDirectory(dir_name_from); - ASSERT_TRUE(base::PathExists(dir_name_from)); - - // Create a file under the directory. - FilePath file_name_from = - dir_name_from.Append(FILE_PATH_LITERAL("Copy_Test_File.txt")); - CreateTextFile(file_name_from, L"Gooooooooooooooooooooogle"); - ASSERT_TRUE(base::PathExists(file_name_from)); - - // Create a subdirectory. - FilePath subdir_name_from = - dir_name_from.Append(FILE_PATH_LITERAL("Subdir")); - file_util::CreateDirectory(subdir_name_from); - ASSERT_TRUE(base::PathExists(subdir_name_from)); - - // Create a file under the subdirectory. - FilePath file_name2_from = - subdir_name_from.Append(FILE_PATH_LITERAL("Copy_Test_File.txt")); - CreateTextFile(file_name2_from, L"Gooooooooooooooooooooogle"); - ASSERT_TRUE(base::PathExists(file_name2_from)); - - // Copy the directory not recursively. - FilePath dir_name_to = - temp_dir_.path().Append(FILE_PATH_LITERAL("Copy_To_Subdir")); - FilePath file_name_to = - dir_name_to.Append(FILE_PATH_LITERAL("Copy_Test_File.txt")); - FilePath subdir_name_to = - dir_name_to.Append(FILE_PATH_LITERAL("Subdir")); - - ASSERT_FALSE(base::PathExists(dir_name_to)); - - EXPECT_TRUE(base::CopyDirectory(dir_name_from, dir_name_to, false)); - - // Check everything has been copied. - EXPECT_TRUE(base::PathExists(dir_name_from)); - EXPECT_TRUE(base::PathExists(file_name_from)); - EXPECT_TRUE(base::PathExists(subdir_name_from)); - EXPECT_TRUE(base::PathExists(file_name2_from)); - EXPECT_TRUE(base::PathExists(dir_name_to)); - EXPECT_TRUE(base::PathExists(file_name_to)); - EXPECT_FALSE(base::PathExists(subdir_name_to)); -} - -TEST_F(FileUtilTest, CopyDirectoryExists) { - // Create a directory. - FilePath dir_name_from = - temp_dir_.path().Append(FILE_PATH_LITERAL("Copy_From_Subdir")); - file_util::CreateDirectory(dir_name_from); - ASSERT_TRUE(base::PathExists(dir_name_from)); - - // Create a file under the directory. - FilePath file_name_from = - dir_name_from.Append(FILE_PATH_LITERAL("Copy_Test_File.txt")); - CreateTextFile(file_name_from, L"Gooooooooooooooooooooogle"); - ASSERT_TRUE(base::PathExists(file_name_from)); - - // Create a subdirectory. - FilePath subdir_name_from = - dir_name_from.Append(FILE_PATH_LITERAL("Subdir")); - file_util::CreateDirectory(subdir_name_from); - ASSERT_TRUE(base::PathExists(subdir_name_from)); - - // Create a file under the subdirectory. - FilePath file_name2_from = - subdir_name_from.Append(FILE_PATH_LITERAL("Copy_Test_File.txt")); - CreateTextFile(file_name2_from, L"Gooooooooooooooooooooogle"); - ASSERT_TRUE(base::PathExists(file_name2_from)); - - // Copy the directory not recursively. - FilePath dir_name_to = - temp_dir_.path().Append(FILE_PATH_LITERAL("Copy_To_Subdir")); - FilePath file_name_to = - dir_name_to.Append(FILE_PATH_LITERAL("Copy_Test_File.txt")); - FilePath subdir_name_to = - dir_name_to.Append(FILE_PATH_LITERAL("Subdir")); - - // Create the destination directory. - file_util::CreateDirectory(dir_name_to); - ASSERT_TRUE(base::PathExists(dir_name_to)); - - EXPECT_TRUE(base::CopyDirectory(dir_name_from, dir_name_to, false)); - - // Check everything has been copied. - EXPECT_TRUE(base::PathExists(dir_name_from)); - EXPECT_TRUE(base::PathExists(file_name_from)); - EXPECT_TRUE(base::PathExists(subdir_name_from)); - EXPECT_TRUE(base::PathExists(file_name2_from)); - EXPECT_TRUE(base::PathExists(dir_name_to)); - EXPECT_TRUE(base::PathExists(file_name_to)); - EXPECT_FALSE(base::PathExists(subdir_name_to)); -} - -TEST_F(FileUtilTest, CopyFileWithCopyDirectoryRecursiveToNew) { - // Create a file - FilePath file_name_from = - temp_dir_.path().Append(FILE_PATH_LITERAL("Copy_Test_File.txt")); - CreateTextFile(file_name_from, L"Gooooooooooooooooooooogle"); - ASSERT_TRUE(base::PathExists(file_name_from)); - - // The destination name - FilePath file_name_to = temp_dir_.path().Append( - FILE_PATH_LITERAL("Copy_Test_File_Destination.txt")); - ASSERT_FALSE(base::PathExists(file_name_to)); - - EXPECT_TRUE(base::CopyDirectory(file_name_from, file_name_to, true)); - - // Check the has been copied - EXPECT_TRUE(base::PathExists(file_name_to)); -} - -TEST_F(FileUtilTest, CopyFileWithCopyDirectoryRecursiveToExisting) { - // Create a file - FilePath file_name_from = - temp_dir_.path().Append(FILE_PATH_LITERAL("Copy_Test_File.txt")); - CreateTextFile(file_name_from, L"Gooooooooooooooooooooogle"); - ASSERT_TRUE(base::PathExists(file_name_from)); - - // The destination name - FilePath file_name_to = temp_dir_.path().Append( - FILE_PATH_LITERAL("Copy_Test_File_Destination.txt")); - CreateTextFile(file_name_to, L"Old file content"); - ASSERT_TRUE(base::PathExists(file_name_to)); - - EXPECT_TRUE(base::CopyDirectory(file_name_from, file_name_to, true)); - - // Check the has been copied - EXPECT_TRUE(base::PathExists(file_name_to)); - EXPECT_TRUE(L"Gooooooooooooooooooooogle" == ReadTextFile(file_name_to)); -} - -TEST_F(FileUtilTest, CopyFileWithCopyDirectoryRecursiveToExistingDirectory) { - // Create a file - FilePath file_name_from = - temp_dir_.path().Append(FILE_PATH_LITERAL("Copy_Test_File.txt")); - CreateTextFile(file_name_from, L"Gooooooooooooooooooooogle"); - ASSERT_TRUE(base::PathExists(file_name_from)); - - // The destination - FilePath dir_name_to = - temp_dir_.path().Append(FILE_PATH_LITERAL("Destination")); - file_util::CreateDirectory(dir_name_to); - ASSERT_TRUE(base::PathExists(dir_name_to)); - FilePath file_name_to = - dir_name_to.Append(FILE_PATH_LITERAL("Copy_Test_File.txt")); - - EXPECT_TRUE(base::CopyDirectory(file_name_from, dir_name_to, true)); - - // Check the has been copied - EXPECT_TRUE(base::PathExists(file_name_to)); -} - -TEST_F(FileUtilTest, CopyDirectoryWithTrailingSeparators) { - // Create a directory. - FilePath dir_name_from = - temp_dir_.path().Append(FILE_PATH_LITERAL("Copy_From_Subdir")); - file_util::CreateDirectory(dir_name_from); - ASSERT_TRUE(base::PathExists(dir_name_from)); - - // Create a file under the directory. - FilePath file_name_from = - dir_name_from.Append(FILE_PATH_LITERAL("Copy_Test_File.txt")); - CreateTextFile(file_name_from, L"Gooooooooooooooooooooogle"); - ASSERT_TRUE(base::PathExists(file_name_from)); - - // Copy the directory recursively. - FilePath dir_name_to = - temp_dir_.path().Append(FILE_PATH_LITERAL("Copy_To_Subdir")); - FilePath file_name_to = - dir_name_to.Append(FILE_PATH_LITERAL("Copy_Test_File.txt")); - - // Create from path with trailing separators. -#if defined(OS_WIN) - FilePath from_path = - temp_dir_.path().Append(FILE_PATH_LITERAL("Copy_From_Subdir\\\\\\")); -#elif defined (OS_POSIX) - FilePath from_path = - temp_dir_.path().Append(FILE_PATH_LITERAL("Copy_From_Subdir///")); -#endif - - EXPECT_TRUE(base::CopyDirectory(from_path, dir_name_to, true)); - - // Check everything has been copied. - EXPECT_TRUE(base::PathExists(dir_name_from)); - EXPECT_TRUE(base::PathExists(file_name_from)); - EXPECT_TRUE(base::PathExists(dir_name_to)); - EXPECT_TRUE(base::PathExists(file_name_to)); -} - -TEST_F(FileUtilTest, CopyFile) { - // Create a directory - FilePath dir_name_from = - temp_dir_.path().Append(FILE_PATH_LITERAL("Copy_From_Subdir")); - file_util::CreateDirectory(dir_name_from); - ASSERT_TRUE(base::PathExists(dir_name_from)); - - // Create a file under the directory - FilePath file_name_from = - dir_name_from.Append(FILE_PATH_LITERAL("Copy_Test_File.txt")); - const std::wstring file_contents(L"Gooooooooooooooooooooogle"); - CreateTextFile(file_name_from, file_contents); - ASSERT_TRUE(base::PathExists(file_name_from)); - - // Copy the file. - FilePath dest_file = dir_name_from.Append(FILE_PATH_LITERAL("DestFile.txt")); - ASSERT_TRUE(base::CopyFile(file_name_from, dest_file)); - - // Copy the file to another location using '..' in the path. - FilePath dest_file2(dir_name_from); - dest_file2 = dest_file2.AppendASCII(".."); - dest_file2 = dest_file2.AppendASCII("DestFile.txt"); - ASSERT_FALSE(base::CopyFile(file_name_from, dest_file2)); - ASSERT_TRUE(base::internal::CopyFileUnsafe(file_name_from, dest_file2)); - - FilePath dest_file2_test(dir_name_from); - dest_file2_test = dest_file2_test.DirName(); - dest_file2_test = dest_file2_test.AppendASCII("DestFile.txt"); - - // Check everything has been copied. - EXPECT_TRUE(base::PathExists(file_name_from)); - EXPECT_TRUE(base::PathExists(dest_file)); - const std::wstring read_contents = ReadTextFile(dest_file); - EXPECT_EQ(file_contents, read_contents); - EXPECT_TRUE(base::PathExists(dest_file2_test)); - EXPECT_TRUE(base::PathExists(dest_file2)); -} - -// file_util winds up using autoreleased objects on the Mac, so this needs -// to be a PlatformTest. -typedef PlatformTest ReadOnlyFileUtilTest; - -TEST_F(ReadOnlyFileUtilTest, ContentsEqual) { - FilePath data_dir; - ASSERT_TRUE(PathService::Get(base::DIR_TEST_DATA, &data_dir)); - data_dir = data_dir.AppendASCII("file_util"); - ASSERT_TRUE(base::PathExists(data_dir)); - - FilePath original_file = - data_dir.Append(FILE_PATH_LITERAL("original.txt")); - FilePath same_file = - data_dir.Append(FILE_PATH_LITERAL("same.txt")); - FilePath same_length_file = - data_dir.Append(FILE_PATH_LITERAL("same_length.txt")); - FilePath different_file = - data_dir.Append(FILE_PATH_LITERAL("different.txt")); - FilePath different_first_file = - data_dir.Append(FILE_PATH_LITERAL("different_first.txt")); - FilePath different_last_file = - data_dir.Append(FILE_PATH_LITERAL("different_last.txt")); - FilePath empty1_file = - data_dir.Append(FILE_PATH_LITERAL("empty1.txt")); - FilePath empty2_file = - data_dir.Append(FILE_PATH_LITERAL("empty2.txt")); - FilePath shortened_file = - data_dir.Append(FILE_PATH_LITERAL("shortened.txt")); - FilePath binary_file = - data_dir.Append(FILE_PATH_LITERAL("binary_file.bin")); - FilePath binary_file_same = - data_dir.Append(FILE_PATH_LITERAL("binary_file_same.bin")); - FilePath binary_file_diff = - data_dir.Append(FILE_PATH_LITERAL("binary_file_diff.bin")); - - EXPECT_TRUE(ContentsEqual(original_file, original_file)); - EXPECT_TRUE(ContentsEqual(original_file, same_file)); - EXPECT_FALSE(ContentsEqual(original_file, same_length_file)); - EXPECT_FALSE(ContentsEqual(original_file, different_file)); - EXPECT_FALSE(ContentsEqual(FilePath(FILE_PATH_LITERAL("bogusname")), - FilePath(FILE_PATH_LITERAL("bogusname")))); - EXPECT_FALSE(ContentsEqual(original_file, different_first_file)); - EXPECT_FALSE(ContentsEqual(original_file, different_last_file)); - EXPECT_TRUE(ContentsEqual(empty1_file, empty2_file)); - EXPECT_FALSE(ContentsEqual(original_file, shortened_file)); - EXPECT_FALSE(ContentsEqual(shortened_file, original_file)); - EXPECT_TRUE(ContentsEqual(binary_file, binary_file_same)); - EXPECT_FALSE(ContentsEqual(binary_file, binary_file_diff)); -} - -TEST_F(ReadOnlyFileUtilTest, TextContentsEqual) { - FilePath data_dir; - ASSERT_TRUE(PathService::Get(base::DIR_TEST_DATA, &data_dir)); - data_dir = data_dir.AppendASCII("file_util"); - ASSERT_TRUE(base::PathExists(data_dir)); - - FilePath original_file = - data_dir.Append(FILE_PATH_LITERAL("original.txt")); - FilePath same_file = - data_dir.Append(FILE_PATH_LITERAL("same.txt")); - FilePath crlf_file = - data_dir.Append(FILE_PATH_LITERAL("crlf.txt")); - FilePath shortened_file = - data_dir.Append(FILE_PATH_LITERAL("shortened.txt")); - FilePath different_file = - data_dir.Append(FILE_PATH_LITERAL("different.txt")); - FilePath different_first_file = - data_dir.Append(FILE_PATH_LITERAL("different_first.txt")); - FilePath different_last_file = - data_dir.Append(FILE_PATH_LITERAL("different_last.txt")); - FilePath first1_file = - data_dir.Append(FILE_PATH_LITERAL("first1.txt")); - FilePath first2_file = - data_dir.Append(FILE_PATH_LITERAL("first2.txt")); - FilePath empty1_file = - data_dir.Append(FILE_PATH_LITERAL("empty1.txt")); - FilePath empty2_file = - data_dir.Append(FILE_PATH_LITERAL("empty2.txt")); - FilePath blank_line_file = - data_dir.Append(FILE_PATH_LITERAL("blank_line.txt")); - FilePath blank_line_crlf_file = - data_dir.Append(FILE_PATH_LITERAL("blank_line_crlf.txt")); - - EXPECT_TRUE(TextContentsEqual(original_file, same_file)); - EXPECT_TRUE(TextContentsEqual(original_file, crlf_file)); - EXPECT_FALSE(TextContentsEqual(original_file, shortened_file)); - EXPECT_FALSE(TextContentsEqual(original_file, different_file)); - EXPECT_FALSE(TextContentsEqual(original_file, different_first_file)); - EXPECT_FALSE(TextContentsEqual(original_file, different_last_file)); - EXPECT_FALSE(TextContentsEqual(first1_file, first2_file)); - EXPECT_TRUE(TextContentsEqual(empty1_file, empty2_file)); - EXPECT_FALSE(TextContentsEqual(original_file, empty1_file)); - EXPECT_TRUE(TextContentsEqual(blank_line_file, blank_line_crlf_file)); -} - -// We don't need equivalent functionality outside of Windows. -#if defined(OS_WIN) -TEST_F(FileUtilTest, CopyAndDeleteDirectoryTest) { - // Create a directory - FilePath dir_name_from = - temp_dir_.path().Append(FILE_PATH_LITERAL("CopyAndDelete_From_Subdir")); - file_util::CreateDirectory(dir_name_from); - ASSERT_TRUE(base::PathExists(dir_name_from)); - - // Create a file under the directory - FilePath file_name_from = - dir_name_from.Append(FILE_PATH_LITERAL("CopyAndDelete_Test_File.txt")); - CreateTextFile(file_name_from, L"Gooooooooooooooooooooogle"); - ASSERT_TRUE(base::PathExists(file_name_from)); - - // Move the directory by using CopyAndDeleteDirectory - FilePath dir_name_to = temp_dir_.path().Append( - FILE_PATH_LITERAL("CopyAndDelete_To_Subdir")); - FilePath file_name_to = - dir_name_to.Append(FILE_PATH_LITERAL("CopyAndDelete_Test_File.txt")); - - ASSERT_FALSE(base::PathExists(dir_name_to)); - - EXPECT_TRUE(base::internal::CopyAndDeleteDirectory(dir_name_from, - dir_name_to)); - - // Check everything has been moved. - EXPECT_FALSE(base::PathExists(dir_name_from)); - EXPECT_FALSE(base::PathExists(file_name_from)); - EXPECT_TRUE(base::PathExists(dir_name_to)); - EXPECT_TRUE(base::PathExists(file_name_to)); -} - -TEST_F(FileUtilTest, GetTempDirTest) { - static const TCHAR* kTmpKey = _T("TMP"); - static const TCHAR* kTmpValues[] = { - _T(""), _T("C:"), _T("C:\\"), _T("C:\\tmp"), _T("C:\\tmp\\") - }; - // Save the original $TMP. - size_t original_tmp_size; - TCHAR* original_tmp; - ASSERT_EQ(0, ::_tdupenv_s(&original_tmp, &original_tmp_size, kTmpKey)); - // original_tmp may be NULL. - - for (unsigned int i = 0; i < arraysize(kTmpValues); ++i) { - FilePath path; - ::_tputenv_s(kTmpKey, kTmpValues[i]); - file_util::GetTempDir(&path); - EXPECT_TRUE(path.IsAbsolute()) << "$TMP=" << kTmpValues[i] << - " result=" << path.value(); - } - - // Restore the original $TMP. - if (original_tmp) { - ::_tputenv_s(kTmpKey, original_tmp); - free(original_tmp); - } else { - ::_tputenv_s(kTmpKey, _T("")); - } -} -#endif // OS_WIN - -TEST_F(FileUtilTest, CreateTemporaryFileTest) { - FilePath temp_files[3]; - for (int i = 0; i < 3; i++) { - ASSERT_TRUE(file_util::CreateTemporaryFile(&(temp_files[i]))); - EXPECT_TRUE(base::PathExists(temp_files[i])); - EXPECT_FALSE(DirectoryExists(temp_files[i])); - } - for (int i = 0; i < 3; i++) - EXPECT_FALSE(temp_files[i] == temp_files[(i+1)%3]); - for (int i = 0; i < 3; i++) - EXPECT_TRUE(base::DeleteFile(temp_files[i], false)); -} - -TEST_F(FileUtilTest, CreateAndOpenTemporaryFileTest) { - FilePath names[3]; - FILE* fps[3]; - int i; - - // Create; make sure they are open and exist. - for (i = 0; i < 3; ++i) { - fps[i] = file_util::CreateAndOpenTemporaryFile(&(names[i])); - ASSERT_TRUE(fps[i]); - EXPECT_TRUE(base::PathExists(names[i])); - } - - // Make sure all names are unique. - for (i = 0; i < 3; ++i) { - EXPECT_FALSE(names[i] == names[(i+1)%3]); - } - - // Close and delete. - for (i = 0; i < 3; ++i) { - EXPECT_TRUE(file_util::CloseFile(fps[i])); - EXPECT_TRUE(base::DeleteFile(names[i], false)); - } -} - -TEST_F(FileUtilTest, CreateNewTempDirectoryTest) { - FilePath temp_dir; - ASSERT_TRUE(file_util::CreateNewTempDirectory(FilePath::StringType(), - &temp_dir)); - EXPECT_TRUE(base::PathExists(temp_dir)); - EXPECT_TRUE(base::DeleteFile(temp_dir, false)); -} - -TEST_F(FileUtilTest, CreateNewTemporaryDirInDirTest) { - FilePath new_dir; - ASSERT_TRUE(file_util::CreateTemporaryDirInDir( - temp_dir_.path(), - FILE_PATH_LITERAL("CreateNewTemporaryDirInDirTest"), - &new_dir)); - EXPECT_TRUE(base::PathExists(new_dir)); - EXPECT_TRUE(temp_dir_.path().IsParent(new_dir)); - EXPECT_TRUE(base::DeleteFile(new_dir, false)); -} - -TEST_F(FileUtilTest, GetShmemTempDirTest) { - FilePath dir; - EXPECT_TRUE(file_util::GetShmemTempDir(&dir, false)); - EXPECT_TRUE(DirectoryExists(dir)); -} - -TEST_F(FileUtilTest, CreateDirectoryTest) { - FilePath test_root = - temp_dir_.path().Append(FILE_PATH_LITERAL("create_directory_test")); -#if defined(OS_WIN) - FilePath test_path = - test_root.Append(FILE_PATH_LITERAL("dir\\tree\\likely\\doesnt\\exist\\")); -#elif defined(OS_POSIX) - FilePath test_path = - test_root.Append(FILE_PATH_LITERAL("dir/tree/likely/doesnt/exist/")); -#endif - - EXPECT_FALSE(base::PathExists(test_path)); - EXPECT_TRUE(file_util::CreateDirectory(test_path)); - EXPECT_TRUE(base::PathExists(test_path)); - // CreateDirectory returns true if the DirectoryExists returns true. - EXPECT_TRUE(file_util::CreateDirectory(test_path)); - - // Doesn't work to create it on top of a non-dir - test_path = test_path.Append(FILE_PATH_LITERAL("foobar.txt")); - EXPECT_FALSE(base::PathExists(test_path)); - CreateTextFile(test_path, L"test file"); - EXPECT_TRUE(base::PathExists(test_path)); - EXPECT_FALSE(file_util::CreateDirectory(test_path)); - - EXPECT_TRUE(base::DeleteFile(test_root, true)); - EXPECT_FALSE(base::PathExists(test_root)); - EXPECT_FALSE(base::PathExists(test_path)); - - // Verify assumptions made by the Windows implementation: - // 1. The current directory always exists. - // 2. The root directory always exists. - ASSERT_TRUE(DirectoryExists(FilePath(FilePath::kCurrentDirectory))); - FilePath top_level = test_root; - while (top_level != top_level.DirName()) { - top_level = top_level.DirName(); - } - ASSERT_TRUE(DirectoryExists(top_level)); - - // Given these assumptions hold, it should be safe to - // test that "creating" these directories succeeds. - EXPECT_TRUE(file_util::CreateDirectory( - FilePath(FilePath::kCurrentDirectory))); - EXPECT_TRUE(file_util::CreateDirectory(top_level)); - -#if defined(OS_WIN) - FilePath invalid_drive(FILE_PATH_LITERAL("o:\\")); - FilePath invalid_path = - invalid_drive.Append(FILE_PATH_LITERAL("some\\inaccessible\\dir")); - if (!base::PathExists(invalid_drive)) { - EXPECT_FALSE(file_util::CreateDirectory(invalid_path)); - } -#endif -} - -TEST_F(FileUtilTest, DetectDirectoryTest) { - // Check a directory - FilePath test_root = - temp_dir_.path().Append(FILE_PATH_LITERAL("detect_directory_test")); - EXPECT_FALSE(base::PathExists(test_root)); - EXPECT_TRUE(file_util::CreateDirectory(test_root)); - EXPECT_TRUE(base::PathExists(test_root)); - EXPECT_TRUE(DirectoryExists(test_root)); - // Check a file - FilePath test_path = - test_root.Append(FILE_PATH_LITERAL("foobar.txt")); - EXPECT_FALSE(base::PathExists(test_path)); - CreateTextFile(test_path, L"test file"); - EXPECT_TRUE(base::PathExists(test_path)); - EXPECT_FALSE(DirectoryExists(test_path)); - EXPECT_TRUE(base::DeleteFile(test_path, false)); - - EXPECT_TRUE(base::DeleteFile(test_root, true)); -} - -TEST_F(FileUtilTest, FileEnumeratorTest) { - // Test an empty directory. - FileEnumerator f0(temp_dir_.path(), true, FILES_AND_DIRECTORIES); - EXPECT_EQ(f0.Next().value(), FPL("")); - EXPECT_EQ(f0.Next().value(), FPL("")); - - // Test an empty directory, non-recursively, including "..". - FileEnumerator f0_dotdot(temp_dir_.path(), false, - FILES_AND_DIRECTORIES | FileEnumerator::INCLUDE_DOT_DOT); - EXPECT_EQ(temp_dir_.path().Append(FPL("..")).value(), - f0_dotdot.Next().value()); - EXPECT_EQ(FPL(""), f0_dotdot.Next().value()); - - // create the directories - FilePath dir1 = temp_dir_.path().Append(FPL("dir1")); - EXPECT_TRUE(file_util::CreateDirectory(dir1)); - FilePath dir2 = temp_dir_.path().Append(FPL("dir2")); - EXPECT_TRUE(file_util::CreateDirectory(dir2)); - FilePath dir2inner = dir2.Append(FPL("inner")); - EXPECT_TRUE(file_util::CreateDirectory(dir2inner)); - - // create the files - FilePath dir2file = dir2.Append(FPL("dir2file.txt")); - CreateTextFile(dir2file, std::wstring()); - FilePath dir2innerfile = dir2inner.Append(FPL("innerfile.txt")); - CreateTextFile(dir2innerfile, std::wstring()); - FilePath file1 = temp_dir_.path().Append(FPL("file1.txt")); - CreateTextFile(file1, std::wstring()); - FilePath file2_rel = dir2.Append(FilePath::kParentDirectory) - .Append(FPL("file2.txt")); - CreateTextFile(file2_rel, std::wstring()); - FilePath file2_abs = temp_dir_.path().Append(FPL("file2.txt")); - - // Only enumerate files. - FileEnumerator f1(temp_dir_.path(), true, FileEnumerator::FILES); - FindResultCollector c1(f1); - EXPECT_TRUE(c1.HasFile(file1)); - EXPECT_TRUE(c1.HasFile(file2_abs)); - EXPECT_TRUE(c1.HasFile(dir2file)); - EXPECT_TRUE(c1.HasFile(dir2innerfile)); - EXPECT_EQ(c1.size(), 4); - - // Only enumerate directories. - FileEnumerator f2(temp_dir_.path(), true, FileEnumerator::DIRECTORIES); - FindResultCollector c2(f2); - EXPECT_TRUE(c2.HasFile(dir1)); - EXPECT_TRUE(c2.HasFile(dir2)); - EXPECT_TRUE(c2.HasFile(dir2inner)); - EXPECT_EQ(c2.size(), 3); - - // Only enumerate directories non-recursively. - FileEnumerator f2_non_recursive( - temp_dir_.path(), false, FileEnumerator::DIRECTORIES); - FindResultCollector c2_non_recursive(f2_non_recursive); - EXPECT_TRUE(c2_non_recursive.HasFile(dir1)); - EXPECT_TRUE(c2_non_recursive.HasFile(dir2)); - EXPECT_EQ(c2_non_recursive.size(), 2); - - // Only enumerate directories, non-recursively, including "..". - FileEnumerator f2_dotdot(temp_dir_.path(), false, - FileEnumerator::DIRECTORIES | - FileEnumerator::INCLUDE_DOT_DOT); - FindResultCollector c2_dotdot(f2_dotdot); - EXPECT_TRUE(c2_dotdot.HasFile(dir1)); - EXPECT_TRUE(c2_dotdot.HasFile(dir2)); - EXPECT_TRUE(c2_dotdot.HasFile(temp_dir_.path().Append(FPL("..")))); - EXPECT_EQ(c2_dotdot.size(), 3); - - // Enumerate files and directories. - FileEnumerator f3(temp_dir_.path(), true, FILES_AND_DIRECTORIES); - FindResultCollector c3(f3); - EXPECT_TRUE(c3.HasFile(dir1)); - EXPECT_TRUE(c3.HasFile(dir2)); - EXPECT_TRUE(c3.HasFile(file1)); - EXPECT_TRUE(c3.HasFile(file2_abs)); - EXPECT_TRUE(c3.HasFile(dir2file)); - EXPECT_TRUE(c3.HasFile(dir2inner)); - EXPECT_TRUE(c3.HasFile(dir2innerfile)); - EXPECT_EQ(c3.size(), 7); - - // Non-recursive operation. - FileEnumerator f4(temp_dir_.path(), false, FILES_AND_DIRECTORIES); - FindResultCollector c4(f4); - EXPECT_TRUE(c4.HasFile(dir2)); - EXPECT_TRUE(c4.HasFile(dir2)); - EXPECT_TRUE(c4.HasFile(file1)); - EXPECT_TRUE(c4.HasFile(file2_abs)); - EXPECT_EQ(c4.size(), 4); - - // Enumerate with a pattern. - FileEnumerator f5(temp_dir_.path(), true, FILES_AND_DIRECTORIES, FPL("dir*")); - FindResultCollector c5(f5); - EXPECT_TRUE(c5.HasFile(dir1)); - EXPECT_TRUE(c5.HasFile(dir2)); - EXPECT_TRUE(c5.HasFile(dir2file)); - EXPECT_TRUE(c5.HasFile(dir2inner)); - EXPECT_TRUE(c5.HasFile(dir2innerfile)); - EXPECT_EQ(c5.size(), 5); - -#if defined(OS_WIN) - { - // Make dir1 point to dir2. - ReparsePoint reparse_point(dir1, dir2); - EXPECT_TRUE(reparse_point.IsValid()); - - if ((base::win::GetVersion() >= base::win::VERSION_VISTA)) { - // There can be a delay for the enumeration code to see the change on - // the file system so skip this test for XP. - // Enumerate the reparse point. - FileEnumerator f6(dir1, true, FILES_AND_DIRECTORIES); - FindResultCollector c6(f6); - FilePath inner2 = dir1.Append(FPL("inner")); - EXPECT_TRUE(c6.HasFile(inner2)); - EXPECT_TRUE(c6.HasFile(inner2.Append(FPL("innerfile.txt")))); - EXPECT_TRUE(c6.HasFile(dir1.Append(FPL("dir2file.txt")))); - EXPECT_EQ(c6.size(), 3); - } - - // No changes for non recursive operation. - FileEnumerator f7(temp_dir_.path(), false, FILES_AND_DIRECTORIES); - FindResultCollector c7(f7); - EXPECT_TRUE(c7.HasFile(dir2)); - EXPECT_TRUE(c7.HasFile(dir2)); - EXPECT_TRUE(c7.HasFile(file1)); - EXPECT_TRUE(c7.HasFile(file2_abs)); - EXPECT_EQ(c7.size(), 4); - - // Should not enumerate inside dir1 when using recursion. - FileEnumerator f8(temp_dir_.path(), true, FILES_AND_DIRECTORIES); - FindResultCollector c8(f8); - EXPECT_TRUE(c8.HasFile(dir1)); - EXPECT_TRUE(c8.HasFile(dir2)); - EXPECT_TRUE(c8.HasFile(file1)); - EXPECT_TRUE(c8.HasFile(file2_abs)); - EXPECT_TRUE(c8.HasFile(dir2file)); - EXPECT_TRUE(c8.HasFile(dir2inner)); - EXPECT_TRUE(c8.HasFile(dir2innerfile)); - EXPECT_EQ(c8.size(), 7); - } -#endif - - // Make sure the destructor closes the find handle while in the middle of a - // query to allow TearDown to delete the directory. - FileEnumerator f9(temp_dir_.path(), true, FILES_AND_DIRECTORIES); - EXPECT_FALSE(f9.Next().value().empty()); // Should have found something - // (we don't care what). -} - -TEST_F(FileUtilTest, AppendToFile) { - FilePath data_dir = - temp_dir_.path().Append(FILE_PATH_LITERAL("FilePathTest")); - - // Create a fresh, empty copy of this directory. - if (base::PathExists(data_dir)) { - ASSERT_TRUE(base::DeleteFile(data_dir, true)); - } - ASSERT_TRUE(file_util::CreateDirectory(data_dir)); - - // Create a fresh, empty copy of this directory. - if (base::PathExists(data_dir)) { - ASSERT_TRUE(base::DeleteFile(data_dir, true)); - } - ASSERT_TRUE(file_util::CreateDirectory(data_dir)); - FilePath foobar(data_dir.Append(FILE_PATH_LITERAL("foobar.txt"))); - - std::string data("hello"); - EXPECT_EQ(-1, file_util::AppendToFile(foobar, data.c_str(), data.length())); - EXPECT_EQ(static_cast(data.length()), - file_util::WriteFile(foobar, data.c_str(), data.length())); - EXPECT_EQ(static_cast(data.length()), - file_util::AppendToFile(foobar, data.c_str(), data.length())); - - const std::wstring read_content = ReadTextFile(foobar); - EXPECT_EQ(L"hellohello", read_content); -} - -TEST_F(FileUtilTest, TouchFile) { - FilePath data_dir = - temp_dir_.path().Append(FILE_PATH_LITERAL("FilePathTest")); - - // Create a fresh, empty copy of this directory. - if (base::PathExists(data_dir)) { - ASSERT_TRUE(base::DeleteFile(data_dir, true)); - } - ASSERT_TRUE(file_util::CreateDirectory(data_dir)); - - FilePath foobar(data_dir.Append(FILE_PATH_LITERAL("foobar.txt"))); - std::string data("hello"); - ASSERT_TRUE(file_util::WriteFile(foobar, data.c_str(), data.length())); - - base::Time access_time; - // This timestamp is divisible by one day (in local timezone), - // to make it work on FAT too. - ASSERT_TRUE(base::Time::FromString("Wed, 16 Nov 1994, 00:00:00", - &access_time)); - - base::Time modification_time; - // Note that this timestamp is divisible by two (seconds) - FAT stores - // modification times with 2s resolution. - ASSERT_TRUE(base::Time::FromString("Tue, 15 Nov 1994, 12:45:26 GMT", - &modification_time)); - - ASSERT_TRUE(file_util::TouchFile(foobar, access_time, modification_time)); - base::PlatformFileInfo file_info; - ASSERT_TRUE(file_util::GetFileInfo(foobar, &file_info)); - EXPECT_EQ(file_info.last_accessed.ToInternalValue(), - access_time.ToInternalValue()); - EXPECT_EQ(file_info.last_modified.ToInternalValue(), - modification_time.ToInternalValue()); -} - -TEST_F(FileUtilTest, IsDirectoryEmpty) { - FilePath empty_dir = temp_dir_.path().Append(FILE_PATH_LITERAL("EmptyDir")); - - ASSERT_FALSE(base::PathExists(empty_dir)); - - ASSERT_TRUE(file_util::CreateDirectory(empty_dir)); - - EXPECT_TRUE(file_util::IsDirectoryEmpty(empty_dir)); - - FilePath foo(empty_dir.Append(FILE_PATH_LITERAL("foo.txt"))); - std::string bar("baz"); - ASSERT_TRUE(file_util::WriteFile(foo, bar.c_str(), bar.length())); - - EXPECT_FALSE(file_util::IsDirectoryEmpty(empty_dir)); -} - -#if defined(OS_POSIX) - -// Testing VerifyPathControlledByAdmin() is hard, because there is no -// way a test can make a file owned by root, or change file paths -// at the root of the file system. VerifyPathControlledByAdmin() -// is implemented as a call to VerifyPathControlledByUser, which gives -// us the ability to test with paths under the test's temp directory, -// using a user id we control. -// Pull tests of VerifyPathControlledByUserTest() into a separate test class -// with a common SetUp() method. -class VerifyPathControlledByUserTest : public FileUtilTest { - protected: - virtual void SetUp() OVERRIDE { - FileUtilTest::SetUp(); - - // Create a basic structure used by each test. - // base_dir_ - // |-> sub_dir_ - // |-> text_file_ - - base_dir_ = temp_dir_.path().AppendASCII("base_dir"); - ASSERT_TRUE(file_util::CreateDirectory(base_dir_)); - - sub_dir_ = base_dir_.AppendASCII("sub_dir"); - ASSERT_TRUE(file_util::CreateDirectory(sub_dir_)); - - text_file_ = sub_dir_.AppendASCII("file.txt"); - CreateTextFile(text_file_, L"This text file has some text in it."); - - // Get the user and group files are created with from |base_dir_|. - struct stat stat_buf; - ASSERT_EQ(0, stat(base_dir_.value().c_str(), &stat_buf)); - uid_ = stat_buf.st_uid; - ok_gids_.insert(stat_buf.st_gid); - bad_gids_.insert(stat_buf.st_gid + 1); - - ASSERT_EQ(uid_, getuid()); // This process should be the owner. - - // To ensure that umask settings do not cause the initial state - // of permissions to be different from what we expect, explicitly - // set permissions on the directories we create. - // Make all files and directories non-world-writable. - - // Users and group can read, write, traverse - int enabled_permissions = - file_util::FILE_PERMISSION_USER_MASK | - file_util::FILE_PERMISSION_GROUP_MASK; - // Other users can't read, write, traverse - int disabled_permissions = - file_util::FILE_PERMISSION_OTHERS_MASK; - - ASSERT_NO_FATAL_FAILURE( - ChangePosixFilePermissions( - base_dir_, enabled_permissions, disabled_permissions)); - ASSERT_NO_FATAL_FAILURE( - ChangePosixFilePermissions( - sub_dir_, enabled_permissions, disabled_permissions)); - } - - FilePath base_dir_; - FilePath sub_dir_; - FilePath text_file_; - uid_t uid_; - - std::set ok_gids_; - std::set bad_gids_; -}; - -TEST_F(VerifyPathControlledByUserTest, BadPaths) { - // File does not exist. - FilePath does_not_exist = base_dir_.AppendASCII("does") - .AppendASCII("not") - .AppendASCII("exist"); - EXPECT_FALSE( - file_util::VerifyPathControlledByUser( - base_dir_, does_not_exist, uid_, ok_gids_)); - - // |base| not a subpath of |path|. - EXPECT_FALSE( - file_util::VerifyPathControlledByUser( - sub_dir_, base_dir_, uid_, ok_gids_)); - - // An empty base path will fail to be a prefix for any path. - FilePath empty; - EXPECT_FALSE( - file_util::VerifyPathControlledByUser( - empty, base_dir_, uid_, ok_gids_)); - - // Finding that a bad call fails proves nothing unless a good call succeeds. - EXPECT_TRUE( - file_util::VerifyPathControlledByUser( - base_dir_, sub_dir_, uid_, ok_gids_)); -} - -TEST_F(VerifyPathControlledByUserTest, Symlinks) { - // Symlinks in the path should cause failure. - - // Symlink to the file at the end of the path. - FilePath file_link = base_dir_.AppendASCII("file_link"); - ASSERT_TRUE(file_util::CreateSymbolicLink(text_file_, file_link)) - << "Failed to create symlink."; - - EXPECT_FALSE( - file_util::VerifyPathControlledByUser( - base_dir_, file_link, uid_, ok_gids_)); - EXPECT_FALSE( - file_util::VerifyPathControlledByUser( - file_link, file_link, uid_, ok_gids_)); - - // Symlink from one directory to another within the path. - FilePath link_to_sub_dir = base_dir_.AppendASCII("link_to_sub_dir"); - ASSERT_TRUE(file_util::CreateSymbolicLink(sub_dir_, link_to_sub_dir)) - << "Failed to create symlink."; - - FilePath file_path_with_link = link_to_sub_dir.AppendASCII("file.txt"); - ASSERT_TRUE(base::PathExists(file_path_with_link)); - - EXPECT_FALSE( - file_util::VerifyPathControlledByUser( - base_dir_, file_path_with_link, uid_, ok_gids_)); - - EXPECT_FALSE( - file_util::VerifyPathControlledByUser( - link_to_sub_dir, file_path_with_link, uid_, ok_gids_)); - - // Symlinks in parents of base path are allowed. - EXPECT_TRUE( - file_util::VerifyPathControlledByUser( - file_path_with_link, file_path_with_link, uid_, ok_gids_)); -} - -TEST_F(VerifyPathControlledByUserTest, OwnershipChecks) { - // Get a uid that is not the uid of files we create. - uid_t bad_uid = uid_ + 1; - - // Make all files and directories non-world-writable. - ASSERT_NO_FATAL_FAILURE( - ChangePosixFilePermissions(base_dir_, 0u, S_IWOTH)); - ASSERT_NO_FATAL_FAILURE( - ChangePosixFilePermissions(sub_dir_, 0u, S_IWOTH)); - ASSERT_NO_FATAL_FAILURE( - ChangePosixFilePermissions(text_file_, 0u, S_IWOTH)); - - // We control these paths. - EXPECT_TRUE( - file_util::VerifyPathControlledByUser( - base_dir_, sub_dir_, uid_, ok_gids_)); - EXPECT_TRUE( - file_util::VerifyPathControlledByUser( - base_dir_, text_file_, uid_, ok_gids_)); - EXPECT_TRUE( - file_util::VerifyPathControlledByUser( - sub_dir_, text_file_, uid_, ok_gids_)); - - // Another user does not control these paths. - EXPECT_FALSE( - file_util::VerifyPathControlledByUser( - base_dir_, sub_dir_, bad_uid, ok_gids_)); - EXPECT_FALSE( - file_util::VerifyPathControlledByUser( - base_dir_, text_file_, bad_uid, ok_gids_)); - EXPECT_FALSE( - file_util::VerifyPathControlledByUser( - sub_dir_, text_file_, bad_uid, ok_gids_)); - - // Another group does not control the paths. - EXPECT_FALSE( - file_util::VerifyPathControlledByUser( - base_dir_, sub_dir_, uid_, bad_gids_)); - EXPECT_FALSE( - file_util::VerifyPathControlledByUser( - base_dir_, text_file_, uid_, bad_gids_)); - EXPECT_FALSE( - file_util::VerifyPathControlledByUser( - sub_dir_, text_file_, uid_, bad_gids_)); -} - -TEST_F(VerifyPathControlledByUserTest, GroupWriteTest) { - // Make all files and directories writable only by their owner. - ASSERT_NO_FATAL_FAILURE( - ChangePosixFilePermissions(base_dir_, 0u, S_IWOTH|S_IWGRP)); - ASSERT_NO_FATAL_FAILURE( - ChangePosixFilePermissions(sub_dir_, 0u, S_IWOTH|S_IWGRP)); - ASSERT_NO_FATAL_FAILURE( - ChangePosixFilePermissions(text_file_, 0u, S_IWOTH|S_IWGRP)); - - // Any group is okay because the path is not group-writable. - EXPECT_TRUE( - file_util::VerifyPathControlledByUser( - base_dir_, sub_dir_, uid_, ok_gids_)); - EXPECT_TRUE( - file_util::VerifyPathControlledByUser( - base_dir_, text_file_, uid_, ok_gids_)); - EXPECT_TRUE( - file_util::VerifyPathControlledByUser( - sub_dir_, text_file_, uid_, ok_gids_)); - - EXPECT_TRUE( - file_util::VerifyPathControlledByUser( - base_dir_, sub_dir_, uid_, bad_gids_)); - EXPECT_TRUE( - file_util::VerifyPathControlledByUser( - base_dir_, text_file_, uid_, bad_gids_)); - EXPECT_TRUE( - file_util::VerifyPathControlledByUser( - sub_dir_, text_file_, uid_, bad_gids_)); - - // No group is okay, because we don't check the group - // if no group can write. - std::set no_gids; // Empty set of gids. - EXPECT_TRUE( - file_util::VerifyPathControlledByUser( - base_dir_, sub_dir_, uid_, no_gids)); - EXPECT_TRUE( - file_util::VerifyPathControlledByUser( - base_dir_, text_file_, uid_, no_gids)); - EXPECT_TRUE( - file_util::VerifyPathControlledByUser( - sub_dir_, text_file_, uid_, no_gids)); - - - // Make all files and directories writable by their group. - ASSERT_NO_FATAL_FAILURE( - ChangePosixFilePermissions(base_dir_, S_IWGRP, 0u)); - ASSERT_NO_FATAL_FAILURE( - ChangePosixFilePermissions(sub_dir_, S_IWGRP, 0u)); - ASSERT_NO_FATAL_FAILURE( - ChangePosixFilePermissions(text_file_, S_IWGRP, 0u)); - - // Now |ok_gids_| works, but |bad_gids_| fails. - EXPECT_TRUE( - file_util::VerifyPathControlledByUser( - base_dir_, sub_dir_, uid_, ok_gids_)); - EXPECT_TRUE( - file_util::VerifyPathControlledByUser( - base_dir_, text_file_, uid_, ok_gids_)); - EXPECT_TRUE( - file_util::VerifyPathControlledByUser( - sub_dir_, text_file_, uid_, ok_gids_)); - - EXPECT_FALSE( - file_util::VerifyPathControlledByUser( - base_dir_, sub_dir_, uid_, bad_gids_)); - EXPECT_FALSE( - file_util::VerifyPathControlledByUser( - base_dir_, text_file_, uid_, bad_gids_)); - EXPECT_FALSE( - file_util::VerifyPathControlledByUser( - sub_dir_, text_file_, uid_, bad_gids_)); - - // Because any group in the group set is allowed, - // the union of good and bad gids passes. - - std::set multiple_gids; - std::set_union( - ok_gids_.begin(), ok_gids_.end(), - bad_gids_.begin(), bad_gids_.end(), - std::inserter(multiple_gids, multiple_gids.begin())); - - EXPECT_TRUE( - file_util::VerifyPathControlledByUser( - base_dir_, sub_dir_, uid_, multiple_gids)); - EXPECT_TRUE( - file_util::VerifyPathControlledByUser( - base_dir_, text_file_, uid_, multiple_gids)); - EXPECT_TRUE( - file_util::VerifyPathControlledByUser( - sub_dir_, text_file_, uid_, multiple_gids)); -} - -TEST_F(VerifyPathControlledByUserTest, WriteBitChecks) { - // Make all files and directories non-world-writable. - ASSERT_NO_FATAL_FAILURE( - ChangePosixFilePermissions(base_dir_, 0u, S_IWOTH)); - ASSERT_NO_FATAL_FAILURE( - ChangePosixFilePermissions(sub_dir_, 0u, S_IWOTH)); - ASSERT_NO_FATAL_FAILURE( - ChangePosixFilePermissions(text_file_, 0u, S_IWOTH)); - - // Initialy, we control all parts of the path. - EXPECT_TRUE( - file_util::VerifyPathControlledByUser( - base_dir_, sub_dir_, uid_, ok_gids_)); - EXPECT_TRUE( - file_util::VerifyPathControlledByUser( - base_dir_, text_file_, uid_, ok_gids_)); - EXPECT_TRUE( - file_util::VerifyPathControlledByUser( - sub_dir_, text_file_, uid_, ok_gids_)); - - // Make base_dir_ world-writable. - ASSERT_NO_FATAL_FAILURE( - ChangePosixFilePermissions(base_dir_, S_IWOTH, 0u)); - EXPECT_FALSE( - file_util::VerifyPathControlledByUser( - base_dir_, sub_dir_, uid_, ok_gids_)); - EXPECT_FALSE( - file_util::VerifyPathControlledByUser( - base_dir_, text_file_, uid_, ok_gids_)); - EXPECT_TRUE( - file_util::VerifyPathControlledByUser( - sub_dir_, text_file_, uid_, ok_gids_)); - - // Make sub_dir_ world writable. - ASSERT_NO_FATAL_FAILURE( - ChangePosixFilePermissions(sub_dir_, S_IWOTH, 0u)); - EXPECT_FALSE( - file_util::VerifyPathControlledByUser( - base_dir_, sub_dir_, uid_, ok_gids_)); - EXPECT_FALSE( - file_util::VerifyPathControlledByUser( - base_dir_, text_file_, uid_, ok_gids_)); - EXPECT_FALSE( - file_util::VerifyPathControlledByUser( - sub_dir_, text_file_, uid_, ok_gids_)); - - // Make text_file_ world writable. - ASSERT_NO_FATAL_FAILURE( - ChangePosixFilePermissions(text_file_, S_IWOTH, 0u)); - EXPECT_FALSE( - file_util::VerifyPathControlledByUser( - base_dir_, sub_dir_, uid_, ok_gids_)); - EXPECT_FALSE( - file_util::VerifyPathControlledByUser( - base_dir_, text_file_, uid_, ok_gids_)); - EXPECT_FALSE( - file_util::VerifyPathControlledByUser( - sub_dir_, text_file_, uid_, ok_gids_)); - - // Make sub_dir_ non-world writable. - ASSERT_NO_FATAL_FAILURE( - ChangePosixFilePermissions(sub_dir_, 0u, S_IWOTH)); - EXPECT_FALSE( - file_util::VerifyPathControlledByUser( - base_dir_, sub_dir_, uid_, ok_gids_)); - EXPECT_FALSE( - file_util::VerifyPathControlledByUser( - base_dir_, text_file_, uid_, ok_gids_)); - EXPECT_FALSE( - file_util::VerifyPathControlledByUser( - sub_dir_, text_file_, uid_, ok_gids_)); - - // Make base_dir_ non-world-writable. - ASSERT_NO_FATAL_FAILURE( - ChangePosixFilePermissions(base_dir_, 0u, S_IWOTH)); - EXPECT_TRUE( - file_util::VerifyPathControlledByUser( - base_dir_, sub_dir_, uid_, ok_gids_)); - EXPECT_FALSE( - file_util::VerifyPathControlledByUser( - base_dir_, text_file_, uid_, ok_gids_)); - EXPECT_FALSE( - file_util::VerifyPathControlledByUser( - sub_dir_, text_file_, uid_, ok_gids_)); - - // Back to the initial state: Nothing is writable, so every path - // should pass. - ASSERT_NO_FATAL_FAILURE( - ChangePosixFilePermissions(text_file_, 0u, S_IWOTH)); - EXPECT_TRUE( - file_util::VerifyPathControlledByUser( - base_dir_, sub_dir_, uid_, ok_gids_)); - EXPECT_TRUE( - file_util::VerifyPathControlledByUser( - base_dir_, text_file_, uid_, ok_gids_)); - EXPECT_TRUE( - file_util::VerifyPathControlledByUser( - sub_dir_, text_file_, uid_, ok_gids_)); -} - -#endif // defined(OS_POSIX) - -} // namespace diff --git a/base/file_util_win.cc b/base/file_util_win.cc deleted file mode 100644 index 39317a3a93..0000000000 --- a/base/file_util_win.cc +++ /dev/null @@ -1,759 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "base/file_util.h" - -#include -#include -#include -#include -#include - -#include -#include -#include - -#include "base/files/file_path.h" -#include "base/logging.h" -#include "base/metrics/histogram.h" -#include "base/process/process_handle.h" -#include "base/rand_util.h" -#include "base/strings/string_number_conversions.h" -#include "base/strings/string_util.h" -#include "base/strings/utf_string_conversions.h" -#include "base/threading/thread_restrictions.h" -#include "base/time/time.h" -#include "base/win/scoped_handle.h" -#include "base/win/windows_version.h" - -namespace base { - -namespace { - -const DWORD kFileShareAll = - FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE; - -bool ShellCopy(const FilePath& from_path, - const FilePath& to_path, - bool recursive) { - // WinXP SHFileOperation doesn't like trailing separators. - FilePath stripped_from = from_path.StripTrailingSeparators(); - FilePath stripped_to = to_path.StripTrailingSeparators(); - - ThreadRestrictions::AssertIOAllowed(); - - // NOTE: I suspect we could support longer paths, but that would involve - // analyzing all our usage of files. - if (stripped_from.value().length() >= MAX_PATH || - stripped_to.value().length() >= MAX_PATH) { - return false; - } - - // SHFILEOPSTRUCT wants the path to be terminated with two NULLs, - // so we have to use wcscpy because wcscpy_s writes non-NULLs - // into the rest of the buffer. - wchar_t double_terminated_path_from[MAX_PATH + 1] = {0}; - wchar_t double_terminated_path_to[MAX_PATH + 1] = {0}; -#pragma warning(suppress:4996) // don't complain about wcscpy deprecation - wcscpy(double_terminated_path_from, stripped_from.value().c_str()); -#pragma warning(suppress:4996) // don't complain about wcscpy deprecation - wcscpy(double_terminated_path_to, stripped_to.value().c_str()); - - SHFILEOPSTRUCT file_operation = {0}; - file_operation.wFunc = FO_COPY; - file_operation.pFrom = double_terminated_path_from; - file_operation.pTo = double_terminated_path_to; - file_operation.fFlags = FOF_NOERRORUI | FOF_SILENT | FOF_NOCONFIRMATION | - FOF_NOCONFIRMMKDIR; - if (!recursive) - file_operation.fFlags |= FOF_NORECURSION | FOF_FILESONLY; - - return (SHFileOperation(&file_operation) == 0); -} - -} // namespace - -FilePath MakeAbsoluteFilePath(const FilePath& input) { - ThreadRestrictions::AssertIOAllowed(); - wchar_t file_path[MAX_PATH]; - if (!_wfullpath(file_path, input.value().c_str(), MAX_PATH)) - return FilePath(); - return FilePath(file_path); -} - -bool DeleteFile(const FilePath& path, bool recursive) { - ThreadRestrictions::AssertIOAllowed(); - - if (path.value().length() >= MAX_PATH) - return false; - - if (!recursive) { - // If not recursing, then first check to see if |path| is a directory. - // If it is, then remove it with RemoveDirectory. - PlatformFileInfo file_info; - if (file_util::GetFileInfo(path, &file_info) && file_info.is_directory) - return RemoveDirectory(path.value().c_str()) != 0; - - // Otherwise, it's a file, wildcard or non-existant. Try DeleteFile first - // because it should be faster. If DeleteFile fails, then we fall through - // to SHFileOperation, which will do the right thing. - if (::DeleteFile(path.value().c_str()) != 0) - return true; - } - - // SHFILEOPSTRUCT wants the path to be terminated with two NULLs, - // so we have to use wcscpy because wcscpy_s writes non-NULLs - // into the rest of the buffer. - wchar_t double_terminated_path[MAX_PATH + 1] = {0}; -#pragma warning(suppress:4996) // don't complain about wcscpy deprecation - if (g_bug108724_debug) - LOG(WARNING) << "copying "; - wcscpy(double_terminated_path, path.value().c_str()); - - SHFILEOPSTRUCT file_operation = {0}; - file_operation.wFunc = FO_DELETE; - file_operation.pFrom = double_terminated_path; - file_operation.fFlags = FOF_NOERRORUI | FOF_SILENT | FOF_NOCONFIRMATION; - if (!recursive) - file_operation.fFlags |= FOF_NORECURSION | FOF_FILESONLY; - if (g_bug108724_debug) - LOG(WARNING) << "Performing shell operation"; - int err = SHFileOperation(&file_operation); - if (g_bug108724_debug) - LOG(WARNING) << "Done: " << err; - - // Since we're passing flags to the operation telling it to be silent, - // it's possible for the operation to be aborted/cancelled without err - // being set (although MSDN doesn't give any scenarios for how this can - // happen). See MSDN for SHFileOperation and SHFILEOPTSTRUCT. - if (file_operation.fAnyOperationsAborted) - return false; - - // Some versions of Windows return ERROR_FILE_NOT_FOUND (0x2) when deleting - // an empty directory and some return 0x402 when they should be returning - // ERROR_FILE_NOT_FOUND. MSDN says Vista and up won't return 0x402. - return (err == 0 || err == ERROR_FILE_NOT_FOUND || err == 0x402); -} - -bool DeleteFileAfterReboot(const FilePath& path) { - ThreadRestrictions::AssertIOAllowed(); - - if (path.value().length() >= MAX_PATH) - return false; - - return MoveFileEx(path.value().c_str(), NULL, - MOVEFILE_DELAY_UNTIL_REBOOT | - MOVEFILE_REPLACE_EXISTING) != FALSE; -} - -bool ReplaceFile(const FilePath& from_path, - const FilePath& to_path, - PlatformFileError* error) { - ThreadRestrictions::AssertIOAllowed(); - // Try a simple move first. It will only succeed when |to_path| doesn't - // already exist. - if (::MoveFile(from_path.value().c_str(), to_path.value().c_str())) - return true; - // Try the full-blown replace if the move fails, as ReplaceFile will only - // succeed when |to_path| does exist. When writing to a network share, we may - // not be able to change the ACLs. Ignore ACL errors then - // (REPLACEFILE_IGNORE_MERGE_ERRORS). - if (::ReplaceFile(to_path.value().c_str(), from_path.value().c_str(), NULL, - REPLACEFILE_IGNORE_MERGE_ERRORS, NULL, NULL)) { - return true; - } - if (error) - *error = LastErrorToPlatformFileError(GetLastError()); - return false; -} - -bool CopyDirectory(const FilePath& from_path, const FilePath& to_path, - bool recursive) { - ThreadRestrictions::AssertIOAllowed(); - - if (recursive) - return ShellCopy(from_path, to_path, true); - - // The following code assumes that from path is a directory. - DCHECK(DirectoryExists(from_path)); - - // Instead of creating a new directory, we copy the old one to include the - // security information of the folder as part of the copy. - if (!PathExists(to_path)) { - // Except that Vista fails to do that, and instead do a recursive copy if - // the target directory doesn't exist. - if (base::win::GetVersion() >= base::win::VERSION_VISTA) - file_util::CreateDirectory(to_path); - else - ShellCopy(from_path, to_path, false); - } - - FilePath directory = from_path.Append(L"*.*"); - return ShellCopy(directory, to_path, false); -} - -bool PathExists(const FilePath& path) { - ThreadRestrictions::AssertIOAllowed(); - return (GetFileAttributes(path.value().c_str()) != INVALID_FILE_ATTRIBUTES); -} - -bool PathIsWritable(const FilePath& path) { - ThreadRestrictions::AssertIOAllowed(); - HANDLE dir = - CreateFile(path.value().c_str(), FILE_ADD_FILE, kFileShareAll, - NULL, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, NULL); - - if (dir == INVALID_HANDLE_VALUE) - return false; - - CloseHandle(dir); - return true; -} - -bool DirectoryExists(const FilePath& path) { - ThreadRestrictions::AssertIOAllowed(); - DWORD fileattr = GetFileAttributes(path.value().c_str()); - if (fileattr != INVALID_FILE_ATTRIBUTES) - return (fileattr & FILE_ATTRIBUTE_DIRECTORY) != 0; - return false; -} - -} // namespace base - -// ----------------------------------------------------------------------------- - -namespace file_util { - -using base::DirectoryExists; -using base::FilePath; -using base::kFileShareAll; - -bool GetTempDir(FilePath* path) { - base::ThreadRestrictions::AssertIOAllowed(); - - wchar_t temp_path[MAX_PATH + 1]; - DWORD path_len = ::GetTempPath(MAX_PATH, temp_path); - if (path_len >= MAX_PATH || path_len <= 0) - return false; - // TODO(evanm): the old behavior of this function was to always strip the - // trailing slash. We duplicate this here, but it shouldn't be necessary - // when everyone is using the appropriate FilePath APIs. - *path = FilePath(temp_path).StripTrailingSeparators(); - return true; -} - -bool GetShmemTempDir(FilePath* path, bool executable) { - return GetTempDir(path); -} - -bool CreateTemporaryFile(FilePath* path) { - base::ThreadRestrictions::AssertIOAllowed(); - - FilePath temp_file; - - if (!GetTempDir(path)) - return false; - - if (CreateTemporaryFileInDir(*path, &temp_file)) { - *path = temp_file; - return true; - } - - return false; -} - -FILE* CreateAndOpenTemporaryShmemFile(FilePath* path, bool executable) { - base::ThreadRestrictions::AssertIOAllowed(); - return CreateAndOpenTemporaryFile(path); -} - -// On POSIX we have semantics to create and open a temporary file -// atomically. -// TODO(jrg): is there equivalent call to use on Windows instead of -// going 2-step? -FILE* CreateAndOpenTemporaryFileInDir(const FilePath& dir, FilePath* path) { - base::ThreadRestrictions::AssertIOAllowed(); - if (!CreateTemporaryFileInDir(dir, path)) { - return NULL; - } - // Open file in binary mode, to avoid problems with fwrite. On Windows - // it replaces \n's with \r\n's, which may surprise you. - // Reference: http://msdn.microsoft.com/en-us/library/h9t88zwz(VS.71).aspx - return OpenFile(*path, "wb+"); -} - -bool CreateTemporaryFileInDir(const FilePath& dir, - FilePath* temp_file) { - base::ThreadRestrictions::AssertIOAllowed(); - - wchar_t temp_name[MAX_PATH + 1]; - - if (!GetTempFileName(dir.value().c_str(), L"", 0, temp_name)) { - DPLOG(WARNING) << "Failed to get temporary file name in " << dir.value(); - return false; - } - - wchar_t long_temp_name[MAX_PATH + 1]; - DWORD long_name_len = GetLongPathName(temp_name, long_temp_name, MAX_PATH); - if (long_name_len > MAX_PATH || long_name_len == 0) { - // GetLongPathName() failed, but we still have a temporary file. - *temp_file = FilePath(temp_name); - return true; - } - - FilePath::StringType long_temp_name_str; - long_temp_name_str.assign(long_temp_name, long_name_len); - *temp_file = FilePath(long_temp_name_str); - return true; -} - -bool CreateTemporaryDirInDir(const FilePath& base_dir, - const FilePath::StringType& prefix, - FilePath* new_dir) { - base::ThreadRestrictions::AssertIOAllowed(); - - FilePath path_to_create; - - for (int count = 0; count < 50; ++count) { - // Try create a new temporary directory with random generated name. If - // the one exists, keep trying another path name until we reach some limit. - string16 new_dir_name; - new_dir_name.assign(prefix); - new_dir_name.append(base::IntToString16(::base::GetCurrentProcId())); - new_dir_name.push_back('_'); - new_dir_name.append(base::IntToString16(base::RandInt(0, kint16max))); - - path_to_create = base_dir.Append(new_dir_name); - if (::CreateDirectory(path_to_create.value().c_str(), NULL)) { - *new_dir = path_to_create; - return true; - } - } - - return false; -} - -bool CreateNewTempDirectory(const FilePath::StringType& prefix, - FilePath* new_temp_path) { - base::ThreadRestrictions::AssertIOAllowed(); - - FilePath system_temp_dir; - if (!GetTempDir(&system_temp_dir)) - return false; - - return CreateTemporaryDirInDir(system_temp_dir, prefix, new_temp_path); -} - -bool CreateDirectoryAndGetError(const FilePath& full_path, - base::PlatformFileError* error) { - base::ThreadRestrictions::AssertIOAllowed(); - - // If the path exists, we've succeeded if it's a directory, failed otherwise. - const wchar_t* full_path_str = full_path.value().c_str(); - DWORD fileattr = ::GetFileAttributes(full_path_str); - if (fileattr != INVALID_FILE_ATTRIBUTES) { - if ((fileattr & FILE_ATTRIBUTE_DIRECTORY) != 0) { - DVLOG(1) << "CreateDirectory(" << full_path_str << "), " - << "directory already exists."; - return true; - } - DLOG(WARNING) << "CreateDirectory(" << full_path_str << "), " - << "conflicts with existing file."; - if (error) { - *error = base::PLATFORM_FILE_ERROR_NOT_A_DIRECTORY; - } - return false; - } - - // Invariant: Path does not exist as file or directory. - - // Attempt to create the parent recursively. This will immediately return - // true if it already exists, otherwise will create all required parent - // directories starting with the highest-level missing parent. - FilePath parent_path(full_path.DirName()); - if (parent_path.value() == full_path.value()) { - if (error) { - *error = base::PLATFORM_FILE_ERROR_NOT_FOUND; - } - return false; - } - if (!CreateDirectoryAndGetError(parent_path, error)) { - DLOG(WARNING) << "Failed to create one of the parent directories."; - if (error) { - DCHECK(*error != base::PLATFORM_FILE_OK); - } - return false; - } - - if (!::CreateDirectory(full_path_str, NULL)) { - DWORD error_code = ::GetLastError(); - if (error_code == ERROR_ALREADY_EXISTS && DirectoryExists(full_path)) { - // This error code ERROR_ALREADY_EXISTS doesn't indicate whether we - // were racing with someone creating the same directory, or a file - // with the same path. If DirectoryExists() returns true, we lost the - // race to create the same directory. - return true; - } else { - if (error) - *error = base::LastErrorToPlatformFileError(error_code); - DLOG(WARNING) << "Failed to create directory " << full_path_str - << ", last error is " << error_code << "."; - return false; - } - } else { - return true; - } -} - -// TODO(rkc): Work out if we want to handle NTFS junctions here or not, handle -// them if we do decide to. -bool IsLink(const FilePath& file_path) { - return false; -} - -bool GetFileInfo(const FilePath& file_path, base::PlatformFileInfo* results) { - base::ThreadRestrictions::AssertIOAllowed(); - - WIN32_FILE_ATTRIBUTE_DATA attr; - if (!GetFileAttributesEx(file_path.value().c_str(), - GetFileExInfoStandard, &attr)) { - return false; - } - - ULARGE_INTEGER size; - size.HighPart = attr.nFileSizeHigh; - size.LowPart = attr.nFileSizeLow; - results->size = size.QuadPart; - - results->is_directory = - (attr.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) != 0; - results->last_modified = base::Time::FromFileTime(attr.ftLastWriteTime); - results->last_accessed = base::Time::FromFileTime(attr.ftLastAccessTime); - results->creation_time = base::Time::FromFileTime(attr.ftCreationTime); - - return true; -} - -FILE* OpenFile(const FilePath& filename, const char* mode) { - base::ThreadRestrictions::AssertIOAllowed(); - std::wstring w_mode = ASCIIToWide(std::string(mode)); - return _wfsopen(filename.value().c_str(), w_mode.c_str(), _SH_DENYNO); -} - -FILE* OpenFile(const std::string& filename, const char* mode) { - base::ThreadRestrictions::AssertIOAllowed(); - return _fsopen(filename.c_str(), mode, _SH_DENYNO); -} - -int ReadFile(const FilePath& filename, char* data, int size) { - base::ThreadRestrictions::AssertIOAllowed(); - base::win::ScopedHandle file(CreateFile(filename.value().c_str(), - GENERIC_READ, - FILE_SHARE_READ | FILE_SHARE_WRITE, - NULL, - OPEN_EXISTING, - FILE_FLAG_SEQUENTIAL_SCAN, - NULL)); - if (!file) - return -1; - - DWORD read; - if (::ReadFile(file, data, size, &read, NULL) && - static_cast(read) == size) - return read; - return -1; -} - -int WriteFile(const FilePath& filename, const char* data, int size) { - base::ThreadRestrictions::AssertIOAllowed(); - base::win::ScopedHandle file(CreateFile(filename.value().c_str(), - GENERIC_WRITE, - 0, - NULL, - CREATE_ALWAYS, - 0, - NULL)); - if (!file) { - DLOG_GETLASTERROR(WARNING) << "CreateFile failed for path " - << filename.value(); - return -1; - } - - DWORD written; - BOOL result = ::WriteFile(file, data, size, &written, NULL); - if (result && static_cast(written) == size) - return written; - - if (!result) { - // WriteFile failed. - DLOG_GETLASTERROR(WARNING) << "writing file " << filename.value() - << " failed"; - } else { - // Didn't write all the bytes. - DLOG(WARNING) << "wrote" << written << " bytes to " - << filename.value() << " expected " << size; - } - return -1; -} - -int AppendToFile(const FilePath& filename, const char* data, int size) { - base::ThreadRestrictions::AssertIOAllowed(); - base::win::ScopedHandle file(CreateFile(filename.value().c_str(), - FILE_APPEND_DATA, - 0, - NULL, - OPEN_EXISTING, - 0, - NULL)); - if (!file) { - DLOG_GETLASTERROR(WARNING) << "CreateFile failed for path " - << filename.value(); - return -1; - } - - DWORD written; - BOOL result = ::WriteFile(file, data, size, &written, NULL); - if (result && static_cast(written) == size) - return written; - - if (!result) { - // WriteFile failed. - DLOG_GETLASTERROR(WARNING) << "writing file " << filename.value() - << " failed"; - } else { - // Didn't write all the bytes. - DLOG(WARNING) << "wrote" << written << " bytes to " - << filename.value() << " expected " << size; - } - return -1; -} - -// Gets the current working directory for the process. -bool GetCurrentDirectory(FilePath* dir) { - base::ThreadRestrictions::AssertIOAllowed(); - - wchar_t system_buffer[MAX_PATH]; - system_buffer[0] = 0; - DWORD len = ::GetCurrentDirectory(MAX_PATH, system_buffer); - if (len == 0 || len > MAX_PATH) - return false; - // TODO(evanm): the old behavior of this function was to always strip the - // trailing slash. We duplicate this here, but it shouldn't be necessary - // when everyone is using the appropriate FilePath APIs. - std::wstring dir_str(system_buffer); - *dir = FilePath(dir_str).StripTrailingSeparators(); - return true; -} - -// Sets the current working directory for the process. -bool SetCurrentDirectory(const FilePath& directory) { - base::ThreadRestrictions::AssertIOAllowed(); - BOOL ret = ::SetCurrentDirectory(directory.value().c_str()); - return ret != 0; -} - -bool NormalizeFilePath(const FilePath& path, FilePath* real_path) { - base::ThreadRestrictions::AssertIOAllowed(); - FilePath mapped_file; - if (!NormalizeToNativeFilePath(path, &mapped_file)) - return false; - // NormalizeToNativeFilePath() will return a path that starts with - // "\Device\Harddisk...". Helper DevicePathToDriveLetterPath() - // will find a drive letter which maps to the path's device, so - // that we return a path starting with a drive letter. - return DevicePathToDriveLetterPath(mapped_file, real_path); -} - -bool DevicePathToDriveLetterPath(const FilePath& nt_device_path, - FilePath* out_drive_letter_path) { - base::ThreadRestrictions::AssertIOAllowed(); - - // Get the mapping of drive letters to device paths. - const int kDriveMappingSize = 1024; - wchar_t drive_mapping[kDriveMappingSize] = {'\0'}; - if (!::GetLogicalDriveStrings(kDriveMappingSize - 1, drive_mapping)) { - DLOG(ERROR) << "Failed to get drive mapping."; - return false; - } - - // The drive mapping is a sequence of null terminated strings. - // The last string is empty. - wchar_t* drive_map_ptr = drive_mapping; - wchar_t device_path_as_string[MAX_PATH]; - wchar_t drive[] = L" :"; - - // For each string in the drive mapping, get the junction that links - // to it. If that junction is a prefix of |device_path|, then we - // know that |drive| is the real path prefix. - while (*drive_map_ptr) { - drive[0] = drive_map_ptr[0]; // Copy the drive letter. - - if (QueryDosDevice(drive, device_path_as_string, MAX_PATH)) { - FilePath device_path(device_path_as_string); - if (device_path == nt_device_path || - device_path.IsParent(nt_device_path)) { - *out_drive_letter_path = FilePath(drive + - nt_device_path.value().substr(wcslen(device_path_as_string))); - return true; - } - } - // Move to the next drive letter string, which starts one - // increment after the '\0' that terminates the current string. - while (*drive_map_ptr++); - } - - // No drive matched. The path does not start with a device junction - // that is mounted as a drive letter. This means there is no drive - // letter path to the volume that holds |device_path|, so fail. - return false; -} - -bool NormalizeToNativeFilePath(const FilePath& path, FilePath* nt_path) { - base::ThreadRestrictions::AssertIOAllowed(); - // In Vista, GetFinalPathNameByHandle() would give us the real path - // from a file handle. If we ever deprecate XP, consider changing the - // code below to a call to GetFinalPathNameByHandle(). The method this - // function uses is explained in the following msdn article: - // http://msdn.microsoft.com/en-us/library/aa366789(VS.85).aspx - base::win::ScopedHandle file_handle( - ::CreateFile(path.value().c_str(), - GENERIC_READ, - kFileShareAll, - NULL, - OPEN_EXISTING, - FILE_ATTRIBUTE_NORMAL, - NULL)); - if (!file_handle) - return false; - - // Create a file mapping object. Can't easily use MemoryMappedFile, because - // we only map the first byte, and need direct access to the handle. You can - // not map an empty file, this call fails in that case. - base::win::ScopedHandle file_map_handle( - ::CreateFileMapping(file_handle.Get(), - NULL, - PAGE_READONLY, - 0, - 1, // Just one byte. No need to look at the data. - NULL)); - if (!file_map_handle) - return false; - - // Use a view of the file to get the path to the file. - void* file_view = MapViewOfFile(file_map_handle.Get(), - FILE_MAP_READ, 0, 0, 1); - if (!file_view) - return false; - - // The expansion of |path| into a full path may make it longer. - // GetMappedFileName() will fail if the result is longer than MAX_PATH. - // Pad a bit to be safe. If kMaxPathLength is ever changed to be less - // than MAX_PATH, it would be nessisary to test that GetMappedFileName() - // not return kMaxPathLength. This would mean that only part of the - // path fit in |mapped_file_path|. - const int kMaxPathLength = MAX_PATH + 10; - wchar_t mapped_file_path[kMaxPathLength]; - bool success = false; - HANDLE cp = GetCurrentProcess(); - if (::GetMappedFileNameW(cp, file_view, mapped_file_path, kMaxPathLength)) { - *nt_path = FilePath(mapped_file_path); - success = true; - } - ::UnmapViewOfFile(file_view); - return success; -} - -int GetMaximumPathComponentLength(const FilePath& path) { - base::ThreadRestrictions::AssertIOAllowed(); - - wchar_t volume_path[MAX_PATH]; - if (!GetVolumePathNameW(path.NormalizePathSeparators().value().c_str(), - volume_path, - arraysize(volume_path))) { - return -1; - } - - DWORD max_length = 0; - if (!GetVolumeInformationW(volume_path, NULL, 0, NULL, &max_length, NULL, - NULL, 0)) { - return -1; - } - - // Length of |path| with path separator appended. - size_t prefix = path.StripTrailingSeparators().value().size() + 1; - // The whole path string must be shorter than MAX_PATH. That is, it must be - // prefix + component_length < MAX_PATH (or equivalently, <= MAX_PATH - 1). - int whole_path_limit = std::max(0, MAX_PATH - 1 - static_cast(prefix)); - return std::min(whole_path_limit, static_cast(max_length)); -} - -} // namespace file_util - -namespace base { -namespace internal { - -bool MoveUnsafe(const FilePath& from_path, const FilePath& to_path) { - ThreadRestrictions::AssertIOAllowed(); - - // NOTE: I suspect we could support longer paths, but that would involve - // analyzing all our usage of files. - if (from_path.value().length() >= MAX_PATH || - to_path.value().length() >= MAX_PATH) { - return false; - } - if (MoveFileEx(from_path.value().c_str(), to_path.value().c_str(), - MOVEFILE_COPY_ALLOWED | MOVEFILE_REPLACE_EXISTING) != 0) - return true; - - // Keep the last error value from MoveFileEx around in case the below - // fails. - bool ret = false; - DWORD last_error = ::GetLastError(); - - if (DirectoryExists(from_path)) { - // MoveFileEx fails if moving directory across volumes. We will simulate - // the move by using Copy and Delete. Ideally we could check whether - // from_path and to_path are indeed in different volumes. - ret = internal::CopyAndDeleteDirectory(from_path, to_path); - } - - if (!ret) { - // Leave a clue about what went wrong so that it can be (at least) picked - // up by a PLOG entry. - ::SetLastError(last_error); - } - - return ret; -} - -bool CopyFileUnsafe(const FilePath& from_path, const FilePath& to_path) { - ThreadRestrictions::AssertIOAllowed(); - - // NOTE: I suspect we could support longer paths, but that would involve - // analyzing all our usage of files. - if (from_path.value().length() >= MAX_PATH || - to_path.value().length() >= MAX_PATH) { - return false; - } - return (::CopyFile(from_path.value().c_str(), to_path.value().c_str(), - false) != 0); -} - -bool CopyAndDeleteDirectory(const FilePath& from_path, - const FilePath& to_path) { - ThreadRestrictions::AssertIOAllowed(); - if (CopyDirectory(from_path, to_path, true)) { - if (DeleteFile(from_path, true)) - return true; - - // Like Move, this function is not transactional, so we just - // leave the copied bits behind if deleting from_path fails. - // If to_path exists previously then we have already overwritten - // it by now, we don't get better off by deleting the new bits. - } - return false; -} - -} // namespace internal -} // namespace base diff --git a/base/file_version_info.h b/base/file_version_info.h deleted file mode 100644 index 59cd45df07..0000000000 --- a/base/file_version_info.h +++ /dev/null @@ -1,87 +0,0 @@ -// Copyright (c) 2011 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef BASE_FILE_VERSION_INFO_H__ -#define BASE_FILE_VERSION_INFO_H__ - -#include "build/build_config.h" - -#if defined(OS_WIN) -#include -// http://blogs.msdn.com/oldnewthing/archive/2004/10/25/247180.aspx -extern "C" IMAGE_DOS_HEADER __ImageBase; -#endif // OS_WIN - -#include - -#include "base/base_export.h" -#include "base/strings/string16.h" - -namespace base { -class FilePath; -} - -// Provides an interface for accessing the version information for a file. This -// is the information you access when you select a file in the Windows Explorer, -// right-click select Properties, then click the Version tab, and on the Mac -// when you select a file in the Finder and do a Get Info. -// -// This list of properties is straight out of Win32's VerQueryValue -// and the Mac -// version returns values from the Info.plist as appropriate. TODO(avi): make -// this a less-obvious Windows-ism. - -class FileVersionInfo { - public: - virtual ~FileVersionInfo() {} -#if defined(OS_WIN) || defined(OS_MACOSX) - // Creates a FileVersionInfo for the specified path. Returns NULL if something - // goes wrong (typically the file does not exit or cannot be opened). The - // returned object should be deleted when you are done with it. - BASE_EXPORT static FileVersionInfo* CreateFileVersionInfo( - const base::FilePath& file_path); -#endif // OS_WIN || OS_MACOSX - -#if defined(OS_WIN) - // Creates a FileVersionInfo for the specified module. Returns NULL in case - // of error. The returned object should be deleted when you are done with it. - BASE_EXPORT static FileVersionInfo* CreateFileVersionInfoForModule( - HMODULE module); - - // Creates a FileVersionInfo for the current module. Returns NULL in case - // of error. The returned object should be deleted when you are done with it. - // This function should be inlined so that the "current module" is evaluated - // correctly, instead of being the module that contains base. - __forceinline static FileVersionInfo* - CreateFileVersionInfoForCurrentModule() { - HMODULE module = reinterpret_cast(&__ImageBase); - return CreateFileVersionInfoForModule(module); - } -#else - // Creates a FileVersionInfo for the current module. Returns NULL in case - // of error. The returned object should be deleted when you are done with it. - BASE_EXPORT static FileVersionInfo* CreateFileVersionInfoForCurrentModule(); -#endif // OS_WIN - - // Accessors to the different version properties. - // Returns an empty string if the property is not found. - virtual string16 company_name() = 0; - virtual string16 company_short_name() = 0; - virtual string16 product_name() = 0; - virtual string16 product_short_name() = 0; - virtual string16 internal_name() = 0; - virtual string16 product_version() = 0; - virtual string16 private_build() = 0; - virtual string16 special_build() = 0; - virtual string16 comments() = 0; - virtual string16 original_filename() = 0; - virtual string16 file_description() = 0; - virtual string16 file_version() = 0; - virtual string16 legal_copyright() = 0; - virtual string16 legal_trademarks() = 0; - virtual string16 last_change() = 0; - virtual bool is_official_build() = 0; -}; - -#endif // BASE_FILE_VERSION_INFO_H__ diff --git a/base/file_version_info_mac.h b/base/file_version_info_mac.h deleted file mode 100644 index f488cce4e5..0000000000 --- a/base/file_version_info_mac.h +++ /dev/null @@ -1,53 +0,0 @@ -// Copyright (c) 2011 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef BASE_FILE_VERSION_INFO_MAC_H_ -#define BASE_FILE_VERSION_INFO_MAC_H_ - -#include - -#include "base/file_version_info.h" -#include "base/mac/scoped_nsobject.h" - -#ifdef __OBJC__ -@class NSBundle; -#else -class NSBundle; -#endif - -class FileVersionInfoMac : public FileVersionInfo { - public: - explicit FileVersionInfoMac(NSBundle *bundle); - virtual ~FileVersionInfoMac(); - - // Accessors to the different version properties. - // Returns an empty string if the property is not found. - virtual string16 company_name() OVERRIDE; - virtual string16 company_short_name() OVERRIDE; - virtual string16 product_name() OVERRIDE; - virtual string16 product_short_name() OVERRIDE; - virtual string16 internal_name() OVERRIDE; - virtual string16 product_version() OVERRIDE; - virtual string16 private_build() OVERRIDE; - virtual string16 special_build() OVERRIDE; - virtual string16 comments() OVERRIDE; - virtual string16 original_filename() OVERRIDE; - virtual string16 file_description() OVERRIDE; - virtual string16 file_version() OVERRIDE; - virtual string16 legal_copyright() OVERRIDE; - virtual string16 legal_trademarks() OVERRIDE; - virtual string16 last_change() OVERRIDE; - virtual bool is_official_build() OVERRIDE; - - private: - // Returns a string16 value for a property name. - // Returns the empty string if the property does not exist. - string16 GetString16Value(CFStringRef name); - - base::scoped_nsobject bundle_; - - DISALLOW_COPY_AND_ASSIGN(FileVersionInfoMac); -}; - -#endif // BASE_FILE_VERSION_INFO_MAC_H_ diff --git a/base/file_version_info_mac.mm b/base/file_version_info_mac.mm deleted file mode 100644 index 0c6f8d4d3c..0000000000 --- a/base/file_version_info_mac.mm +++ /dev/null @@ -1,120 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "base/file_version_info_mac.h" - -#import - -#include "base/files/file_path.h" -#include "base/logging.h" -#include "base/mac/bundle_locations.h" -#include "base/mac/foundation_util.h" -#include "base/strings/sys_string_conversions.h" - -FileVersionInfoMac::FileVersionInfoMac(NSBundle *bundle) - : bundle_([bundle retain]) { -} - -FileVersionInfoMac::~FileVersionInfoMac() {} - -// static -FileVersionInfo* FileVersionInfo::CreateFileVersionInfoForCurrentModule() { - return CreateFileVersionInfo(base::mac::FrameworkBundlePath()); -} - -// static -FileVersionInfo* FileVersionInfo::CreateFileVersionInfo( - const base::FilePath& file_path) { - NSString* path = base::SysUTF8ToNSString(file_path.value()); - NSBundle* bundle = [NSBundle bundleWithPath:path]; - return new FileVersionInfoMac(bundle); -} - -string16 FileVersionInfoMac::company_name() { - return string16(); -} - -string16 FileVersionInfoMac::company_short_name() { - return string16(); -} - -string16 FileVersionInfoMac::internal_name() { - return string16(); -} - -string16 FileVersionInfoMac::product_name() { - return GetString16Value(kCFBundleNameKey); -} - -string16 FileVersionInfoMac::product_short_name() { - return GetString16Value(kCFBundleNameKey); -} - -string16 FileVersionInfoMac::comments() { - return string16(); -} - -string16 FileVersionInfoMac::legal_copyright() { - return GetString16Value(CFSTR("CFBundleGetInfoString")); -} - -string16 FileVersionInfoMac::product_version() { - // On OS X, CFBundleVersion is used by LaunchServices, and must follow - // specific formatting rules, so the four-part Chrome version is in - // CFBundleShortVersionString. On iOS, however, CFBundleVersion can be the - // full version, but CFBundleShortVersionString has a policy-enfoced limit - // of three version components. -#if defined(OS_IOS) - return GetString16Value(CFSTR("CFBundleVersion")); -#else - return GetString16Value(CFSTR("CFBundleShortVersionString")); -#endif // defined(OS_IOS) -} - -string16 FileVersionInfoMac::file_description() { - return string16(); -} - -string16 FileVersionInfoMac::legal_trademarks() { - return string16(); -} - -string16 FileVersionInfoMac::private_build() { - return string16(); -} - -string16 FileVersionInfoMac::file_version() { - return product_version(); -} - -string16 FileVersionInfoMac::original_filename() { - return GetString16Value(kCFBundleNameKey); -} - -string16 FileVersionInfoMac::special_build() { - return string16(); -} - -string16 FileVersionInfoMac::last_change() { - return GetString16Value(CFSTR("SCMRevision")); -} - -bool FileVersionInfoMac::is_official_build() { -#if defined (GOOGLE_CHROME_BUILD) - return true; -#else - return false; -#endif -} - -string16 FileVersionInfoMac::GetString16Value(CFStringRef name) { - if (bundle_) { - NSString *ns_name = base::mac::CFToNSCast(name); - NSString* value = [bundle_ objectForInfoDictionaryKey:ns_name]; - if (value) { - return base::SysNSStringToUTF16(value); - } - } - return string16(); -} diff --git a/base/file_version_info_unittest.cc b/base/file_version_info_unittest.cc deleted file mode 100644 index 5c899ba3dd..0000000000 --- a/base/file_version_info_unittest.cc +++ /dev/null @@ -1,140 +0,0 @@ -// Copyright (c) 2011 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "base/file_version_info.h" -#include "base/files/file_path.h" -#include "base/memory/scoped_ptr.h" -#include "base/path_service.h" -#include "testing/gtest/include/gtest/gtest.h" - -#if defined(OS_WIN) -#include "base/file_version_info_win.h" -#endif - -using base::FilePath; - -namespace { - -#if defined(OS_WIN) -FilePath GetTestDataPath() { - FilePath path; - PathService::Get(base::DIR_SOURCE_ROOT, &path); - path = path.AppendASCII("base"); - path = path.AppendASCII("data"); - path = path.AppendASCII("file_version_info_unittest"); - return path; -} -#endif - -} // namespace - -#if defined(OS_WIN) -TEST(FileVersionInfoTest, HardCodedProperties) { - const wchar_t* kDLLNames[] = { - L"FileVersionInfoTest1.dll" - }; - - const wchar_t* kExpectedValues[1][15] = { - // FileVersionInfoTest.dll - L"Goooooogle", // company_name - L"Google", // company_short_name - L"This is the product name", // product_name - L"This is the product short name", // product_short_name - L"The Internal Name", // internal_name - L"4.3.2.1", // product_version - L"Private build property", // private_build - L"Special build property", // special_build - L"This is a particularly interesting comment", // comments - L"This is the original filename", // original_filename - L"This is my file description", // file_description - L"1.2.3.4", // file_version - L"This is the legal copyright", // legal_copyright - L"This is the legal trademarks", // legal_trademarks - L"This is the last change", // last_change - }; - - for (int i = 0; i < arraysize(kDLLNames); ++i) { - FilePath dll_path = GetTestDataPath(); - dll_path = dll_path.Append(kDLLNames[i]); - - scoped_ptr version_info( - FileVersionInfo::CreateFileVersionInfo(dll_path)); - - int j = 0; - EXPECT_EQ(kExpectedValues[i][j++], version_info->company_name()); - EXPECT_EQ(kExpectedValues[i][j++], version_info->company_short_name()); - EXPECT_EQ(kExpectedValues[i][j++], version_info->product_name()); - EXPECT_EQ(kExpectedValues[i][j++], version_info->product_short_name()); - EXPECT_EQ(kExpectedValues[i][j++], version_info->internal_name()); - EXPECT_EQ(kExpectedValues[i][j++], version_info->product_version()); - EXPECT_EQ(kExpectedValues[i][j++], version_info->private_build()); - EXPECT_EQ(kExpectedValues[i][j++], version_info->special_build()); - EXPECT_EQ(kExpectedValues[i][j++], version_info->comments()); - EXPECT_EQ(kExpectedValues[i][j++], version_info->original_filename()); - EXPECT_EQ(kExpectedValues[i][j++], version_info->file_description()); - EXPECT_EQ(kExpectedValues[i][j++], version_info->file_version()); - EXPECT_EQ(kExpectedValues[i][j++], version_info->legal_copyright()); - EXPECT_EQ(kExpectedValues[i][j++], version_info->legal_trademarks()); - EXPECT_EQ(kExpectedValues[i][j++], version_info->last_change()); - } -} -#endif - -#if defined(OS_WIN) -TEST(FileVersionInfoTest, IsOfficialBuild) { - const wchar_t* kDLLNames[] = { - L"FileVersionInfoTest1.dll", - L"FileVersionInfoTest2.dll" - }; - - const bool kExpected[] = { - true, - false, - }; - - // Test consistency check. - ASSERT_EQ(arraysize(kDLLNames), arraysize(kExpected)); - - for (int i = 0; i < arraysize(kDLLNames); ++i) { - FilePath dll_path = GetTestDataPath(); - dll_path = dll_path.Append(kDLLNames[i]); - - scoped_ptr version_info( - FileVersionInfo::CreateFileVersionInfo(dll_path)); - - EXPECT_EQ(kExpected[i], version_info->is_official_build()); - } -} -#endif - -#if defined(OS_WIN) -TEST(FileVersionInfoTest, CustomProperties) { - FilePath dll_path = GetTestDataPath(); - dll_path = dll_path.AppendASCII("FileVersionInfoTest1.dll"); - - scoped_ptr version_info( - FileVersionInfo::CreateFileVersionInfo(dll_path)); - - // Test few existing properties. - std::wstring str; - FileVersionInfoWin* version_info_win = - static_cast(version_info.get()); - EXPECT_TRUE(version_info_win->GetValue(L"Custom prop 1", &str)); - EXPECT_EQ(L"Un", str); - EXPECT_EQ(L"Un", version_info_win->GetStringValue(L"Custom prop 1")); - - EXPECT_TRUE(version_info_win->GetValue(L"Custom prop 2", &str)); - EXPECT_EQ(L"Deux", str); - EXPECT_EQ(L"Deux", version_info_win->GetStringValue(L"Custom prop 2")); - - EXPECT_TRUE(version_info_win->GetValue(L"Custom prop 3", &str)); - EXPECT_EQ(L"1600 Amphitheatre Parkway Mountain View, CA 94043", str); - EXPECT_EQ(L"1600 Amphitheatre Parkway Mountain View, CA 94043", - version_info_win->GetStringValue(L"Custom prop 3")); - - // Test an non-existing property. - EXPECT_FALSE(version_info_win->GetValue(L"Unknown property", &str)); - EXPECT_EQ(L"", version_info_win->GetStringValue(L"Unknown property")); -} -#endif diff --git a/base/file_version_info_win.cc b/base/file_version_info_win.cc deleted file mode 100644 index 80dbaeaadb..0000000000 --- a/base/file_version_info_win.cc +++ /dev/null @@ -1,189 +0,0 @@ -// Copyright (c) 2011 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "base/file_version_info_win.h" - -#include - -#include "base/file_version_info.h" -#include "base/files/file_path.h" -#include "base/logging.h" -#include "base/path_service.h" -#include "base/threading/thread_restrictions.h" - -using base::FilePath; - -FileVersionInfoWin::FileVersionInfoWin(void* data, int language, int code_page) - : language_(language), code_page_(code_page) { - base::ThreadRestrictions::AssertIOAllowed(); - data_.reset((char*) data); - fixed_file_info_ = NULL; - UINT size; - ::VerQueryValue(data_.get(), L"\\", (LPVOID*)&fixed_file_info_, &size); -} - -FileVersionInfoWin::~FileVersionInfoWin() { - DCHECK(data_.get()); -} - -typedef struct { - WORD language; - WORD code_page; -} LanguageAndCodePage; - -// static -FileVersionInfo* FileVersionInfo::CreateFileVersionInfoForModule( - HMODULE module) { - // Note that the use of MAX_PATH is basically in line with what we do for - // all registered paths (PathProviderWin). - wchar_t system_buffer[MAX_PATH]; - system_buffer[0] = 0; - if (!GetModuleFileName(module, system_buffer, MAX_PATH)) - return NULL; - - FilePath app_path(system_buffer); - return CreateFileVersionInfo(app_path); -} - -// static -FileVersionInfo* FileVersionInfo::CreateFileVersionInfo( - const FilePath& file_path) { - base::ThreadRestrictions::AssertIOAllowed(); - - DWORD dummy; - const wchar_t* path = file_path.value().c_str(); - DWORD length = ::GetFileVersionInfoSize(path, &dummy); - if (length == 0) - return NULL; - - void* data = calloc(length, 1); - if (!data) - return NULL; - - if (!::GetFileVersionInfo(path, dummy, length, data)) { - free(data); - return NULL; - } - - LanguageAndCodePage* translate = NULL; - uint32 page_count; - BOOL query_result = VerQueryValue(data, L"\\VarFileInfo\\Translation", - (void**) &translate, &page_count); - - if (query_result && translate) { - return new FileVersionInfoWin(data, translate->language, - translate->code_page); - - } else { - free(data); - return NULL; - } -} - -string16 FileVersionInfoWin::company_name() { - return GetStringValue(L"CompanyName"); -} - -string16 FileVersionInfoWin::company_short_name() { - return GetStringValue(L"CompanyShortName"); -} - -string16 FileVersionInfoWin::internal_name() { - return GetStringValue(L"InternalName"); -} - -string16 FileVersionInfoWin::product_name() { - return GetStringValue(L"ProductName"); -} - -string16 FileVersionInfoWin::product_short_name() { - return GetStringValue(L"ProductShortName"); -} - -string16 FileVersionInfoWin::comments() { - return GetStringValue(L"Comments"); -} - -string16 FileVersionInfoWin::legal_copyright() { - return GetStringValue(L"LegalCopyright"); -} - -string16 FileVersionInfoWin::product_version() { - return GetStringValue(L"ProductVersion"); -} - -string16 FileVersionInfoWin::file_description() { - return GetStringValue(L"FileDescription"); -} - -string16 FileVersionInfoWin::legal_trademarks() { - return GetStringValue(L"LegalTrademarks"); -} - -string16 FileVersionInfoWin::private_build() { - return GetStringValue(L"PrivateBuild"); -} - -string16 FileVersionInfoWin::file_version() { - return GetStringValue(L"FileVersion"); -} - -string16 FileVersionInfoWin::original_filename() { - return GetStringValue(L"OriginalFilename"); -} - -string16 FileVersionInfoWin::special_build() { - return GetStringValue(L"SpecialBuild"); -} - -string16 FileVersionInfoWin::last_change() { - return GetStringValue(L"LastChange"); -} - -bool FileVersionInfoWin::is_official_build() { - return (GetStringValue(L"Official Build").compare(L"1") == 0); -} - -bool FileVersionInfoWin::GetValue(const wchar_t* name, - std::wstring* value_str) { - WORD lang_codepage[8]; - int i = 0; - // Use the language and codepage from the DLL. - lang_codepage[i++] = language_; - lang_codepage[i++] = code_page_; - // Use the default language and codepage from the DLL. - lang_codepage[i++] = ::GetUserDefaultLangID(); - lang_codepage[i++] = code_page_; - // Use the language from the DLL and Latin codepage (most common). - lang_codepage[i++] = language_; - lang_codepage[i++] = 1252; - // Use the default language and Latin codepage (most common). - lang_codepage[i++] = ::GetUserDefaultLangID(); - lang_codepage[i++] = 1252; - - i = 0; - while (i < arraysize(lang_codepage)) { - wchar_t sub_block[MAX_PATH]; - WORD language = lang_codepage[i++]; - WORD code_page = lang_codepage[i++]; - _snwprintf_s(sub_block, MAX_PATH, MAX_PATH, - L"\\StringFileInfo\\%04x%04x\\%ls", language, code_page, name); - LPVOID value = NULL; - uint32 size; - BOOL r = ::VerQueryValue(data_.get(), sub_block, &value, &size); - if (r && value) { - value_str->assign(static_cast(value)); - return true; - } - } - return false; -} - -std::wstring FileVersionInfoWin::GetStringValue(const wchar_t* name) { - std::wstring str; - if (GetValue(name, &str)) - return str; - else - return L""; -} diff --git a/base/file_version_info_win.h b/base/file_version_info_win.h deleted file mode 100644 index a37857783a..0000000000 --- a/base/file_version_info_win.h +++ /dev/null @@ -1,62 +0,0 @@ -// Copyright (c) 2011 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef BASE_FILE_VERSION_INFO_WIN_H_ -#define BASE_FILE_VERSION_INFO_WIN_H_ - -#include - -#include "base/base_export.h" -#include "base/basictypes.h" -#include "base/file_version_info.h" -#include "base/memory/scoped_ptr.h" - -struct tagVS_FIXEDFILEINFO; -typedef tagVS_FIXEDFILEINFO VS_FIXEDFILEINFO; - -class FileVersionInfoWin : public FileVersionInfo { - public: - BASE_EXPORT FileVersionInfoWin(void* data, int language, int code_page); - BASE_EXPORT ~FileVersionInfoWin(); - - // Accessors to the different version properties. - // Returns an empty string if the property is not found. - virtual string16 company_name() OVERRIDE; - virtual string16 company_short_name() OVERRIDE; - virtual string16 product_name() OVERRIDE; - virtual string16 product_short_name() OVERRIDE; - virtual string16 internal_name() OVERRIDE; - virtual string16 product_version() OVERRIDE; - virtual string16 private_build() OVERRIDE; - virtual string16 special_build() OVERRIDE; - virtual string16 comments() OVERRIDE; - virtual string16 original_filename() OVERRIDE; - virtual string16 file_description() OVERRIDE; - virtual string16 file_version() OVERRIDE; - virtual string16 legal_copyright() OVERRIDE; - virtual string16 legal_trademarks() OVERRIDE; - virtual string16 last_change() OVERRIDE; - virtual bool is_official_build() OVERRIDE; - - // Lets you access other properties not covered above. - BASE_EXPORT bool GetValue(const wchar_t* name, std::wstring* value); - - // Similar to GetValue but returns a wstring (empty string if the property - // does not exist). - BASE_EXPORT std::wstring GetStringValue(const wchar_t* name); - - // Get the fixed file info if it exists. Otherwise NULL - VS_FIXEDFILEINFO* fixed_file_info() { return fixed_file_info_; } - - private: - scoped_ptr_malloc data_; - int language_; - int code_page_; - // This is a pointer into the data_ if it exists. Otherwise NULL. - VS_FIXEDFILEINFO* fixed_file_info_; - - DISALLOW_COPY_AND_ASSIGN(FileVersionInfoWin); -}; - -#endif // BASE_FILE_VERSION_INFO_WIN_H_ diff --git a/base/files/OWNERS b/base/files/OWNERS deleted file mode 100644 index 7260260bb4..0000000000 --- a/base/files/OWNERS +++ /dev/null @@ -1,2 +0,0 @@ -# for file_path_watcher* -mnissler@chromium.org diff --git a/base/files/dir_reader_fallback.h b/base/files/dir_reader_fallback.h deleted file mode 100644 index a435f25963..0000000000 --- a/base/files/dir_reader_fallback.h +++ /dev/null @@ -1,35 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef BASE_FILES_DIR_READER_FALLBACK_H_ -#define BASE_FILES_DIR_READER_FALLBACK_H_ - -namespace base { - -class DirReaderFallback { - public: - // Open a directory. If |IsValid| is true, then |Next| can be called to start - // the iteration at the beginning of the directory. - explicit DirReaderFallback(const char* directory_path) {} - - // After construction, IsValid returns true iff the directory was - // successfully opened. - bool IsValid() const { return false; } - - // Move to the next entry returning false if the iteration is complete. - bool Next() { return false; } - - // Return the name of the current directory entry. - const char* name() { return 0;} - - // Return the file descriptor which is being used. - int fd() const { return -1; } - - // Returns true if this is a no-op fallback class (for testing). - static bool IsFallback() { return true; } -}; - -} // namespace base - -#endif // BASE_FILES_DIR_READER_FALLBACK_H_ diff --git a/base/files/dir_reader_linux.h b/base/files/dir_reader_linux.h deleted file mode 100644 index 3e0721ec26..0000000000 --- a/base/files/dir_reader_linux.h +++ /dev/null @@ -1,98 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef BASE_FILES_DIR_READER_LINUX_H_ -#define BASE_FILES_DIR_READER_LINUX_H_ - -#include -#include -#include -#include -#include - -#include "base/logging.h" -#include "base/posix/eintr_wrapper.h" - -// See the comments in dir_reader_posix.h about this. - -namespace base { - -struct linux_dirent { - uint64_t d_ino; - int64_t d_off; - unsigned short d_reclen; - unsigned char d_type; - char d_name[0]; -}; - -class DirReaderLinux { - public: - explicit DirReaderLinux(const char* directory_path) - : fd_(open(directory_path, O_RDONLY | O_DIRECTORY)), - offset_(0), - size_(0) { - memset(buf_, 0, sizeof(buf_)); - } - - ~DirReaderLinux() { - if (fd_ >= 0) { - if (HANDLE_EINTR(close(fd_))) - RAW_LOG(ERROR, "Failed to close directory handle"); - } - } - - bool IsValid() const { - return fd_ >= 0; - } - - // Move to the next entry returning false if the iteration is complete. - bool Next() { - if (size_) { - linux_dirent* dirent = reinterpret_cast(&buf_[offset_]); - offset_ += dirent->d_reclen; - } - - if (offset_ != size_) - return true; - - const int r = syscall(__NR_getdents64, fd_, buf_, sizeof(buf_)); - if (r == 0) - return false; - if (r == -1) { - DPLOG(FATAL) << "getdents64 returned an error: " << errno; - return false; - } - size_ = r; - offset_ = 0; - return true; - } - - const char* name() const { - if (!size_) - return NULL; - - const linux_dirent* dirent = - reinterpret_cast(&buf_[offset_]); - return dirent->d_name; - } - - int fd() const { - return fd_; - } - - static bool IsFallback() { - return false; - } - - private: - const int fd_; - unsigned char buf_[512]; - size_t offset_, size_; - - DISALLOW_COPY_AND_ASSIGN(DirReaderLinux); -}; - -} // namespace base - -#endif // BASE_FILES_DIR_READER_LINUX_H_ diff --git a/base/files/dir_reader_posix.h b/base/files/dir_reader_posix.h deleted file mode 100644 index 6a20ced022..0000000000 --- a/base/files/dir_reader_posix.h +++ /dev/null @@ -1,36 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef BASE_FILES_DIR_READER_POSIX_H_ -#define BASE_FILES_DIR_READER_POSIX_H_ - -#include "build/build_config.h" - -// This header provides a class, DirReaderPosix, which allows one to open and -// read from directories without allocating memory. For the interface, see -// the generic fallback in dir_reader_fallback.h. - -// Mac note: OS X has getdirentries, but it only works if we restrict Chrome to -// 32-bit inodes. There is a getdirentries64 syscall in 10.6, but it's not -// wrapped and the direct syscall interface is unstable. Using an unstable API -// seems worse than falling back to enumerating all file descriptors so we will -// probably never implement this on the Mac. - -#if defined(OS_LINUX) -#include "base/files/dir_reader_linux.h" -#else -#include "base/files/dir_reader_fallback.h" -#endif - -namespace base { - -#if defined(OS_LINUX) -typedef DirReaderLinux DirReaderPosix; -#else -typedef DirReaderFallback DirReaderPosix; -#endif - -} // namespace base - -#endif // BASE_FILES_DIR_READER_POSIX_H_ diff --git a/base/files/dir_reader_posix_unittest.cc b/base/files/dir_reader_posix_unittest.cc deleted file mode 100644 index 0685031a98..0000000000 --- a/base/files/dir_reader_posix_unittest.cc +++ /dev/null @@ -1,92 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "base/files/dir_reader_posix.h" - -#include -#include -#include -#include -#include - -#include "base/logging.h" -#include "testing/gtest/include/gtest/gtest.h" - -#if defined(OS_ANDROID) -#include "base/os_compat_android.h" -#endif - -namespace base { - -TEST(DirReaderPosixUnittest, Read) { - static const unsigned kNumFiles = 100; - - if (DirReaderPosix::IsFallback()) - return; - - char kDirTemplate[] = "/tmp/org.chromium.dir-reader-posix-XXXXXX"; - const char* dir = mkdtemp(kDirTemplate); - ASSERT_TRUE(dir); - - const int prev_wd = open(".", O_RDONLY | O_DIRECTORY); - DCHECK_GE(prev_wd, 0); - - PCHECK(chdir(dir) == 0); - - for (unsigned i = 0; i < kNumFiles; i++) { - char buf[16]; - snprintf(buf, sizeof(buf), "%d", i); - const int fd = open(buf, O_CREAT | O_RDONLY | O_EXCL, 0600); - PCHECK(fd >= 0); - PCHECK(close(fd) == 0); - } - - std::set seen; - - DirReaderPosix reader(dir); - EXPECT_TRUE(reader.IsValid()); - - if (!reader.IsValid()) - return; - - bool seen_dot = false, seen_dotdot = false; - - for (; reader.Next(); ) { - if (strcmp(reader.name(), ".") == 0) { - seen_dot = true; - continue; - } - if (strcmp(reader.name(), "..") == 0) { - seen_dotdot = true; - continue; - } - - SCOPED_TRACE(testing::Message() << "reader.name(): " << reader.name()); - - char *endptr; - const unsigned long value = strtoul(reader.name(), &endptr, 10); - - EXPECT_FALSE(*endptr); - EXPECT_LT(value, kNumFiles); - EXPECT_EQ(0u, seen.count(value)); - seen.insert(value); - } - - for (unsigned i = 0; i < kNumFiles; i++) { - char buf[16]; - snprintf(buf, sizeof(buf), "%d", i); - PCHECK(unlink(buf) == 0); - } - - PCHECK(rmdir(dir) == 0); - - PCHECK(fchdir(prev_wd) == 0); - PCHECK(close(prev_wd) == 0); - - EXPECT_TRUE(seen_dot); - EXPECT_TRUE(seen_dotdot); - EXPECT_EQ(kNumFiles, seen.size()); -} - -} // namespace base diff --git a/base/files/file_enumerator.cc b/base/files/file_enumerator.cc deleted file mode 100644 index e49f465f67..0000000000 --- a/base/files/file_enumerator.cc +++ /dev/null @@ -1,21 +0,0 @@ -// Copyright (c) 2013 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "base/files/file_enumerator.h" - -#include "base/file_util.h" - -namespace base { - -FileEnumerator::FileInfo::~FileInfo() { -} - -bool FileEnumerator::ShouldSkip(const FilePath& path) { - FilePath::StringType basename = path.BaseName().value(); - return basename == FILE_PATH_LITERAL(".") || - (basename == FILE_PATH_LITERAL("..") && - !(INCLUDE_DOT_DOT & file_type_)); -} - -} // namespace base diff --git a/base/files/file_enumerator.h b/base/files/file_enumerator.h deleted file mode 100644 index ce9bd1fd26..0000000000 --- a/base/files/file_enumerator.h +++ /dev/null @@ -1,156 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef BASE_FILES_FILE_ENUMERATOR_H_ -#define BASE_FILES_FILE_ENUMERATOR_H_ - -#include -#include - -#include "base/base_export.h" -#include "base/basictypes.h" -#include "base/files/file_path.h" -#include "base/time/time.h" -#include "build/build_config.h" - -#if defined(OS_WIN) -#include -#elif defined(OS_POSIX) -#include -#include -#endif - -namespace base { - -// A class for enumerating the files in a provided path. The order of the -// results is not guaranteed. -// -// This is blocking. Do not use on critical threads. -// -// Example: -// -// base::FileEnumerator enum(my_dir, false, base::FileEnumerator::FILES, -// FILE_PATH_LITERAL("*.txt")); -// for (base::FilePath name = enum.Next(); !name.empty(); name = enum.Next()) -// ... -class BASE_EXPORT FileEnumerator { - public: - // Note: copy & assign supported. - class BASE_EXPORT FileInfo { - public: - FileInfo(); - ~FileInfo(); - - bool IsDirectory() const; - - // The name of the file. This will not include any path information. This - // is in constrast to the value returned by FileEnumerator.Next() which - // includes the |root_path| passed into the FileEnumerator constructor. - FilePath GetName() const; - - int64 GetSize() const; - Time GetLastModifiedTime() const; - -#if defined(OS_WIN) - const WIN32_FIND_DATA& find_data() const { return find_data_; } -#elif defined(OS_POSIX) - const struct stat& stat() const { return stat_; } -#endif - - private: - friend class FileEnumerator; - -#if defined(OS_WIN) - WIN32_FIND_DATA find_data_; -#elif defined(OS_POSIX) - struct stat stat_; - FilePath filename_; -#endif - }; - - enum FileType { - FILES = 1 << 0, - DIRECTORIES = 1 << 1, - INCLUDE_DOT_DOT = 1 << 2, -#if defined(OS_POSIX) - SHOW_SYM_LINKS = 1 << 4, -#endif - }; - - // |root_path| is the starting directory to search for. It may or may not end - // in a slash. - // - // If |recursive| is true, this will enumerate all matches in any - // subdirectories matched as well. It does a breadth-first search, so all - // files in one directory will be returned before any files in a - // subdirectory. - // - // |file_type|, a bit mask of FileType, specifies whether the enumerator - // should match files, directories, or both. - // - // |pattern| is an optional pattern for which files to match. This - // works like shell globbing. For example, "*.txt" or "Foo???.doc". - // However, be careful in specifying patterns that aren't cross platform - // since the underlying code uses OS-specific matching routines. In general, - // Windows matching is less featureful than others, so test there first. - // If unspecified, this will match all files. - // NOTE: the pattern only matches the contents of root_path, not files in - // recursive subdirectories. - // TODO(erikkay): Fix the pattern matching to work at all levels. - FileEnumerator(const FilePath& root_path, - bool recursive, - int file_type); - FileEnumerator(const FilePath& root_path, - bool recursive, - int file_type, - const FilePath::StringType& pattern); - ~FileEnumerator(); - - // Returns the next file or an empty string if there are no more results. - // - // The returned path will incorporate the |root_path| passed in the - // constructor: "/file_name.txt". If the |root_path| is absolute, - // then so will be the result of Next(). - FilePath Next(); - - // Write the file info into |info|. - FileInfo GetInfo() const; - - private: - // Returns true if the given path should be skipped in enumeration. - bool ShouldSkip(const FilePath& path); - -#if defined(OS_WIN) - // True when find_data_ is valid. - bool has_find_data_; - WIN32_FIND_DATA find_data_; - HANDLE find_handle_; -#elif defined(OS_POSIX) - - // Read the filenames in source into the vector of DirectoryEntryInfo's - static bool ReadDirectory(std::vector* entries, - const FilePath& source, bool show_links); - - // The files in the current directory - std::vector directory_entries_; - - // The next entry to use from the directory_entries_ vector - size_t current_directory_entry_; -#endif - - FilePath root_path_; - bool recursive_; - int file_type_; - FilePath::StringType pattern_; // Empty when we want to find everything. - - // A stack that keeps track of which subdirectories we still need to - // enumerate in the breadth-first search. - std::stack pending_paths_; - - DISALLOW_COPY_AND_ASSIGN(FileEnumerator); -}; - -} // namespace base - -#endif // BASE_FILES_FILE_ENUMERATOR_H_ diff --git a/base/files/file_enumerator_posix.cc b/base/files/file_enumerator_posix.cc deleted file mode 100644 index 7533a24c35..0000000000 --- a/base/files/file_enumerator_posix.cc +++ /dev/null @@ -1,160 +0,0 @@ -// Copyright (c) 2013 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "base/files/file_enumerator.h" - -#include -#include -#include - -#include "base/logging.h" -#include "base/threading/thread_restrictions.h" - -namespace base { - -// FileEnumerator::FileInfo ---------------------------------------------------- - -FileEnumerator::FileInfo::FileInfo() { - memset(&stat_, 0, sizeof(stat_)); -} - -bool FileEnumerator::FileInfo::IsDirectory() const { - return S_ISDIR(stat_.st_mode); -} - -FilePath FileEnumerator::FileInfo::GetName() const { - return filename_; -} - -int64 FileEnumerator::FileInfo::GetSize() const { - return stat_.st_size; -} - -base::Time FileEnumerator::FileInfo::GetLastModifiedTime() const { - return base::Time::FromTimeT(stat_.st_mtime); -} - -// FileEnumerator -------------------------------------------------------------- - -FileEnumerator::FileEnumerator(const FilePath& root_path, - bool recursive, - int file_type) - : current_directory_entry_(0), - root_path_(root_path), - recursive_(recursive), - file_type_(file_type) { - // INCLUDE_DOT_DOT must not be specified if recursive. - DCHECK(!(recursive && (INCLUDE_DOT_DOT & file_type_))); - pending_paths_.push(root_path); -} - -FileEnumerator::FileEnumerator(const FilePath& root_path, - bool recursive, - int file_type, - const FilePath::StringType& pattern) - : current_directory_entry_(0), - root_path_(root_path), - recursive_(recursive), - file_type_(file_type), - pattern_(root_path.Append(pattern).value()) { - // INCLUDE_DOT_DOT must not be specified if recursive. - DCHECK(!(recursive && (INCLUDE_DOT_DOT & file_type_))); - // The Windows version of this code appends the pattern to the root_path, - // potentially only matching against items in the top-most directory. - // Do the same here. - if (pattern.empty()) - pattern_ = FilePath::StringType(); - pending_paths_.push(root_path); -} - -FileEnumerator::~FileEnumerator() { -} - -FilePath FileEnumerator::Next() { - ++current_directory_entry_; - - // While we've exhausted the entries in the current directory, do the next - while (current_directory_entry_ >= directory_entries_.size()) { - if (pending_paths_.empty()) - return FilePath(); - - root_path_ = pending_paths_.top(); - root_path_ = root_path_.StripTrailingSeparators(); - pending_paths_.pop(); - - std::vector entries; - if (!ReadDirectory(&entries, root_path_, file_type_ & SHOW_SYM_LINKS)) - continue; - - directory_entries_.clear(); - current_directory_entry_ = 0; - for (std::vector::const_iterator i = entries.begin(); - i != entries.end(); ++i) { - FilePath full_path = root_path_.Append(i->filename_); - if (ShouldSkip(full_path)) - continue; - - if (pattern_.size() && - fnmatch(pattern_.c_str(), full_path.value().c_str(), FNM_NOESCAPE)) - continue; - - if (recursive_ && S_ISDIR(i->stat_.st_mode)) - pending_paths_.push(full_path); - - if ((S_ISDIR(i->stat_.st_mode) && (file_type_ & DIRECTORIES)) || - (!S_ISDIR(i->stat_.st_mode) && (file_type_ & FILES))) - directory_entries_.push_back(*i); - } - } - - return root_path_.Append( - directory_entries_[current_directory_entry_].filename_); -} - -FileEnumerator::FileInfo FileEnumerator::GetInfo() const { - return directory_entries_[current_directory_entry_]; -} - -bool FileEnumerator::ReadDirectory(std::vector* entries, - const FilePath& source, bool show_links) { - base::ThreadRestrictions::AssertIOAllowed(); - DIR* dir = opendir(source.value().c_str()); - if (!dir) - return false; - -#if !defined(OS_LINUX) && !defined(OS_MACOSX) && !defined(OS_BSD) && \ - !defined(OS_SOLARIS) && !defined(OS_ANDROID) - #error Port warning: depending on the definition of struct dirent, \ - additional space for pathname may be needed -#endif - - struct dirent dent_buf; - struct dirent* dent; - while (readdir_r(dir, &dent_buf, &dent) == 0 && dent) { - FileInfo info; - info.filename_ = FilePath(dent->d_name); - - FilePath full_name = source.Append(dent->d_name); - int ret; - if (show_links) - ret = lstat(full_name.value().c_str(), &info.stat_); - else - ret = stat(full_name.value().c_str(), &info.stat_); - if (ret < 0) { - // Print the stat() error message unless it was ENOENT and we're - // following symlinks. - if (!(errno == ENOENT && !show_links)) { - DPLOG(ERROR) << "Couldn't stat " - << source.Append(dent->d_name).value(); - } - memset(&info.stat_, 0, sizeof(info.stat_)); - } - entries->push_back(info); - } - - closedir(dir); - return true; -} - -} // namespace base diff --git a/base/files/file_enumerator_win.cc b/base/files/file_enumerator_win.cc deleted file mode 100644 index e47f5421a7..0000000000 --- a/base/files/file_enumerator_win.cc +++ /dev/null @@ -1,151 +0,0 @@ -// Copyright (c) 2013 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "base/files/file_enumerator.h" - -#include - -#include "base/logging.h" -#include "base/threading/thread_restrictions.h" - -namespace base { - -// FileEnumerator::FileInfo ---------------------------------------------------- - -FileEnumerator::FileInfo::FileInfo() { - memset(&find_data_, 0, sizeof(find_data_)); -} - -bool FileEnumerator::FileInfo::IsDirectory() const { - return (find_data_.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) != 0; -} - -FilePath FileEnumerator::FileInfo::GetName() const { - return FilePath(find_data_.cFileName); -} - -int64 FileEnumerator::FileInfo::GetSize() const { - ULARGE_INTEGER size; - size.HighPart = find_data_.nFileSizeHigh; - size.LowPart = find_data_.nFileSizeLow; - DCHECK_LE(size.QuadPart, std::numeric_limits::max()); - return static_cast(size.QuadPart); -} - -base::Time FileEnumerator::FileInfo::GetLastModifiedTime() const { - return base::Time::FromFileTime(find_data_.ftLastWriteTime); -} - -// FileEnumerator -------------------------------------------------------------- - -FileEnumerator::FileEnumerator(const FilePath& root_path, - bool recursive, - int file_type) - : recursive_(recursive), - file_type_(file_type), - has_find_data_(false), - find_handle_(INVALID_HANDLE_VALUE) { - // INCLUDE_DOT_DOT must not be specified if recursive. - DCHECK(!(recursive && (INCLUDE_DOT_DOT & file_type_))); - memset(&find_data_, 0, sizeof(find_data_)); - pending_paths_.push(root_path); -} - -FileEnumerator::FileEnumerator(const FilePath& root_path, - bool recursive, - int file_type, - const FilePath::StringType& pattern) - : recursive_(recursive), - file_type_(file_type), - has_find_data_(false), - pattern_(pattern), - find_handle_(INVALID_HANDLE_VALUE) { - // INCLUDE_DOT_DOT must not be specified if recursive. - DCHECK(!(recursive && (INCLUDE_DOT_DOT & file_type_))); - memset(&find_data_, 0, sizeof(find_data_)); - pending_paths_.push(root_path); -} - -FileEnumerator::~FileEnumerator() { - if (find_handle_ != INVALID_HANDLE_VALUE) - FindClose(find_handle_); -} - -FileEnumerator::FileInfo FileEnumerator::GetInfo() const { - if (!has_find_data_) { - NOTREACHED(); - return FileInfo(); - } - FileInfo ret; - memcpy(&ret.find_data_, &find_data_, sizeof(find_data_)); - return ret; -} - -FilePath FileEnumerator::Next() { - base::ThreadRestrictions::AssertIOAllowed(); - - while (has_find_data_ || !pending_paths_.empty()) { - if (!has_find_data_) { - // The last find FindFirstFile operation is done, prepare a new one. - root_path_ = pending_paths_.top(); - pending_paths_.pop(); - - // Start a new find operation. - FilePath src = root_path_; - - if (pattern_.empty()) - src = src.Append(L"*"); // No pattern = match everything. - else - src = src.Append(pattern_); - - find_handle_ = FindFirstFile(src.value().c_str(), &find_data_); - has_find_data_ = true; - } else { - // Search for the next file/directory. - if (!FindNextFile(find_handle_, &find_data_)) { - FindClose(find_handle_); - find_handle_ = INVALID_HANDLE_VALUE; - } - } - - if (INVALID_HANDLE_VALUE == find_handle_) { - has_find_data_ = false; - - // This is reached when we have finished a directory and are advancing to - // the next one in the queue. We applied the pattern (if any) to the files - // in the root search directory, but for those directories which were - // matched, we want to enumerate all files inside them. This will happen - // when the handle is empty. - pattern_ = FilePath::StringType(); - - continue; - } - - FilePath cur_file(find_data_.cFileName); - if (ShouldSkip(cur_file)) - continue; - - // Construct the absolute filename. - cur_file = root_path_.Append(find_data_.cFileName); - - if (find_data_.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) { - if (recursive_) { - // If |cur_file| is a directory, and we are doing recursive searching, - // add it to pending_paths_ so we scan it after we finish scanning this - // directory. However, don't do recursion through reparse points or we - // may end up with an infinite cycle. - if (!(find_data_.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT)) - pending_paths_.push(cur_file); - } - if (file_type_ & FileEnumerator::DIRECTORIES) - return cur_file; - } else if (file_type_ & FileEnumerator::FILES) { - return cur_file; - } - } - - return FilePath(); -} - -} // namespace base diff --git a/base/files/file_path.cc b/base/files/file_path.cc deleted file mode 100644 index be34634293..0000000000 --- a/base/files/file_path.cc +++ /dev/null @@ -1,1300 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "base/files/file_path.h" - -#include -#include - -#include "base/basictypes.h" -#include "base/logging.h" -#include "base/pickle.h" - -// These includes are just for the *Hack functions, and should be removed -// when those functions are removed. -#include "base/strings/string_piece.h" -#include "base/strings/string_util.h" -#include "base/strings/sys_string_conversions.h" -#include "base/strings/utf_string_conversions.h" - -#if defined(OS_MACOSX) -#include "base/mac/scoped_cftyperef.h" -#include "base/third_party/icu/icu_utf.h" -#endif - -#if defined(OS_WIN) -#include -#elif defined(OS_MACOSX) -#include -#endif - -namespace base { - -typedef FilePath::StringType StringType; - -namespace { - -const char* kCommonDoubleExtensionSuffixes[] = { "gz", "z", "bz2" }; -const char* kCommonDoubleExtensions[] = { "user.js" }; - -const FilePath::CharType kStringTerminator = FILE_PATH_LITERAL('\0'); - -// If this FilePath contains a drive letter specification, returns the -// position of the last character of the drive letter specification, -// otherwise returns npos. This can only be true on Windows, when a pathname -// begins with a letter followed by a colon. On other platforms, this always -// returns npos. -StringType::size_type FindDriveLetter(const StringType& path) { -#if defined(FILE_PATH_USES_DRIVE_LETTERS) - // This is dependent on an ASCII-based character set, but that's a - // reasonable assumption. iswalpha can be too inclusive here. - if (path.length() >= 2 && path[1] == L':' && - ((path[0] >= L'A' && path[0] <= L'Z') || - (path[0] >= L'a' && path[0] <= L'z'))) { - return 1; - } -#endif // FILE_PATH_USES_DRIVE_LETTERS - return StringType::npos; -} - -#if defined(FILE_PATH_USES_DRIVE_LETTERS) -bool EqualDriveLetterCaseInsensitive(const StringType& a, - const StringType& b) { - size_t a_letter_pos = FindDriveLetter(a); - size_t b_letter_pos = FindDriveLetter(b); - - if (a_letter_pos == StringType::npos || b_letter_pos == StringType::npos) - return a == b; - - StringType a_letter(a.substr(0, a_letter_pos + 1)); - StringType b_letter(b.substr(0, b_letter_pos + 1)); - if (!StartsWith(a_letter, b_letter, false)) - return false; - - StringType a_rest(a.substr(a_letter_pos + 1)); - StringType b_rest(b.substr(b_letter_pos + 1)); - return a_rest == b_rest; -} -#endif // defined(FILE_PATH_USES_DRIVE_LETTERS) - -bool IsPathAbsolute(const StringType& path) { -#if defined(FILE_PATH_USES_DRIVE_LETTERS) - StringType::size_type letter = FindDriveLetter(path); - if (letter != StringType::npos) { - // Look for a separator right after the drive specification. - return path.length() > letter + 1 && - FilePath::IsSeparator(path[letter + 1]); - } - // Look for a pair of leading separators. - return path.length() > 1 && - FilePath::IsSeparator(path[0]) && FilePath::IsSeparator(path[1]); -#else // FILE_PATH_USES_DRIVE_LETTERS - // Look for a separator in the first position. - return path.length() > 0 && FilePath::IsSeparator(path[0]); -#endif // FILE_PATH_USES_DRIVE_LETTERS -} - -bool AreAllSeparators(const StringType& input) { - for (StringType::const_iterator it = input.begin(); - it != input.end(); ++it) { - if (!FilePath::IsSeparator(*it)) - return false; - } - - return true; -} - -// Find the position of the '.' that separates the extension from the rest -// of the file name. The position is relative to BaseName(), not value(). -// This allows a second extension component of up to 4 characters when the -// rightmost extension component is a common double extension (gz, bz2, Z). -// For example, foo.tar.gz or foo.tar.Z would have extension components of -// '.tar.gz' and '.tar.Z' respectively. Returns npos if it can't find an -// extension. -StringType::size_type ExtensionSeparatorPosition(const StringType& path) { - // Special case "." and ".." - if (path == FilePath::kCurrentDirectory || path == FilePath::kParentDirectory) - return StringType::npos; - - const StringType::size_type last_dot = - path.rfind(FilePath::kExtensionSeparator); - - // No extension, or the extension is the whole filename. - if (last_dot == StringType::npos || last_dot == 0U) - return last_dot; - - const StringType::size_type penultimate_dot = - path.rfind(FilePath::kExtensionSeparator, last_dot - 1); - const StringType::size_type last_separator = - path.find_last_of(FilePath::kSeparators, last_dot - 1, - FilePath::kSeparatorsLength - 1); - - if (penultimate_dot == StringType::npos || - (last_separator != StringType::npos && - penultimate_dot < last_separator)) { - return last_dot; - } - - for (size_t i = 0; i < arraysize(kCommonDoubleExtensions); ++i) { - StringType extension(path, penultimate_dot + 1); - if (LowerCaseEqualsASCII(extension, kCommonDoubleExtensions[i])) - return penultimate_dot; - } - - StringType extension(path, last_dot + 1); - for (size_t i = 0; i < arraysize(kCommonDoubleExtensionSuffixes); ++i) { - if (LowerCaseEqualsASCII(extension, kCommonDoubleExtensionSuffixes[i])) { - if ((last_dot - penultimate_dot) <= 5U && - (last_dot - penultimate_dot) > 1U) { - return penultimate_dot; - } - } - } - - return last_dot; -} - -// Returns true if path is "", ".", or "..". -bool IsEmptyOrSpecialCase(const StringType& path) { - // Special cases "", ".", and ".." - if (path.empty() || path == FilePath::kCurrentDirectory || - path == FilePath::kParentDirectory) { - return true; - } - - return false; -} - -} // namespace - -FilePath::FilePath() { -} - -FilePath::FilePath(const FilePath& that) : path_(that.path_) { -} - -FilePath::FilePath(const StringType& path) : path_(path) { - StringType::size_type nul_pos = path_.find(kStringTerminator); - if (nul_pos != StringType::npos) - path_.erase(nul_pos, StringType::npos); -} - -FilePath::~FilePath() { -} - -FilePath& FilePath::operator=(const FilePath& that) { - path_ = that.path_; - return *this; -} - -bool FilePath::operator==(const FilePath& that) const { -#if defined(FILE_PATH_USES_DRIVE_LETTERS) - return EqualDriveLetterCaseInsensitive(this->path_, that.path_); -#else // defined(FILE_PATH_USES_DRIVE_LETTERS) - return path_ == that.path_; -#endif // defined(FILE_PATH_USES_DRIVE_LETTERS) -} - -bool FilePath::operator!=(const FilePath& that) const { -#if defined(FILE_PATH_USES_DRIVE_LETTERS) - return !EqualDriveLetterCaseInsensitive(this->path_, that.path_); -#else // defined(FILE_PATH_USES_DRIVE_LETTERS) - return path_ != that.path_; -#endif // defined(FILE_PATH_USES_DRIVE_LETTERS) -} - -// static -bool FilePath::IsSeparator(CharType character) { - for (size_t i = 0; i < kSeparatorsLength - 1; ++i) { - if (character == kSeparators[i]) { - return true; - } - } - - return false; -} - -void FilePath::GetComponents(std::vector* components) const { - DCHECK(components); - if (!components) - return; - components->clear(); - if (value().empty()) - return; - - std::vector ret_val; - FilePath current = *this; - FilePath base; - - // Capture path components. - while (current != current.DirName()) { - base = current.BaseName(); - if (!AreAllSeparators(base.value())) - ret_val.push_back(base.value()); - current = current.DirName(); - } - - // Capture root, if any. - base = current.BaseName(); - if (!base.value().empty() && base.value() != kCurrentDirectory) - ret_val.push_back(current.BaseName().value()); - - // Capture drive letter, if any. - FilePath dir = current.DirName(); - StringType::size_type letter = FindDriveLetter(dir.value()); - if (letter != StringType::npos) { - ret_val.push_back(StringType(dir.value(), 0, letter + 1)); - } - - *components = std::vector(ret_val.rbegin(), ret_val.rend()); -} - -bool FilePath::IsParent(const FilePath& child) const { - return AppendRelativePath(child, NULL); -} - -bool FilePath::AppendRelativePath(const FilePath& child, - FilePath* path) const { - std::vector parent_components; - std::vector child_components; - GetComponents(&parent_components); - child.GetComponents(&child_components); - - if (parent_components.empty() || - parent_components.size() >= child_components.size()) - return false; - - std::vector::const_iterator parent_comp = - parent_components.begin(); - std::vector::const_iterator child_comp = - child_components.begin(); - -#if defined(FILE_PATH_USES_DRIVE_LETTERS) - // Windows can access case sensitive filesystems, so component - // comparisions must be case sensitive, but drive letters are - // never case sensitive. - if ((FindDriveLetter(*parent_comp) != StringType::npos) && - (FindDriveLetter(*child_comp) != StringType::npos)) { - if (!StartsWith(*parent_comp, *child_comp, false)) - return false; - ++parent_comp; - ++child_comp; - } -#endif // defined(FILE_PATH_USES_DRIVE_LETTERS) - - while (parent_comp != parent_components.end()) { - if (*parent_comp != *child_comp) - return false; - ++parent_comp; - ++child_comp; - } - - if (path != NULL) { - for (; child_comp != child_components.end(); ++child_comp) { - *path = path->Append(*child_comp); - } - } - return true; -} - -// libgen's dirname and basename aren't guaranteed to be thread-safe and aren't -// guaranteed to not modify their input strings, and in fact are implemented -// differently in this regard on different platforms. Don't use them, but -// adhere to their behavior. -FilePath FilePath::DirName() const { - FilePath new_path(path_); - new_path.StripTrailingSeparatorsInternal(); - - // The drive letter, if any, always needs to remain in the output. If there - // is no drive letter, as will always be the case on platforms which do not - // support drive letters, letter will be npos, or -1, so the comparisons and - // resizes below using letter will still be valid. - StringType::size_type letter = FindDriveLetter(new_path.path_); - - StringType::size_type last_separator = - new_path.path_.find_last_of(kSeparators, StringType::npos, - kSeparatorsLength - 1); - if (last_separator == StringType::npos) { - // path_ is in the current directory. - new_path.path_.resize(letter + 1); - } else if (last_separator == letter + 1) { - // path_ is in the root directory. - new_path.path_.resize(letter + 2); - } else if (last_separator == letter + 2 && - IsSeparator(new_path.path_[letter + 1])) { - // path_ is in "//" (possibly with a drive letter); leave the double - // separator intact indicating alternate root. - new_path.path_.resize(letter + 3); - } else if (last_separator != 0) { - // path_ is somewhere else, trim the basename. - new_path.path_.resize(last_separator); - } - - new_path.StripTrailingSeparatorsInternal(); - if (!new_path.path_.length()) - new_path.path_ = kCurrentDirectory; - - return new_path; -} - -FilePath FilePath::BaseName() const { - FilePath new_path(path_); - new_path.StripTrailingSeparatorsInternal(); - - // The drive letter, if any, is always stripped. - StringType::size_type letter = FindDriveLetter(new_path.path_); - if (letter != StringType::npos) { - new_path.path_.erase(0, letter + 1); - } - - // Keep everything after the final separator, but if the pathname is only - // one character and it's a separator, leave it alone. - StringType::size_type last_separator = - new_path.path_.find_last_of(kSeparators, StringType::npos, - kSeparatorsLength - 1); - if (last_separator != StringType::npos && - last_separator < new_path.path_.length() - 1) { - new_path.path_.erase(0, last_separator + 1); - } - - return new_path; -} - -StringType FilePath::Extension() const { - FilePath base(BaseName()); - const StringType::size_type dot = ExtensionSeparatorPosition(base.path_); - if (dot == StringType::npos) - return StringType(); - - return base.path_.substr(dot, StringType::npos); -} - -FilePath FilePath::RemoveExtension() const { - if (Extension().empty()) - return *this; - - const StringType::size_type dot = ExtensionSeparatorPosition(path_); - if (dot == StringType::npos) - return *this; - - return FilePath(path_.substr(0, dot)); -} - -FilePath FilePath::InsertBeforeExtension(const StringType& suffix) const { - if (suffix.empty()) - return FilePath(path_); - - if (IsEmptyOrSpecialCase(BaseName().value())) - return FilePath(); - - StringType ext = Extension(); - StringType ret = RemoveExtension().value(); - ret.append(suffix); - ret.append(ext); - return FilePath(ret); -} - -FilePath FilePath::InsertBeforeExtensionASCII(const StringPiece& suffix) - const { - DCHECK(IsStringASCII(suffix)); -#if defined(OS_WIN) - return InsertBeforeExtension(ASCIIToUTF16(suffix.as_string())); -#elif defined(OS_POSIX) - return InsertBeforeExtension(suffix.as_string()); -#endif -} - -FilePath FilePath::AddExtension(const StringType& extension) const { - if (IsEmptyOrSpecialCase(BaseName().value())) - return FilePath(); - - // If the new extension is "" or ".", then just return the current FilePath. - if (extension.empty() || extension == StringType(1, kExtensionSeparator)) - return *this; - - StringType str = path_; - if (extension[0] != kExtensionSeparator && - *(str.end() - 1) != kExtensionSeparator) { - str.append(1, kExtensionSeparator); - } - str.append(extension); - return FilePath(str); -} - -FilePath FilePath::ReplaceExtension(const StringType& extension) const { - if (IsEmptyOrSpecialCase(BaseName().value())) - return FilePath(); - - FilePath no_ext = RemoveExtension(); - // If the new extension is "" or ".", then just remove the current extension. - if (extension.empty() || extension == StringType(1, kExtensionSeparator)) - return no_ext; - - StringType str = no_ext.value(); - if (extension[0] != kExtensionSeparator) - str.append(1, kExtensionSeparator); - str.append(extension); - return FilePath(str); -} - -bool FilePath::MatchesExtension(const StringType& extension) const { - DCHECK(extension.empty() || extension[0] == kExtensionSeparator); - - StringType current_extension = Extension(); - - if (current_extension.length() != extension.length()) - return false; - - return FilePath::CompareEqualIgnoreCase(extension, current_extension); -} - -FilePath FilePath::Append(const StringType& component) const { - const StringType* appended = &component; - StringType without_nuls; - - StringType::size_type nul_pos = component.find(kStringTerminator); - if (nul_pos != StringType::npos) { - without_nuls = component.substr(0, nul_pos); - appended = &without_nuls; - } - - DCHECK(!IsPathAbsolute(*appended)); - - if (path_.compare(kCurrentDirectory) == 0) { - // Append normally doesn't do any normalization, but as a special case, - // when appending to kCurrentDirectory, just return a new path for the - // component argument. Appending component to kCurrentDirectory would - // serve no purpose other than needlessly lengthening the path, and - // it's likely in practice to wind up with FilePath objects containing - // only kCurrentDirectory when calling DirName on a single relative path - // component. - return FilePath(*appended); - } - - FilePath new_path(path_); - new_path.StripTrailingSeparatorsInternal(); - - // Don't append a separator if the path is empty (indicating the current - // directory) or if the path component is empty (indicating nothing to - // append). - if (appended->length() > 0 && new_path.path_.length() > 0) { - // Don't append a separator if the path still ends with a trailing - // separator after stripping (indicating the root directory). - if (!IsSeparator(new_path.path_[new_path.path_.length() - 1])) { - // Don't append a separator if the path is just a drive letter. - if (FindDriveLetter(new_path.path_) + 1 != new_path.path_.length()) { - new_path.path_.append(1, kSeparators[0]); - } - } - } - - new_path.path_.append(*appended); - return new_path; -} - -FilePath FilePath::Append(const FilePath& component) const { - return Append(component.value()); -} - -FilePath FilePath::AppendASCII(const StringPiece& component) const { - DCHECK(IsStringASCII(component)); -#if defined(OS_WIN) - return Append(ASCIIToUTF16(component.as_string())); -#elif defined(OS_POSIX) - return Append(component.as_string()); -#endif -} - -bool FilePath::IsAbsolute() const { - return IsPathAbsolute(path_); -} - -bool FilePath::EndsWithSeparator() const { - if (empty()) - return false; - return IsSeparator(path_[path_.size() - 1]); -} - -FilePath FilePath::AsEndingWithSeparator() const { - if (EndsWithSeparator() || path_.empty()) - return *this; - - StringType path_str; - path_str.reserve(path_.length() + 1); // Only allocate string once. - - path_str = path_; - path_str.append(&kSeparators[0], 1); - return FilePath(path_str); -} - -FilePath FilePath::StripTrailingSeparators() const { - FilePath new_path(path_); - new_path.StripTrailingSeparatorsInternal(); - - return new_path; -} - -bool FilePath::ReferencesParent() const { - std::vector components; - GetComponents(&components); - - std::vector::const_iterator it = components.begin(); - for (; it != components.end(); ++it) { - const StringType& component = *it; - // Windows has odd, undocumented behavior with path components containing - // only whitespace and . characters. So, if all we see is . and - // whitespace, then we treat any .. sequence as referencing parent. - // For simplicity we enforce this on all platforms. - if (component.find_first_not_of(FILE_PATH_LITERAL(". \n\r\t")) == - std::string::npos && - component.find(kParentDirectory) != std::string::npos) { - return true; - } - } - return false; -} - -#if defined(OS_POSIX) -// See file_path.h for a discussion of the encoding of paths on POSIX -// platforms. These encoding conversion functions are not quite correct. - -string16 FilePath::LossyDisplayName() const { - return WideToUTF16(SysNativeMBToWide(path_)); -} - -std::string FilePath::MaybeAsASCII() const { - if (IsStringASCII(path_)) - return path_; - return std::string(); -} - -std::string FilePath::AsUTF8Unsafe() const { -#if defined(OS_MACOSX) || defined(OS_CHROMEOS) - return value(); -#else - return WideToUTF8(SysNativeMBToWide(value())); -#endif -} - -string16 FilePath::AsUTF16Unsafe() const { -#if defined(OS_MACOSX) || defined(OS_CHROMEOS) - return UTF8ToUTF16(value()); -#else - return WideToUTF16(SysNativeMBToWide(value())); -#endif -} - -// The *Hack functions are temporary while we fix the remainder of the code. -// Remember to remove the #includes at the top when you remove these. - -// static -FilePath FilePath::FromWStringHack(const std::wstring& wstring) { - return FilePath(SysWideToNativeMB(wstring)); -} - -// static -FilePath FilePath::FromUTF8Unsafe(const std::string& utf8) { -#if defined(OS_MACOSX) || defined(OS_CHROMEOS) - return FilePath(utf8); -#else - return FilePath(SysWideToNativeMB(UTF8ToWide(utf8))); -#endif -} - -// static -FilePath FilePath::FromUTF16Unsafe(const string16& utf16) { -#if defined(OS_MACOSX) || defined(OS_CHROMEOS) - return FilePath(UTF16ToUTF8(utf16)); -#else - return FilePath(SysWideToNativeMB(UTF16ToWide(utf16))); -#endif -} - -#elif defined(OS_WIN) -string16 FilePath::LossyDisplayName() const { - return path_; -} - -std::string FilePath::MaybeAsASCII() const { - if (IsStringASCII(path_)) - return WideToASCII(path_); - return ""; -} - -std::string FilePath::AsUTF8Unsafe() const { - return WideToUTF8(value()); -} - -string16 FilePath::AsUTF16Unsafe() const { - return value(); -} - -// static -FilePath FilePath::FromWStringHack(const std::wstring& wstring) { - return FilePath(wstring); -} - -// static -FilePath FilePath::FromUTF8Unsafe(const std::string& utf8) { - return FilePath(UTF8ToWide(utf8)); -} - -// static -FilePath FilePath::FromUTF16Unsafe(const string16& utf16) { - return FilePath(utf16); -} -#endif - -void FilePath::WriteToPickle(Pickle* pickle) const { -#if defined(OS_WIN) - pickle->WriteString16(path_); -#else - pickle->WriteString(path_); -#endif -} - -bool FilePath::ReadFromPickle(PickleIterator* iter) { -#if defined(OS_WIN) - if (!iter->ReadString16(&path_)) - return false; -#else - if (!iter->ReadString(&path_)) - return false; -#endif - - if (path_.find(kStringTerminator) != StringType::npos) - return false; - - return true; -} - -#if defined(OS_WIN) -// Windows specific implementation of file string comparisons - -int FilePath::CompareIgnoreCase(const StringType& string1, - const StringType& string2) { - // Perform character-wise upper case comparison rather than using the - // fully Unicode-aware CompareString(). For details see: - // http://blogs.msdn.com/michkap/archive/2005/10/17/481600.aspx - StringType::const_iterator i1 = string1.begin(); - StringType::const_iterator i2 = string2.begin(); - StringType::const_iterator string1end = string1.end(); - StringType::const_iterator string2end = string2.end(); - for ( ; i1 != string1end && i2 != string2end; ++i1, ++i2) { - wchar_t c1 = (wchar_t)LOWORD(::CharUpperW((LPWSTR)MAKELONG(*i1, 0))); - wchar_t c2 = (wchar_t)LOWORD(::CharUpperW((LPWSTR)MAKELONG(*i2, 0))); - if (c1 < c2) - return -1; - if (c1 > c2) - return 1; - } - if (i1 != string1end) - return 1; - if (i2 != string2end) - return -1; - return 0; -} - -#elif defined(OS_MACOSX) -// Mac OS X specific implementation of file string comparisons - -// cf. http://developer.apple.com/mac/library/technotes/tn/tn1150.html#UnicodeSubtleties -// -// "When using CreateTextEncoding to create a text encoding, you should set -// the TextEncodingBase to kTextEncodingUnicodeV2_0, set the -// TextEncodingVariant to kUnicodeCanonicalDecompVariant, and set the -// TextEncodingFormat to kUnicode16BitFormat. Using these values ensures that -// the Unicode will be in the same form as on an HFS Plus volume, even as the -// Unicode standard evolves." -// -// Another technical article for X 10.4 updates this: one should use -// the new (unambiguous) kUnicodeHFSPlusDecompVariant. -// cf. http://developer.apple.com/mac/library/releasenotes/TextFonts/RN-TEC/index.html -// -// This implementation uses CFStringGetFileSystemRepresentation() to get the -// decomposed form, and an adapted version of the FastUnicodeCompare as -// described in the tech note to compare the strings. - -// Character conversion table for FastUnicodeCompare() -// -// The lower case table consists of a 256-entry high-byte table followed by -// some number of 256-entry subtables. The high-byte table contains either an -// offset to the subtable for characters with that high byte or zero, which -// means that there are no case mappings or ignored characters in that block. -// Ignored characters are mapped to zero. -// -// cf. downloadable file linked in -// http://developer.apple.com/mac/library/technotes/tn/tn1150.html#StringComparisonAlgorithm - -namespace { - -const UInt16 lower_case_table[] = { - // High-byte indices ( == 0 iff no case mapping and no ignorables ) - - /* 0 */ 0x0100, 0x0200, 0x0000, 0x0300, 0x0400, 0x0500, 0x0000, 0x0000, - 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, - /* 1 */ 0x0600, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, - 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, - /* 2 */ 0x0700, 0x0800, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, - 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, - /* 3 */ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, - 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, - /* 4 */ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, - 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, - /* 5 */ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, - 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, - /* 6 */ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, - 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, - /* 7 */ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, - 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, - /* 8 */ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, - 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, - /* 9 */ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, - 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, - /* A */ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, - 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, - /* B */ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, - 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, - /* C */ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, - 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, - /* D */ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, - 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, - /* E */ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, - 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, - /* F */ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, - 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0900, 0x0A00, - - // Table 1 (for high byte 0x00) - - /* 0 */ 0xFFFF, 0x0001, 0x0002, 0x0003, 0x0004, 0x0005, 0x0006, 0x0007, - 0x0008, 0x0009, 0x000A, 0x000B, 0x000C, 0x000D, 0x000E, 0x000F, - /* 1 */ 0x0010, 0x0011, 0x0012, 0x0013, 0x0014, 0x0015, 0x0016, 0x0017, - 0x0018, 0x0019, 0x001A, 0x001B, 0x001C, 0x001D, 0x001E, 0x001F, - /* 2 */ 0x0020, 0x0021, 0x0022, 0x0023, 0x0024, 0x0025, 0x0026, 0x0027, - 0x0028, 0x0029, 0x002A, 0x002B, 0x002C, 0x002D, 0x002E, 0x002F, - /* 3 */ 0x0030, 0x0031, 0x0032, 0x0033, 0x0034, 0x0035, 0x0036, 0x0037, - 0x0038, 0x0039, 0x003A, 0x003B, 0x003C, 0x003D, 0x003E, 0x003F, - /* 4 */ 0x0040, 0x0061, 0x0062, 0x0063, 0x0064, 0x0065, 0x0066, 0x0067, - 0x0068, 0x0069, 0x006A, 0x006B, 0x006C, 0x006D, 0x006E, 0x006F, - /* 5 */ 0x0070, 0x0071, 0x0072, 0x0073, 0x0074, 0x0075, 0x0076, 0x0077, - 0x0078, 0x0079, 0x007A, 0x005B, 0x005C, 0x005D, 0x005E, 0x005F, - /* 6 */ 0x0060, 0x0061, 0x0062, 0x0063, 0x0064, 0x0065, 0x0066, 0x0067, - 0x0068, 0x0069, 0x006A, 0x006B, 0x006C, 0x006D, 0x006E, 0x006F, - /* 7 */ 0x0070, 0x0071, 0x0072, 0x0073, 0x0074, 0x0075, 0x0076, 0x0077, - 0x0078, 0x0079, 0x007A, 0x007B, 0x007C, 0x007D, 0x007E, 0x007F, - /* 8 */ 0x0080, 0x0081, 0x0082, 0x0083, 0x0084, 0x0085, 0x0086, 0x0087, - 0x0088, 0x0089, 0x008A, 0x008B, 0x008C, 0x008D, 0x008E, 0x008F, - /* 9 */ 0x0090, 0x0091, 0x0092, 0x0093, 0x0094, 0x0095, 0x0096, 0x0097, - 0x0098, 0x0099, 0x009A, 0x009B, 0x009C, 0x009D, 0x009E, 0x009F, - /* A */ 0x00A0, 0x00A1, 0x00A2, 0x00A3, 0x00A4, 0x00A5, 0x00A6, 0x00A7, - 0x00A8, 0x00A9, 0x00AA, 0x00AB, 0x00AC, 0x00AD, 0x00AE, 0x00AF, - /* B */ 0x00B0, 0x00B1, 0x00B2, 0x00B3, 0x00B4, 0x00B5, 0x00B6, 0x00B7, - 0x00B8, 0x00B9, 0x00BA, 0x00BB, 0x00BC, 0x00BD, 0x00BE, 0x00BF, - /* C */ 0x00C0, 0x00C1, 0x00C2, 0x00C3, 0x00C4, 0x00C5, 0x00E6, 0x00C7, - 0x00C8, 0x00C9, 0x00CA, 0x00CB, 0x00CC, 0x00CD, 0x00CE, 0x00CF, - /* D */ 0x00F0, 0x00D1, 0x00D2, 0x00D3, 0x00D4, 0x00D5, 0x00D6, 0x00D7, - 0x00F8, 0x00D9, 0x00DA, 0x00DB, 0x00DC, 0x00DD, 0x00FE, 0x00DF, - /* E */ 0x00E0, 0x00E1, 0x00E2, 0x00E3, 0x00E4, 0x00E5, 0x00E6, 0x00E7, - 0x00E8, 0x00E9, 0x00EA, 0x00EB, 0x00EC, 0x00ED, 0x00EE, 0x00EF, - /* F */ 0x00F0, 0x00F1, 0x00F2, 0x00F3, 0x00F4, 0x00F5, 0x00F6, 0x00F7, - 0x00F8, 0x00F9, 0x00FA, 0x00FB, 0x00FC, 0x00FD, 0x00FE, 0x00FF, - - // Table 2 (for high byte 0x01) - - /* 0 */ 0x0100, 0x0101, 0x0102, 0x0103, 0x0104, 0x0105, 0x0106, 0x0107, - 0x0108, 0x0109, 0x010A, 0x010B, 0x010C, 0x010D, 0x010E, 0x010F, - /* 1 */ 0x0111, 0x0111, 0x0112, 0x0113, 0x0114, 0x0115, 0x0116, 0x0117, - 0x0118, 0x0119, 0x011A, 0x011B, 0x011C, 0x011D, 0x011E, 0x011F, - /* 2 */ 0x0120, 0x0121, 0x0122, 0x0123, 0x0124, 0x0125, 0x0127, 0x0127, - 0x0128, 0x0129, 0x012A, 0x012B, 0x012C, 0x012D, 0x012E, 0x012F, - /* 3 */ 0x0130, 0x0131, 0x0133, 0x0133, 0x0134, 0x0135, 0x0136, 0x0137, - 0x0138, 0x0139, 0x013A, 0x013B, 0x013C, 0x013D, 0x013E, 0x0140, - /* 4 */ 0x0140, 0x0142, 0x0142, 0x0143, 0x0144, 0x0145, 0x0146, 0x0147, - 0x0148, 0x0149, 0x014B, 0x014B, 0x014C, 0x014D, 0x014E, 0x014F, - /* 5 */ 0x0150, 0x0151, 0x0153, 0x0153, 0x0154, 0x0155, 0x0156, 0x0157, - 0x0158, 0x0159, 0x015A, 0x015B, 0x015C, 0x015D, 0x015E, 0x015F, - /* 6 */ 0x0160, 0x0161, 0x0162, 0x0163, 0x0164, 0x0165, 0x0167, 0x0167, - 0x0168, 0x0169, 0x016A, 0x016B, 0x016C, 0x016D, 0x016E, 0x016F, - /* 7 */ 0x0170, 0x0171, 0x0172, 0x0173, 0x0174, 0x0175, 0x0176, 0x0177, - 0x0178, 0x0179, 0x017A, 0x017B, 0x017C, 0x017D, 0x017E, 0x017F, - /* 8 */ 0x0180, 0x0253, 0x0183, 0x0183, 0x0185, 0x0185, 0x0254, 0x0188, - 0x0188, 0x0256, 0x0257, 0x018C, 0x018C, 0x018D, 0x01DD, 0x0259, - /* 9 */ 0x025B, 0x0192, 0x0192, 0x0260, 0x0263, 0x0195, 0x0269, 0x0268, - 0x0199, 0x0199, 0x019A, 0x019B, 0x026F, 0x0272, 0x019E, 0x0275, - /* A */ 0x01A0, 0x01A1, 0x01A3, 0x01A3, 0x01A5, 0x01A5, 0x01A6, 0x01A8, - 0x01A8, 0x0283, 0x01AA, 0x01AB, 0x01AD, 0x01AD, 0x0288, 0x01AF, - /* B */ 0x01B0, 0x028A, 0x028B, 0x01B4, 0x01B4, 0x01B6, 0x01B6, 0x0292, - 0x01B9, 0x01B9, 0x01BA, 0x01BB, 0x01BD, 0x01BD, 0x01BE, 0x01BF, - /* C */ 0x01C0, 0x01C1, 0x01C2, 0x01C3, 0x01C6, 0x01C6, 0x01C6, 0x01C9, - 0x01C9, 0x01C9, 0x01CC, 0x01CC, 0x01CC, 0x01CD, 0x01CE, 0x01CF, - /* D */ 0x01D0, 0x01D1, 0x01D2, 0x01D3, 0x01D4, 0x01D5, 0x01D6, 0x01D7, - 0x01D8, 0x01D9, 0x01DA, 0x01DB, 0x01DC, 0x01DD, 0x01DE, 0x01DF, - /* E */ 0x01E0, 0x01E1, 0x01E2, 0x01E3, 0x01E5, 0x01E5, 0x01E6, 0x01E7, - 0x01E8, 0x01E9, 0x01EA, 0x01EB, 0x01EC, 0x01ED, 0x01EE, 0x01EF, - /* F */ 0x01F0, 0x01F3, 0x01F3, 0x01F3, 0x01F4, 0x01F5, 0x01F6, 0x01F7, - 0x01F8, 0x01F9, 0x01FA, 0x01FB, 0x01FC, 0x01FD, 0x01FE, 0x01FF, - - // Table 3 (for high byte 0x03) - - /* 0 */ 0x0300, 0x0301, 0x0302, 0x0303, 0x0304, 0x0305, 0x0306, 0x0307, - 0x0308, 0x0309, 0x030A, 0x030B, 0x030C, 0x030D, 0x030E, 0x030F, - /* 1 */ 0x0310, 0x0311, 0x0312, 0x0313, 0x0314, 0x0315, 0x0316, 0x0317, - 0x0318, 0x0319, 0x031A, 0x031B, 0x031C, 0x031D, 0x031E, 0x031F, - /* 2 */ 0x0320, 0x0321, 0x0322, 0x0323, 0x0324, 0x0325, 0x0326, 0x0327, - 0x0328, 0x0329, 0x032A, 0x032B, 0x032C, 0x032D, 0x032E, 0x032F, - /* 3 */ 0x0330, 0x0331, 0x0332, 0x0333, 0x0334, 0x0335, 0x0336, 0x0337, - 0x0338, 0x0339, 0x033A, 0x033B, 0x033C, 0x033D, 0x033E, 0x033F, - /* 4 */ 0x0340, 0x0341, 0x0342, 0x0343, 0x0344, 0x0345, 0x0346, 0x0347, - 0x0348, 0x0349, 0x034A, 0x034B, 0x034C, 0x034D, 0x034E, 0x034F, - /* 5 */ 0x0350, 0x0351, 0x0352, 0x0353, 0x0354, 0x0355, 0x0356, 0x0357, - 0x0358, 0x0359, 0x035A, 0x035B, 0x035C, 0x035D, 0x035E, 0x035F, - /* 6 */ 0x0360, 0x0361, 0x0362, 0x0363, 0x0364, 0x0365, 0x0366, 0x0367, - 0x0368, 0x0369, 0x036A, 0x036B, 0x036C, 0x036D, 0x036E, 0x036F, - /* 7 */ 0x0370, 0x0371, 0x0372, 0x0373, 0x0374, 0x0375, 0x0376, 0x0377, - 0x0378, 0x0379, 0x037A, 0x037B, 0x037C, 0x037D, 0x037E, 0x037F, - /* 8 */ 0x0380, 0x0381, 0x0382, 0x0383, 0x0384, 0x0385, 0x0386, 0x0387, - 0x0388, 0x0389, 0x038A, 0x038B, 0x038C, 0x038D, 0x038E, 0x038F, - /* 9 */ 0x0390, 0x03B1, 0x03B2, 0x03B3, 0x03B4, 0x03B5, 0x03B6, 0x03B7, - 0x03B8, 0x03B9, 0x03BA, 0x03BB, 0x03BC, 0x03BD, 0x03BE, 0x03BF, - /* A */ 0x03C0, 0x03C1, 0x03A2, 0x03C3, 0x03C4, 0x03C5, 0x03C6, 0x03C7, - 0x03C8, 0x03C9, 0x03AA, 0x03AB, 0x03AC, 0x03AD, 0x03AE, 0x03AF, - /* B */ 0x03B0, 0x03B1, 0x03B2, 0x03B3, 0x03B4, 0x03B5, 0x03B6, 0x03B7, - 0x03B8, 0x03B9, 0x03BA, 0x03BB, 0x03BC, 0x03BD, 0x03BE, 0x03BF, - /* C */ 0x03C0, 0x03C1, 0x03C2, 0x03C3, 0x03C4, 0x03C5, 0x03C6, 0x03C7, - 0x03C8, 0x03C9, 0x03CA, 0x03CB, 0x03CC, 0x03CD, 0x03CE, 0x03CF, - /* D */ 0x03D0, 0x03D1, 0x03D2, 0x03D3, 0x03D4, 0x03D5, 0x03D6, 0x03D7, - 0x03D8, 0x03D9, 0x03DA, 0x03DB, 0x03DC, 0x03DD, 0x03DE, 0x03DF, - /* E */ 0x03E0, 0x03E1, 0x03E3, 0x03E3, 0x03E5, 0x03E5, 0x03E7, 0x03E7, - 0x03E9, 0x03E9, 0x03EB, 0x03EB, 0x03ED, 0x03ED, 0x03EF, 0x03EF, - /* F */ 0x03F0, 0x03F1, 0x03F2, 0x03F3, 0x03F4, 0x03F5, 0x03F6, 0x03F7, - 0x03F8, 0x03F9, 0x03FA, 0x03FB, 0x03FC, 0x03FD, 0x03FE, 0x03FF, - - // Table 4 (for high byte 0x04) - - /* 0 */ 0x0400, 0x0401, 0x0452, 0x0403, 0x0454, 0x0455, 0x0456, 0x0407, - 0x0458, 0x0459, 0x045A, 0x045B, 0x040C, 0x040D, 0x040E, 0x045F, - /* 1 */ 0x0430, 0x0431, 0x0432, 0x0433, 0x0434, 0x0435, 0x0436, 0x0437, - 0x0438, 0x0419, 0x043A, 0x043B, 0x043C, 0x043D, 0x043E, 0x043F, - /* 2 */ 0x0440, 0x0441, 0x0442, 0x0443, 0x0444, 0x0445, 0x0446, 0x0447, - 0x0448, 0x0449, 0x044A, 0x044B, 0x044C, 0x044D, 0x044E, 0x044F, - /* 3 */ 0x0430, 0x0431, 0x0432, 0x0433, 0x0434, 0x0435, 0x0436, 0x0437, - 0x0438, 0x0439, 0x043A, 0x043B, 0x043C, 0x043D, 0x043E, 0x043F, - /* 4 */ 0x0440, 0x0441, 0x0442, 0x0443, 0x0444, 0x0445, 0x0446, 0x0447, - 0x0448, 0x0449, 0x044A, 0x044B, 0x044C, 0x044D, 0x044E, 0x044F, - /* 5 */ 0x0450, 0x0451, 0x0452, 0x0453, 0x0454, 0x0455, 0x0456, 0x0457, - 0x0458, 0x0459, 0x045A, 0x045B, 0x045C, 0x045D, 0x045E, 0x045F, - /* 6 */ 0x0461, 0x0461, 0x0463, 0x0463, 0x0465, 0x0465, 0x0467, 0x0467, - 0x0469, 0x0469, 0x046B, 0x046B, 0x046D, 0x046D, 0x046F, 0x046F, - /* 7 */ 0x0471, 0x0471, 0x0473, 0x0473, 0x0475, 0x0475, 0x0476, 0x0477, - 0x0479, 0x0479, 0x047B, 0x047B, 0x047D, 0x047D, 0x047F, 0x047F, - /* 8 */ 0x0481, 0x0481, 0x0482, 0x0483, 0x0484, 0x0485, 0x0486, 0x0487, - 0x0488, 0x0489, 0x048A, 0x048B, 0x048C, 0x048D, 0x048E, 0x048F, - /* 9 */ 0x0491, 0x0491, 0x0493, 0x0493, 0x0495, 0x0495, 0x0497, 0x0497, - 0x0499, 0x0499, 0x049B, 0x049B, 0x049D, 0x049D, 0x049F, 0x049F, - /* A */ 0x04A1, 0x04A1, 0x04A3, 0x04A3, 0x04A5, 0x04A5, 0x04A7, 0x04A7, - 0x04A9, 0x04A9, 0x04AB, 0x04AB, 0x04AD, 0x04AD, 0x04AF, 0x04AF, - /* B */ 0x04B1, 0x04B1, 0x04B3, 0x04B3, 0x04B5, 0x04B5, 0x04B7, 0x04B7, - 0x04B9, 0x04B9, 0x04BB, 0x04BB, 0x04BD, 0x04BD, 0x04BF, 0x04BF, - /* C */ 0x04C0, 0x04C1, 0x04C2, 0x04C4, 0x04C4, 0x04C5, 0x04C6, 0x04C8, - 0x04C8, 0x04C9, 0x04CA, 0x04CC, 0x04CC, 0x04CD, 0x04CE, 0x04CF, - /* D */ 0x04D0, 0x04D1, 0x04D2, 0x04D3, 0x04D4, 0x04D5, 0x04D6, 0x04D7, - 0x04D8, 0x04D9, 0x04DA, 0x04DB, 0x04DC, 0x04DD, 0x04DE, 0x04DF, - /* E */ 0x04E0, 0x04E1, 0x04E2, 0x04E3, 0x04E4, 0x04E5, 0x04E6, 0x04E7, - 0x04E8, 0x04E9, 0x04EA, 0x04EB, 0x04EC, 0x04ED, 0x04EE, 0x04EF, - /* F */ 0x04F0, 0x04F1, 0x04F2, 0x04F3, 0x04F4, 0x04F5, 0x04F6, 0x04F7, - 0x04F8, 0x04F9, 0x04FA, 0x04FB, 0x04FC, 0x04FD, 0x04FE, 0x04FF, - - // Table 5 (for high byte 0x05) - - /* 0 */ 0x0500, 0x0501, 0x0502, 0x0503, 0x0504, 0x0505, 0x0506, 0x0507, - 0x0508, 0x0509, 0x050A, 0x050B, 0x050C, 0x050D, 0x050E, 0x050F, - /* 1 */ 0x0510, 0x0511, 0x0512, 0x0513, 0x0514, 0x0515, 0x0516, 0x0517, - 0x0518, 0x0519, 0x051A, 0x051B, 0x051C, 0x051D, 0x051E, 0x051F, - /* 2 */ 0x0520, 0x0521, 0x0522, 0x0523, 0x0524, 0x0525, 0x0526, 0x0527, - 0x0528, 0x0529, 0x052A, 0x052B, 0x052C, 0x052D, 0x052E, 0x052F, - /* 3 */ 0x0530, 0x0561, 0x0562, 0x0563, 0x0564, 0x0565, 0x0566, 0x0567, - 0x0568, 0x0569, 0x056A, 0x056B, 0x056C, 0x056D, 0x056E, 0x056F, - /* 4 */ 0x0570, 0x0571, 0x0572, 0x0573, 0x0574, 0x0575, 0x0576, 0x0577, - 0x0578, 0x0579, 0x057A, 0x057B, 0x057C, 0x057D, 0x057E, 0x057F, - /* 5 */ 0x0580, 0x0581, 0x0582, 0x0583, 0x0584, 0x0585, 0x0586, 0x0557, - 0x0558, 0x0559, 0x055A, 0x055B, 0x055C, 0x055D, 0x055E, 0x055F, - /* 6 */ 0x0560, 0x0561, 0x0562, 0x0563, 0x0564, 0x0565, 0x0566, 0x0567, - 0x0568, 0x0569, 0x056A, 0x056B, 0x056C, 0x056D, 0x056E, 0x056F, - /* 7 */ 0x0570, 0x0571, 0x0572, 0x0573, 0x0574, 0x0575, 0x0576, 0x0577, - 0x0578, 0x0579, 0x057A, 0x057B, 0x057C, 0x057D, 0x057E, 0x057F, - /* 8 */ 0x0580, 0x0581, 0x0582, 0x0583, 0x0584, 0x0585, 0x0586, 0x0587, - 0x0588, 0x0589, 0x058A, 0x058B, 0x058C, 0x058D, 0x058E, 0x058F, - /* 9 */ 0x0590, 0x0591, 0x0592, 0x0593, 0x0594, 0x0595, 0x0596, 0x0597, - 0x0598, 0x0599, 0x059A, 0x059B, 0x059C, 0x059D, 0x059E, 0x059F, - /* A */ 0x05A0, 0x05A1, 0x05A2, 0x05A3, 0x05A4, 0x05A5, 0x05A6, 0x05A7, - 0x05A8, 0x05A9, 0x05AA, 0x05AB, 0x05AC, 0x05AD, 0x05AE, 0x05AF, - /* B */ 0x05B0, 0x05B1, 0x05B2, 0x05B3, 0x05B4, 0x05B5, 0x05B6, 0x05B7, - 0x05B8, 0x05B9, 0x05BA, 0x05BB, 0x05BC, 0x05BD, 0x05BE, 0x05BF, - /* C */ 0x05C0, 0x05C1, 0x05C2, 0x05C3, 0x05C4, 0x05C5, 0x05C6, 0x05C7, - 0x05C8, 0x05C9, 0x05CA, 0x05CB, 0x05CC, 0x05CD, 0x05CE, 0x05CF, - /* D */ 0x05D0, 0x05D1, 0x05D2, 0x05D3, 0x05D4, 0x05D5, 0x05D6, 0x05D7, - 0x05D8, 0x05D9, 0x05DA, 0x05DB, 0x05DC, 0x05DD, 0x05DE, 0x05DF, - /* E */ 0x05E0, 0x05E1, 0x05E2, 0x05E3, 0x05E4, 0x05E5, 0x05E6, 0x05E7, - 0x05E8, 0x05E9, 0x05EA, 0x05EB, 0x05EC, 0x05ED, 0x05EE, 0x05EF, - /* F */ 0x05F0, 0x05F1, 0x05F2, 0x05F3, 0x05F4, 0x05F5, 0x05F6, 0x05F7, - 0x05F8, 0x05F9, 0x05FA, 0x05FB, 0x05FC, 0x05FD, 0x05FE, 0x05FF, - - // Table 6 (for high byte 0x10) - - /* 0 */ 0x1000, 0x1001, 0x1002, 0x1003, 0x1004, 0x1005, 0x1006, 0x1007, - 0x1008, 0x1009, 0x100A, 0x100B, 0x100C, 0x100D, 0x100E, 0x100F, - /* 1 */ 0x1010, 0x1011, 0x1012, 0x1013, 0x1014, 0x1015, 0x1016, 0x1017, - 0x1018, 0x1019, 0x101A, 0x101B, 0x101C, 0x101D, 0x101E, 0x101F, - /* 2 */ 0x1020, 0x1021, 0x1022, 0x1023, 0x1024, 0x1025, 0x1026, 0x1027, - 0x1028, 0x1029, 0x102A, 0x102B, 0x102C, 0x102D, 0x102E, 0x102F, - /* 3 */ 0x1030, 0x1031, 0x1032, 0x1033, 0x1034, 0x1035, 0x1036, 0x1037, - 0x1038, 0x1039, 0x103A, 0x103B, 0x103C, 0x103D, 0x103E, 0x103F, - /* 4 */ 0x1040, 0x1041, 0x1042, 0x1043, 0x1044, 0x1045, 0x1046, 0x1047, - 0x1048, 0x1049, 0x104A, 0x104B, 0x104C, 0x104D, 0x104E, 0x104F, - /* 5 */ 0x1050, 0x1051, 0x1052, 0x1053, 0x1054, 0x1055, 0x1056, 0x1057, - 0x1058, 0x1059, 0x105A, 0x105B, 0x105C, 0x105D, 0x105E, 0x105F, - /* 6 */ 0x1060, 0x1061, 0x1062, 0x1063, 0x1064, 0x1065, 0x1066, 0x1067, - 0x1068, 0x1069, 0x106A, 0x106B, 0x106C, 0x106D, 0x106E, 0x106F, - /* 7 */ 0x1070, 0x1071, 0x1072, 0x1073, 0x1074, 0x1075, 0x1076, 0x1077, - 0x1078, 0x1079, 0x107A, 0x107B, 0x107C, 0x107D, 0x107E, 0x107F, - /* 8 */ 0x1080, 0x1081, 0x1082, 0x1083, 0x1084, 0x1085, 0x1086, 0x1087, - 0x1088, 0x1089, 0x108A, 0x108B, 0x108C, 0x108D, 0x108E, 0x108F, - /* 9 */ 0x1090, 0x1091, 0x1092, 0x1093, 0x1094, 0x1095, 0x1096, 0x1097, - 0x1098, 0x1099, 0x109A, 0x109B, 0x109C, 0x109D, 0x109E, 0x109F, - /* A */ 0x10D0, 0x10D1, 0x10D2, 0x10D3, 0x10D4, 0x10D5, 0x10D6, 0x10D7, - 0x10D8, 0x10D9, 0x10DA, 0x10DB, 0x10DC, 0x10DD, 0x10DE, 0x10DF, - /* B */ 0x10E0, 0x10E1, 0x10E2, 0x10E3, 0x10E4, 0x10E5, 0x10E6, 0x10E7, - 0x10E8, 0x10E9, 0x10EA, 0x10EB, 0x10EC, 0x10ED, 0x10EE, 0x10EF, - /* C */ 0x10F0, 0x10F1, 0x10F2, 0x10F3, 0x10F4, 0x10F5, 0x10C6, 0x10C7, - 0x10C8, 0x10C9, 0x10CA, 0x10CB, 0x10CC, 0x10CD, 0x10CE, 0x10CF, - /* D */ 0x10D0, 0x10D1, 0x10D2, 0x10D3, 0x10D4, 0x10D5, 0x10D6, 0x10D7, - 0x10D8, 0x10D9, 0x10DA, 0x10DB, 0x10DC, 0x10DD, 0x10DE, 0x10DF, - /* E */ 0x10E0, 0x10E1, 0x10E2, 0x10E3, 0x10E4, 0x10E5, 0x10E6, 0x10E7, - 0x10E8, 0x10E9, 0x10EA, 0x10EB, 0x10EC, 0x10ED, 0x10EE, 0x10EF, - /* F */ 0x10F0, 0x10F1, 0x10F2, 0x10F3, 0x10F4, 0x10F5, 0x10F6, 0x10F7, - 0x10F8, 0x10F9, 0x10FA, 0x10FB, 0x10FC, 0x10FD, 0x10FE, 0x10FF, - - // Table 7 (for high byte 0x20) - - /* 0 */ 0x2000, 0x2001, 0x2002, 0x2003, 0x2004, 0x2005, 0x2006, 0x2007, - 0x2008, 0x2009, 0x200A, 0x200B, 0x0000, 0x0000, 0x0000, 0x0000, - /* 1 */ 0x2010, 0x2011, 0x2012, 0x2013, 0x2014, 0x2015, 0x2016, 0x2017, - 0x2018, 0x2019, 0x201A, 0x201B, 0x201C, 0x201D, 0x201E, 0x201F, - /* 2 */ 0x2020, 0x2021, 0x2022, 0x2023, 0x2024, 0x2025, 0x2026, 0x2027, - 0x2028, 0x2029, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x202F, - /* 3 */ 0x2030, 0x2031, 0x2032, 0x2033, 0x2034, 0x2035, 0x2036, 0x2037, - 0x2038, 0x2039, 0x203A, 0x203B, 0x203C, 0x203D, 0x203E, 0x203F, - /* 4 */ 0x2040, 0x2041, 0x2042, 0x2043, 0x2044, 0x2045, 0x2046, 0x2047, - 0x2048, 0x2049, 0x204A, 0x204B, 0x204C, 0x204D, 0x204E, 0x204F, - /* 5 */ 0x2050, 0x2051, 0x2052, 0x2053, 0x2054, 0x2055, 0x2056, 0x2057, - 0x2058, 0x2059, 0x205A, 0x205B, 0x205C, 0x205D, 0x205E, 0x205F, - /* 6 */ 0x2060, 0x2061, 0x2062, 0x2063, 0x2064, 0x2065, 0x2066, 0x2067, - 0x2068, 0x2069, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, - /* 7 */ 0x2070, 0x2071, 0x2072, 0x2073, 0x2074, 0x2075, 0x2076, 0x2077, - 0x2078, 0x2079, 0x207A, 0x207B, 0x207C, 0x207D, 0x207E, 0x207F, - /* 8 */ 0x2080, 0x2081, 0x2082, 0x2083, 0x2084, 0x2085, 0x2086, 0x2087, - 0x2088, 0x2089, 0x208A, 0x208B, 0x208C, 0x208D, 0x208E, 0x208F, - /* 9 */ 0x2090, 0x2091, 0x2092, 0x2093, 0x2094, 0x2095, 0x2096, 0x2097, - 0x2098, 0x2099, 0x209A, 0x209B, 0x209C, 0x209D, 0x209E, 0x209F, - /* A */ 0x20A0, 0x20A1, 0x20A2, 0x20A3, 0x20A4, 0x20A5, 0x20A6, 0x20A7, - 0x20A8, 0x20A9, 0x20AA, 0x20AB, 0x20AC, 0x20AD, 0x20AE, 0x20AF, - /* B */ 0x20B0, 0x20B1, 0x20B2, 0x20B3, 0x20B4, 0x20B5, 0x20B6, 0x20B7, - 0x20B8, 0x20B9, 0x20BA, 0x20BB, 0x20BC, 0x20BD, 0x20BE, 0x20BF, - /* C */ 0x20C0, 0x20C1, 0x20C2, 0x20C3, 0x20C4, 0x20C5, 0x20C6, 0x20C7, - 0x20C8, 0x20C9, 0x20CA, 0x20CB, 0x20CC, 0x20CD, 0x20CE, 0x20CF, - /* D */ 0x20D0, 0x20D1, 0x20D2, 0x20D3, 0x20D4, 0x20D5, 0x20D6, 0x20D7, - 0x20D8, 0x20D9, 0x20DA, 0x20DB, 0x20DC, 0x20DD, 0x20DE, 0x20DF, - /* E */ 0x20E0, 0x20E1, 0x20E2, 0x20E3, 0x20E4, 0x20E5, 0x20E6, 0x20E7, - 0x20E8, 0x20E9, 0x20EA, 0x20EB, 0x20EC, 0x20ED, 0x20EE, 0x20EF, - /* F */ 0x20F0, 0x20F1, 0x20F2, 0x20F3, 0x20F4, 0x20F5, 0x20F6, 0x20F7, - 0x20F8, 0x20F9, 0x20FA, 0x20FB, 0x20FC, 0x20FD, 0x20FE, 0x20FF, - - // Table 8 (for high byte 0x21) - - /* 0 */ 0x2100, 0x2101, 0x2102, 0x2103, 0x2104, 0x2105, 0x2106, 0x2107, - 0x2108, 0x2109, 0x210A, 0x210B, 0x210C, 0x210D, 0x210E, 0x210F, - /* 1 */ 0x2110, 0x2111, 0x2112, 0x2113, 0x2114, 0x2115, 0x2116, 0x2117, - 0x2118, 0x2119, 0x211A, 0x211B, 0x211C, 0x211D, 0x211E, 0x211F, - /* 2 */ 0x2120, 0x2121, 0x2122, 0x2123, 0x2124, 0x2125, 0x2126, 0x2127, - 0x2128, 0x2129, 0x212A, 0x212B, 0x212C, 0x212D, 0x212E, 0x212F, - /* 3 */ 0x2130, 0x2131, 0x2132, 0x2133, 0x2134, 0x2135, 0x2136, 0x2137, - 0x2138, 0x2139, 0x213A, 0x213B, 0x213C, 0x213D, 0x213E, 0x213F, - /* 4 */ 0x2140, 0x2141, 0x2142, 0x2143, 0x2144, 0x2145, 0x2146, 0x2147, - 0x2148, 0x2149, 0x214A, 0x214B, 0x214C, 0x214D, 0x214E, 0x214F, - /* 5 */ 0x2150, 0x2151, 0x2152, 0x2153, 0x2154, 0x2155, 0x2156, 0x2157, - 0x2158, 0x2159, 0x215A, 0x215B, 0x215C, 0x215D, 0x215E, 0x215F, - /* 6 */ 0x2170, 0x2171, 0x2172, 0x2173, 0x2174, 0x2175, 0x2176, 0x2177, - 0x2178, 0x2179, 0x217A, 0x217B, 0x217C, 0x217D, 0x217E, 0x217F, - /* 7 */ 0x2170, 0x2171, 0x2172, 0x2173, 0x2174, 0x2175, 0x2176, 0x2177, - 0x2178, 0x2179, 0x217A, 0x217B, 0x217C, 0x217D, 0x217E, 0x217F, - /* 8 */ 0x2180, 0x2181, 0x2182, 0x2183, 0x2184, 0x2185, 0x2186, 0x2187, - 0x2188, 0x2189, 0x218A, 0x218B, 0x218C, 0x218D, 0x218E, 0x218F, - /* 9 */ 0x2190, 0x2191, 0x2192, 0x2193, 0x2194, 0x2195, 0x2196, 0x2197, - 0x2198, 0x2199, 0x219A, 0x219B, 0x219C, 0x219D, 0x219E, 0x219F, - /* A */ 0x21A0, 0x21A1, 0x21A2, 0x21A3, 0x21A4, 0x21A5, 0x21A6, 0x21A7, - 0x21A8, 0x21A9, 0x21AA, 0x21AB, 0x21AC, 0x21AD, 0x21AE, 0x21AF, - /* B */ 0x21B0, 0x21B1, 0x21B2, 0x21B3, 0x21B4, 0x21B5, 0x21B6, 0x21B7, - 0x21B8, 0x21B9, 0x21BA, 0x21BB, 0x21BC, 0x21BD, 0x21BE, 0x21BF, - /* C */ 0x21C0, 0x21C1, 0x21C2, 0x21C3, 0x21C4, 0x21C5, 0x21C6, 0x21C7, - 0x21C8, 0x21C9, 0x21CA, 0x21CB, 0x21CC, 0x21CD, 0x21CE, 0x21CF, - /* D */ 0x21D0, 0x21D1, 0x21D2, 0x21D3, 0x21D4, 0x21D5, 0x21D6, 0x21D7, - 0x21D8, 0x21D9, 0x21DA, 0x21DB, 0x21DC, 0x21DD, 0x21DE, 0x21DF, - /* E */ 0x21E0, 0x21E1, 0x21E2, 0x21E3, 0x21E4, 0x21E5, 0x21E6, 0x21E7, - 0x21E8, 0x21E9, 0x21EA, 0x21EB, 0x21EC, 0x21ED, 0x21EE, 0x21EF, - /* F */ 0x21F0, 0x21F1, 0x21F2, 0x21F3, 0x21F4, 0x21F5, 0x21F6, 0x21F7, - 0x21F8, 0x21F9, 0x21FA, 0x21FB, 0x21FC, 0x21FD, 0x21FE, 0x21FF, - - // Table 9 (for high byte 0xFE) - - /* 0 */ 0xFE00, 0xFE01, 0xFE02, 0xFE03, 0xFE04, 0xFE05, 0xFE06, 0xFE07, - 0xFE08, 0xFE09, 0xFE0A, 0xFE0B, 0xFE0C, 0xFE0D, 0xFE0E, 0xFE0F, - /* 1 */ 0xFE10, 0xFE11, 0xFE12, 0xFE13, 0xFE14, 0xFE15, 0xFE16, 0xFE17, - 0xFE18, 0xFE19, 0xFE1A, 0xFE1B, 0xFE1C, 0xFE1D, 0xFE1E, 0xFE1F, - /* 2 */ 0xFE20, 0xFE21, 0xFE22, 0xFE23, 0xFE24, 0xFE25, 0xFE26, 0xFE27, - 0xFE28, 0xFE29, 0xFE2A, 0xFE2B, 0xFE2C, 0xFE2D, 0xFE2E, 0xFE2F, - /* 3 */ 0xFE30, 0xFE31, 0xFE32, 0xFE33, 0xFE34, 0xFE35, 0xFE36, 0xFE37, - 0xFE38, 0xFE39, 0xFE3A, 0xFE3B, 0xFE3C, 0xFE3D, 0xFE3E, 0xFE3F, - /* 4 */ 0xFE40, 0xFE41, 0xFE42, 0xFE43, 0xFE44, 0xFE45, 0xFE46, 0xFE47, - 0xFE48, 0xFE49, 0xFE4A, 0xFE4B, 0xFE4C, 0xFE4D, 0xFE4E, 0xFE4F, - /* 5 */ 0xFE50, 0xFE51, 0xFE52, 0xFE53, 0xFE54, 0xFE55, 0xFE56, 0xFE57, - 0xFE58, 0xFE59, 0xFE5A, 0xFE5B, 0xFE5C, 0xFE5D, 0xFE5E, 0xFE5F, - /* 6 */ 0xFE60, 0xFE61, 0xFE62, 0xFE63, 0xFE64, 0xFE65, 0xFE66, 0xFE67, - 0xFE68, 0xFE69, 0xFE6A, 0xFE6B, 0xFE6C, 0xFE6D, 0xFE6E, 0xFE6F, - /* 7 */ 0xFE70, 0xFE71, 0xFE72, 0xFE73, 0xFE74, 0xFE75, 0xFE76, 0xFE77, - 0xFE78, 0xFE79, 0xFE7A, 0xFE7B, 0xFE7C, 0xFE7D, 0xFE7E, 0xFE7F, - /* 8 */ 0xFE80, 0xFE81, 0xFE82, 0xFE83, 0xFE84, 0xFE85, 0xFE86, 0xFE87, - 0xFE88, 0xFE89, 0xFE8A, 0xFE8B, 0xFE8C, 0xFE8D, 0xFE8E, 0xFE8F, - /* 9 */ 0xFE90, 0xFE91, 0xFE92, 0xFE93, 0xFE94, 0xFE95, 0xFE96, 0xFE97, - 0xFE98, 0xFE99, 0xFE9A, 0xFE9B, 0xFE9C, 0xFE9D, 0xFE9E, 0xFE9F, - /* A */ 0xFEA0, 0xFEA1, 0xFEA2, 0xFEA3, 0xFEA4, 0xFEA5, 0xFEA6, 0xFEA7, - 0xFEA8, 0xFEA9, 0xFEAA, 0xFEAB, 0xFEAC, 0xFEAD, 0xFEAE, 0xFEAF, - /* B */ 0xFEB0, 0xFEB1, 0xFEB2, 0xFEB3, 0xFEB4, 0xFEB5, 0xFEB6, 0xFEB7, - 0xFEB8, 0xFEB9, 0xFEBA, 0xFEBB, 0xFEBC, 0xFEBD, 0xFEBE, 0xFEBF, - /* C */ 0xFEC0, 0xFEC1, 0xFEC2, 0xFEC3, 0xFEC4, 0xFEC5, 0xFEC6, 0xFEC7, - 0xFEC8, 0xFEC9, 0xFECA, 0xFECB, 0xFECC, 0xFECD, 0xFECE, 0xFECF, - /* D */ 0xFED0, 0xFED1, 0xFED2, 0xFED3, 0xFED4, 0xFED5, 0xFED6, 0xFED7, - 0xFED8, 0xFED9, 0xFEDA, 0xFEDB, 0xFEDC, 0xFEDD, 0xFEDE, 0xFEDF, - /* E */ 0xFEE0, 0xFEE1, 0xFEE2, 0xFEE3, 0xFEE4, 0xFEE5, 0xFEE6, 0xFEE7, - 0xFEE8, 0xFEE9, 0xFEEA, 0xFEEB, 0xFEEC, 0xFEED, 0xFEEE, 0xFEEF, - /* F */ 0xFEF0, 0xFEF1, 0xFEF2, 0xFEF3, 0xFEF4, 0xFEF5, 0xFEF6, 0xFEF7, - 0xFEF8, 0xFEF9, 0xFEFA, 0xFEFB, 0xFEFC, 0xFEFD, 0xFEFE, 0x0000, - - // Table 10 (for high byte 0xFF) - - /* 0 */ 0xFF00, 0xFF01, 0xFF02, 0xFF03, 0xFF04, 0xFF05, 0xFF06, 0xFF07, - 0xFF08, 0xFF09, 0xFF0A, 0xFF0B, 0xFF0C, 0xFF0D, 0xFF0E, 0xFF0F, - /* 1 */ 0xFF10, 0xFF11, 0xFF12, 0xFF13, 0xFF14, 0xFF15, 0xFF16, 0xFF17, - 0xFF18, 0xFF19, 0xFF1A, 0xFF1B, 0xFF1C, 0xFF1D, 0xFF1E, 0xFF1F, - /* 2 */ 0xFF20, 0xFF41, 0xFF42, 0xFF43, 0xFF44, 0xFF45, 0xFF46, 0xFF47, - 0xFF48, 0xFF49, 0xFF4A, 0xFF4B, 0xFF4C, 0xFF4D, 0xFF4E, 0xFF4F, - /* 3 */ 0xFF50, 0xFF51, 0xFF52, 0xFF53, 0xFF54, 0xFF55, 0xFF56, 0xFF57, - 0xFF58, 0xFF59, 0xFF5A, 0xFF3B, 0xFF3C, 0xFF3D, 0xFF3E, 0xFF3F, - /* 4 */ 0xFF40, 0xFF41, 0xFF42, 0xFF43, 0xFF44, 0xFF45, 0xFF46, 0xFF47, - 0xFF48, 0xFF49, 0xFF4A, 0xFF4B, 0xFF4C, 0xFF4D, 0xFF4E, 0xFF4F, - /* 5 */ 0xFF50, 0xFF51, 0xFF52, 0xFF53, 0xFF54, 0xFF55, 0xFF56, 0xFF57, - 0xFF58, 0xFF59, 0xFF5A, 0xFF5B, 0xFF5C, 0xFF5D, 0xFF5E, 0xFF5F, - /* 6 */ 0xFF60, 0xFF61, 0xFF62, 0xFF63, 0xFF64, 0xFF65, 0xFF66, 0xFF67, - 0xFF68, 0xFF69, 0xFF6A, 0xFF6B, 0xFF6C, 0xFF6D, 0xFF6E, 0xFF6F, - /* 7 */ 0xFF70, 0xFF71, 0xFF72, 0xFF73, 0xFF74, 0xFF75, 0xFF76, 0xFF77, - 0xFF78, 0xFF79, 0xFF7A, 0xFF7B, 0xFF7C, 0xFF7D, 0xFF7E, 0xFF7F, - /* 8 */ 0xFF80, 0xFF81, 0xFF82, 0xFF83, 0xFF84, 0xFF85, 0xFF86, 0xFF87, - 0xFF88, 0xFF89, 0xFF8A, 0xFF8B, 0xFF8C, 0xFF8D, 0xFF8E, 0xFF8F, - /* 9 */ 0xFF90, 0xFF91, 0xFF92, 0xFF93, 0xFF94, 0xFF95, 0xFF96, 0xFF97, - 0xFF98, 0xFF99, 0xFF9A, 0xFF9B, 0xFF9C, 0xFF9D, 0xFF9E, 0xFF9F, - /* A */ 0xFFA0, 0xFFA1, 0xFFA2, 0xFFA3, 0xFFA4, 0xFFA5, 0xFFA6, 0xFFA7, - 0xFFA8, 0xFFA9, 0xFFAA, 0xFFAB, 0xFFAC, 0xFFAD, 0xFFAE, 0xFFAF, - /* B */ 0xFFB0, 0xFFB1, 0xFFB2, 0xFFB3, 0xFFB4, 0xFFB5, 0xFFB6, 0xFFB7, - 0xFFB8, 0xFFB9, 0xFFBA, 0xFFBB, 0xFFBC, 0xFFBD, 0xFFBE, 0xFFBF, - /* C */ 0xFFC0, 0xFFC1, 0xFFC2, 0xFFC3, 0xFFC4, 0xFFC5, 0xFFC6, 0xFFC7, - 0xFFC8, 0xFFC9, 0xFFCA, 0xFFCB, 0xFFCC, 0xFFCD, 0xFFCE, 0xFFCF, - /* D */ 0xFFD0, 0xFFD1, 0xFFD2, 0xFFD3, 0xFFD4, 0xFFD5, 0xFFD6, 0xFFD7, - 0xFFD8, 0xFFD9, 0xFFDA, 0xFFDB, 0xFFDC, 0xFFDD, 0xFFDE, 0xFFDF, - /* E */ 0xFFE0, 0xFFE1, 0xFFE2, 0xFFE3, 0xFFE4, 0xFFE5, 0xFFE6, 0xFFE7, - 0xFFE8, 0xFFE9, 0xFFEA, 0xFFEB, 0xFFEC, 0xFFED, 0xFFEE, 0xFFEF, - /* F */ 0xFFF0, 0xFFF1, 0xFFF2, 0xFFF3, 0xFFF4, 0xFFF5, 0xFFF6, 0xFFF7, - 0xFFF8, 0xFFF9, 0xFFFA, 0xFFFB, 0xFFFC, 0xFFFD, 0xFFFE, 0xFFFF, -}; - -// Returns the next non-ignorable codepoint within string starting from the -// position indicated by index, or zero if there are no more. -// The passed-in index is automatically advanced as the characters in the input -// HFS-decomposed UTF-8 strings are read. -inline int HFSReadNextNonIgnorableCodepoint(const char* string, - int length, - int* index) { - int codepoint = 0; - while (*index < length && codepoint == 0) { - // CBU8_NEXT returns a value < 0 in error cases. For purposes of string - // comparison, we just use that value and flag it with DCHECK. - CBU8_NEXT(string, *index, length, codepoint); - DCHECK_GT(codepoint, 0); - if (codepoint > 0) { - // Check if there is a subtable for this upper byte. - int lookup_offset = lower_case_table[codepoint >> 8]; - if (lookup_offset != 0) - codepoint = lower_case_table[lookup_offset + (codepoint & 0x00FF)]; - // Note: codepoint1 may be again 0 at this point if the character was - // an ignorable. - } - } - return codepoint; -} - -} // anonymous namespace - -// Special UTF-8 version of FastUnicodeCompare. Cf: -// http://developer.apple.com/mac/library/technotes/tn/tn1150.html#StringComparisonAlgorithm -// The input strings must be in the special HFS decomposed form. -int FilePath::HFSFastUnicodeCompare(const StringType& string1, - const StringType& string2) { - int length1 = string1.length(); - int length2 = string2.length(); - int index1 = 0; - int index2 = 0; - - for (;;) { - int codepoint1 = HFSReadNextNonIgnorableCodepoint(string1.c_str(), - length1, - &index1); - int codepoint2 = HFSReadNextNonIgnorableCodepoint(string2.c_str(), - length2, - &index2); - if (codepoint1 != codepoint2) - return (codepoint1 < codepoint2) ? -1 : 1; - if (codepoint1 == 0) { - DCHECK_EQ(index1, length1); - DCHECK_EQ(index2, length2); - return 0; - } - } -} - -StringType FilePath::GetHFSDecomposedForm(const StringType& string) { - ScopedCFTypeRef cfstring( - CFStringCreateWithBytesNoCopy( - NULL, - reinterpret_cast(string.c_str()), - string.length(), - kCFStringEncodingUTF8, - false, - kCFAllocatorNull)); - // Query the maximum length needed to store the result. In most cases this - // will overestimate the required space. The return value also already - // includes the space needed for a terminating 0. - CFIndex length = CFStringGetMaximumSizeOfFileSystemRepresentation(cfstring); - DCHECK_GT(length, 0); // should be at least 1 for the 0-terminator. - // Reserve enough space for CFStringGetFileSystemRepresentation to write into. - // Also set the length to the maximum so that we can shrink it later. - // (Increasing rather than decreasing it would clobber the string contents!) - StringType result; - result.reserve(length); - result.resize(length - 1); - Boolean success = CFStringGetFileSystemRepresentation(cfstring, - &result[0], - length); - if (success) { - // Reduce result.length() to actual string length. - result.resize(strlen(result.c_str())); - } else { - // An error occurred -> clear result. - result.clear(); - } - return result; -} - -int FilePath::CompareIgnoreCase(const StringType& string1, - const StringType& string2) { - // Quick checks for empty strings - these speed things up a bit and make the - // following code cleaner. - if (string1.empty()) - return string2.empty() ? 0 : -1; - if (string2.empty()) - return 1; - - StringType hfs1 = GetHFSDecomposedForm(string1); - StringType hfs2 = GetHFSDecomposedForm(string2); - - // GetHFSDecomposedForm() returns an empty string in an error case. - if (hfs1.empty() || hfs2.empty()) { - NOTREACHED(); - ScopedCFTypeRef cfstring1( - CFStringCreateWithBytesNoCopy( - NULL, - reinterpret_cast(string1.c_str()), - string1.length(), - kCFStringEncodingUTF8, - false, - kCFAllocatorNull)); - ScopedCFTypeRef cfstring2( - CFStringCreateWithBytesNoCopy( - NULL, - reinterpret_cast(string2.c_str()), - string2.length(), - kCFStringEncodingUTF8, - false, - kCFAllocatorNull)); - return CFStringCompare(cfstring1, - cfstring2, - kCFCompareCaseInsensitive); - } - - return HFSFastUnicodeCompare(hfs1, hfs2); -} - -#else // << WIN. MACOSX | other (POSIX) >> - -// Generic (POSIX) implementation of file string comparison. -// TODO(rolandsteiner) check if this is sufficient/correct. -int FilePath::CompareIgnoreCase(const StringType& string1, - const StringType& string2) { - int comparison = strcasecmp(string1.c_str(), string2.c_str()); - if (comparison < 0) - return -1; - if (comparison > 0) - return 1; - return 0; -} - -#endif // OS versions of CompareIgnoreCase() - - -void FilePath::StripTrailingSeparatorsInternal() { - // If there is no drive letter, start will be 1, which will prevent stripping - // the leading separator if there is only one separator. If there is a drive - // letter, start will be set appropriately to prevent stripping the first - // separator following the drive letter, if a separator immediately follows - // the drive letter. - StringType::size_type start = FindDriveLetter(path_) + 2; - - StringType::size_type last_stripped = StringType::npos; - for (StringType::size_type pos = path_.length(); - pos > start && IsSeparator(path_[pos - 1]); - --pos) { - // If the string only has two separators and they're at the beginning, - // don't strip them, unless the string began with more than two separators. - if (pos != start + 1 || last_stripped == start + 2 || - !IsSeparator(path_[start - 1])) { - path_.resize(pos - 1); - last_stripped = pos; - } - } -} - -FilePath FilePath::NormalizePathSeparators() const { -#if defined(FILE_PATH_USES_WIN_SEPARATORS) - StringType copy = path_; - for (size_t i = 1; i < kSeparatorsLength; ++i) { - std::replace(copy.begin(), copy.end(), kSeparators[i], kSeparators[0]); - } - return FilePath(copy); -#else - return *this; -#endif -} - -} // namespace base - -void PrintTo(const base::FilePath& path, std::ostream* out) { - *out << path.value(); -} diff --git a/base/files/file_path.h b/base/files/file_path.h deleted file mode 100644 index 8b69ea493a..0000000000 --- a/base/files/file_path.h +++ /dev/null @@ -1,458 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -// FilePath is a container for pathnames stored in a platform's native string -// type, providing containers for manipulation in according with the -// platform's conventions for pathnames. It supports the following path -// types: -// -// POSIX Windows -// --------------- ---------------------------------- -// Fundamental type char[] wchar_t[] -// Encoding unspecified* UTF-16 -// Separator / \, tolerant of / -// Drive letters no case-insensitive A-Z followed by : -// Alternate root // (surprise!) \\, for UNC paths -// -// * The encoding need not be specified on POSIX systems, although some -// POSIX-compliant systems do specify an encoding. Mac OS X uses UTF-8. -// Chrome OS also uses UTF-8. -// Linux does not specify an encoding, but in practice, the locale's -// character set may be used. -// -// For more arcane bits of path trivia, see below. -// -// FilePath objects are intended to be used anywhere paths are. An -// application may pass FilePath objects around internally, masking the -// underlying differences between systems, only differing in implementation -// where interfacing directly with the system. For example, a single -// OpenFile(const FilePath &) function may be made available, allowing all -// callers to operate without regard to the underlying implementation. On -// POSIX-like platforms, OpenFile might wrap fopen, and on Windows, it might -// wrap _wfopen_s, perhaps both by calling file_path.value().c_str(). This -// allows each platform to pass pathnames around without requiring conversions -// between encodings, which has an impact on performance, but more imporantly, -// has an impact on correctness on platforms that do not have well-defined -// encodings for pathnames. -// -// Several methods are available to perform common operations on a FilePath -// object, such as determining the parent directory (DirName), isolating the -// final path component (BaseName), and appending a relative pathname string -// to an existing FilePath object (Append). These methods are highly -// recommended over attempting to split and concatenate strings directly. -// These methods are based purely on string manipulation and knowledge of -// platform-specific pathname conventions, and do not consult the filesystem -// at all, making them safe to use without fear of blocking on I/O operations. -// These methods do not function as mutators but instead return distinct -// instances of FilePath objects, and are therefore safe to use on const -// objects. The objects themselves are safe to share between threads. -// -// To aid in initialization of FilePath objects from string literals, a -// FILE_PATH_LITERAL macro is provided, which accounts for the difference -// between char[]-based pathnames on POSIX systems and wchar_t[]-based -// pathnames on Windows. -// -// Paths can't contain NULs as a precaution agaist premature truncation. -// -// Because a FilePath object should not be instantiated at the global scope, -// instead, use a FilePath::CharType[] and initialize it with -// FILE_PATH_LITERAL. At runtime, a FilePath object can be created from the -// character array. Example: -// -// | const FilePath::CharType kLogFileName[] = FILE_PATH_LITERAL("log.txt"); -// | -// | void Function() { -// | FilePath log_file_path(kLogFileName); -// | [...] -// | } -// -// WARNING: FilePaths should ALWAYS be displayed with LTR directionality, even -// when the UI language is RTL. This means you always need to pass filepaths -// through base::i18n::WrapPathWithLTRFormatting() before displaying it in the -// RTL UI. -// -// This is a very common source of bugs, please try to keep this in mind. -// -// ARCANE BITS OF PATH TRIVIA -// -// - A double leading slash is actually part of the POSIX standard. Systems -// are allowed to treat // as an alternate root, as Windows does for UNC -// (network share) paths. Most POSIX systems don't do anything special -// with two leading slashes, but FilePath handles this case properly -// in case it ever comes across such a system. FilePath needs this support -// for Windows UNC paths, anyway. -// References: -// The Open Group Base Specifications Issue 7, sections 3.266 ("Pathname") -// and 4.12 ("Pathname Resolution"), available at: -// http://www.opengroup.org/onlinepubs/9699919799/basedefs/V1_chap03.html#tag_03_266 -// http://www.opengroup.org/onlinepubs/9699919799/basedefs/V1_chap04.html#tag_04_12 -// -// - Windows treats c:\\ the same way it treats \\. This was intended to -// allow older applications that require drive letters to support UNC paths -// like \\server\share\path, by permitting c:\\server\share\path as an -// equivalent. Since the OS treats these paths specially, FilePath needs -// to do the same. Since Windows can use either / or \ as the separator, -// FilePath treats c://, c:\\, //, and \\ all equivalently. -// Reference: -// The Old New Thing, "Why is a drive letter permitted in front of UNC -// paths (sometimes)?", available at: -// http://blogs.msdn.com/oldnewthing/archive/2005/11/22/495740.aspx - -#ifndef BASE_FILES_FILE_PATH_H_ -#define BASE_FILES_FILE_PATH_H_ - -#include -#include -#include - -#include "base/base_export.h" -#include "base/compiler_specific.h" -#include "base/containers/hash_tables.h" -#include "base/strings/string16.h" -#include "base/strings/string_piece.h" // For implicit conversions. -#include "build/build_config.h" - -// Windows-style drive letter support and pathname separator characters can be -// enabled and disabled independently, to aid testing. These #defines are -// here so that the same setting can be used in both the implementation and -// in the unit test. -#if defined(OS_WIN) -#define FILE_PATH_USES_DRIVE_LETTERS -#define FILE_PATH_USES_WIN_SEPARATORS -#endif // OS_WIN - -class Pickle; -class PickleIterator; - -namespace base { - -// An abstraction to isolate users from the differences between native -// pathnames on different platforms. -class BASE_EXPORT FilePath { - public: -#if defined(OS_POSIX) - // On most platforms, native pathnames are char arrays, and the encoding - // may or may not be specified. On Mac OS X, native pathnames are encoded - // in UTF-8. - typedef std::string StringType; -#elif defined(OS_WIN) - // On Windows, for Unicode-aware applications, native pathnames are wchar_t - // arrays encoded in UTF-16. - typedef std::wstring StringType; -#endif // OS_WIN - - typedef StringType::value_type CharType; - - // Null-terminated array of separators used to separate components in - // hierarchical paths. Each character in this array is a valid separator, - // but kSeparators[0] is treated as the canonical separator and will be used - // when composing pathnames. - static const CharType kSeparators[]; - - // arraysize(kSeparators). - static const size_t kSeparatorsLength; - - // A special path component meaning "this directory." - static const CharType kCurrentDirectory[]; - - // A special path component meaning "the parent directory." - static const CharType kParentDirectory[]; - - // The character used to identify a file extension. - static const CharType kExtensionSeparator; - - FilePath(); - FilePath(const FilePath& that); - explicit FilePath(const StringType& path); - ~FilePath(); - FilePath& operator=(const FilePath& that); - - bool operator==(const FilePath& that) const; - - bool operator!=(const FilePath& that) const; - - // Required for some STL containers and operations - bool operator<(const FilePath& that) const { - return path_ < that.path_; - } - - const StringType& value() const { return path_; } - - bool empty() const { return path_.empty(); } - - void clear() { path_.clear(); } - - // Returns true if |character| is in kSeparators. - static bool IsSeparator(CharType character); - - // Returns a vector of all of the components of the provided path. It is - // equivalent to calling DirName().value() on the path's root component, - // and BaseName().value() on each child component. - void GetComponents(std::vector* components) const; - - // Returns true if this FilePath is a strict parent of the |child|. Absolute - // and relative paths are accepted i.e. is /foo parent to /foo/bar and - // is foo parent to foo/bar. Does not convert paths to absolute, follow - // symlinks or directory navigation (e.g. ".."). A path is *NOT* its own - // parent. - bool IsParent(const FilePath& child) const; - - // If IsParent(child) holds, appends to path (if non-NULL) the - // relative path to child and returns true. For example, if parent - // holds "/Users/johndoe/Library/Application Support", child holds - // "/Users/johndoe/Library/Application Support/Google/Chrome/Default", and - // *path holds "/Users/johndoe/Library/Caches", then after - // parent.AppendRelativePath(child, path) is called *path will hold - // "/Users/johndoe/Library/Caches/Google/Chrome/Default". Otherwise, - // returns false. - bool AppendRelativePath(const FilePath& child, FilePath* path) const; - - // Returns a FilePath corresponding to the directory containing the path - // named by this object, stripping away the file component. If this object - // only contains one component, returns a FilePath identifying - // kCurrentDirectory. If this object already refers to the root directory, - // returns a FilePath identifying the root directory. - FilePath DirName() const WARN_UNUSED_RESULT; - - // Returns a FilePath corresponding to the last path component of this - // object, either a file or a directory. If this object already refers to - // the root directory, returns a FilePath identifying the root directory; - // this is the only situation in which BaseName will return an absolute path. - FilePath BaseName() const WARN_UNUSED_RESULT; - - // Returns ".jpg" for path "C:\pics\jojo.jpg", or an empty string if - // the file has no extension. If non-empty, Extension() will always start - // with precisely one ".". The following code should always work regardless - // of the value of path. - // new_path = path.RemoveExtension().value().append(path.Extension()); - // ASSERT(new_path == path.value()); - // NOTE: this is different from the original file_util implementation which - // returned the extension without a leading "." ("jpg" instead of ".jpg") - StringType Extension() const; - - // Returns "C:\pics\jojo" for path "C:\pics\jojo.jpg" - // NOTE: this is slightly different from the similar file_util implementation - // which returned simply 'jojo'. - FilePath RemoveExtension() const WARN_UNUSED_RESULT; - - // Inserts |suffix| after the file name portion of |path| but before the - // extension. Returns "" if BaseName() == "." or "..". - // Examples: - // path == "C:\pics\jojo.jpg" suffix == " (1)", returns "C:\pics\jojo (1).jpg" - // path == "jojo.jpg" suffix == " (1)", returns "jojo (1).jpg" - // path == "C:\pics\jojo" suffix == " (1)", returns "C:\pics\jojo (1)" - // path == "C:\pics.old\jojo" suffix == " (1)", returns "C:\pics.old\jojo (1)" - FilePath InsertBeforeExtension( - const StringType& suffix) const WARN_UNUSED_RESULT; - FilePath InsertBeforeExtensionASCII( - const base::StringPiece& suffix) const WARN_UNUSED_RESULT; - - // Adds |extension| to |file_name|. Returns the current FilePath if - // |extension| is empty. Returns "" if BaseName() == "." or "..". - FilePath AddExtension( - const StringType& extension) const WARN_UNUSED_RESULT; - - // Replaces the extension of |file_name| with |extension|. If |file_name| - // does not have an extension, then |extension| is added. If |extension| is - // empty, then the extension is removed from |file_name|. - // Returns "" if BaseName() == "." or "..". - FilePath ReplaceExtension( - const StringType& extension) const WARN_UNUSED_RESULT; - - // Returns true if the file path matches the specified extension. The test is - // case insensitive. Don't forget the leading period if appropriate. - bool MatchesExtension(const StringType& extension) const; - - // Returns a FilePath by appending a separator and the supplied path - // component to this object's path. Append takes care to avoid adding - // excessive separators if this object's path already ends with a separator. - // If this object's path is kCurrentDirectory, a new FilePath corresponding - // only to |component| is returned. |component| must be a relative path; - // it is an error to pass an absolute path. - FilePath Append(const StringType& component) const WARN_UNUSED_RESULT; - FilePath Append(const FilePath& component) const WARN_UNUSED_RESULT; - - // Although Windows StringType is std::wstring, since the encoding it uses for - // paths is well defined, it can handle ASCII path components as well. - // Mac uses UTF8, and since ASCII is a subset of that, it works there as well. - // On Linux, although it can use any 8-bit encoding for paths, we assume that - // ASCII is a valid subset, regardless of the encoding, since many operating - // system paths will always be ASCII. - FilePath AppendASCII(const base::StringPiece& component) - const WARN_UNUSED_RESULT; - - // Returns true if this FilePath contains an absolute path. On Windows, an - // absolute path begins with either a drive letter specification followed by - // a separator character, or with two separator characters. On POSIX - // platforms, an absolute path begins with a separator character. - bool IsAbsolute() const; - - // Returns true if the patch ends with a path separator character. - bool EndsWithSeparator() const WARN_UNUSED_RESULT; - - // Returns a copy of this FilePath that ends with a trailing separator. If - // the input path is empty, an empty FilePath will be returned. - FilePath AsEndingWithSeparator() const WARN_UNUSED_RESULT; - - // Returns a copy of this FilePath that does not end with a trailing - // separator. - FilePath StripTrailingSeparators() const WARN_UNUSED_RESULT; - - // Returns true if this FilePath contains any attempt to reference a parent - // directory (i.e. has a path component that is ".." - bool ReferencesParent() const; - - // Return a Unicode human-readable version of this path. - // Warning: you can *not*, in general, go from a display name back to a real - // path. Only use this when displaying paths to users, not just when you - // want to stuff a string16 into some other API. - string16 LossyDisplayName() const; - - // Return the path as ASCII, or the empty string if the path is not ASCII. - // This should only be used for cases where the FilePath is representing a - // known-ASCII filename. - std::string MaybeAsASCII() const; - - // Return the path as UTF-8. - // - // This function is *unsafe* as there is no way to tell what encoding is - // used in file names on POSIX systems other than Mac and Chrome OS, - // although UTF-8 is practically used everywhere these days. To mitigate - // the encoding issue, this function internally calls - // SysNativeMBToWide() on POSIX systems other than Mac and Chrome OS, - // per assumption that the current locale's encoding is used in file - // names, but this isn't a perfect solution. - // - // Once it becomes safe to to stop caring about non-UTF-8 file names, - // the SysNativeMBToWide() hack will be removed from the code, along - // with "Unsafe" in the function name. - std::string AsUTF8Unsafe() const; - - // Similar to AsUTF8Unsafe, but returns UTF-16 instead. - string16 AsUTF16Unsafe() const; - - // Older Chromium code assumes that paths are always wstrings. - // This function converts wstrings to FilePaths, and is - // useful to smooth porting that old code to the FilePath API. - // It has "Hack" its name so people feel bad about using it. - // http://code.google.com/p/chromium/issues/detail?id=24672 - // - // If you are trying to be a good citizen and remove these, ask yourself: - // - Am I interacting with other Chrome code that deals with files? Then - // try to convert the API into using FilePath. - // - Am I interacting with OS-native calls? Then use value() to get at an - // OS-native string format. - // - Am I using well-known file names, like "config.ini"? Then use the - // ASCII functions (we require paths to always be supersets of ASCII). - // - Am I displaying a string to the user in some UI? Then use the - // LossyDisplayName() function, but keep in mind that you can't - // ever use the result of that again as a path. - static FilePath FromWStringHack(const std::wstring& wstring); - - // Returns a FilePath object from a path name in UTF-8. This function - // should only be used for cases where you are sure that the input - // string is UTF-8. - // - // Like AsUTF8Unsafe(), this function is unsafe. This function - // internally calls SysWideToNativeMB() on POSIX systems other than Mac - // and Chrome OS, to mitigate the encoding issue. See the comment at - // AsUTF8Unsafe() for details. - static FilePath FromUTF8Unsafe(const std::string& utf8); - - // Similar to FromUTF8Unsafe, but accepts UTF-16 instead. - static FilePath FromUTF16Unsafe(const string16& utf16); - - void WriteToPickle(Pickle* pickle) const; - bool ReadFromPickle(PickleIterator* iter); - - // Normalize all path separators to backslash on Windows - // (if FILE_PATH_USES_WIN_SEPARATORS is true), or do nothing on POSIX systems. - FilePath NormalizePathSeparators() const; - - // Compare two strings in the same way the file system does. - // Note that these always ignore case, even on file systems that are case- - // sensitive. If case-sensitive comparison is ever needed, add corresponding - // methods here. - // The methods are written as a static method so that they can also be used - // on parts of a file path, e.g., just the extension. - // CompareIgnoreCase() returns -1, 0 or 1 for less-than, equal-to and - // greater-than respectively. - static int CompareIgnoreCase(const StringType& string1, - const StringType& string2); - static bool CompareEqualIgnoreCase(const StringType& string1, - const StringType& string2) { - return CompareIgnoreCase(string1, string2) == 0; - } - static bool CompareLessIgnoreCase(const StringType& string1, - const StringType& string2) { - return CompareIgnoreCase(string1, string2) < 0; - } - -#if defined(OS_MACOSX) - // Returns the string in the special canonical decomposed form as defined for - // HFS, which is close to, but not quite, decomposition form D. See - // http://developer.apple.com/mac/library/technotes/tn/tn1150.html#UnicodeSubtleties - // for further comments. - // Returns the epmty string if the conversion failed. - static StringType GetHFSDecomposedForm(const FilePath::StringType& string); - - // Special UTF-8 version of FastUnicodeCompare. Cf: - // http://developer.apple.com/mac/library/technotes/tn/tn1150.html#StringComparisonAlgorithm - // IMPORTANT: The input strings must be in the special HFS decomposed form! - // (cf. above GetHFSDecomposedForm method) - static int HFSFastUnicodeCompare(const StringType& string1, - const StringType& string2); -#endif - - private: - // Remove trailing separators from this object. If the path is absolute, it - // will never be stripped any more than to refer to the absolute root - // directory, so "////" will become "/", not "". A leading pair of - // separators is never stripped, to support alternate roots. This is used to - // support UNC paths on Windows. - void StripTrailingSeparatorsInternal(); - - StringType path_; -}; - -} // namespace base - -// This is required by googletest to print a readable output on test failures. -BASE_EXPORT extern void PrintTo(const base::FilePath& path, std::ostream* out); - -// Macros for string literal initialization of FilePath::CharType[], and for -// using a FilePath::CharType[] in a printf-style format string. -#if defined(OS_POSIX) -#define FILE_PATH_LITERAL(x) x -#define PRFilePath "s" -#define PRFilePathLiteral "%s" -#elif defined(OS_WIN) -#define FILE_PATH_LITERAL(x) L ## x -#define PRFilePath "ls" -#define PRFilePathLiteral L"%ls" -#endif // OS_WIN - -// Provide a hash function so that hash_sets and maps can contain FilePath -// objects. -namespace BASE_HASH_NAMESPACE { -#if defined(COMPILER_GCC) - -template<> -struct hash { - size_t operator()(const base::FilePath& f) const { - return hash()(f.value()); - } -}; - -#elif defined(COMPILER_MSVC) - -inline size_t hash_value(const base::FilePath& f) { - return hash_value(f.value()); -} - -#endif // COMPILER - -} // namespace BASE_HASH_NAMESPACE - -#endif // BASE_FILES_FILE_PATH_H_ diff --git a/base/files/file_path_constants.cc b/base/files/file_path_constants.cc deleted file mode 100644 index 34b17a60b7..0000000000 --- a/base/files/file_path_constants.cc +++ /dev/null @@ -1,22 +0,0 @@ -// Copyright 2013 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "base/files/file_path.h" - -namespace base { - -#if defined(FILE_PATH_USES_WIN_SEPARATORS) -const FilePath::CharType FilePath::kSeparators[] = FILE_PATH_LITERAL("\\/"); -#else // FILE_PATH_USES_WIN_SEPARATORS -const FilePath::CharType FilePath::kSeparators[] = FILE_PATH_LITERAL("/"); -#endif // FILE_PATH_USES_WIN_SEPARATORS - -const size_t FilePath::kSeparatorsLength = arraysize(kSeparators); - -const FilePath::CharType FilePath::kCurrentDirectory[] = FILE_PATH_LITERAL("."); -const FilePath::CharType FilePath::kParentDirectory[] = FILE_PATH_LITERAL(".."); - -const FilePath::CharType FilePath::kExtensionSeparator = FILE_PATH_LITERAL('.'); - -} // namespace base diff --git a/base/files/file_path_unittest.cc b/base/files/file_path_unittest.cc deleted file mode 100644 index 8b2fcf531c..0000000000 --- a/base/files/file_path_unittest.cc +++ /dev/null @@ -1,1231 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "base/basictypes.h" -#include "base/files/file_path.h" -#include "base/strings/utf_string_conversions.h" -#include "testing/gtest/include/gtest/gtest.h" -#include "testing/platform_test.h" - -// This macro helps avoid wrapped lines in the test structs. -#define FPL(x) FILE_PATH_LITERAL(x) - -// This macro constructs strings which can contain NULs. -#define FPS(x) FilePath::StringType(FPL(x), arraysize(FPL(x)) - 1) - -namespace base { - -struct UnaryTestData { - const FilePath::CharType* input; - const FilePath::CharType* expected; -}; - -struct UnaryBooleanTestData { - const FilePath::CharType* input; - bool expected; -}; - -struct BinaryTestData { - const FilePath::CharType* inputs[2]; - const FilePath::CharType* expected; -}; - -struct BinaryBooleanTestData { - const FilePath::CharType* inputs[2]; - bool expected; -}; - -struct BinaryIntTestData { - const FilePath::CharType* inputs[2]; - int expected; -}; - -struct UTF8TestData { - const FilePath::CharType* native; - const char* utf8; -}; - -// file_util winds up using autoreleased objects on the Mac, so this needs -// to be a PlatformTest -class FilePathTest : public PlatformTest { - protected: - virtual void SetUp() OVERRIDE { - PlatformTest::SetUp(); - } - virtual void TearDown() OVERRIDE { - PlatformTest::TearDown(); - } -}; - -TEST_F(FilePathTest, DirName) { - const struct UnaryTestData cases[] = { - { FPL(""), FPL(".") }, - { FPL("aa"), FPL(".") }, - { FPL("/aa/bb"), FPL("/aa") }, - { FPL("/aa/bb/"), FPL("/aa") }, - { FPL("/aa/bb//"), FPL("/aa") }, - { FPL("/aa/bb/ccc"), FPL("/aa/bb") }, - { FPL("/aa"), FPL("/") }, - { FPL("/aa/"), FPL("/") }, - { FPL("/"), FPL("/") }, - { FPL("//"), FPL("//") }, - { FPL("///"), FPL("/") }, - { FPL("aa/"), FPL(".") }, - { FPL("aa/bb"), FPL("aa") }, - { FPL("aa/bb/"), FPL("aa") }, - { FPL("aa/bb//"), FPL("aa") }, - { FPL("aa//bb//"), FPL("aa") }, - { FPL("aa//bb/"), FPL("aa") }, - { FPL("aa//bb"), FPL("aa") }, - { FPL("//aa/bb"), FPL("//aa") }, - { FPL("//aa/"), FPL("//") }, - { FPL("//aa"), FPL("//") }, - { FPL("0:"), FPL(".") }, - { FPL("@:"), FPL(".") }, - { FPL("[:"), FPL(".") }, - { FPL("`:"), FPL(".") }, - { FPL("{:"), FPL(".") }, - { FPL("\xB3:"), FPL(".") }, - { FPL("\xC5:"), FPL(".") }, -#if defined(OS_WIN) - { FPL("\x0143:"), FPL(".") }, -#endif // OS_WIN -#if defined(FILE_PATH_USES_DRIVE_LETTERS) - { FPL("c:"), FPL("c:") }, - { FPL("C:"), FPL("C:") }, - { FPL("A:"), FPL("A:") }, - { FPL("Z:"), FPL("Z:") }, - { FPL("a:"), FPL("a:") }, - { FPL("z:"), FPL("z:") }, - { FPL("c:aa"), FPL("c:") }, - { FPL("c:/"), FPL("c:/") }, - { FPL("c://"), FPL("c://") }, - { FPL("c:///"), FPL("c:/") }, - { FPL("c:/aa"), FPL("c:/") }, - { FPL("c:/aa/"), FPL("c:/") }, - { FPL("c:/aa/bb"), FPL("c:/aa") }, - { FPL("c:aa/bb"), FPL("c:aa") }, -#endif // FILE_PATH_USES_DRIVE_LETTERS -#if defined(FILE_PATH_USES_WIN_SEPARATORS) - { FPL("\\aa\\bb"), FPL("\\aa") }, - { FPL("\\aa\\bb\\"), FPL("\\aa") }, - { FPL("\\aa\\bb\\\\"), FPL("\\aa") }, - { FPL("\\aa\\bb\\ccc"), FPL("\\aa\\bb") }, - { FPL("\\aa"), FPL("\\") }, - { FPL("\\aa\\"), FPL("\\") }, - { FPL("\\"), FPL("\\") }, - { FPL("\\\\"), FPL("\\\\") }, - { FPL("\\\\\\"), FPL("\\") }, - { FPL("aa\\"), FPL(".") }, - { FPL("aa\\bb"), FPL("aa") }, - { FPL("aa\\bb\\"), FPL("aa") }, - { FPL("aa\\bb\\\\"), FPL("aa") }, - { FPL("aa\\\\bb\\\\"), FPL("aa") }, - { FPL("aa\\\\bb\\"), FPL("aa") }, - { FPL("aa\\\\bb"), FPL("aa") }, - { FPL("\\\\aa\\bb"), FPL("\\\\aa") }, - { FPL("\\\\aa\\"), FPL("\\\\") }, - { FPL("\\\\aa"), FPL("\\\\") }, -#if defined(FILE_PATH_USES_DRIVE_LETTERS) - { FPL("c:\\"), FPL("c:\\") }, - { FPL("c:\\\\"), FPL("c:\\\\") }, - { FPL("c:\\\\\\"), FPL("c:\\") }, - { FPL("c:\\aa"), FPL("c:\\") }, - { FPL("c:\\aa\\"), FPL("c:\\") }, - { FPL("c:\\aa\\bb"), FPL("c:\\aa") }, - { FPL("c:aa\\bb"), FPL("c:aa") }, -#endif // FILE_PATH_USES_DRIVE_LETTERS -#endif // FILE_PATH_USES_WIN_SEPARATORS - }; - - for (size_t i = 0; i < arraysize(cases); ++i) { - FilePath input(cases[i].input); - FilePath observed = input.DirName(); - EXPECT_EQ(FilePath::StringType(cases[i].expected), observed.value()) << - "i: " << i << ", input: " << input.value(); - } -} - -TEST_F(FilePathTest, BaseName) { - const struct UnaryTestData cases[] = { - { FPL(""), FPL("") }, - { FPL("aa"), FPL("aa") }, - { FPL("/aa/bb"), FPL("bb") }, - { FPL("/aa/bb/"), FPL("bb") }, - { FPL("/aa/bb//"), FPL("bb") }, - { FPL("/aa/bb/ccc"), FPL("ccc") }, - { FPL("/aa"), FPL("aa") }, - { FPL("/"), FPL("/") }, - { FPL("//"), FPL("//") }, - { FPL("///"), FPL("/") }, - { FPL("aa/"), FPL("aa") }, - { FPL("aa/bb"), FPL("bb") }, - { FPL("aa/bb/"), FPL("bb") }, - { FPL("aa/bb//"), FPL("bb") }, - { FPL("aa//bb//"), FPL("bb") }, - { FPL("aa//bb/"), FPL("bb") }, - { FPL("aa//bb"), FPL("bb") }, - { FPL("//aa/bb"), FPL("bb") }, - { FPL("//aa/"), FPL("aa") }, - { FPL("//aa"), FPL("aa") }, - { FPL("0:"), FPL("0:") }, - { FPL("@:"), FPL("@:") }, - { FPL("[:"), FPL("[:") }, - { FPL("`:"), FPL("`:") }, - { FPL("{:"), FPL("{:") }, - { FPL("\xB3:"), FPL("\xB3:") }, - { FPL("\xC5:"), FPL("\xC5:") }, -#if defined(OS_WIN) - { FPL("\x0143:"), FPL("\x0143:") }, -#endif // OS_WIN -#if defined(FILE_PATH_USES_DRIVE_LETTERS) - { FPL("c:"), FPL("") }, - { FPL("C:"), FPL("") }, - { FPL("A:"), FPL("") }, - { FPL("Z:"), FPL("") }, - { FPL("a:"), FPL("") }, - { FPL("z:"), FPL("") }, - { FPL("c:aa"), FPL("aa") }, - { FPL("c:/"), FPL("/") }, - { FPL("c://"), FPL("//") }, - { FPL("c:///"), FPL("/") }, - { FPL("c:/aa"), FPL("aa") }, - { FPL("c:/aa/"), FPL("aa") }, - { FPL("c:/aa/bb"), FPL("bb") }, - { FPL("c:aa/bb"), FPL("bb") }, -#endif // FILE_PATH_USES_DRIVE_LETTERS -#if defined(FILE_PATH_USES_WIN_SEPARATORS) - { FPL("\\aa\\bb"), FPL("bb") }, - { FPL("\\aa\\bb\\"), FPL("bb") }, - { FPL("\\aa\\bb\\\\"), FPL("bb") }, - { FPL("\\aa\\bb\\ccc"), FPL("ccc") }, - { FPL("\\aa"), FPL("aa") }, - { FPL("\\"), FPL("\\") }, - { FPL("\\\\"), FPL("\\\\") }, - { FPL("\\\\\\"), FPL("\\") }, - { FPL("aa\\"), FPL("aa") }, - { FPL("aa\\bb"), FPL("bb") }, - { FPL("aa\\bb\\"), FPL("bb") }, - { FPL("aa\\bb\\\\"), FPL("bb") }, - { FPL("aa\\\\bb\\\\"), FPL("bb") }, - { FPL("aa\\\\bb\\"), FPL("bb") }, - { FPL("aa\\\\bb"), FPL("bb") }, - { FPL("\\\\aa\\bb"), FPL("bb") }, - { FPL("\\\\aa\\"), FPL("aa") }, - { FPL("\\\\aa"), FPL("aa") }, -#if defined(FILE_PATH_USES_DRIVE_LETTERS) - { FPL("c:\\"), FPL("\\") }, - { FPL("c:\\\\"), FPL("\\\\") }, - { FPL("c:\\\\\\"), FPL("\\") }, - { FPL("c:\\aa"), FPL("aa") }, - { FPL("c:\\aa\\"), FPL("aa") }, - { FPL("c:\\aa\\bb"), FPL("bb") }, - { FPL("c:aa\\bb"), FPL("bb") }, -#endif // FILE_PATH_USES_DRIVE_LETTERS -#endif // FILE_PATH_USES_WIN_SEPARATORS - }; - - for (size_t i = 0; i < arraysize(cases); ++i) { - FilePath input(cases[i].input); - FilePath observed = input.BaseName(); - EXPECT_EQ(FilePath::StringType(cases[i].expected), observed.value()) << - "i: " << i << ", input: " << input.value(); - } -} - -TEST_F(FilePathTest, Append) { - const struct BinaryTestData cases[] = { - { { FPL(""), FPL("cc") }, FPL("cc") }, - { { FPL("."), FPL("ff") }, FPL("ff") }, - { { FPL("/"), FPL("cc") }, FPL("/cc") }, - { { FPL("/aa"), FPL("") }, FPL("/aa") }, - { { FPL("/aa/"), FPL("") }, FPL("/aa") }, - { { FPL("//aa"), FPL("") }, FPL("//aa") }, - { { FPL("//aa/"), FPL("") }, FPL("//aa") }, - { { FPL("//"), FPL("aa") }, FPL("//aa") }, -#if defined(FILE_PATH_USES_DRIVE_LETTERS) - { { FPL("c:"), FPL("a") }, FPL("c:a") }, - { { FPL("c:"), FPL("") }, FPL("c:") }, - { { FPL("c:/"), FPL("a") }, FPL("c:/a") }, - { { FPL("c://"), FPL("a") }, FPL("c://a") }, - { { FPL("c:///"), FPL("a") }, FPL("c:/a") }, -#endif // FILE_PATH_USES_DRIVE_LETTERS -#if defined(FILE_PATH_USES_WIN_SEPARATORS) - // Append introduces the default separator character, so these test cases - // need to be defined with different expected results on platforms that use - // different default separator characters. - { { FPL("\\"), FPL("cc") }, FPL("\\cc") }, - { { FPL("\\aa"), FPL("") }, FPL("\\aa") }, - { { FPL("\\aa\\"), FPL("") }, FPL("\\aa") }, - { { FPL("\\\\aa"), FPL("") }, FPL("\\\\aa") }, - { { FPL("\\\\aa\\"), FPL("") }, FPL("\\\\aa") }, - { { FPL("\\\\"), FPL("aa") }, FPL("\\\\aa") }, - { { FPL("/aa/bb"), FPL("cc") }, FPL("/aa/bb\\cc") }, - { { FPL("/aa/bb/"), FPL("cc") }, FPL("/aa/bb\\cc") }, - { { FPL("aa/bb/"), FPL("cc") }, FPL("aa/bb\\cc") }, - { { FPL("aa/bb"), FPL("cc") }, FPL("aa/bb\\cc") }, - { { FPL("a/b"), FPL("c") }, FPL("a/b\\c") }, - { { FPL("a/b/"), FPL("c") }, FPL("a/b\\c") }, - { { FPL("//aa"), FPL("bb") }, FPL("//aa\\bb") }, - { { FPL("//aa/"), FPL("bb") }, FPL("//aa\\bb") }, - { { FPL("\\aa\\bb"), FPL("cc") }, FPL("\\aa\\bb\\cc") }, - { { FPL("\\aa\\bb\\"), FPL("cc") }, FPL("\\aa\\bb\\cc") }, - { { FPL("aa\\bb\\"), FPL("cc") }, FPL("aa\\bb\\cc") }, - { { FPL("aa\\bb"), FPL("cc") }, FPL("aa\\bb\\cc") }, - { { FPL("a\\b"), FPL("c") }, FPL("a\\b\\c") }, - { { FPL("a\\b\\"), FPL("c") }, FPL("a\\b\\c") }, - { { FPL("\\\\aa"), FPL("bb") }, FPL("\\\\aa\\bb") }, - { { FPL("\\\\aa\\"), FPL("bb") }, FPL("\\\\aa\\bb") }, -#if defined(FILE_PATH_USES_DRIVE_LETTERS) - { { FPL("c:\\"), FPL("a") }, FPL("c:\\a") }, - { { FPL("c:\\\\"), FPL("a") }, FPL("c:\\\\a") }, - { { FPL("c:\\\\\\"), FPL("a") }, FPL("c:\\a") }, - { { FPL("c:\\"), FPL("") }, FPL("c:\\") }, - { { FPL("c:\\a"), FPL("b") }, FPL("c:\\a\\b") }, - { { FPL("c:\\a\\"), FPL("b") }, FPL("c:\\a\\b") }, -#endif // FILE_PATH_USES_DRIVE_LETTERS -#else // FILE_PATH_USES_WIN_SEPARATORS - { { FPL("/aa/bb"), FPL("cc") }, FPL("/aa/bb/cc") }, - { { FPL("/aa/bb/"), FPL("cc") }, FPL("/aa/bb/cc") }, - { { FPL("aa/bb/"), FPL("cc") }, FPL("aa/bb/cc") }, - { { FPL("aa/bb"), FPL("cc") }, FPL("aa/bb/cc") }, - { { FPL("a/b"), FPL("c") }, FPL("a/b/c") }, - { { FPL("a/b/"), FPL("c") }, FPL("a/b/c") }, - { { FPL("//aa"), FPL("bb") }, FPL("//aa/bb") }, - { { FPL("//aa/"), FPL("bb") }, FPL("//aa/bb") }, -#if defined(FILE_PATH_USES_DRIVE_LETTERS) - { { FPL("c:/"), FPL("a") }, FPL("c:/a") }, - { { FPL("c:/"), FPL("") }, FPL("c:/") }, - { { FPL("c:/a"), FPL("b") }, FPL("c:/a/b") }, - { { FPL("c:/a/"), FPL("b") }, FPL("c:/a/b") }, -#endif // FILE_PATH_USES_DRIVE_LETTERS -#endif // FILE_PATH_USES_WIN_SEPARATORS - }; - - for (size_t i = 0; i < arraysize(cases); ++i) { - FilePath root(cases[i].inputs[0]); - FilePath::StringType leaf(cases[i].inputs[1]); - FilePath observed_str = root.Append(leaf); - EXPECT_EQ(FilePath::StringType(cases[i].expected), observed_str.value()) << - "i: " << i << ", root: " << root.value() << ", leaf: " << leaf; - FilePath observed_path = root.Append(FilePath(leaf)); - EXPECT_EQ(FilePath::StringType(cases[i].expected), observed_path.value()) << - "i: " << i << ", root: " << root.value() << ", leaf: " << leaf; - - // TODO(erikkay): It would be nice to have a unicode test append value to - // handle the case when AppendASCII is passed UTF8 -#if defined(OS_WIN) - std::string ascii = WideToUTF8(leaf); -#elif defined(OS_POSIX) - std::string ascii = leaf; -#endif - observed_str = root.AppendASCII(ascii); - EXPECT_EQ(FilePath::StringType(cases[i].expected), observed_str.value()) << - "i: " << i << ", root: " << root.value() << ", leaf: " << leaf; - } -} - -TEST_F(FilePathTest, StripTrailingSeparators) { - const struct UnaryTestData cases[] = { - { FPL(""), FPL("") }, - { FPL("/"), FPL("/") }, - { FPL("//"), FPL("//") }, - { FPL("///"), FPL("/") }, - { FPL("////"), FPL("/") }, - { FPL("a/"), FPL("a") }, - { FPL("a//"), FPL("a") }, - { FPL("a///"), FPL("a") }, - { FPL("a////"), FPL("a") }, - { FPL("/a"), FPL("/a") }, - { FPL("/a/"), FPL("/a") }, - { FPL("/a//"), FPL("/a") }, - { FPL("/a///"), FPL("/a") }, - { FPL("/a////"), FPL("/a") }, -#if defined(FILE_PATH_USES_DRIVE_LETTERS) - { FPL("c:"), FPL("c:") }, - { FPL("c:/"), FPL("c:/") }, - { FPL("c://"), FPL("c://") }, - { FPL("c:///"), FPL("c:/") }, - { FPL("c:////"), FPL("c:/") }, - { FPL("c:/a"), FPL("c:/a") }, - { FPL("c:/a/"), FPL("c:/a") }, - { FPL("c:/a//"), FPL("c:/a") }, - { FPL("c:/a///"), FPL("c:/a") }, - { FPL("c:/a////"), FPL("c:/a") }, -#endif // FILE_PATH_USES_DRIVE_LETTERS -#if defined(FILE_PATH_USES_WIN_SEPARATORS) - { FPL("\\"), FPL("\\") }, - { FPL("\\\\"), FPL("\\\\") }, - { FPL("\\\\\\"), FPL("\\") }, - { FPL("\\\\\\\\"), FPL("\\") }, - { FPL("a\\"), FPL("a") }, - { FPL("a\\\\"), FPL("a") }, - { FPL("a\\\\\\"), FPL("a") }, - { FPL("a\\\\\\\\"), FPL("a") }, - { FPL("\\a"), FPL("\\a") }, - { FPL("\\a\\"), FPL("\\a") }, - { FPL("\\a\\\\"), FPL("\\a") }, - { FPL("\\a\\\\\\"), FPL("\\a") }, - { FPL("\\a\\\\\\\\"), FPL("\\a") }, -#if defined(FILE_PATH_USES_DRIVE_LETTERS) - { FPL("c:\\"), FPL("c:\\") }, - { FPL("c:\\\\"), FPL("c:\\\\") }, - { FPL("c:\\\\\\"), FPL("c:\\") }, - { FPL("c:\\\\\\\\"), FPL("c:\\") }, - { FPL("c:\\a"), FPL("c:\\a") }, - { FPL("c:\\a\\"), FPL("c:\\a") }, - { FPL("c:\\a\\\\"), FPL("c:\\a") }, - { FPL("c:\\a\\\\\\"), FPL("c:\\a") }, - { FPL("c:\\a\\\\\\\\"), FPL("c:\\a") }, -#endif // FILE_PATH_USES_DRIVE_LETTERS -#endif // FILE_PATH_USES_WIN_SEPARATORS - }; - - for (size_t i = 0; i < arraysize(cases); ++i) { - FilePath input(cases[i].input); - FilePath observed = input.StripTrailingSeparators(); - EXPECT_EQ(FilePath::StringType(cases[i].expected), observed.value()) << - "i: " << i << ", input: " << input.value(); - } -} - -TEST_F(FilePathTest, IsAbsolute) { - const struct UnaryBooleanTestData cases[] = { - { FPL(""), false }, - { FPL("a"), false }, - { FPL("c:"), false }, - { FPL("c:a"), false }, - { FPL("a/b"), false }, - { FPL("//"), true }, - { FPL("//a"), true }, - { FPL("c:a/b"), false }, - { FPL("?:/a"), false }, -#if defined(FILE_PATH_USES_DRIVE_LETTERS) - { FPL("/"), false }, - { FPL("/a"), false }, - { FPL("/."), false }, - { FPL("/.."), false }, - { FPL("c:/"), true }, - { FPL("c:/a"), true }, - { FPL("c:/."), true }, - { FPL("c:/.."), true }, - { FPL("C:/a"), true }, - { FPL("d:/a"), true }, -#else // FILE_PATH_USES_DRIVE_LETTERS - { FPL("/"), true }, - { FPL("/a"), true }, - { FPL("/."), true }, - { FPL("/.."), true }, - { FPL("c:/"), false }, -#endif // FILE_PATH_USES_DRIVE_LETTERS -#if defined(FILE_PATH_USES_WIN_SEPARATORS) - { FPL("a\\b"), false }, - { FPL("\\\\"), true }, - { FPL("\\\\a"), true }, - { FPL("a\\b"), false }, - { FPL("\\\\"), true }, - { FPL("//a"), true }, - { FPL("c:a\\b"), false }, - { FPL("?:\\a"), false }, -#if defined(FILE_PATH_USES_DRIVE_LETTERS) - { FPL("\\"), false }, - { FPL("\\a"), false }, - { FPL("\\."), false }, - { FPL("\\.."), false }, - { FPL("c:\\"), true }, - { FPL("c:\\"), true }, - { FPL("c:\\a"), true }, - { FPL("c:\\."), true }, - { FPL("c:\\.."), true }, - { FPL("C:\\a"), true }, - { FPL("d:\\a"), true }, -#else // FILE_PATH_USES_DRIVE_LETTERS - { FPL("\\"), true }, - { FPL("\\a"), true }, - { FPL("\\."), true }, - { FPL("\\.."), true }, - { FPL("c:\\"), false }, -#endif // FILE_PATH_USES_DRIVE_LETTERS -#endif // FILE_PATH_USES_WIN_SEPARATORS - }; - - for (size_t i = 0; i < arraysize(cases); ++i) { - FilePath input(cases[i].input); - bool observed = input.IsAbsolute(); - EXPECT_EQ(cases[i].expected, observed) << - "i: " << i << ", input: " << input.value(); - } -} - -TEST_F(FilePathTest, PathComponentsTest) { - const struct UnaryTestData cases[] = { - { FPL("//foo/bar/baz/"), FPL("|//|foo|bar|baz")}, - { FPL("///"), FPL("|/")}, - { FPL("/foo//bar//baz/"), FPL("|/|foo|bar|baz")}, - { FPL("/foo/bar/baz/"), FPL("|/|foo|bar|baz")}, - { FPL("/foo/bar/baz//"), FPL("|/|foo|bar|baz")}, - { FPL("/foo/bar/baz///"), FPL("|/|foo|bar|baz")}, - { FPL("/foo/bar/baz"), FPL("|/|foo|bar|baz")}, - { FPL("/foo/bar.bot/baz.txt"), FPL("|/|foo|bar.bot|baz.txt")}, - { FPL("//foo//bar/baz"), FPL("|//|foo|bar|baz")}, - { FPL("/"), FPL("|/")}, - { FPL("foo"), FPL("|foo")}, - { FPL(""), FPL("")}, -#if defined(FILE_PATH_USES_DRIVE_LETTERS) - { FPL("e:/foo"), FPL("|e:|/|foo")}, - { FPL("e:/"), FPL("|e:|/")}, - { FPL("e:"), FPL("|e:")}, -#endif // FILE_PATH_USES_DRIVE_LETTERS -#if defined(FILE_PATH_USES_WIN_SEPARATORS) - { FPL("../foo"), FPL("|..|foo")}, - { FPL("./foo"), FPL("|foo")}, - { FPL("../foo/bar/"), FPL("|..|foo|bar") }, - { FPL("\\\\foo\\bar\\baz\\"), FPL("|\\\\|foo|bar|baz")}, - { FPL("\\\\\\"), FPL("|\\")}, - { FPL("\\foo\\\\bar\\\\baz\\"), FPL("|\\|foo|bar|baz")}, - { FPL("\\foo\\bar\\baz\\"), FPL("|\\|foo|bar|baz")}, - { FPL("\\foo\\bar\\baz\\\\"), FPL("|\\|foo|bar|baz")}, - { FPL("\\foo\\bar\\baz\\\\\\"), FPL("|\\|foo|bar|baz")}, - { FPL("\\foo\\bar\\baz"), FPL("|\\|foo|bar|baz")}, - { FPL("\\foo\\bar/baz\\\\\\"), FPL("|\\|foo|bar|baz")}, - { FPL("/foo\\bar\\baz"), FPL("|/|foo|bar|baz")}, - { FPL("\\foo\\bar.bot\\baz.txt"), FPL("|\\|foo|bar.bot|baz.txt")}, - { FPL("\\\\foo\\\\bar\\baz"), FPL("|\\\\|foo|bar|baz")}, - { FPL("\\"), FPL("|\\")}, -#endif // FILE_PATH_USES_WIN_SEPARATORS - }; - - for (size_t i = 0; i < arraysize(cases); ++i) { - FilePath input(cases[i].input); - std::vector comps; - input.GetComponents(&comps); - - FilePath::StringType observed; - for (size_t j = 0; j < comps.size(); ++j) { - observed.append(FILE_PATH_LITERAL("|"), 1); - observed.append(comps[j]); - } - EXPECT_EQ(FilePath::StringType(cases[i].expected), observed) << - "i: " << i << ", input: " << input.value(); - } -} - -TEST_F(FilePathTest, IsParentTest) { - const struct BinaryBooleanTestData cases[] = { - { { FPL("/"), FPL("/foo/bar/baz") }, true}, - { { FPL("/foo/bar"), FPL("/foo/bar/baz") }, true}, - { { FPL("/foo/bar/"), FPL("/foo/bar/baz") }, true}, - { { FPL("//foo/bar/"), FPL("//foo/bar/baz") }, true}, - { { FPL("/foo/bar"), FPL("/foo2/bar/baz") }, false}, - { { FPL("/foo/bar.txt"), FPL("/foo/bar/baz") }, false}, - { { FPL("/foo/bar"), FPL("/foo/bar2/baz") }, false}, - { { FPL("/foo/bar"), FPL("/foo/bar") }, false}, - { { FPL("/foo/bar/baz"), FPL("/foo/bar") }, false}, - { { FPL("foo/bar"), FPL("foo/bar/baz") }, true}, - { { FPL("foo/bar"), FPL("foo2/bar/baz") }, false}, - { { FPL("foo/bar"), FPL("foo/bar2/baz") }, false}, - { { FPL(""), FPL("foo") }, false}, -#if defined(FILE_PATH_USES_DRIVE_LETTERS) - { { FPL("c:/foo/bar"), FPL("c:/foo/bar/baz") }, true}, - { { FPL("E:/foo/bar"), FPL("e:/foo/bar/baz") }, true}, - { { FPL("f:/foo/bar"), FPL("F:/foo/bar/baz") }, true}, - { { FPL("E:/Foo/bar"), FPL("e:/foo/bar/baz") }, false}, - { { FPL("f:/foo/bar"), FPL("F:/foo/Bar/baz") }, false}, - { { FPL("c:/"), FPL("c:/foo/bar/baz") }, true}, - { { FPL("c:"), FPL("c:/foo/bar/baz") }, true}, - { { FPL("c:/foo/bar"), FPL("d:/foo/bar/baz") }, false}, - { { FPL("c:/foo/bar"), FPL("D:/foo/bar/baz") }, false}, - { { FPL("C:/foo/bar"), FPL("d:/foo/bar/baz") }, false}, - { { FPL("c:/foo/bar"), FPL("c:/foo2/bar/baz") }, false}, - { { FPL("e:/foo/bar"), FPL("E:/foo2/bar/baz") }, false}, - { { FPL("F:/foo/bar"), FPL("f:/foo2/bar/baz") }, false}, - { { FPL("c:/foo/bar"), FPL("c:/foo/bar2/baz") }, false}, -#endif // FILE_PATH_USES_DRIVE_LETTERS -#if defined(FILE_PATH_USES_WIN_SEPARATORS) - { { FPL("\\foo\\bar"), FPL("\\foo\\bar\\baz") }, true}, - { { FPL("\\foo/bar"), FPL("\\foo\\bar\\baz") }, true}, - { { FPL("\\foo/bar"), FPL("\\foo/bar/baz") }, true}, - { { FPL("\\"), FPL("\\foo\\bar\\baz") }, true}, - { { FPL(""), FPL("\\foo\\bar\\baz") }, false}, - { { FPL("\\foo\\bar"), FPL("\\foo2\\bar\\baz") }, false}, - { { FPL("\\foo\\bar"), FPL("\\foo\\bar2\\baz") }, false}, -#endif // FILE_PATH_USES_WIN_SEPARATORS - }; - - for (size_t i = 0; i < arraysize(cases); ++i) { - FilePath parent(cases[i].inputs[0]); - FilePath child(cases[i].inputs[1]); - - EXPECT_EQ(parent.IsParent(child), cases[i].expected) << - "i: " << i << ", parent: " << parent.value() << ", child: " << - child.value(); - } -} - -TEST_F(FilePathTest, AppendRelativePathTest) { - const struct BinaryTestData cases[] = { -#if defined(FILE_PATH_USES_WIN_SEPARATORS) - { { FPL("/"), FPL("/foo/bar/baz") }, FPL("foo\\bar\\baz")}, -#else // FILE_PATH_USES_WIN_SEPARATORS - { { FPL("/"), FPL("/foo/bar/baz") }, FPL("foo/bar/baz")}, -#endif // FILE_PATH_USES_WIN_SEPARATORS - { { FPL("/foo/bar"), FPL("/foo/bar/baz") }, FPL("baz")}, - { { FPL("/foo/bar/"), FPL("/foo/bar/baz") }, FPL("baz")}, - { { FPL("//foo/bar/"), FPL("//foo/bar/baz") }, FPL("baz")}, - { { FPL("/foo/bar"), FPL("/foo2/bar/baz") }, FPL("")}, - { { FPL("/foo/bar.txt"), FPL("/foo/bar/baz") }, FPL("")}, - { { FPL("/foo/bar"), FPL("/foo/bar2/baz") }, FPL("")}, - { { FPL("/foo/bar"), FPL("/foo/bar") }, FPL("")}, - { { FPL("/foo/bar/baz"), FPL("/foo/bar") }, FPL("")}, - { { FPL("foo/bar"), FPL("foo/bar/baz") }, FPL("baz")}, - { { FPL("foo/bar"), FPL("foo2/bar/baz") }, FPL("")}, - { { FPL("foo/bar"), FPL("foo/bar2/baz") }, FPL("")}, - { { FPL(""), FPL("foo") }, FPL("")}, -#if defined(FILE_PATH_USES_DRIVE_LETTERS) - { { FPL("c:/foo/bar"), FPL("c:/foo/bar/baz") }, FPL("baz")}, - { { FPL("E:/foo/bar"), FPL("e:/foo/bar/baz") }, FPL("baz")}, - { { FPL("f:/foo/bar"), FPL("F:/foo/bar/baz") }, FPL("baz")}, - { { FPL("E:/Foo/bar"), FPL("e:/foo/bar/baz") }, FPL("")}, - { { FPL("f:/foo/bar"), FPL("F:/foo/Bar/baz") }, FPL("")}, -#if defined(FILE_PATH_USES_WIN_SEPARATORS) - { { FPL("c:/"), FPL("c:/foo/bar/baz") }, FPL("foo\\bar\\baz")}, - // TODO(akalin): Figure out how to handle the corner case in the - // commented-out test case below. Appending to an empty path gives - // /foo\bar\baz but appending to a nonempty path "blah" gives - // blah\foo\bar\baz. - // { { FPL("c:"), FPL("c:/foo/bar/baz") }, FPL("foo\\bar\\baz")}, -#endif // FILE_PATH_USES_WIN_SEPARATORS - { { FPL("c:/foo/bar"), FPL("d:/foo/bar/baz") }, FPL("")}, - { { FPL("c:/foo/bar"), FPL("D:/foo/bar/baz") }, FPL("")}, - { { FPL("C:/foo/bar"), FPL("d:/foo/bar/baz") }, FPL("")}, - { { FPL("c:/foo/bar"), FPL("c:/foo2/bar/baz") }, FPL("")}, - { { FPL("e:/foo/bar"), FPL("E:/foo2/bar/baz") }, FPL("")}, - { { FPL("F:/foo/bar"), FPL("f:/foo2/bar/baz") }, FPL("")}, - { { FPL("c:/foo/bar"), FPL("c:/foo/bar2/baz") }, FPL("")}, -#endif // FILE_PATH_USES_DRIVE_LETTERS -#if defined(FILE_PATH_USES_WIN_SEPARATORS) - { { FPL("\\foo\\bar"), FPL("\\foo\\bar\\baz") }, FPL("baz")}, - { { FPL("\\foo/bar"), FPL("\\foo\\bar\\baz") }, FPL("baz")}, - { { FPL("\\foo/bar"), FPL("\\foo/bar/baz") }, FPL("baz")}, - { { FPL("\\"), FPL("\\foo\\bar\\baz") }, FPL("foo\\bar\\baz")}, - { { FPL(""), FPL("\\foo\\bar\\baz") }, FPL("")}, - { { FPL("\\foo\\bar"), FPL("\\foo2\\bar\\baz") }, FPL("")}, - { { FPL("\\foo\\bar"), FPL("\\foo\\bar2\\baz") }, FPL("")}, -#endif // FILE_PATH_USES_WIN_SEPARATORS - }; - - const FilePath base(FPL("blah")); - - for (size_t i = 0; i < arraysize(cases); ++i) { - FilePath parent(cases[i].inputs[0]); - FilePath child(cases[i].inputs[1]); - { - FilePath result; - bool success = parent.AppendRelativePath(child, &result); - EXPECT_EQ(cases[i].expected[0] != '\0', success) << - "i: " << i << ", parent: " << parent.value() << ", child: " << - child.value(); - EXPECT_STREQ(cases[i].expected, result.value().c_str()) << - "i: " << i << ", parent: " << parent.value() << ", child: " << - child.value(); - } - { - FilePath result(base); - bool success = parent.AppendRelativePath(child, &result); - EXPECT_EQ(cases[i].expected[0] != '\0', success) << - "i: " << i << ", parent: " << parent.value() << ", child: " << - child.value(); - EXPECT_EQ(base.Append(cases[i].expected).value(), result.value()) << - "i: " << i << ", parent: " << parent.value() << ", child: " << - child.value(); - } - } -} - -TEST_F(FilePathTest, EqualityTest) { - const struct BinaryBooleanTestData cases[] = { - { { FPL("/foo/bar/baz"), FPL("/foo/bar/baz") }, true}, - { { FPL("/foo/bar"), FPL("/foo/bar/baz") }, false}, - { { FPL("/foo/bar/baz"), FPL("/foo/bar") }, false}, - { { FPL("//foo/bar/"), FPL("//foo/bar/") }, true}, - { { FPL("/foo/bar"), FPL("/foo2/bar") }, false}, - { { FPL("/foo/bar.txt"), FPL("/foo/bar") }, false}, - { { FPL("foo/bar"), FPL("foo/bar") }, true}, - { { FPL("foo/bar"), FPL("foo/bar/baz") }, false}, - { { FPL(""), FPL("foo") }, false}, -#if defined(FILE_PATH_USES_DRIVE_LETTERS) - { { FPL("c:/foo/bar"), FPL("c:/foo/bar") }, true}, - { { FPL("E:/foo/bar"), FPL("e:/foo/bar") }, true}, - { { FPL("f:/foo/bar"), FPL("F:/foo/bar") }, true}, - { { FPL("E:/Foo/bar"), FPL("e:/foo/bar") }, false}, - { { FPL("f:/foo/bar"), FPL("F:/foo/Bar") }, false}, - { { FPL("c:/"), FPL("c:/") }, true}, - { { FPL("c:"), FPL("c:") }, true}, - { { FPL("c:/foo/bar"), FPL("d:/foo/bar") }, false}, - { { FPL("c:/foo/bar"), FPL("D:/foo/bar") }, false}, - { { FPL("C:/foo/bar"), FPL("d:/foo/bar") }, false}, - { { FPL("c:/foo/bar"), FPL("c:/foo2/bar") }, false}, -#endif // FILE_PATH_USES_DRIVE_LETTERS -#if defined(FILE_PATH_USES_WIN_SEPARATORS) - { { FPL("\\foo\\bar"), FPL("\\foo\\bar") }, true}, - { { FPL("\\foo/bar"), FPL("\\foo/bar") }, true}, - { { FPL("\\foo/bar"), FPL("\\foo\\bar") }, false}, - { { FPL("\\"), FPL("\\") }, true}, - { { FPL("\\"), FPL("/") }, false}, - { { FPL(""), FPL("\\") }, false}, - { { FPL("\\foo\\bar"), FPL("\\foo2\\bar") }, false}, - { { FPL("\\foo\\bar"), FPL("\\foo\\bar2") }, false}, -#if defined(FILE_PATH_USES_DRIVE_LETTERS) - { { FPL("c:\\foo\\bar"), FPL("c:\\foo\\bar") }, true}, - { { FPL("E:\\foo\\bar"), FPL("e:\\foo\\bar") }, true}, - { { FPL("f:\\foo\\bar"), FPL("F:\\foo/bar") }, false}, -#endif // FILE_PATH_USES_DRIVE_LETTERS -#endif // FILE_PATH_USES_WIN_SEPARATORS - }; - - for (size_t i = 0; i < arraysize(cases); ++i) { - FilePath a(cases[i].inputs[0]); - FilePath b(cases[i].inputs[1]); - - EXPECT_EQ(a == b, cases[i].expected) << - "equality i: " << i << ", a: " << a.value() << ", b: " << - b.value(); - } - - for (size_t i = 0; i < arraysize(cases); ++i) { - FilePath a(cases[i].inputs[0]); - FilePath b(cases[i].inputs[1]); - - EXPECT_EQ(a != b, !cases[i].expected) << - "inequality i: " << i << ", a: " << a.value() << ", b: " << - b.value(); - } -} - -TEST_F(FilePathTest, Extension) { - FilePath base_dir(FILE_PATH_LITERAL("base_dir")); - - FilePath jpg = base_dir.Append(FILE_PATH_LITERAL("foo.jpg")); - EXPECT_EQ(FILE_PATH_LITERAL(".jpg"), jpg.Extension()); - - FilePath base = jpg.BaseName().RemoveExtension(); - EXPECT_EQ(FILE_PATH_LITERAL("foo"), base.value()); - - FilePath path_no_ext = base_dir.Append(base); - EXPECT_EQ(path_no_ext.value(), jpg.RemoveExtension().value()); - - EXPECT_EQ(path_no_ext.value(), path_no_ext.RemoveExtension().value()); - EXPECT_EQ(FILE_PATH_LITERAL(""), path_no_ext.Extension()); -} - -TEST_F(FilePathTest, Extension2) { - const struct UnaryTestData cases[] = { -#if defined(FILE_PATH_USES_WIN_SEPARATORS) - { FPL("C:\\a\\b\\c.ext"), FPL(".ext") }, - { FPL("C:\\a\\b\\c."), FPL(".") }, - { FPL("C:\\a\\b\\c"), FPL("") }, - { FPL("C:\\a\\b\\"), FPL("") }, - { FPL("C:\\a\\b.\\"), FPL(".") }, - { FPL("C:\\a\\b\\c.ext1.ext2"), FPL(".ext2") }, - { FPL("C:\\foo.bar\\\\\\"), FPL(".bar") }, - { FPL("C:\\foo.bar\\.."), FPL("") }, - { FPL("C:\\foo.bar\\..\\\\"), FPL("") }, -#endif - { FPL("/foo/bar/baz.ext"), FPL(".ext") }, - { FPL("/foo/bar/baz."), FPL(".") }, - { FPL("/foo/bar/baz.."), FPL(".") }, - { FPL("/foo/bar/baz"), FPL("") }, - { FPL("/foo/bar/"), FPL("") }, - { FPL("/foo/bar./"), FPL(".") }, - { FPL("/foo/bar/baz.ext1.ext2"), FPL(".ext2") }, - { FPL("/foo.tar.gz"), FPL(".tar.gz") }, - { FPL("/foo.tar.Z"), FPL(".tar.Z") }, - { FPL("/foo.tar.bz2"), FPL(".tar.bz2") }, - { FPL("/subversion-1.6.12.zip"), FPL(".zip") }, - { FPL("/foo.1234.gz"), FPL(".1234.gz") }, - { FPL("/foo.12345.gz"), FPL(".gz") }, - { FPL("/foo..gz"), FPL(".gz") }, - { FPL("/foo.1234.tar.gz"), FPL(".tar.gz") }, - { FPL("/foo.tar.tar.gz"), FPL(".tar.gz") }, - { FPL("/foo.tar.gz.gz"), FPL(".gz.gz") }, - { FPL("."), FPL("") }, - { FPL(".."), FPL("") }, - { FPL("./foo"), FPL("") }, - { FPL("./foo.ext"), FPL(".ext") }, - { FPL("/foo.ext1/bar.ext2"), FPL(".ext2") }, - { FPL("/foo.bar////"), FPL(".bar") }, - { FPL("/foo.bar/.."), FPL("") }, - { FPL("/foo.bar/..////"), FPL("") }, - { FPL("/foo.1234.user.js"), FPL(".user.js") }, - { FPL("foo.user.js"), FPL(".user.js") }, - { FPL("/foo.1234.luser.js"), FPL(".js") }, - { FPL("/user.js"), FPL(".js") }, - }; - for (unsigned int i = 0; i < arraysize(cases); ++i) { - FilePath path(cases[i].input); - FilePath::StringType extension = path.Extension(); - EXPECT_STREQ(cases[i].expected, extension.c_str()) << "i: " << i << - ", path: " << path.value(); - } -} - -TEST_F(FilePathTest, InsertBeforeExtension) { - const struct BinaryTestData cases[] = { - { { FPL(""), FPL("") }, FPL("") }, - { { FPL(""), FPL("txt") }, FPL("") }, - { { FPL("."), FPL("txt") }, FPL("") }, - { { FPL(".."), FPL("txt") }, FPL("") }, - { { FPL("foo.dll"), FPL("txt") }, FPL("footxt.dll") }, - { { FPL("."), FPL("") }, FPL(".") }, - { { FPL("foo.dll"), FPL(".txt") }, FPL("foo.txt.dll") }, - { { FPL("foo"), FPL("txt") }, FPL("footxt") }, - { { FPL("foo"), FPL(".txt") }, FPL("foo.txt") }, - { { FPL("foo.baz.dll"), FPL("txt") }, FPL("foo.baztxt.dll") }, - { { FPL("foo.baz.dll"), FPL(".txt") }, FPL("foo.baz.txt.dll") }, - { { FPL("foo.dll"), FPL("") }, FPL("foo.dll") }, - { { FPL("foo.dll"), FPL(".") }, FPL("foo..dll") }, - { { FPL("foo"), FPL("") }, FPL("foo") }, - { { FPL("foo"), FPL(".") }, FPL("foo.") }, - { { FPL("foo.baz.dll"), FPL("") }, FPL("foo.baz.dll") }, - { { FPL("foo.baz.dll"), FPL(".") }, FPL("foo.baz..dll") }, -#if defined(FILE_PATH_USES_WIN_SEPARATORS) - { { FPL("\\"), FPL("") }, FPL("\\") }, - { { FPL("\\"), FPL("txt") }, FPL("\\txt") }, - { { FPL("\\."), FPL("txt") }, FPL("") }, - { { FPL("\\.."), FPL("txt") }, FPL("") }, - { { FPL("\\."), FPL("") }, FPL("\\.") }, - { { FPL("C:\\bar\\foo.dll"), FPL("txt") }, - FPL("C:\\bar\\footxt.dll") }, - { { FPL("C:\\bar.baz\\foodll"), FPL("txt") }, - FPL("C:\\bar.baz\\foodlltxt") }, - { { FPL("C:\\bar.baz\\foo.dll"), FPL("txt") }, - FPL("C:\\bar.baz\\footxt.dll") }, - { { FPL("C:\\bar.baz\\foo.dll.exe"), FPL("txt") }, - FPL("C:\\bar.baz\\foo.dlltxt.exe") }, - { { FPL("C:\\bar.baz\\foo"), FPL("") }, - FPL("C:\\bar.baz\\foo") }, - { { FPL("C:\\bar.baz\\foo.exe"), FPL("") }, - FPL("C:\\bar.baz\\foo.exe") }, - { { FPL("C:\\bar.baz\\foo.dll.exe"), FPL("") }, - FPL("C:\\bar.baz\\foo.dll.exe") }, - { { FPL("C:\\bar\\baz\\foo.exe"), FPL(" (1)") }, - FPL("C:\\bar\\baz\\foo (1).exe") }, - { { FPL("C:\\foo.baz\\\\"), FPL(" (1)") }, FPL("C:\\foo (1).baz") }, - { { FPL("C:\\foo.baz\\..\\"), FPL(" (1)") }, FPL("") }, -#endif - { { FPL("/"), FPL("") }, FPL("/") }, - { { FPL("/"), FPL("txt") }, FPL("/txt") }, - { { FPL("/."), FPL("txt") }, FPL("") }, - { { FPL("/.."), FPL("txt") }, FPL("") }, - { { FPL("/."), FPL("") }, FPL("/.") }, - { { FPL("/bar/foo.dll"), FPL("txt") }, FPL("/bar/footxt.dll") }, - { { FPL("/bar.baz/foodll"), FPL("txt") }, FPL("/bar.baz/foodlltxt") }, - { { FPL("/bar.baz/foo.dll"), FPL("txt") }, FPL("/bar.baz/footxt.dll") }, - { { FPL("/bar.baz/foo.dll.exe"), FPL("txt") }, - FPL("/bar.baz/foo.dlltxt.exe") }, - { { FPL("/bar.baz/foo"), FPL("") }, FPL("/bar.baz/foo") }, - { { FPL("/bar.baz/foo.exe"), FPL("") }, FPL("/bar.baz/foo.exe") }, - { { FPL("/bar.baz/foo.dll.exe"), FPL("") }, FPL("/bar.baz/foo.dll.exe") }, - { { FPL("/bar/baz/foo.exe"), FPL(" (1)") }, FPL("/bar/baz/foo (1).exe") }, - { { FPL("/bar/baz/..////"), FPL(" (1)") }, FPL("") }, - }; - for (unsigned int i = 0; i < arraysize(cases); ++i) { - FilePath path(cases[i].inputs[0]); - FilePath result = path.InsertBeforeExtension(cases[i].inputs[1]); - EXPECT_EQ(cases[i].expected, result.value()) << "i: " << i << - ", path: " << path.value() << ", insert: " << cases[i].inputs[1]; - } -} - -TEST_F(FilePathTest, RemoveExtension) { - const struct UnaryTestData cases[] = { - { FPL(""), FPL("") }, - { FPL("."), FPL(".") }, - { FPL(".."), FPL("..") }, - { FPL("foo.dll"), FPL("foo") }, - { FPL("./foo.dll"), FPL("./foo") }, - { FPL("foo..dll"), FPL("foo.") }, - { FPL("foo"), FPL("foo") }, - { FPL("foo."), FPL("foo") }, - { FPL("foo.."), FPL("foo.") }, - { FPL("foo.baz.dll"), FPL("foo.baz") }, - { FPL("foo.tar.gz"), FPL("foo") }, -#if defined(FILE_PATH_USES_WIN_SEPARATORS) - { FPL("C:\\foo.bar\\foo"), FPL("C:\\foo.bar\\foo") }, - { FPL("C:\\foo.bar\\..\\\\"), FPL("C:\\foo.bar\\..\\\\") }, -#endif - { FPL("/foo.bar/foo"), FPL("/foo.bar/foo") }, - { FPL("/foo.bar/..////"), FPL("/foo.bar/..////") }, - }; - for (unsigned int i = 0; i < arraysize(cases); ++i) { - FilePath path(cases[i].input); - FilePath removed = path.RemoveExtension(); - EXPECT_EQ(cases[i].expected, removed.value()) << "i: " << i << - ", path: " << path.value(); - } -} - -TEST_F(FilePathTest, ReplaceExtension) { - const struct BinaryTestData cases[] = { - { { FPL(""), FPL("") }, FPL("") }, - { { FPL(""), FPL("txt") }, FPL("") }, - { { FPL("."), FPL("txt") }, FPL("") }, - { { FPL(".."), FPL("txt") }, FPL("") }, - { { FPL("."), FPL("") }, FPL("") }, - { { FPL("foo.dll"), FPL("txt") }, FPL("foo.txt") }, - { { FPL("./foo.dll"), FPL("txt") }, FPL("./foo.txt") }, - { { FPL("foo..dll"), FPL("txt") }, FPL("foo..txt") }, - { { FPL("foo.dll"), FPL(".txt") }, FPL("foo.txt") }, - { { FPL("foo"), FPL("txt") }, FPL("foo.txt") }, - { { FPL("foo."), FPL("txt") }, FPL("foo.txt") }, - { { FPL("foo.."), FPL("txt") }, FPL("foo..txt") }, - { { FPL("foo"), FPL(".txt") }, FPL("foo.txt") }, - { { FPL("foo.baz.dll"), FPL("txt") }, FPL("foo.baz.txt") }, - { { FPL("foo.baz.dll"), FPL(".txt") }, FPL("foo.baz.txt") }, - { { FPL("foo.dll"), FPL("") }, FPL("foo") }, - { { FPL("foo.dll"), FPL(".") }, FPL("foo") }, - { { FPL("foo"), FPL("") }, FPL("foo") }, - { { FPL("foo"), FPL(".") }, FPL("foo") }, - { { FPL("foo.baz.dll"), FPL("") }, FPL("foo.baz") }, - { { FPL("foo.baz.dll"), FPL(".") }, FPL("foo.baz") }, -#if defined(FILE_PATH_USES_WIN_SEPARATORS) - { { FPL("C:\\foo.bar\\foo"), FPL("baz") }, FPL("C:\\foo.bar\\foo.baz") }, - { { FPL("C:\\foo.bar\\..\\\\"), FPL("baz") }, FPL("") }, -#endif - { { FPL("/foo.bar/foo"), FPL("baz") }, FPL("/foo.bar/foo.baz") }, - { { FPL("/foo.bar/..////"), FPL("baz") }, FPL("") }, - }; - for (unsigned int i = 0; i < arraysize(cases); ++i) { - FilePath path(cases[i].inputs[0]); - FilePath replaced = path.ReplaceExtension(cases[i].inputs[1]); - EXPECT_EQ(cases[i].expected, replaced.value()) << "i: " << i << - ", path: " << path.value() << ", replace: " << cases[i].inputs[1]; - } -} - -TEST_F(FilePathTest, AddExtension) { - const struct BinaryTestData cases[] = { - { { FPL(""), FPL("") }, FPL("") }, - { { FPL(""), FPL("txt") }, FPL("") }, - { { FPL("."), FPL("txt") }, FPL("") }, - { { FPL(".."), FPL("txt") }, FPL("") }, - { { FPL("."), FPL("") }, FPL("") }, - { { FPL("foo.dll"), FPL("txt") }, FPL("foo.dll.txt") }, - { { FPL("./foo.dll"), FPL("txt") }, FPL("./foo.dll.txt") }, - { { FPL("foo..dll"), FPL("txt") }, FPL("foo..dll.txt") }, - { { FPL("foo.dll"), FPL(".txt") }, FPL("foo.dll.txt") }, - { { FPL("foo"), FPL("txt") }, FPL("foo.txt") }, - { { FPL("foo."), FPL("txt") }, FPL("foo.txt") }, - { { FPL("foo.."), FPL("txt") }, FPL("foo..txt") }, - { { FPL("foo"), FPL(".txt") }, FPL("foo.txt") }, - { { FPL("foo.baz.dll"), FPL("txt") }, FPL("foo.baz.dll.txt") }, - { { FPL("foo.baz.dll"), FPL(".txt") }, FPL("foo.baz.dll.txt") }, - { { FPL("foo.dll"), FPL("") }, FPL("foo.dll") }, - { { FPL("foo.dll"), FPL(".") }, FPL("foo.dll") }, - { { FPL("foo"), FPL("") }, FPL("foo") }, - { { FPL("foo"), FPL(".") }, FPL("foo") }, - { { FPL("foo.baz.dll"), FPL("") }, FPL("foo.baz.dll") }, - { { FPL("foo.baz.dll"), FPL(".") }, FPL("foo.baz.dll") }, -#if defined(FILE_PATH_USES_WIN_SEPARATORS) - { { FPL("C:\\foo.bar\\foo"), FPL("baz") }, FPL("C:\\foo.bar\\foo.baz") }, - { { FPL("C:\\foo.bar\\..\\\\"), FPL("baz") }, FPL("") }, -#endif - { { FPL("/foo.bar/foo"), FPL("baz") }, FPL("/foo.bar/foo.baz") }, - { { FPL("/foo.bar/..////"), FPL("baz") }, FPL("") }, - }; - for (unsigned int i = 0; i < arraysize(cases); ++i) { - FilePath path(cases[i].inputs[0]); - FilePath added = path.AddExtension(cases[i].inputs[1]); - EXPECT_EQ(cases[i].expected, added.value()) << "i: " << i << - ", path: " << path.value() << ", add: " << cases[i].inputs[1]; - } -} - -TEST_F(FilePathTest, MatchesExtension) { - const struct BinaryBooleanTestData cases[] = { - { { FPL("foo"), FPL("") }, true}, - { { FPL("foo"), FPL(".") }, false}, - { { FPL("foo."), FPL("") }, false}, - { { FPL("foo."), FPL(".") }, true}, - { { FPL("foo.txt"), FPL(".dll") }, false}, - { { FPL("foo.txt"), FPL(".txt") }, true}, - { { FPL("foo.txt.dll"), FPL(".txt") }, false}, - { { FPL("foo.txt.dll"), FPL(".dll") }, true}, - { { FPL("foo.TXT"), FPL(".txt") }, true}, - { { FPL("foo.txt"), FPL(".TXT") }, true}, - { { FPL("foo.tXt"), FPL(".txt") }, true}, - { { FPL("foo.txt"), FPL(".tXt") }, true}, - { { FPL("foo.tXt"), FPL(".TXT") }, true}, - { { FPL("foo.tXt"), FPL(".tXt") }, true}, -#if defined(FILE_PATH_USES_DRIVE_LETTERS) - { { FPL("c:/foo.txt.dll"), FPL(".txt") }, false}, - { { FPL("c:/foo.txt"), FPL(".txt") }, true}, -#endif // FILE_PATH_USES_DRIVE_LETTERS -#if defined(FILE_PATH_USES_WIN_SEPARATORS) - { { FPL("c:\\bar\\foo.txt.dll"), FPL(".txt") }, false}, - { { FPL("c:\\bar\\foo.txt"), FPL(".txt") }, true}, -#endif // FILE_PATH_USES_DRIVE_LETTERS - { { FPL("/bar/foo.txt.dll"), FPL(".txt") }, false}, - { { FPL("/bar/foo.txt"), FPL(".txt") }, true}, -#if defined(OS_WIN) || defined(OS_MACOSX) - // Umlauts A, O, U: direct comparison, and upper case vs. lower case - { { FPL("foo.\u00E4\u00F6\u00FC"), FPL(".\u00E4\u00F6\u00FC") }, true}, - { { FPL("foo.\u00C4\u00D6\u00DC"), FPL(".\u00E4\u00F6\u00FC") }, true}, - // C with circumflex: direct comparison, and upper case vs. lower case - { { FPL("foo.\u0109"), FPL(".\u0109") }, true}, - { { FPL("foo.\u0108"), FPL(".\u0109") }, true}, -#endif - }; - - for (size_t i = 0; i < arraysize(cases); ++i) { - FilePath path(cases[i].inputs[0]); - FilePath::StringType ext(cases[i].inputs[1]); - - EXPECT_EQ(cases[i].expected, path.MatchesExtension(ext)) << - "i: " << i << ", path: " << path.value() << ", ext: " << ext; - } -} - -TEST_F(FilePathTest, CompareIgnoreCase) { - const struct BinaryIntTestData cases[] = { - { { FPL("foo"), FPL("foo") }, 0}, - { { FPL("FOO"), FPL("foo") }, 0}, - { { FPL("foo.ext"), FPL("foo.ext") }, 0}, - { { FPL("FOO.EXT"), FPL("foo.ext") }, 0}, - { { FPL("Foo.Ext"), FPL("foo.ext") }, 0}, - { { FPL("foO"), FPL("foo") }, 0}, - { { FPL("foo"), FPL("foO") }, 0}, - { { FPL("fOo"), FPL("foo") }, 0}, - { { FPL("foo"), FPL("fOo") }, 0}, - { { FPL("bar"), FPL("foo") }, -1}, - { { FPL("foo"), FPL("bar") }, 1}, - { { FPL("BAR"), FPL("foo") }, -1}, - { { FPL("FOO"), FPL("bar") }, 1}, - { { FPL("bar"), FPL("FOO") }, -1}, - { { FPL("foo"), FPL("BAR") }, 1}, - { { FPL("BAR"), FPL("FOO") }, -1}, - { { FPL("FOO"), FPL("BAR") }, 1}, - // German "Eszett" (lower case and the new-fangled upper case) - // Note that uc() => "SS", NOT ! - // However, neither Windows nor Mac OSX converts these. - // (or even have glyphs for ) - { { FPL("\u00DF"), FPL("\u00DF") }, 0}, - { { FPL("\u1E9E"), FPL("\u1E9E") }, 0}, - { { FPL("\u00DF"), FPL("\u1E9E") }, -1}, - { { FPL("SS"), FPL("\u00DF") }, -1}, - { { FPL("SS"), FPL("\u1E9E") }, -1}, -#if defined(OS_WIN) || defined(OS_MACOSX) - // Umlauts A, O, U: direct comparison, and upper case vs. lower case - { { FPL("\u00E4\u00F6\u00FC"), FPL("\u00E4\u00F6\u00FC") }, 0}, - { { FPL("\u00C4\u00D6\u00DC"), FPL("\u00E4\u00F6\u00FC") }, 0}, - // C with circumflex: direct comparison, and upper case vs. lower case - { { FPL("\u0109"), FPL("\u0109") }, 0}, - { { FPL("\u0108"), FPL("\u0109") }, 0}, - // Cyrillic letter SHA: direct comparison, and upper case vs. lower case - { { FPL("\u0428"), FPL("\u0428") }, 0}, - { { FPL("\u0428"), FPL("\u0448") }, 0}, - // Greek letter DELTA: direct comparison, and upper case vs. lower case - { { FPL("\u0394"), FPL("\u0394") }, 0}, - { { FPL("\u0394"), FPL("\u03B4") }, 0}, - // Japanese full-width A: direct comparison, and upper case vs. lower case - // Note that full-width and standard characters are considered different. - { { FPL("\uFF21"), FPL("\uFF21") }, 0}, - { { FPL("\uFF21"), FPL("\uFF41") }, 0}, - { { FPL("A"), FPL("\uFF21") }, -1}, - { { FPL("A"), FPL("\uFF41") }, -1}, - { { FPL("a"), FPL("\uFF21") }, -1}, - { { FPL("a"), FPL("\uFF41") }, -1}, -#endif -#if defined(OS_MACOSX) - // Codepoints > 0x1000 - // Georgian letter DON: direct comparison, and upper case vs. lower case - { { FPL("\u10A3"), FPL("\u10A3") }, 0}, - { { FPL("\u10A3"), FPL("\u10D3") }, 0}, - // Combining characters vs. pre-composed characters, upper and lower case - { { FPL("k\u0301u\u032Do\u0304\u0301n"), FPL("\u1E31\u1E77\u1E53n") }, 0}, - { { FPL("k\u0301u\u032Do\u0304\u0301n"), FPL("kuon") }, 1}, - { { FPL("kuon"), FPL("k\u0301u\u032Do\u0304\u0301n") }, -1}, - { { FPL("K\u0301U\u032DO\u0304\u0301N"), FPL("KUON") }, 1}, - { { FPL("KUON"), FPL("K\u0301U\u032DO\u0304\u0301N") }, -1}, - { { FPL("k\u0301u\u032Do\u0304\u0301n"), FPL("KUON") }, 1}, - { { FPL("K\u0301U\u032DO\u0304\u0301N"), FPL("\u1E31\u1E77\u1E53n") }, 0}, - { { FPL("k\u0301u\u032Do\u0304\u0301n"), FPL("\u1E30\u1E76\u1E52n") }, 0}, - { { FPL("k\u0301u\u032Do\u0304\u0302n"), FPL("\u1E30\u1E76\u1E52n") }, 1}, -#endif - }; - - for (size_t i = 0; i < arraysize(cases); ++i) { - FilePath::StringType s1(cases[i].inputs[0]); - FilePath::StringType s2(cases[i].inputs[1]); - int result = FilePath::CompareIgnoreCase(s1, s2); - EXPECT_EQ(cases[i].expected, result) << - "i: " << i << ", s1: " << s1 << ", s2: " << s2; - } -} - -TEST_F(FilePathTest, ReferencesParent) { - const struct UnaryBooleanTestData cases[] = { - { FPL("."), false }, - { FPL(".."), true }, - { FPL(".. "), true }, - { FPL(" .."), true }, - { FPL("..."), true }, - { FPL("a.."), false }, - { FPL("..a"), false }, - { FPL("../"), true }, - { FPL("/.."), true }, - { FPL("/../"), true }, - { FPL("/a../"), false }, - { FPL("/..a/"), false }, - { FPL("//.."), true }, - { FPL("..//"), true }, - { FPL("//..//"), true }, - { FPL("a//..//c"), true }, - { FPL("../b/c"), true }, - { FPL("/../b/c"), true }, - { FPL("a/b/.."), true }, - { FPL("a/b/../"), true }, - { FPL("a/../c"), true }, - { FPL("a/b/c"), false }, - }; - - for (size_t i = 0; i < arraysize(cases); ++i) { - FilePath input(cases[i].input); - bool observed = input.ReferencesParent(); - EXPECT_EQ(cases[i].expected, observed) << - "i: " << i << ", input: " << input.value(); - } -} - -TEST_F(FilePathTest, FromUTF8Unsafe_And_AsUTF8Unsafe) { - const struct UTF8TestData cases[] = { - { FPL("foo.txt"), "foo.txt" }, - // "aeo" with accents. Use http://0xcc.net/jsescape/ to decode them. - { FPL("\u00E0\u00E8\u00F2.txt"), "\xC3\xA0\xC3\xA8\xC3\xB2.txt" }, - // Full-width "ABC". - { FPL("\uFF21\uFF22\uFF23.txt"), - "\xEF\xBC\xA1\xEF\xBC\xA2\xEF\xBC\xA3.txt" }, - }; - - for (size_t i = 0; i < arraysize(cases); ++i) { - // Test FromUTF8Unsafe() works. - FilePath from_utf8 = FilePath::FromUTF8Unsafe(cases[i].utf8); - EXPECT_EQ(cases[i].native, from_utf8.value()) - << "i: " << i << ", input: " << cases[i].native; - // Test AsUTF8Unsafe() works. - FilePath from_native = FilePath(cases[i].native); - EXPECT_EQ(cases[i].utf8, from_native.AsUTF8Unsafe()) - << "i: " << i << ", input: " << cases[i].native; - // Test the two file paths are identical. - EXPECT_EQ(from_utf8.value(), from_native.value()); - } -} - -TEST_F(FilePathTest, ConstructWithNUL) { - // Assert FPS() works. - ASSERT_EQ(3U, FPS("a\0b").length()); - - // Test constructor strips '\0' - FilePath path(FPS("a\0b")); - EXPECT_EQ(1U, path.value().length()); - EXPECT_EQ(FPL("a"), path.value()); -} - -TEST_F(FilePathTest, AppendWithNUL) { - // Assert FPS() works. - ASSERT_EQ(3U, FPS("b\0b").length()); - - // Test Append() strips '\0' - FilePath path(FPL("a")); - path = path.Append(FPS("b\0b")); - EXPECT_EQ(3U, path.value().length()); -#if defined(FILE_PATH_USES_WIN_SEPARATORS) - EXPECT_EQ(FPL("a\\b"), path.value()); -#else - EXPECT_EQ(FPL("a/b"), path.value()); -#endif -} - -TEST_F(FilePathTest, ReferencesParentWithNUL) { - // Assert FPS() works. - ASSERT_EQ(3U, FPS("..\0").length()); - - // Test ReferencesParent() doesn't break with "..\0" - FilePath path(FPS("..\0")); - EXPECT_TRUE(path.ReferencesParent()); -} - -#if defined(FILE_PATH_USES_WIN_SEPARATORS) -TEST_F(FilePathTest, NormalizePathSeparators) { - const struct UnaryTestData cases[] = { - { FPL("foo/bar"), FPL("foo\\bar") }, - { FPL("foo/bar\\betz"), FPL("foo\\bar\\betz") }, - { FPL("foo\\bar"), FPL("foo\\bar") }, - { FPL("foo\\bar/betz"), FPL("foo\\bar\\betz") }, - { FPL("foo"), FPL("foo") }, - // Trailing slashes don't automatically get stripped. That's what - // StripTrailingSeparators() is for. - { FPL("foo\\"), FPL("foo\\") }, - { FPL("foo/"), FPL("foo\\") }, - { FPL("foo/bar\\"), FPL("foo\\bar\\") }, - { FPL("foo\\bar/"), FPL("foo\\bar\\") }, - { FPL("foo/bar/"), FPL("foo\\bar\\") }, - { FPL("foo\\bar\\"), FPL("foo\\bar\\") }, - { FPL("\\foo/bar"), FPL("\\foo\\bar") }, - { FPL("/foo\\bar"), FPL("\\foo\\bar") }, - { FPL("c:/foo/bar/"), FPL("c:\\foo\\bar\\") }, - { FPL("/foo/bar/"), FPL("\\foo\\bar\\") }, - { FPL("\\foo\\bar\\"), FPL("\\foo\\bar\\") }, - { FPL("c:\\foo/bar"), FPL("c:\\foo\\bar") }, - { FPL("//foo\\bar\\"), FPL("\\\\foo\\bar\\") }, - { FPL("\\\\foo\\bar\\"), FPL("\\\\foo\\bar\\") }, - { FPL("//foo\\bar\\"), FPL("\\\\foo\\bar\\") }, - // This method does not normalize the number of path separators. - { FPL("foo\\\\bar"), FPL("foo\\\\bar") }, - { FPL("foo//bar"), FPL("foo\\\\bar") }, - { FPL("foo/\\bar"), FPL("foo\\\\bar") }, - { FPL("foo\\/bar"), FPL("foo\\\\bar") }, - { FPL("///foo\\\\bar"), FPL("\\\\\\foo\\\\bar") }, - { FPL("foo//bar///"), FPL("foo\\\\bar\\\\\\") }, - { FPL("foo/\\bar/\\"), FPL("foo\\\\bar\\\\") }, - { FPL("/\\foo\\/bar"), FPL("\\\\foo\\\\bar") }, - }; - for (size_t i = 0; i < arraysize(cases); ++i) { - FilePath input(cases[i].input); - FilePath observed = input.NormalizePathSeparators(); - EXPECT_EQ(FilePath::StringType(cases[i].expected), observed.value()) << - "i: " << i << ", input: " << input.value(); - } -} -#endif - -TEST_F(FilePathTest, EndsWithSeparator) { - const UnaryBooleanTestData cases[] = { - { FPL(""), false }, - { FPL("/"), true }, - { FPL("foo/"), true }, - { FPL("bar"), false }, - { FPL("/foo/bar"), false }, - }; - for (size_t i = 0; i < arraysize(cases); ++i) { - FilePath input = FilePath(cases[i].input).NormalizePathSeparators(); - EXPECT_EQ(cases[i].expected, input.EndsWithSeparator()); - } -} - -TEST_F(FilePathTest, AsEndingWithSeparator) { - const UnaryTestData cases[] = { - { FPL(""), FPL("") }, - { FPL("/"), FPL("/") }, - { FPL("foo"), FPL("foo/") }, - { FPL("foo/"), FPL("foo/") } - }; - for (size_t i = 0; i < arraysize(cases); ++i) { - FilePath input = FilePath(cases[i].input).NormalizePathSeparators(); - FilePath expected = FilePath(cases[i].expected).NormalizePathSeparators(); - EXPECT_EQ(expected.value(), input.AsEndingWithSeparator().value()); - } -} - -} // namespace base diff --git a/base/files/file_path_watcher.cc b/base/files/file_path_watcher.cc deleted file mode 100644 index 49e0a237f6..0000000000 --- a/base/files/file_path_watcher.cc +++ /dev/null @@ -1,39 +0,0 @@ -// Copyright (c) 2011 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -// Cross platform methods for FilePathWatcher. See the various platform -// specific implementation files, too. - -#include "base/files/file_path_watcher.h" - -#include "base/logging.h" -#include "base/message_loop/message_loop.h" - -namespace base { - -FilePathWatcher::~FilePathWatcher() { - impl_->Cancel(); -} - -// static -void FilePathWatcher::CancelWatch( - const scoped_refptr& delegate) { - delegate->CancelOnMessageLoopThread(); -} - -FilePathWatcher::PlatformDelegate::PlatformDelegate(): cancelled_(false) { -} - -FilePathWatcher::PlatformDelegate::~PlatformDelegate() { - DCHECK(is_cancelled()); -} - -bool FilePathWatcher::Watch(const FilePath& path, - bool recursive, - const Callback& callback) { - DCHECK(path.IsAbsolute()); - return impl_->Watch(path, recursive, callback); -} - -} // namespace base diff --git a/base/files/file_path_watcher.h b/base/files/file_path_watcher.h deleted file mode 100644 index 3c1941f012..0000000000 --- a/base/files/file_path_watcher.h +++ /dev/null @@ -1,108 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -// This module provides a way to monitor a file or directory for changes. - -#ifndef BASE_FILES_FILE_PATH_WATCHER_H_ -#define BASE_FILES_FILE_PATH_WATCHER_H_ - -#include "base/base_export.h" -#include "base/basictypes.h" -#include "base/callback.h" -#include "base/files/file_path.h" -#include "base/memory/ref_counted.h" -#include "base/message_loop/message_loop_proxy.h" - -namespace base { - -// This class lets you register interest in changes on a FilePath. -// The callback will get called whenever the file or directory referenced by the -// FilePath is changed, including created or deleted. Due to limitations in the -// underlying OS APIs, FilePathWatcher has slightly different semantics on OS X -// than on Windows or Linux. FilePathWatcher on Linux and Windows will detect -// modifications to files in a watched directory. FilePathWatcher on Mac will -// detect the creation and deletion of files in a watched directory, but will -// not detect modifications to those files. See file_path_watcher_kqueue.cc for -// details. -class BASE_EXPORT FilePathWatcher { - public: - // Callback type for Watch(). |path| points to the file that was updated, - // and |error| is true if the platform specific code detected an error. In - // that case, the callback won't be invoked again. - typedef base::Callback Callback; - - // Used internally to encapsulate different members on different platforms. - class PlatformDelegate : public base::RefCountedThreadSafe { - public: - PlatformDelegate(); - - // Start watching for the given |path| and notify |delegate| about changes. - virtual bool Watch(const FilePath& path, - bool recursive, - const Callback& callback) WARN_UNUSED_RESULT = 0; - - // Stop watching. This is called from FilePathWatcher's dtor in order to - // allow to shut down properly while the object is still alive. - // It can be called from any thread. - virtual void Cancel() = 0; - - protected: - friend class base::RefCountedThreadSafe; - friend class FilePathWatcher; - - virtual ~PlatformDelegate(); - - // Stop watching. This is only called on the thread of the appropriate - // message loop. Since it can also be called more than once, it should - // check |is_cancelled()| to avoid duplicate work. - virtual void CancelOnMessageLoopThread() = 0; - - scoped_refptr message_loop() const { - return message_loop_; - } - - void set_message_loop(base::MessageLoopProxy* loop) { - message_loop_ = loop; - } - - // Must be called before the PlatformDelegate is deleted. - void set_cancelled() { - cancelled_ = true; - } - - bool is_cancelled() const { - return cancelled_; - } - - private: - scoped_refptr message_loop_; - bool cancelled_; - }; - - FilePathWatcher(); - virtual ~FilePathWatcher(); - - // A callback that always cleans up the PlatformDelegate, either when executed - // or when deleted without having been executed at all, as can happen during - // shutdown. - static void CancelWatch(const scoped_refptr& delegate); - - // Invokes |callback| whenever updates to |path| are detected. This should be - // called at most once, and from a MessageLoop of TYPE_IO. Set |recursive| to - // true, to watch |path| and its children. The callback will be invoked on - // the same loop. Returns true on success. - // - // NOTE: Recursive watch is not supported on all platforms and file systems. - // Watch() will return false in the case of failure. - bool Watch(const FilePath& path, bool recursive, const Callback& callback); - - private: - scoped_refptr impl_; - - DISALLOW_COPY_AND_ASSIGN(FilePathWatcher); -}; - -} // namespace base - -#endif // BASE_FILES_FILE_PATH_WATCHER_H_ diff --git a/base/files/file_path_watcher_browsertest.cc b/base/files/file_path_watcher_browsertest.cc deleted file mode 100644 index 69ff80608a..0000000000 --- a/base/files/file_path_watcher_browsertest.cc +++ /dev/null @@ -1,909 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "base/files/file_path_watcher.h" - -#if defined(OS_WIN) -#include -#include -#elif defined(OS_POSIX) -#include -#endif - -#include - -#include "base/basictypes.h" -#include "base/bind.h" -#include "base/bind_helpers.h" -#include "base/compiler_specific.h" -#include "base/file_util.h" -#include "base/files/file_path.h" -#include "base/files/scoped_temp_dir.h" -#include "base/message_loop/message_loop.h" -#include "base/message_loop/message_loop_proxy.h" -#include "base/run_loop.h" -#include "base/stl_util.h" -#include "base/strings/stringprintf.h" -#include "base/synchronization/waitable_event.h" -#include "base/test/test_file_util.h" -#include "base/test/test_timeouts.h" -#include "base/threading/thread.h" -#include "testing/gtest/include/gtest/gtest.h" - -namespace base { - -namespace { - -class TestDelegate; - -// Aggregates notifications from the test delegates and breaks the message loop -// the test thread is waiting on once they all came in. -class NotificationCollector - : public base::RefCountedThreadSafe { - public: - NotificationCollector() - : loop_(base::MessageLoopProxy::current()) {} - - // Called from the file thread by the delegates. - void OnChange(TestDelegate* delegate) { - loop_->PostTask(FROM_HERE, - base::Bind(&NotificationCollector::RecordChange, this, - base::Unretained(delegate))); - } - - void Register(TestDelegate* delegate) { - delegates_.insert(delegate); - } - - void Reset() { - signaled_.clear(); - } - - bool Success() { - return signaled_ == delegates_; - } - - private: - friend class base::RefCountedThreadSafe; - ~NotificationCollector() {} - - void RecordChange(TestDelegate* delegate) { - // Warning: |delegate| is Unretained. Do not dereference. - ASSERT_TRUE(loop_->BelongsToCurrentThread()); - ASSERT_TRUE(delegates_.count(delegate)); - signaled_.insert(delegate); - - // Check whether all delegates have been signaled. - if (signaled_ == delegates_) - loop_->PostTask(FROM_HERE, MessageLoop::QuitWhenIdleClosure()); - } - - // Set of registered delegates. - std::set delegates_; - - // Set of signaled delegates. - std::set signaled_; - - // The loop we should break after all delegates signaled. - scoped_refptr loop_; -}; - -class TestDelegateBase : public SupportsWeakPtr { - public: - TestDelegateBase() {} - virtual ~TestDelegateBase() {} - - virtual void OnFileChanged(const FilePath& path, bool error) = 0; - - private: - DISALLOW_COPY_AND_ASSIGN(TestDelegateBase); -}; - -// A mock class for testing. Gmock is not appropriate because it is not -// thread-safe for setting expectations. Thus the test code cannot safely -// reset expectations while the file watcher is running. -// Instead, TestDelegate gets the notifications from FilePathWatcher and uses -// NotificationCollector to aggregate the results. -class TestDelegate : public TestDelegateBase { - public: - explicit TestDelegate(NotificationCollector* collector) - : collector_(collector) { - collector_->Register(this); - } - virtual ~TestDelegate() {} - - virtual void OnFileChanged(const FilePath& path, bool error) OVERRIDE { - if (error) - ADD_FAILURE() << "Error " << path.value(); - else - collector_->OnChange(this); - } - - private: - scoped_refptr collector_; - - DISALLOW_COPY_AND_ASSIGN(TestDelegate); -}; - -void SetupWatchCallback(const FilePath& target, - FilePathWatcher* watcher, - TestDelegateBase* delegate, - bool recursive_watch, - bool* result, - base::WaitableEvent* completion) { - *result = watcher->Watch(target, recursive_watch, - base::Bind(&TestDelegateBase::OnFileChanged, - delegate->AsWeakPtr())); - completion->Signal(); -} - -void QuitLoopWatchCallback(MessageLoop* loop, - const FilePath& expected_path, - bool expected_error, - bool* flag, - const FilePath& path, - bool error) { - ASSERT_TRUE(flag); - *flag = true; - EXPECT_EQ(expected_path, path); - EXPECT_EQ(expected_error, error); - loop->PostTask(FROM_HERE, loop->QuitWhenIdleClosure()); -} - -class FilePathWatcherTest : public testing::Test { - public: - FilePathWatcherTest() - : file_thread_("FilePathWatcherTest") {} - - virtual ~FilePathWatcherTest() {} - - protected: - virtual void SetUp() OVERRIDE { - // Create a separate file thread in order to test proper thread usage. - base::Thread::Options options(MessageLoop::TYPE_IO, 0); - ASSERT_TRUE(file_thread_.StartWithOptions(options)); - ASSERT_TRUE(temp_dir_.CreateUniqueTempDir()); - collector_ = new NotificationCollector(); - } - - virtual void TearDown() OVERRIDE { - RunLoop().RunUntilIdle(); - } - - void DeleteDelegateOnFileThread(TestDelegate* delegate) { - file_thread_.message_loop_proxy()->DeleteSoon(FROM_HERE, delegate); - } - - FilePath test_file() { - return temp_dir_.path().AppendASCII("FilePathWatcherTest"); - } - - FilePath test_link() { - return temp_dir_.path().AppendASCII("FilePathWatcherTest.lnk"); - } - - // Write |content| to |file|. Returns true on success. - bool WriteFile(const FilePath& file, const std::string& content) { - int write_size = file_util::WriteFile(file, content.c_str(), - content.length()); - return write_size == static_cast(content.length()); - } - - bool SetupWatch(const FilePath& target, - FilePathWatcher* watcher, - TestDelegateBase* delegate, - bool recursive_watch) WARN_UNUSED_RESULT; - - bool WaitForEvents() WARN_UNUSED_RESULT { - collector_->Reset(); - loop_.Run(); - return collector_->Success(); - } - - NotificationCollector* collector() { return collector_.get(); } - - MessageLoop loop_; - base::Thread file_thread_; - ScopedTempDir temp_dir_; - scoped_refptr collector_; - - DISALLOW_COPY_AND_ASSIGN(FilePathWatcherTest); -}; - -bool FilePathWatcherTest::SetupWatch(const FilePath& target, - FilePathWatcher* watcher, - TestDelegateBase* delegate, - bool recursive_watch) { - base::WaitableEvent completion(false, false); - bool result; - file_thread_.message_loop_proxy()->PostTask( - FROM_HERE, - base::Bind(SetupWatchCallback, - target, watcher, delegate, recursive_watch, &result, - &completion)); - completion.Wait(); - return result; -} - -// Basic test: Create the file and verify that we notice. -TEST_F(FilePathWatcherTest, NewFile) { - FilePathWatcher watcher; - scoped_ptr delegate(new TestDelegate(collector())); - ASSERT_TRUE(SetupWatch(test_file(), &watcher, delegate.get(), false)); - - ASSERT_TRUE(WriteFile(test_file(), "content")); - ASSERT_TRUE(WaitForEvents()); - DeleteDelegateOnFileThread(delegate.release()); -} - -// Verify that modifying the file is caught. -TEST_F(FilePathWatcherTest, ModifiedFile) { - ASSERT_TRUE(WriteFile(test_file(), "content")); - - FilePathWatcher watcher; - scoped_ptr delegate(new TestDelegate(collector())); - ASSERT_TRUE(SetupWatch(test_file(), &watcher, delegate.get(), false)); - - // Now make sure we get notified if the file is modified. - ASSERT_TRUE(WriteFile(test_file(), "new content")); - ASSERT_TRUE(WaitForEvents()); - DeleteDelegateOnFileThread(delegate.release()); -} - -// Verify that moving the file into place is caught. -TEST_F(FilePathWatcherTest, MovedFile) { - FilePath source_file(temp_dir_.path().AppendASCII("source")); - ASSERT_TRUE(WriteFile(source_file, "content")); - - FilePathWatcher watcher; - scoped_ptr delegate(new TestDelegate(collector())); - ASSERT_TRUE(SetupWatch(test_file(), &watcher, delegate.get(), false)); - - // Now make sure we get notified if the file is modified. - ASSERT_TRUE(base::Move(source_file, test_file())); - ASSERT_TRUE(WaitForEvents()); - DeleteDelegateOnFileThread(delegate.release()); -} - -TEST_F(FilePathWatcherTest, DeletedFile) { - ASSERT_TRUE(WriteFile(test_file(), "content")); - - FilePathWatcher watcher; - scoped_ptr delegate(new TestDelegate(collector())); - ASSERT_TRUE(SetupWatch(test_file(), &watcher, delegate.get(), false)); - - // Now make sure we get notified if the file is deleted. - base::DeleteFile(test_file(), false); - ASSERT_TRUE(WaitForEvents()); - DeleteDelegateOnFileThread(delegate.release()); -} - -// Used by the DeleteDuringNotify test below. -// Deletes the FilePathWatcher when it's notified. -class Deleter : public TestDelegateBase { - public: - Deleter(FilePathWatcher* watcher, MessageLoop* loop) - : watcher_(watcher), - loop_(loop) { - } - virtual ~Deleter() {} - - virtual void OnFileChanged(const FilePath&, bool) OVERRIDE { - watcher_.reset(); - loop_->PostTask(FROM_HERE, MessageLoop::QuitWhenIdleClosure()); - } - - FilePathWatcher* watcher() const { return watcher_.get(); } - - private: - scoped_ptr watcher_; - MessageLoop* loop_; - - DISALLOW_COPY_AND_ASSIGN(Deleter); -}; - -// Verify that deleting a watcher during the callback doesn't crash. -TEST_F(FilePathWatcherTest, DeleteDuringNotify) { - FilePathWatcher* watcher = new FilePathWatcher; - // Takes ownership of watcher. - scoped_ptr deleter(new Deleter(watcher, &loop_)); - ASSERT_TRUE(SetupWatch(test_file(), watcher, deleter.get(), false)); - - ASSERT_TRUE(WriteFile(test_file(), "content")); - ASSERT_TRUE(WaitForEvents()); - - // We win if we haven't crashed yet. - // Might as well double-check it got deleted, too. - ASSERT_TRUE(deleter->watcher() == NULL); -} - -// Verify that deleting the watcher works even if there is a pending -// notification. -// Flaky on MacOS (and ARM linux): http://crbug.com/85930 -TEST_F(FilePathWatcherTest, DISABLED_DestroyWithPendingNotification) { - scoped_ptr delegate(new TestDelegate(collector())); - FilePathWatcher* watcher = new FilePathWatcher; - ASSERT_TRUE(SetupWatch(test_file(), watcher, delegate.get(), false)); - ASSERT_TRUE(WriteFile(test_file(), "content")); - file_thread_.message_loop_proxy()->DeleteSoon(FROM_HERE, watcher); - DeleteDelegateOnFileThread(delegate.release()); -} - -TEST_F(FilePathWatcherTest, MultipleWatchersSingleFile) { - FilePathWatcher watcher1, watcher2; - scoped_ptr delegate1(new TestDelegate(collector())); - scoped_ptr delegate2(new TestDelegate(collector())); - ASSERT_TRUE(SetupWatch(test_file(), &watcher1, delegate1.get(), false)); - ASSERT_TRUE(SetupWatch(test_file(), &watcher2, delegate2.get(), false)); - - ASSERT_TRUE(WriteFile(test_file(), "content")); - ASSERT_TRUE(WaitForEvents()); - DeleteDelegateOnFileThread(delegate1.release()); - DeleteDelegateOnFileThread(delegate2.release()); -} - -// Verify that watching a file whose parent directory doesn't exist yet works if -// the directory and file are created eventually. -TEST_F(FilePathWatcherTest, NonExistentDirectory) { - FilePathWatcher watcher; - FilePath dir(temp_dir_.path().AppendASCII("dir")); - FilePath file(dir.AppendASCII("file")); - scoped_ptr delegate(new TestDelegate(collector())); - ASSERT_TRUE(SetupWatch(file, &watcher, delegate.get(), false)); - - ASSERT_TRUE(file_util::CreateDirectory(dir)); - - ASSERT_TRUE(WriteFile(file, "content")); - - VLOG(1) << "Waiting for file creation"; - ASSERT_TRUE(WaitForEvents()); - - ASSERT_TRUE(WriteFile(file, "content v2")); - VLOG(1) << "Waiting for file change"; - ASSERT_TRUE(WaitForEvents()); - - ASSERT_TRUE(base::DeleteFile(file, false)); - VLOG(1) << "Waiting for file deletion"; - ASSERT_TRUE(WaitForEvents()); - DeleteDelegateOnFileThread(delegate.release()); -} - -// Exercises watch reconfiguration for the case that directories on the path -// are rapidly created. -TEST_F(FilePathWatcherTest, DirectoryChain) { - FilePath path(temp_dir_.path()); - std::vector dir_names; - for (int i = 0; i < 20; i++) { - std::string dir(base::StringPrintf("d%d", i)); - dir_names.push_back(dir); - path = path.AppendASCII(dir); - } - - FilePathWatcher watcher; - FilePath file(path.AppendASCII("file")); - scoped_ptr delegate(new TestDelegate(collector())); - ASSERT_TRUE(SetupWatch(file, &watcher, delegate.get(), false)); - - FilePath sub_path(temp_dir_.path()); - for (std::vector::const_iterator d(dir_names.begin()); - d != dir_names.end(); ++d) { - sub_path = sub_path.AppendASCII(*d); - ASSERT_TRUE(file_util::CreateDirectory(sub_path)); - } - VLOG(1) << "Create File"; - ASSERT_TRUE(WriteFile(file, "content")); - VLOG(1) << "Waiting for file creation"; - ASSERT_TRUE(WaitForEvents()); - - ASSERT_TRUE(WriteFile(file, "content v2")); - VLOG(1) << "Waiting for file modification"; - ASSERT_TRUE(WaitForEvents()); - DeleteDelegateOnFileThread(delegate.release()); -} - -#if defined(OS_MACOSX) -// http://crbug.com/85930 -#define DisappearingDirectory DISABLED_DisappearingDirectory -#endif -TEST_F(FilePathWatcherTest, DisappearingDirectory) { - FilePathWatcher watcher; - FilePath dir(temp_dir_.path().AppendASCII("dir")); - FilePath file(dir.AppendASCII("file")); - ASSERT_TRUE(file_util::CreateDirectory(dir)); - ASSERT_TRUE(WriteFile(file, "content")); - scoped_ptr delegate(new TestDelegate(collector())); - ASSERT_TRUE(SetupWatch(file, &watcher, delegate.get(), false)); - - ASSERT_TRUE(base::DeleteFile(dir, true)); - ASSERT_TRUE(WaitForEvents()); - DeleteDelegateOnFileThread(delegate.release()); -} - -// Tests that a file that is deleted and reappears is tracked correctly. -TEST_F(FilePathWatcherTest, DeleteAndRecreate) { - ASSERT_TRUE(WriteFile(test_file(), "content")); - FilePathWatcher watcher; - scoped_ptr delegate(new TestDelegate(collector())); - ASSERT_TRUE(SetupWatch(test_file(), &watcher, delegate.get(), false)); - - ASSERT_TRUE(base::DeleteFile(test_file(), false)); - VLOG(1) << "Waiting for file deletion"; - ASSERT_TRUE(WaitForEvents()); - - ASSERT_TRUE(WriteFile(test_file(), "content")); - VLOG(1) << "Waiting for file creation"; - ASSERT_TRUE(WaitForEvents()); - DeleteDelegateOnFileThread(delegate.release()); -} - -TEST_F(FilePathWatcherTest, WatchDirectory) { - FilePathWatcher watcher; - FilePath dir(temp_dir_.path().AppendASCII("dir")); - FilePath file1(dir.AppendASCII("file1")); - FilePath file2(dir.AppendASCII("file2")); - scoped_ptr delegate(new TestDelegate(collector())); - ASSERT_TRUE(SetupWatch(dir, &watcher, delegate.get(), false)); - - ASSERT_TRUE(file_util::CreateDirectory(dir)); - VLOG(1) << "Waiting for directory creation"; - ASSERT_TRUE(WaitForEvents()); - - ASSERT_TRUE(WriteFile(file1, "content")); - VLOG(1) << "Waiting for file1 creation"; - ASSERT_TRUE(WaitForEvents()); - -#if !defined(OS_MACOSX) - // Mac implementation does not detect files modified in a directory. - ASSERT_TRUE(WriteFile(file1, "content v2")); - VLOG(1) << "Waiting for file1 modification"; - ASSERT_TRUE(WaitForEvents()); -#endif // !OS_MACOSX - - ASSERT_TRUE(base::DeleteFile(file1, false)); - VLOG(1) << "Waiting for file1 deletion"; - ASSERT_TRUE(WaitForEvents()); - - ASSERT_TRUE(WriteFile(file2, "content")); - VLOG(1) << "Waiting for file2 creation"; - ASSERT_TRUE(WaitForEvents()); - DeleteDelegateOnFileThread(delegate.release()); -} - -TEST_F(FilePathWatcherTest, MoveParent) { - FilePathWatcher file_watcher; - FilePathWatcher subdir_watcher; - FilePath dir(temp_dir_.path().AppendASCII("dir")); - FilePath dest(temp_dir_.path().AppendASCII("dest")); - FilePath subdir(dir.AppendASCII("subdir")); - FilePath file(subdir.AppendASCII("file")); - scoped_ptr file_delegate(new TestDelegate(collector())); - ASSERT_TRUE(SetupWatch(file, &file_watcher, file_delegate.get(), false)); - scoped_ptr subdir_delegate(new TestDelegate(collector())); - ASSERT_TRUE(SetupWatch(subdir, &subdir_watcher, subdir_delegate.get(), - false)); - - // Setup a directory hierarchy. - ASSERT_TRUE(file_util::CreateDirectory(subdir)); - ASSERT_TRUE(WriteFile(file, "content")); - VLOG(1) << "Waiting for file creation"; - ASSERT_TRUE(WaitForEvents()); - - // Move the parent directory. - base::Move(dir, dest); - VLOG(1) << "Waiting for directory move"; - ASSERT_TRUE(WaitForEvents()); - DeleteDelegateOnFileThread(file_delegate.release()); - DeleteDelegateOnFileThread(subdir_delegate.release()); -} - -#if defined(OS_WIN) -TEST_F(FilePathWatcherTest, RecursiveWatch) { - FilePathWatcher watcher; - FilePath dir(temp_dir_.path().AppendASCII("dir")); - scoped_ptr delegate(new TestDelegate(collector())); - ASSERT_TRUE(SetupWatch(dir, &watcher, delegate.get(), true)); - - // Main directory("dir") creation. - ASSERT_TRUE(file_util::CreateDirectory(dir)); - ASSERT_TRUE(WaitForEvents()); - - // Create "$dir/file1". - FilePath file1(dir.AppendASCII("file1")); - ASSERT_TRUE(WriteFile(file1, "content")); - ASSERT_TRUE(WaitForEvents()); - - // Create "$dir/subdir". - FilePath subdir(dir.AppendASCII("subdir")); - ASSERT_TRUE(file_util::CreateDirectory(subdir)); - ASSERT_TRUE(WaitForEvents()); - - // Create "$dir/subdir/subdir_file1". - FilePath subdir_file1(subdir.AppendASCII("subdir_file1")); - ASSERT_TRUE(WriteFile(subdir_file1, "content")); - ASSERT_TRUE(WaitForEvents()); - - // Create "$dir/subdir/subdir_child_dir". - FilePath subdir_child_dir(subdir.AppendASCII("subdir_child_dir")); - ASSERT_TRUE(file_util::CreateDirectory(subdir_child_dir)); - ASSERT_TRUE(WaitForEvents()); - - // Create "$dir/subdir/subdir_child_dir/child_dir_file1". - FilePath child_dir_file1(subdir_child_dir.AppendASCII("child_dir_file1")); - ASSERT_TRUE(WriteFile(child_dir_file1, "content v2")); - ASSERT_TRUE(WaitForEvents()); - - // Write into "$dir/subdir/subdir_child_dir/child_dir_file1". - ASSERT_TRUE(WriteFile(child_dir_file1, "content")); - ASSERT_TRUE(WaitForEvents()); - - // Modify "$dir/subdir/subdir_child_dir/child_dir_file1" attributes. - ASSERT_TRUE(file_util::MakeFileUnreadable(child_dir_file1)); - ASSERT_TRUE(WaitForEvents()); - - // Delete "$dir/subdir/subdir_file1". - ASSERT_TRUE(base::DeleteFile(subdir_file1, false)); - ASSERT_TRUE(WaitForEvents()); - - // Delete "$dir/subdir/subdir_child_dir/child_dir_file1". - ASSERT_TRUE(base::DeleteFile(child_dir_file1, false)); - ASSERT_TRUE(WaitForEvents()); - DeleteDelegateOnFileThread(delegate.release()); -} -#else -TEST_F(FilePathWatcherTest, RecursiveWatch) { - FilePathWatcher watcher; - FilePath dir(temp_dir_.path().AppendASCII("dir")); - scoped_ptr delegate(new TestDelegate(collector())); - // Non-Windows implementaion does not support recursive watching. - ASSERT_FALSE(SetupWatch(dir, &watcher, delegate.get(), true)); - DeleteDelegateOnFileThread(delegate.release()); -} -#endif - -TEST_F(FilePathWatcherTest, MoveChild) { - FilePathWatcher file_watcher; - FilePathWatcher subdir_watcher; - FilePath source_dir(temp_dir_.path().AppendASCII("source")); - FilePath source_subdir(source_dir.AppendASCII("subdir")); - FilePath source_file(source_subdir.AppendASCII("file")); - FilePath dest_dir(temp_dir_.path().AppendASCII("dest")); - FilePath dest_subdir(dest_dir.AppendASCII("subdir")); - FilePath dest_file(dest_subdir.AppendASCII("file")); - - // Setup a directory hierarchy. - ASSERT_TRUE(file_util::CreateDirectory(source_subdir)); - ASSERT_TRUE(WriteFile(source_file, "content")); - - scoped_ptr file_delegate(new TestDelegate(collector())); - ASSERT_TRUE(SetupWatch(dest_file, &file_watcher, file_delegate.get(), false)); - scoped_ptr subdir_delegate(new TestDelegate(collector())); - ASSERT_TRUE(SetupWatch(dest_subdir, &subdir_watcher, subdir_delegate.get(), - false)); - - // Move the directory into place, s.t. the watched file appears. - ASSERT_TRUE(base::Move(source_dir, dest_dir)); - ASSERT_TRUE(WaitForEvents()); - DeleteDelegateOnFileThread(file_delegate.release()); - DeleteDelegateOnFileThread(subdir_delegate.release()); -} - -#if !defined(OS_LINUX) -// Linux implementation of FilePathWatcher doesn't catch attribute changes. -// http://crbug.com/78043 - -// Verify that changing attributes on a file is caught -TEST_F(FilePathWatcherTest, FileAttributesChanged) { - ASSERT_TRUE(WriteFile(test_file(), "content")); - FilePathWatcher watcher; - scoped_ptr delegate(new TestDelegate(collector())); - ASSERT_TRUE(SetupWatch(test_file(), &watcher, delegate.get(), false)); - - // Now make sure we get notified if the file is modified. - ASSERT_TRUE(file_util::MakeFileUnreadable(test_file())); - ASSERT_TRUE(WaitForEvents()); - DeleteDelegateOnFileThread(delegate.release()); -} - -#endif // !OS_LINUX - -#if defined(OS_LINUX) - -// Verify that creating a symlink is caught. -TEST_F(FilePathWatcherTest, CreateLink) { - FilePathWatcher watcher; - scoped_ptr delegate(new TestDelegate(collector())); - // Note that we are watching the symlink - ASSERT_TRUE(SetupWatch(test_link(), &watcher, delegate.get(), false)); - - // Now make sure we get notified if the link is created. - // Note that test_file() doesn't have to exist. - ASSERT_TRUE(file_util::CreateSymbolicLink(test_file(), test_link())); - ASSERT_TRUE(WaitForEvents()); - DeleteDelegateOnFileThread(delegate.release()); -} - -// Verify that deleting a symlink is caught. -TEST_F(FilePathWatcherTest, DeleteLink) { - // Unfortunately this test case only works if the link target exists. - // TODO(craig) fix this as part of crbug.com/91561. - ASSERT_TRUE(WriteFile(test_file(), "content")); - ASSERT_TRUE(file_util::CreateSymbolicLink(test_file(), test_link())); - FilePathWatcher watcher; - scoped_ptr delegate(new TestDelegate(collector())); - ASSERT_TRUE(SetupWatch(test_link(), &watcher, delegate.get(), false)); - - // Now make sure we get notified if the link is deleted. - ASSERT_TRUE(base::DeleteFile(test_link(), false)); - ASSERT_TRUE(WaitForEvents()); - DeleteDelegateOnFileThread(delegate.release()); -} - -// Verify that modifying a target file that a link is pointing to -// when we are watching the link is caught. -TEST_F(FilePathWatcherTest, ModifiedLinkedFile) { - ASSERT_TRUE(WriteFile(test_file(), "content")); - ASSERT_TRUE(file_util::CreateSymbolicLink(test_file(), test_link())); - FilePathWatcher watcher; - scoped_ptr delegate(new TestDelegate(collector())); - // Note that we are watching the symlink. - ASSERT_TRUE(SetupWatch(test_link(), &watcher, delegate.get(), false)); - - // Now make sure we get notified if the file is modified. - ASSERT_TRUE(WriteFile(test_file(), "new content")); - ASSERT_TRUE(WaitForEvents()); - DeleteDelegateOnFileThread(delegate.release()); -} - -// Verify that creating a target file that a link is pointing to -// when we are watching the link is caught. -TEST_F(FilePathWatcherTest, CreateTargetLinkedFile) { - ASSERT_TRUE(file_util::CreateSymbolicLink(test_file(), test_link())); - FilePathWatcher watcher; - scoped_ptr delegate(new TestDelegate(collector())); - // Note that we are watching the symlink. - ASSERT_TRUE(SetupWatch(test_link(), &watcher, delegate.get(), false)); - - // Now make sure we get notified if the target file is created. - ASSERT_TRUE(WriteFile(test_file(), "content")); - ASSERT_TRUE(WaitForEvents()); - DeleteDelegateOnFileThread(delegate.release()); -} - -// Verify that deleting a target file that a link is pointing to -// when we are watching the link is caught. -TEST_F(FilePathWatcherTest, DeleteTargetLinkedFile) { - ASSERT_TRUE(WriteFile(test_file(), "content")); - ASSERT_TRUE(file_util::CreateSymbolicLink(test_file(), test_link())); - FilePathWatcher watcher; - scoped_ptr delegate(new TestDelegate(collector())); - // Note that we are watching the symlink. - ASSERT_TRUE(SetupWatch(test_link(), &watcher, delegate.get(), false)); - - // Now make sure we get notified if the target file is deleted. - ASSERT_TRUE(base::DeleteFile(test_file(), false)); - ASSERT_TRUE(WaitForEvents()); - DeleteDelegateOnFileThread(delegate.release()); -} - -// Verify that watching a file whose parent directory is a link that -// doesn't exist yet works if the symlink is created eventually. -TEST_F(FilePathWatcherTest, LinkedDirectoryPart1) { - FilePathWatcher watcher; - FilePath dir(temp_dir_.path().AppendASCII("dir")); - FilePath link_dir(temp_dir_.path().AppendASCII("dir.lnk")); - FilePath file(dir.AppendASCII("file")); - FilePath linkfile(link_dir.AppendASCII("file")); - scoped_ptr delegate(new TestDelegate(collector())); - // dir/file should exist. - ASSERT_TRUE(file_util::CreateDirectory(dir)); - ASSERT_TRUE(WriteFile(file, "content")); - // Note that we are watching dir.lnk/file which doesn't exist yet. - ASSERT_TRUE(SetupWatch(linkfile, &watcher, delegate.get(), false)); - - ASSERT_TRUE(file_util::CreateSymbolicLink(dir, link_dir)); - VLOG(1) << "Waiting for link creation"; - ASSERT_TRUE(WaitForEvents()); - - ASSERT_TRUE(WriteFile(file, "content v2")); - VLOG(1) << "Waiting for file change"; - ASSERT_TRUE(WaitForEvents()); - - ASSERT_TRUE(base::DeleteFile(file, false)); - VLOG(1) << "Waiting for file deletion"; - ASSERT_TRUE(WaitForEvents()); - DeleteDelegateOnFileThread(delegate.release()); -} - -// Verify that watching a file whose parent directory is a -// dangling symlink works if the directory is created eventually. -TEST_F(FilePathWatcherTest, LinkedDirectoryPart2) { - FilePathWatcher watcher; - FilePath dir(temp_dir_.path().AppendASCII("dir")); - FilePath link_dir(temp_dir_.path().AppendASCII("dir.lnk")); - FilePath file(dir.AppendASCII("file")); - FilePath linkfile(link_dir.AppendASCII("file")); - scoped_ptr delegate(new TestDelegate(collector())); - // Now create the link from dir.lnk pointing to dir but - // neither dir nor dir/file exist yet. - ASSERT_TRUE(file_util::CreateSymbolicLink(dir, link_dir)); - // Note that we are watching dir.lnk/file. - ASSERT_TRUE(SetupWatch(linkfile, &watcher, delegate.get(), false)); - - ASSERT_TRUE(file_util::CreateDirectory(dir)); - ASSERT_TRUE(WriteFile(file, "content")); - VLOG(1) << "Waiting for dir/file creation"; - ASSERT_TRUE(WaitForEvents()); - - ASSERT_TRUE(WriteFile(file, "content v2")); - VLOG(1) << "Waiting for file change"; - ASSERT_TRUE(WaitForEvents()); - - ASSERT_TRUE(base::DeleteFile(file, false)); - VLOG(1) << "Waiting for file deletion"; - ASSERT_TRUE(WaitForEvents()); - DeleteDelegateOnFileThread(delegate.release()); -} - -// Verify that watching a file with a symlink on the path -// to the file works. -TEST_F(FilePathWatcherTest, LinkedDirectoryPart3) { - FilePathWatcher watcher; - FilePath dir(temp_dir_.path().AppendASCII("dir")); - FilePath link_dir(temp_dir_.path().AppendASCII("dir.lnk")); - FilePath file(dir.AppendASCII("file")); - FilePath linkfile(link_dir.AppendASCII("file")); - scoped_ptr delegate(new TestDelegate(collector())); - ASSERT_TRUE(file_util::CreateDirectory(dir)); - ASSERT_TRUE(file_util::CreateSymbolicLink(dir, link_dir)); - // Note that we are watching dir.lnk/file but the file doesn't exist yet. - ASSERT_TRUE(SetupWatch(linkfile, &watcher, delegate.get(), false)); - - ASSERT_TRUE(WriteFile(file, "content")); - VLOG(1) << "Waiting for file creation"; - ASSERT_TRUE(WaitForEvents()); - - ASSERT_TRUE(WriteFile(file, "content v2")); - VLOG(1) << "Waiting for file change"; - ASSERT_TRUE(WaitForEvents()); - - ASSERT_TRUE(base::DeleteFile(file, false)); - VLOG(1) << "Waiting for file deletion"; - ASSERT_TRUE(WaitForEvents()); - DeleteDelegateOnFileThread(delegate.release()); -} - -#endif // OS_LINUX - -enum Permission { - Read, - Write, - Execute -}; - -bool ChangeFilePermissions(const FilePath& path, Permission perm, bool allow) { -#if defined(OS_POSIX) - struct stat stat_buf; - - if (stat(path.value().c_str(), &stat_buf) != 0) - return false; - - mode_t mode = 0; - switch (perm) { - case Read: - mode = S_IRUSR | S_IRGRP | S_IROTH; - break; - case Write: - mode = S_IWUSR | S_IWGRP | S_IWOTH; - break; - case Execute: - mode = S_IXUSR | S_IXGRP | S_IXOTH; - break; - default: - ADD_FAILURE() << "unknown perm " << perm; - return false; - } - if (allow) { - stat_buf.st_mode |= mode; - } else { - stat_buf.st_mode &= ~mode; - } - return chmod(path.value().c_str(), stat_buf.st_mode) == 0; - -#elif defined(OS_WIN) - PACL old_dacl; - PSECURITY_DESCRIPTOR security_descriptor; - if (GetNamedSecurityInfo(const_cast(path.value().c_str()), - SE_FILE_OBJECT, - DACL_SECURITY_INFORMATION, NULL, NULL, &old_dacl, - NULL, &security_descriptor) != ERROR_SUCCESS) - return false; - - DWORD mode = 0; - switch (perm) { - case Read: - mode = GENERIC_READ; - break; - case Write: - mode = GENERIC_WRITE; - break; - case Execute: - mode = GENERIC_EXECUTE; - break; - default: - ADD_FAILURE() << "unknown perm " << perm; - return false; - } - - // Deny Read access for the current user. - EXPLICIT_ACCESS change; - change.grfAccessPermissions = mode; - change.grfAccessMode = allow ? GRANT_ACCESS : DENY_ACCESS; - change.grfInheritance = 0; - change.Trustee.pMultipleTrustee = NULL; - change.Trustee.MultipleTrusteeOperation = NO_MULTIPLE_TRUSTEE; - change.Trustee.TrusteeForm = TRUSTEE_IS_NAME; - change.Trustee.TrusteeType = TRUSTEE_IS_USER; - change.Trustee.ptstrName = L"CURRENT_USER"; - - PACL new_dacl; - if (SetEntriesInAcl(1, &change, old_dacl, &new_dacl) != ERROR_SUCCESS) { - LocalFree(security_descriptor); - return false; - } - - DWORD rc = SetNamedSecurityInfo(const_cast(path.value().c_str()), - SE_FILE_OBJECT, DACL_SECURITY_INFORMATION, - NULL, NULL, new_dacl, NULL); - LocalFree(security_descriptor); - LocalFree(new_dacl); - - return rc == ERROR_SUCCESS; -#else - NOTIMPLEMENTED(); - return false; -#endif -} - -#if defined(OS_MACOSX) -// Linux implementation of FilePathWatcher doesn't catch attribute changes. -// http://crbug.com/78043 -// Windows implementation of FilePathWatcher catches attribute changes that -// don't affect the path being watched. -// http://crbug.com/78045 - -// Verify that changing attributes on a directory works. -TEST_F(FilePathWatcherTest, DirAttributesChanged) { - FilePath test_dir1(temp_dir_.path().AppendASCII("DirAttributesChangedDir1")); - FilePath test_dir2(test_dir1.AppendASCII("DirAttributesChangedDir2")); - FilePath test_file(test_dir2.AppendASCII("DirAttributesChangedFile")); - // Setup a directory hierarchy. - ASSERT_TRUE(file_util::CreateDirectory(test_dir1)); - ASSERT_TRUE(file_util::CreateDirectory(test_dir2)); - ASSERT_TRUE(WriteFile(test_file, "content")); - - FilePathWatcher watcher; - scoped_ptr delegate(new TestDelegate(collector())); - ASSERT_TRUE(SetupWatch(test_file, &watcher, delegate.get(), false)); - - // We should not get notified in this case as it hasn't affected our ability - // to access the file. - ASSERT_TRUE(ChangeFilePermissions(test_dir1, Read, false)); - loop_.PostDelayedTask(FROM_HERE, - MessageLoop::QuitWhenIdleClosure(), - TestTimeouts::tiny_timeout()); - ASSERT_FALSE(WaitForEvents()); - ASSERT_TRUE(ChangeFilePermissions(test_dir1, Read, true)); - - // We should get notified in this case because filepathwatcher can no - // longer access the file - ASSERT_TRUE(ChangeFilePermissions(test_dir1, Execute, false)); - ASSERT_TRUE(WaitForEvents()); - ASSERT_TRUE(ChangeFilePermissions(test_dir1, Execute, true)); - DeleteDelegateOnFileThread(delegate.release()); -} - -#endif // OS_MACOSX -} // namespace - -} // namespace base diff --git a/base/files/file_path_watcher_kqueue.cc b/base/files/file_path_watcher_kqueue.cc deleted file mode 100644 index 2ffb83622c..0000000000 --- a/base/files/file_path_watcher_kqueue.cc +++ /dev/null @@ -1,518 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "base/files/file_path_watcher.h" - -#include -#include -#include - -#include - -#include "base/bind.h" -#include "base/file_util.h" -#include "base/logging.h" -#include "base/message_loop/message_loop.h" -#include "base/message_loop/message_loop_proxy.h" -#include "base/strings/stringprintf.h" - -// On some platforms these are not defined. -#if !defined(EV_RECEIPT) -#define EV_RECEIPT 0 -#endif -#if !defined(O_EVTONLY) -#define O_EVTONLY O_RDONLY -#endif - -namespace base { - -namespace { - -// Mac-specific file watcher implementation based on kqueue. -// Originally it was based on FSEvents so that the semantics were equivalent -// on Linux, OSX and Windows where it was able to detect: -// - file creation/deletion/modification in a watched directory -// - file creation/deletion/modification for a watched file -// - modifications to the paths to a watched object that would affect the -// object such as renaming/attibute changes etc. -// The FSEvents version did all of the above except handling attribute changes -// to path components. Unfortunately FSEvents appears to have an issue where the -// current implementation (Mac OS X 10.6.7) sometimes drops events and doesn't -// send notifications. See -// http://code.google.com/p/chromium/issues/detail?id=54822#c31 for source that -// will reproduce the problem. FSEvents also required having a CFRunLoop -// backing the thread that it was running on, that caused added complexity -// in the interfaces. -// The kqueue implementation will handle all of the items in the list above -// except for detecting modifications to files in a watched directory. It will -// detect the creation and deletion of files, just not the modification of -// files. It does however detect the attribute changes that the FSEvents impl -// would miss. -class FilePathWatcherImpl : public FilePathWatcher::PlatformDelegate, - public MessageLoopForIO::Watcher, - public MessageLoop::DestructionObserver { - public: - FilePathWatcherImpl() : kqueue_(-1) {} - - // MessageLoopForIO::Watcher overrides. - virtual void OnFileCanReadWithoutBlocking(int fd) OVERRIDE; - virtual void OnFileCanWriteWithoutBlocking(int fd) OVERRIDE; - - // MessageLoop::DestructionObserver overrides. - virtual void WillDestroyCurrentMessageLoop() OVERRIDE; - - // FilePathWatcher::PlatformDelegate overrides. - virtual bool Watch(const FilePath& path, - bool recursive, - const FilePathWatcher::Callback& callback) OVERRIDE; - virtual void Cancel() OVERRIDE; - - protected: - virtual ~FilePathWatcherImpl() {} - - private: - class EventData { - public: - EventData(const FilePath& path, const FilePath::StringType& subdir) - : path_(path), subdir_(subdir) { } - FilePath path_; // Full path to this item. - FilePath::StringType subdir_; // Path to any sub item. - }; - typedef std::vector EventVector; - - // Can only be called on |io_message_loop_|'s thread. - virtual void CancelOnMessageLoopThread() OVERRIDE; - - // Returns true if the kevent values are error free. - bool AreKeventValuesValid(struct kevent* kevents, int count); - - // Respond to a change of attributes of the path component represented by - // |event|. Sets |target_file_affected| to true if |target_| is affected. - // Sets |update_watches| to true if |events_| need to be updated. - void HandleAttributesChange(const EventVector::iterator& event, - bool* target_file_affected, - bool* update_watches); - - // Respond to a move or deletion of the path component represented by - // |event|. Sets |target_file_affected| to true if |target_| is affected. - // Sets |update_watches| to true if |events_| need to be updated. - void HandleDeleteOrMoveChange(const EventVector::iterator& event, - bool* target_file_affected, - bool* update_watches); - - // Respond to a creation of an item in the path component represented by - // |event|. Sets |target_file_affected| to true if |target_| is affected. - // Sets |update_watches| to true if |events_| need to be updated. - void HandleCreateItemChange(const EventVector::iterator& event, - bool* target_file_affected, - bool* update_watches); - - // Update |events_| with the current status of the system. - // Sets |target_file_affected| to true if |target_| is affected. - // Returns false if an error occurs. - bool UpdateWatches(bool* target_file_affected); - - // Fills |events| with one kevent per component in |path|. - // Returns the number of valid events created where a valid event is - // defined as one that has a ident (file descriptor) field != -1. - static int EventsForPath(FilePath path, EventVector *events); - - // Release a kevent generated by EventsForPath. - static void ReleaseEvent(struct kevent& event); - - // Returns a file descriptor that will not block the system from deleting - // the file it references. - static uintptr_t FileDescriptorForPath(const FilePath& path); - - static const uintptr_t kNoFileDescriptor = static_cast(-1); - - // Closes |*fd| and sets |*fd| to -1. - static void CloseFileDescriptor(uintptr_t* fd); - - // Returns true if kevent has open file descriptor. - static bool IsKeventFileDescriptorOpen(const struct kevent& event) { - return event.ident != kNoFileDescriptor; - } - - static EventData* EventDataForKevent(const struct kevent& event) { - return reinterpret_cast(event.udata); - } - - EventVector events_; - scoped_refptr io_message_loop_; - MessageLoopForIO::FileDescriptorWatcher kqueue_watcher_; - FilePathWatcher::Callback callback_; - FilePath target_; - int kqueue_; - - DISALLOW_COPY_AND_ASSIGN(FilePathWatcherImpl); -}; - -void FilePathWatcherImpl::ReleaseEvent(struct kevent& event) { - CloseFileDescriptor(&event.ident); - EventData* entry = EventDataForKevent(event); - delete entry; - event.udata = NULL; -} - -int FilePathWatcherImpl::EventsForPath(FilePath path, EventVector* events) { - DCHECK(MessageLoopForIO::current()); - // Make sure that we are working with a clean slate. - DCHECK(events->empty()); - - std::vector components; - path.GetComponents(&components); - - if (components.size() < 1) { - return -1; - } - - int last_existing_entry = 0; - FilePath built_path; - bool path_still_exists = true; - for (std::vector::iterator i = components.begin(); - i != components.end(); ++i) { - if (i == components.begin()) { - built_path = FilePath(*i); - } else { - built_path = built_path.Append(*i); - } - uintptr_t fd = kNoFileDescriptor; - if (path_still_exists) { - fd = FileDescriptorForPath(built_path); - if (fd == kNoFileDescriptor) { - path_still_exists = false; - } else { - ++last_existing_entry; - } - } - FilePath::StringType subdir = (i != (components.end() - 1)) ? *(i + 1) : ""; - EventData* data = new EventData(built_path, subdir); - struct kevent event; - EV_SET(&event, fd, EVFILT_VNODE, (EV_ADD | EV_CLEAR | EV_RECEIPT), - (NOTE_DELETE | NOTE_WRITE | NOTE_ATTRIB | - NOTE_RENAME | NOTE_REVOKE | NOTE_EXTEND), 0, data); - events->push_back(event); - } - return last_existing_entry; -} - -uintptr_t FilePathWatcherImpl::FileDescriptorForPath(const FilePath& path) { - int fd = HANDLE_EINTR(open(path.value().c_str(), O_EVTONLY)); - if (fd == -1) - return kNoFileDescriptor; - return fd; -} - -void FilePathWatcherImpl::CloseFileDescriptor(uintptr_t* fd) { - if (*fd == kNoFileDescriptor) { - return; - } - - if (HANDLE_EINTR(close(*fd)) != 0) { - DPLOG(ERROR) << "close"; - } - *fd = kNoFileDescriptor; -} - -bool FilePathWatcherImpl::AreKeventValuesValid(struct kevent* kevents, - int count) { - if (count < 0) { - DPLOG(ERROR) << "kevent"; - return false; - } - bool valid = true; - for (int i = 0; i < count; ++i) { - if (kevents[i].flags & EV_ERROR && kevents[i].data) { - // Find the kevent in |events_| that matches the kevent with the error. - EventVector::iterator event = events_.begin(); - for (; event != events_.end(); ++event) { - if (event->ident == kevents[i].ident) { - break; - } - } - std::string path_name; - if (event != events_.end()) { - EventData* event_data = EventDataForKevent(*event); - if (event_data != NULL) { - path_name = event_data->path_.value(); - } - } - if (path_name.empty()) { - path_name = base::StringPrintf( - "fd %ld", reinterpret_cast(&kevents[i].ident)); - } - DLOG(ERROR) << "Error: " << kevents[i].data << " for " << path_name; - valid = false; - } - } - return valid; -} - -void FilePathWatcherImpl::HandleAttributesChange( - const EventVector::iterator& event, - bool* target_file_affected, - bool* update_watches) { - EventVector::iterator next_event = event + 1; - EventData* next_event_data = EventDataForKevent(*next_event); - // Check to see if the next item in path is still accessible. - uintptr_t have_access = FileDescriptorForPath(next_event_data->path_); - if (have_access == kNoFileDescriptor) { - *target_file_affected = true; - *update_watches = true; - EventVector::iterator local_event(event); - for (; local_event != events_.end(); ++local_event) { - // Close all nodes from the event down. This has the side effect of - // potentially rendering other events in |updates| invalid. - // There is no need to remove the events from |kqueue_| because this - // happens as a side effect of closing the file descriptor. - CloseFileDescriptor(&local_event->ident); - } - } else { - CloseFileDescriptor(&have_access); - } -} - -void FilePathWatcherImpl::HandleDeleteOrMoveChange( - const EventVector::iterator& event, - bool* target_file_affected, - bool* update_watches) { - *target_file_affected = true; - *update_watches = true; - EventVector::iterator local_event(event); - for (; local_event != events_.end(); ++local_event) { - // Close all nodes from the event down. This has the side effect of - // potentially rendering other events in |updates| invalid. - // There is no need to remove the events from |kqueue_| because this - // happens as a side effect of closing the file descriptor. - CloseFileDescriptor(&local_event->ident); - } -} - -void FilePathWatcherImpl::HandleCreateItemChange( - const EventVector::iterator& event, - bool* target_file_affected, - bool* update_watches) { - // Get the next item in the path. - EventVector::iterator next_event = event + 1; - // Check to see if it already has a valid file descriptor. - if (!IsKeventFileDescriptorOpen(*next_event)) { - EventData* next_event_data = EventDataForKevent(*next_event); - // If not, attempt to open a file descriptor for it. - next_event->ident = FileDescriptorForPath(next_event_data->path_); - if (IsKeventFileDescriptorOpen(*next_event)) { - *update_watches = true; - if (next_event_data->subdir_.empty()) { - *target_file_affected = true; - } - } - } -} - -bool FilePathWatcherImpl::UpdateWatches(bool* target_file_affected) { - // Iterate over events adding kevents for items that exist to the kqueue. - // Then check to see if new components in the path have been created. - // Repeat until no new components in the path are detected. - // This is to get around races in directory creation in a watched path. - bool update_watches = true; - while (update_watches) { - size_t valid; - for (valid = 0; valid < events_.size(); ++valid) { - if (!IsKeventFileDescriptorOpen(events_[valid])) { - break; - } - } - if (valid == 0) { - // The root of the file path is inaccessible? - return false; - } - - EventVector updates(valid); - int count = HANDLE_EINTR(kevent(kqueue_, &events_[0], valid, &updates[0], - valid, NULL)); - if (!AreKeventValuesValid(&updates[0], count)) { - return false; - } - update_watches = false; - for (; valid < events_.size(); ++valid) { - EventData* event_data = EventDataForKevent(events_[valid]); - events_[valid].ident = FileDescriptorForPath(event_data->path_); - if (IsKeventFileDescriptorOpen(events_[valid])) { - update_watches = true; - if (event_data->subdir_.empty()) { - *target_file_affected = true; - } - } else { - break; - } - } - } - return true; -} - -void FilePathWatcherImpl::OnFileCanReadWithoutBlocking(int fd) { - DCHECK(MessageLoopForIO::current()); - DCHECK_EQ(fd, kqueue_); - DCHECK(events_.size()); - - // Request the file system update notifications that have occurred and return - // them in |updates|. |count| will contain the number of updates that have - // occurred. - EventVector updates(events_.size()); - struct timespec timeout = {0, 0}; - int count = HANDLE_EINTR(kevent(kqueue_, NULL, 0, &updates[0], updates.size(), - &timeout)); - - // Error values are stored within updates, so check to make sure that no - // errors occurred. - if (!AreKeventValuesValid(&updates[0], count)) { - callback_.Run(target_, true /* error */); - Cancel(); - return; - } - - bool update_watches = false; - bool send_notification = false; - - // Iterate through each of the updates and react to them. - for (int i = 0; i < count; ++i) { - // Find our kevent record that matches the update notification. - EventVector::iterator event = events_.begin(); - for (; event != events_.end(); ++event) { - if (!IsKeventFileDescriptorOpen(*event) || - event->ident == updates[i].ident) { - break; - } - } - if (event == events_.end() || !IsKeventFileDescriptorOpen(*event)) { - // The event may no longer exist in |events_| because another event - // modified |events_| in such a way to make it invalid. For example if - // the path is /foo/bar/bam and foo is deleted, NOTE_DELETE events for - // foo, bar and bam will be sent. If foo is processed first, then - // the file descriptors for bar and bam will already be closed and set - // to -1 before they get a chance to be processed. - continue; - } - - EventData* event_data = EventDataForKevent(*event); - - // If the subdir is empty, this is the last item on the path and is the - // target file. - bool target_file_affected = event_data->subdir_.empty(); - if ((updates[i].fflags & NOTE_ATTRIB) && !target_file_affected) { - HandleAttributesChange(event, &target_file_affected, &update_watches); - } - if (updates[i].fflags & (NOTE_DELETE | NOTE_REVOKE | NOTE_RENAME)) { - HandleDeleteOrMoveChange(event, &target_file_affected, &update_watches); - } - if ((updates[i].fflags & NOTE_WRITE) && !target_file_affected) { - HandleCreateItemChange(event, &target_file_affected, &update_watches); - } - send_notification |= target_file_affected; - } - - if (update_watches) { - if (!UpdateWatches(&send_notification)) { - callback_.Run(target_, true /* error */); - Cancel(); - } - } - - if (send_notification) { - callback_.Run(target_, false); - } -} - -void FilePathWatcherImpl::OnFileCanWriteWithoutBlocking(int fd) { - NOTREACHED(); -} - -void FilePathWatcherImpl::WillDestroyCurrentMessageLoop() { - CancelOnMessageLoopThread(); -} - -bool FilePathWatcherImpl::Watch(const FilePath& path, - bool recursive, - const FilePathWatcher::Callback& callback) { - DCHECK(MessageLoopForIO::current()); - DCHECK(target_.value().empty()); // Can only watch one path. - DCHECK(!callback.is_null()); - DCHECK_EQ(kqueue_, -1); - - if (recursive) { - // Recursive watch is not supported on this platform. - NOTIMPLEMENTED(); - return false; - } - - callback_ = callback; - target_ = path; - - MessageLoop::current()->AddDestructionObserver(this); - io_message_loop_ = base::MessageLoopProxy::current(); - - kqueue_ = kqueue(); - if (kqueue_ == -1) { - DPLOG(ERROR) << "kqueue"; - return false; - } - - int last_entry = EventsForPath(target_, &events_); - DCHECK_NE(last_entry, 0); - - EventVector responses(last_entry); - - int count = HANDLE_EINTR(kevent(kqueue_, &events_[0], last_entry, - &responses[0], last_entry, NULL)); - if (!AreKeventValuesValid(&responses[0], count)) { - // Calling Cancel() here to close any file descriptors that were opened. - // This would happen in the destructor anyways, but FilePathWatchers tend to - // be long lived, and if an error has occurred, there is no reason to waste - // the file descriptors. - Cancel(); - return false; - } - - return MessageLoopForIO::current()->WatchFileDescriptor( - kqueue_, true, MessageLoopForIO::WATCH_READ, &kqueue_watcher_, this); -} - -void FilePathWatcherImpl::Cancel() { - base::MessageLoopProxy* proxy = io_message_loop_.get(); - if (!proxy) { - set_cancelled(); - return; - } - if (!proxy->BelongsToCurrentThread()) { - proxy->PostTask(FROM_HERE, - base::Bind(&FilePathWatcherImpl::Cancel, this)); - return; - } - CancelOnMessageLoopThread(); -} - -void FilePathWatcherImpl::CancelOnMessageLoopThread() { - DCHECK(MessageLoopForIO::current()); - if (!is_cancelled()) { - set_cancelled(); - kqueue_watcher_.StopWatchingFileDescriptor(); - if (HANDLE_EINTR(close(kqueue_)) != 0) { - DPLOG(ERROR) << "close kqueue"; - } - kqueue_ = -1; - std::for_each(events_.begin(), events_.end(), ReleaseEvent); - events_.clear(); - io_message_loop_ = NULL; - MessageLoop::current()->RemoveDestructionObserver(this); - callback_.Reset(); - } -} - -} // namespace - -FilePathWatcher::FilePathWatcher() { - impl_ = new FilePathWatcherImpl(); -} - -} // namespace base diff --git a/base/files/file_path_watcher_linux.cc b/base/files/file_path_watcher_linux.cc deleted file mode 100644 index 86a4226bf3..0000000000 --- a/base/files/file_path_watcher_linux.cc +++ /dev/null @@ -1,487 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "base/files/file_path_watcher.h" - -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include - -#include "base/bind.h" -#include "base/containers/hash_tables.h" -#include "base/file_util.h" -#include "base/files/file_path.h" -#include "base/lazy_instance.h" -#include "base/location.h" -#include "base/logging.h" -#include "base/memory/scoped_ptr.h" -#include "base/message_loop/message_loop.h" -#include "base/message_loop/message_loop_proxy.h" -#include "base/posix/eintr_wrapper.h" -#include "base/synchronization/lock.h" -#include "base/threading/thread.h" - -namespace base { - -namespace { - -class FilePathWatcherImpl; - -// Singleton to manage all inotify watches. -// TODO(tony): It would be nice if this wasn't a singleton. -// http://crbug.com/38174 -class InotifyReader { - public: - typedef int Watch; // Watch descriptor used by AddWatch and RemoveWatch. - static const Watch kInvalidWatch = -1; - - // Watch directory |path| for changes. |watcher| will be notified on each - // change. Returns kInvalidWatch on failure. - Watch AddWatch(const FilePath& path, FilePathWatcherImpl* watcher); - - // Remove |watch|. Returns true on success. - bool RemoveWatch(Watch watch, FilePathWatcherImpl* watcher); - - // Callback for InotifyReaderTask. - void OnInotifyEvent(const inotify_event* event); - - private: - friend struct ::base::DefaultLazyInstanceTraits; - - typedef std::set WatcherSet; - - InotifyReader(); - ~InotifyReader(); - - // We keep track of which delegates want to be notified on which watches. - base::hash_map watchers_; - - // Lock to protect watchers_. - base::Lock lock_; - - // Separate thread on which we run blocking read for inotify events. - base::Thread thread_; - - // File descriptor returned by inotify_init. - const int inotify_fd_; - - // Use self-pipe trick to unblock select during shutdown. - int shutdown_pipe_[2]; - - // Flag set to true when startup was successful. - bool valid_; - - DISALLOW_COPY_AND_ASSIGN(InotifyReader); -}; - -class FilePathWatcherImpl : public FilePathWatcher::PlatformDelegate, - public MessageLoop::DestructionObserver { - public: - FilePathWatcherImpl(); - - // Called for each event coming from the watch. |fired_watch| identifies the - // watch that fired, |child| indicates what has changed, and is relative to - // the currently watched path for |fired_watch|. The flag |created| is true if - // the object appears. - void OnFilePathChanged(InotifyReader::Watch fired_watch, - const FilePath::StringType& child, - bool created); - - // Start watching |path| for changes and notify |delegate| on each change. - // Returns true if watch for |path| has been added successfully. - virtual bool Watch(const FilePath& path, - bool recursive, - const FilePathWatcher::Callback& callback) OVERRIDE; - - // Cancel the watch. This unregisters the instance with InotifyReader. - virtual void Cancel() OVERRIDE; - - // Deletion of the FilePathWatcher will call Cancel() to dispose of this - // object in the right thread. This also observes destruction of the required - // cleanup thread, in case it quits before Cancel() is called. - virtual void WillDestroyCurrentMessageLoop() OVERRIDE; - - protected: - virtual ~FilePathWatcherImpl() {} - - private: - // Cleans up and stops observing the |message_loop_| thread. - virtual void CancelOnMessageLoopThread() OVERRIDE; - - // Inotify watches are installed for all directory components of |target_|. A - // WatchEntry instance holds the watch descriptor for a component and the - // subdirectory for that identifies the next component. If a symbolic link - // is being watched, the target of the link is also kept. - struct WatchEntry { - WatchEntry(InotifyReader::Watch watch, const FilePath::StringType& subdir) - : watch_(watch), - subdir_(subdir) {} - - InotifyReader::Watch watch_; - FilePath::StringType subdir_; - FilePath::StringType linkname_; - }; - typedef std::vector WatchVector; - - // Reconfigure to watch for the most specific parent directory of |target_| - // that exists. Updates |watched_path_|. Returns true on success. - bool UpdateWatches() WARN_UNUSED_RESULT; - - // Callback to notify upon changes. - FilePathWatcher::Callback callback_; - - // The file or directory we're supposed to watch. - FilePath target_; - - // The vector of watches and next component names for all path components, - // starting at the root directory. The last entry corresponds to the watch for - // |target_| and always stores an empty next component name in |subdir_|. - WatchVector watches_; - - DISALLOW_COPY_AND_ASSIGN(FilePathWatcherImpl); -}; - -void InotifyReaderCallback(InotifyReader* reader, int inotify_fd, - int shutdown_fd) { - // Make sure the file descriptors are good for use with select(). - CHECK_LE(0, inotify_fd); - CHECK_GT(FD_SETSIZE, inotify_fd); - CHECK_LE(0, shutdown_fd); - CHECK_GT(FD_SETSIZE, shutdown_fd); - - while (true) { - fd_set rfds; - FD_ZERO(&rfds); - FD_SET(inotify_fd, &rfds); - FD_SET(shutdown_fd, &rfds); - - // Wait until some inotify events are available. - int select_result = - HANDLE_EINTR(select(std::max(inotify_fd, shutdown_fd) + 1, - &rfds, NULL, NULL, NULL)); - if (select_result < 0) { - DPLOG(WARNING) << "select failed"; - return; - } - - if (FD_ISSET(shutdown_fd, &rfds)) - return; - - // Adjust buffer size to current event queue size. - int buffer_size; - int ioctl_result = HANDLE_EINTR(ioctl(inotify_fd, FIONREAD, - &buffer_size)); - - if (ioctl_result != 0) { - DPLOG(WARNING) << "ioctl failed"; - return; - } - - std::vector buffer(buffer_size); - - ssize_t bytes_read = HANDLE_EINTR(read(inotify_fd, &buffer[0], - buffer_size)); - - if (bytes_read < 0) { - DPLOG(WARNING) << "read from inotify fd failed"; - return; - } - - ssize_t i = 0; - while (i < bytes_read) { - inotify_event* event = reinterpret_cast(&buffer[i]); - size_t event_size = sizeof(inotify_event) + event->len; - DCHECK(i + event_size <= static_cast(bytes_read)); - reader->OnInotifyEvent(event); - i += event_size; - } - } -} - -static base::LazyInstance::Leaky g_inotify_reader = - LAZY_INSTANCE_INITIALIZER; - -InotifyReader::InotifyReader() - : thread_("inotify_reader"), - inotify_fd_(inotify_init()), - valid_(false) { - shutdown_pipe_[0] = -1; - shutdown_pipe_[1] = -1; - if (inotify_fd_ >= 0 && pipe(shutdown_pipe_) == 0 && thread_.Start()) { - thread_.message_loop()->PostTask( - FROM_HERE, base::Bind(&InotifyReaderCallback, this, inotify_fd_, - shutdown_pipe_[0])); - valid_ = true; - } -} - -InotifyReader::~InotifyReader() { - if (valid_) { - // Write to the self-pipe so that the select call in InotifyReaderTask - // returns. - ssize_t ret = HANDLE_EINTR(write(shutdown_pipe_[1], "", 1)); - DPCHECK(ret > 0); - DCHECK_EQ(ret, 1); - thread_.Stop(); - } - if (inotify_fd_ >= 0) - close(inotify_fd_); - if (shutdown_pipe_[0] >= 0) - close(shutdown_pipe_[0]); - if (shutdown_pipe_[1] >= 0) - close(shutdown_pipe_[1]); -} - -InotifyReader::Watch InotifyReader::AddWatch( - const FilePath& path, FilePathWatcherImpl* watcher) { - if (!valid_) - return kInvalidWatch; - - base::AutoLock auto_lock(lock_); - - Watch watch = inotify_add_watch(inotify_fd_, path.value().c_str(), - IN_CREATE | IN_DELETE | - IN_CLOSE_WRITE | IN_MOVE | - IN_ONLYDIR); - - if (watch == kInvalidWatch) - return kInvalidWatch; - - watchers_[watch].insert(watcher); - - return watch; -} - -bool InotifyReader::RemoveWatch(Watch watch, - FilePathWatcherImpl* watcher) { - if (!valid_) - return false; - - base::AutoLock auto_lock(lock_); - - watchers_[watch].erase(watcher); - - if (watchers_[watch].empty()) { - watchers_.erase(watch); - return (inotify_rm_watch(inotify_fd_, watch) == 0); - } - - return true; -} - -void InotifyReader::OnInotifyEvent(const inotify_event* event) { - if (event->mask & IN_IGNORED) - return; - - FilePath::StringType child(event->len ? event->name : FILE_PATH_LITERAL("")); - base::AutoLock auto_lock(lock_); - - for (WatcherSet::iterator watcher = watchers_[event->wd].begin(); - watcher != watchers_[event->wd].end(); - ++watcher) { - (*watcher)->OnFilePathChanged(event->wd, - child, - event->mask & (IN_CREATE | IN_MOVED_TO)); - } -} - -FilePathWatcherImpl::FilePathWatcherImpl() { -} - -void FilePathWatcherImpl::OnFilePathChanged(InotifyReader::Watch fired_watch, - const FilePath::StringType& child, - bool created) { - if (!message_loop()->BelongsToCurrentThread()) { - // Switch to message_loop_ to access watches_ safely. - message_loop()->PostTask(FROM_HERE, - base::Bind(&FilePathWatcherImpl::OnFilePathChanged, - this, - fired_watch, - child, - created)); - return; - } - - DCHECK(MessageLoopForIO::current()); - - // Find the entry in |watches_| that corresponds to |fired_watch|. - WatchVector::const_iterator watch_entry(watches_.begin()); - for ( ; watch_entry != watches_.end(); ++watch_entry) { - if (fired_watch == watch_entry->watch_) { - // Check whether a path component of |target_| changed. - bool change_on_target_path = child.empty() || - ((child == watch_entry->subdir_) && watch_entry->linkname_.empty()) || - (child == watch_entry->linkname_); - - // Check whether the change references |target_| or a direct child. - DCHECK(watch_entry->subdir_.empty() || - (watch_entry + 1) != watches_.end()); - bool target_changed = - (watch_entry->subdir_.empty() && (child == watch_entry->linkname_)) || - (watch_entry->subdir_.empty() && watch_entry->linkname_.empty()) || - (watch_entry->subdir_ == child && (watch_entry + 1)->subdir_.empty()); - - // Update watches if a directory component of the |target_| path - // (dis)appears. Note that we don't add the additional restriction - // of checking the event mask to see if it is for a directory here - // as changes to symlinks on the target path will not have - // IN_ISDIR set in the event masks. As a result we may sometimes - // call UpdateWatches() unnecessarily. - if (change_on_target_path && !UpdateWatches()) { - callback_.Run(target_, true /* error */); - return; - } - - // Report the following events: - // - The target or a direct child of the target got changed (in case the - // watched path refers to a directory). - // - One of the parent directories got moved or deleted, since the target - // disappears in this case. - // - One of the parent directories appears. The event corresponding to - // the target appearing might have been missed in this case, so - // recheck. - if (target_changed || - (change_on_target_path && !created) || - (change_on_target_path && PathExists(target_))) { - callback_.Run(target_, false); - return; - } - } - } -} - -bool FilePathWatcherImpl::Watch(const FilePath& path, - bool recursive, - const FilePathWatcher::Callback& callback) { - DCHECK(target_.empty()); - DCHECK(MessageLoopForIO::current()); - if (recursive) { - // Recursive watch is not supported on this platform. - NOTIMPLEMENTED(); - return false; - } - - set_message_loop(base::MessageLoopProxy::current().get()); - callback_ = callback; - target_ = path; - MessageLoop::current()->AddDestructionObserver(this); - - std::vector comps; - target_.GetComponents(&comps); - DCHECK(!comps.empty()); - std::vector::const_iterator comp = comps.begin(); - for (++comp; comp != comps.end(); ++comp) - watches_.push_back(WatchEntry(InotifyReader::kInvalidWatch, *comp)); - - watches_.push_back(WatchEntry(InotifyReader::kInvalidWatch, - FilePath::StringType())); - return UpdateWatches(); -} - -void FilePathWatcherImpl::Cancel() { - if (callback_.is_null()) { - // Watch was never called, or the |message_loop_| thread is already gone. - set_cancelled(); - return; - } - - // Switch to the message_loop_ if necessary so we can access |watches_|. - if (!message_loop()->BelongsToCurrentThread()) { - message_loop()->PostTask(FROM_HERE, - base::Bind(&FilePathWatcher::CancelWatch, - make_scoped_refptr(this))); - } else { - CancelOnMessageLoopThread(); - } -} - -void FilePathWatcherImpl::CancelOnMessageLoopThread() { - if (!is_cancelled()) - set_cancelled(); - - if (!callback_.is_null()) { - MessageLoop::current()->RemoveDestructionObserver(this); - callback_.Reset(); - } - - for (WatchVector::iterator watch_entry(watches_.begin()); - watch_entry != watches_.end(); ++watch_entry) { - if (watch_entry->watch_ != InotifyReader::kInvalidWatch) - g_inotify_reader.Get().RemoveWatch(watch_entry->watch_, this); - } - watches_.clear(); - target_.clear(); -} - -void FilePathWatcherImpl::WillDestroyCurrentMessageLoop() { - CancelOnMessageLoopThread(); -} - -bool FilePathWatcherImpl::UpdateWatches() { - // Ensure this runs on the |message_loop_| exclusively in order to avoid - // concurrency issues. - DCHECK(message_loop()->BelongsToCurrentThread()); - - // Walk the list of watches and update them as we go. - FilePath path(FILE_PATH_LITERAL("/")); - bool path_valid = true; - for (WatchVector::iterator watch_entry(watches_.begin()); - watch_entry != watches_.end(); ++watch_entry) { - InotifyReader::Watch old_watch = watch_entry->watch_; - if (path_valid) { - watch_entry->watch_ = g_inotify_reader.Get().AddWatch(path, this); - if ((watch_entry->watch_ == InotifyReader::kInvalidWatch) && - file_util::IsLink(path)) { - FilePath link; - if (file_util::ReadSymbolicLink(path, &link)) { - if (!link.IsAbsolute()) - link = path.DirName().Append(link); - // Try watching symlink target directory. If the link target is "/", - // then we shouldn't get here in normal situations and if we do, we'd - // watch "/" for changes to a component "/" which is harmless so no - // special treatment of this case is required. - watch_entry->watch_ = - g_inotify_reader.Get().AddWatch(link.DirName(), this); - if (watch_entry->watch_ != InotifyReader::kInvalidWatch) { - watch_entry->linkname_ = link.BaseName().value(); - } else { - DPLOG(WARNING) << "Watch failed for " << link.DirName().value(); - // TODO(craig) Symlinks only work if the parent directory - // for the target exist. Ideally we should make sure we've - // watched all the components of the symlink path for - // changes. See crbug.com/91561 for details. - } - } - } - if (watch_entry->watch_ == InotifyReader::kInvalidWatch) { - path_valid = false; - } - } else { - watch_entry->watch_ = InotifyReader::kInvalidWatch; - } - if (old_watch != InotifyReader::kInvalidWatch && - old_watch != watch_entry->watch_) { - g_inotify_reader.Get().RemoveWatch(old_watch, this); - } - path = path.Append(watch_entry->subdir_); - } - - return true; -} - -} // namespace - -FilePathWatcher::FilePathWatcher() { - impl_ = new FilePathWatcherImpl(); -} - -} // namespace base diff --git a/base/files/file_path_watcher_stub.cc b/base/files/file_path_watcher_stub.cc deleted file mode 100644 index afca0dab96..0000000000 --- a/base/files/file_path_watcher_stub.cc +++ /dev/null @@ -1,36 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -// This file exists for Unix systems which don't have the inotify headers, and -// thus cannot build file_watcher_inotify.cc - -#include "base/files/file_path_watcher.h" - -namespace base { - -namespace { - -class FilePathWatcherImpl : public FilePathWatcher::PlatformDelegate { - public: - virtual bool Watch(const FilePath& path, - bool recursive, - const FilePathWatcher::Callback& callback) OVERRIDE { - return false; - } - - virtual void Cancel() OVERRIDE {} - - virtual void CancelOnMessageLoopThread() OVERRIDE {} - - protected: - virtual ~FilePathWatcherImpl() {} -}; - -} // namespace - -FilePathWatcher::FilePathWatcher() { - impl_ = new FilePathWatcherImpl(); -} - -} // namespace base diff --git a/base/files/file_path_watcher_win.cc b/base/files/file_path_watcher_win.cc deleted file mode 100644 index ac092a931b..0000000000 --- a/base/files/file_path_watcher_win.cc +++ /dev/null @@ -1,292 +0,0 @@ -// Copyright (c) 2011 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "base/files/file_path_watcher.h" - -#include "base/bind.h" -#include "base/file_util.h" -#include "base/files/file_path.h" -#include "base/logging.h" -#include "base/memory/ref_counted.h" -#include "base/message_loop/message_loop_proxy.h" -#include "base/time/time.h" -#include "base/win/object_watcher.h" - -namespace base { - -namespace { - -class FilePathWatcherImpl : public FilePathWatcher::PlatformDelegate, - public base::win::ObjectWatcher::Delegate, - public MessageLoop::DestructionObserver { - public: - FilePathWatcherImpl() - : handle_(INVALID_HANDLE_VALUE), - recursive_watch_(false) {} - - // FilePathWatcher::PlatformDelegate overrides. - virtual bool Watch(const FilePath& path, - bool recursive, - const FilePathWatcher::Callback& callback) OVERRIDE; - virtual void Cancel() OVERRIDE; - - // Deletion of the FilePathWatcher will call Cancel() to dispose of this - // object in the right thread. This also observes destruction of the required - // cleanup thread, in case it quits before Cancel() is called. - virtual void WillDestroyCurrentMessageLoop() OVERRIDE; - - // Callback from MessageLoopForIO. - virtual void OnObjectSignaled(HANDLE object); - - private: - virtual ~FilePathWatcherImpl() {} - - // Setup a watch handle for directory |dir|. Set |recursive| to true to watch - // the directory sub trees. Returns true if no fatal error occurs. |handle| - // will receive the handle value if |dir| is watchable, otherwise - // INVALID_HANDLE_VALUE. - static bool SetupWatchHandle(const FilePath& dir, - bool recursive, - HANDLE* handle) WARN_UNUSED_RESULT; - - // (Re-)Initialize the watch handle. - bool UpdateWatch() WARN_UNUSED_RESULT; - - // Destroy the watch handle. - void DestroyWatch(); - - // Cleans up and stops observing the |message_loop_| thread. - void CancelOnMessageLoopThread() OVERRIDE; - - // Callback to notify upon changes. - FilePathWatcher::Callback callback_; - - // Path we're supposed to watch (passed to callback). - FilePath target_; - - // Handle for FindFirstChangeNotification. - HANDLE handle_; - - // ObjectWatcher to watch handle_ for events. - base::win::ObjectWatcher watcher_; - - // Set to true to watch the sub trees of the specified directory file path. - bool recursive_watch_; - - // Keep track of the last modified time of the file. We use nulltime - // to represent the file not existing. - base::Time last_modified_; - - // The time at which we processed the first notification with the - // |last_modified_| time stamp. - base::Time first_notification_; - - DISALLOW_COPY_AND_ASSIGN(FilePathWatcherImpl); -}; - -bool FilePathWatcherImpl::Watch(const FilePath& path, - bool recursive, - const FilePathWatcher::Callback& callback) { - DCHECK(target_.value().empty()); // Can only watch one path. - - set_message_loop(base::MessageLoopProxy::current()); - callback_ = callback; - target_ = path; - recursive_watch_ = recursive; - MessageLoop::current()->AddDestructionObserver(this); - - if (!UpdateWatch()) - return false; - - watcher_.StartWatching(handle_, this); - - return true; -} - -void FilePathWatcherImpl::Cancel() { - if (callback_.is_null()) { - // Watch was never called, or the |message_loop_| has already quit. - set_cancelled(); - return; - } - - // Switch to the file thread if necessary so we can stop |watcher_|. - if (!message_loop()->BelongsToCurrentThread()) { - message_loop()->PostTask(FROM_HERE, - base::Bind(&FilePathWatcher::CancelWatch, - make_scoped_refptr(this))); - } else { - CancelOnMessageLoopThread(); - } -} - -void FilePathWatcherImpl::CancelOnMessageLoopThread() { - set_cancelled(); - - if (handle_ != INVALID_HANDLE_VALUE) - DestroyWatch(); - - if (!callback_.is_null()) { - MessageLoop::current()->RemoveDestructionObserver(this); - callback_.Reset(); - } -} - -void FilePathWatcherImpl::WillDestroyCurrentMessageLoop() { - CancelOnMessageLoopThread(); -} - -void FilePathWatcherImpl::OnObjectSignaled(HANDLE object) { - DCHECK(object == handle_); - // Make sure we stay alive through the body of this function. - scoped_refptr keep_alive(this); - - if (!UpdateWatch()) { - callback_.Run(target_, true /* error */); - return; - } - - // Check whether the event applies to |target_| and notify the callback. - base::PlatformFileInfo file_info; - bool file_exists = file_util::GetFileInfo(target_, &file_info); - if (file_exists && (last_modified_.is_null() || - last_modified_ != file_info.last_modified)) { - last_modified_ = file_info.last_modified; - first_notification_ = base::Time::Now(); - callback_.Run(target_, false); - } else if (file_exists && !first_notification_.is_null()) { - // The target's last modification time is equal to what's on record. This - // means that either an unrelated event occurred, or the target changed - // again (file modification times only have a resolution of 1s). Comparing - // file modification times against the wall clock is not reliable to find - // out whether the change is recent, since this code might just run too - // late. Moreover, there's no guarantee that file modification time and wall - // clock times come from the same source. - // - // Instead, the time at which the first notification carrying the current - // |last_notified_| time stamp is recorded. Later notifications that find - // the same file modification time only need to be forwarded until wall - // clock has advanced one second from the initial notification. After that - // interval, client code is guaranteed to having seen the current revision - // of the file. - if (base::Time::Now() - first_notification_ > - base::TimeDelta::FromSeconds(1)) { - // Stop further notifications for this |last_modification_| time stamp. - first_notification_ = base::Time(); - } - callback_.Run(target_, false); - } else if (!file_exists && !last_modified_.is_null()) { - last_modified_ = base::Time(); - callback_.Run(target_, false); - } - - // The watch may have been cancelled by the callback. - if (handle_ != INVALID_HANDLE_VALUE) - watcher_.StartWatching(handle_, this); -} - -// static -bool FilePathWatcherImpl::SetupWatchHandle(const FilePath& dir, - bool recursive, - HANDLE* handle) { - *handle = FindFirstChangeNotification( - dir.value().c_str(), - recursive, - FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_SIZE | - FILE_NOTIFY_CHANGE_LAST_WRITE | FILE_NOTIFY_CHANGE_DIR_NAME | - FILE_NOTIFY_CHANGE_ATTRIBUTES | FILE_NOTIFY_CHANGE_SECURITY); - if (*handle != INVALID_HANDLE_VALUE) { - // Make sure the handle we got points to an existing directory. It seems - // that windows sometimes hands out watches to directories that are - // about to go away, but doesn't sent notifications if that happens. - if (!DirectoryExists(dir)) { - FindCloseChangeNotification(*handle); - *handle = INVALID_HANDLE_VALUE; - } - return true; - } - - // If FindFirstChangeNotification failed because the target directory - // doesn't exist, access is denied (happens if the file is already gone but - // there are still handles open), or the target is not a directory, try the - // immediate parent directory instead. - DWORD error_code = GetLastError(); - if (error_code != ERROR_FILE_NOT_FOUND && - error_code != ERROR_PATH_NOT_FOUND && - error_code != ERROR_ACCESS_DENIED && - error_code != ERROR_SHARING_VIOLATION && - error_code != ERROR_DIRECTORY) { - using ::operator<<; // Pick the right operator<< below. - DPLOG(ERROR) << "FindFirstChangeNotification failed for " - << dir.value(); - return false; - } - - return true; -} - -bool FilePathWatcherImpl::UpdateWatch() { - if (handle_ != INVALID_HANDLE_VALUE) - DestroyWatch(); - - base::PlatformFileInfo file_info; - if (file_util::GetFileInfo(target_, &file_info)) { - last_modified_ = file_info.last_modified; - first_notification_ = base::Time::Now(); - } - - // Start at the target and walk up the directory chain until we succesfully - // create a watch handle in |handle_|. |child_dirs| keeps a stack of child - // directories stripped from target, in reverse order. - std::vector child_dirs; - FilePath watched_path(target_); - while (true) { - if (!SetupWatchHandle(watched_path, recursive_watch_, &handle_)) - return false; - - // Break if a valid handle is returned. Try the parent directory otherwise. - if (handle_ != INVALID_HANDLE_VALUE) - break; - - // Abort if we hit the root directory. - child_dirs.push_back(watched_path.BaseName()); - FilePath parent(watched_path.DirName()); - if (parent == watched_path) { - DLOG(ERROR) << "Reached the root directory"; - return false; - } - watched_path = parent; - } - - // At this point, handle_ is valid. However, the bottom-up search that the - // above code performs races against directory creation. So try to walk back - // down and see whether any children appeared in the mean time. - while (!child_dirs.empty()) { - watched_path = watched_path.Append(child_dirs.back()); - child_dirs.pop_back(); - HANDLE temp_handle = INVALID_HANDLE_VALUE; - if (!SetupWatchHandle(watched_path, recursive_watch_, &temp_handle)) - return false; - if (temp_handle == INVALID_HANDLE_VALUE) - break; - FindCloseChangeNotification(handle_); - handle_ = temp_handle; - } - - return true; -} - -void FilePathWatcherImpl::DestroyWatch() { - watcher_.StopWatching(); - FindCloseChangeNotification(handle_); - handle_ = INVALID_HANDLE_VALUE; -} - -} // namespace - -FilePathWatcher::FilePathWatcher() { - impl_ = new FilePathWatcherImpl(); -} - -} // namespace base diff --git a/base/files/file_util_proxy.cc b/base/files/file_util_proxy.cc deleted file mode 100644 index 5f6d405a90..0000000000 --- a/base/files/file_util_proxy.cc +++ /dev/null @@ -1,414 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "base/files/file_util_proxy.h" - -#include "base/bind.h" -#include "base/bind_helpers.h" -#include "base/file_util.h" -#include "base/location.h" -#include "base/message_loop/message_loop_proxy.h" -#include "base/task_runner.h" -#include "base/task_runner_util.h" - -namespace base { - -namespace { - -void CallWithTranslatedParameter(const FileUtilProxy::StatusCallback& callback, - bool value) { - DCHECK(!callback.is_null()); - callback.Run(value ? PLATFORM_FILE_OK : PLATFORM_FILE_ERROR_FAILED); -} - -// Helper classes or routines for individual methods. -class CreateOrOpenHelper { - public: - CreateOrOpenHelper(TaskRunner* task_runner, - const FileUtilProxy::CloseTask& close_task) - : task_runner_(task_runner), - close_task_(close_task), - file_handle_(kInvalidPlatformFileValue), - created_(false), - error_(PLATFORM_FILE_OK) {} - - ~CreateOrOpenHelper() { - if (file_handle_ != kInvalidPlatformFileValue) { - task_runner_->PostTask( - FROM_HERE, - base::Bind(base::IgnoreResult(close_task_), file_handle_)); - } - } - - void RunWork(const FileUtilProxy::CreateOrOpenTask& task) { - error_ = task.Run(&file_handle_, &created_); - } - - void Reply(const FileUtilProxy::CreateOrOpenCallback& callback) { - DCHECK(!callback.is_null()); - callback.Run(error_, PassPlatformFile(&file_handle_), created_); - } - - private: - scoped_refptr task_runner_; - FileUtilProxy::CloseTask close_task_; - PlatformFile file_handle_; - bool created_; - PlatformFileError error_; - DISALLOW_COPY_AND_ASSIGN(CreateOrOpenHelper); -}; - -class CreateTemporaryHelper { - public: - explicit CreateTemporaryHelper(TaskRunner* task_runner) - : task_runner_(task_runner), - file_handle_(kInvalidPlatformFileValue), - error_(PLATFORM_FILE_OK) {} - - ~CreateTemporaryHelper() { - if (file_handle_ != kInvalidPlatformFileValue) { - FileUtilProxy::Close( - task_runner_.get(), file_handle_, FileUtilProxy::StatusCallback()); - } - } - - void RunWork(int additional_file_flags) { - // TODO(darin): file_util should have a variant of CreateTemporaryFile - // that returns a FilePath and a PlatformFile. - file_util::CreateTemporaryFile(&file_path_); - - int file_flags = - PLATFORM_FILE_WRITE | - PLATFORM_FILE_TEMPORARY | - PLATFORM_FILE_CREATE_ALWAYS | - additional_file_flags; - - error_ = PLATFORM_FILE_OK; - file_handle_ = CreatePlatformFile(file_path_, file_flags, NULL, &error_); - } - - void Reply(const FileUtilProxy::CreateTemporaryCallback& callback) { - DCHECK(!callback.is_null()); - callback.Run(error_, PassPlatformFile(&file_handle_), file_path_); - } - - private: - scoped_refptr task_runner_; - PlatformFile file_handle_; - FilePath file_path_; - PlatformFileError error_; - DISALLOW_COPY_AND_ASSIGN(CreateTemporaryHelper); -}; - -class GetFileInfoHelper { - public: - GetFileInfoHelper() - : error_(PLATFORM_FILE_OK) {} - - void RunWorkForFilePath(const FilePath& file_path) { - if (!PathExists(file_path)) { - error_ = PLATFORM_FILE_ERROR_NOT_FOUND; - return; - } - if (!file_util::GetFileInfo(file_path, &file_info_)) - error_ = PLATFORM_FILE_ERROR_FAILED; - } - - void RunWorkForPlatformFile(PlatformFile file) { - if (!GetPlatformFileInfo(file, &file_info_)) - error_ = PLATFORM_FILE_ERROR_FAILED; - } - - void Reply(const FileUtilProxy::GetFileInfoCallback& callback) { - if (!callback.is_null()) { - callback.Run(error_, file_info_); - } - } - - private: - PlatformFileError error_; - PlatformFileInfo file_info_; - DISALLOW_COPY_AND_ASSIGN(GetFileInfoHelper); -}; - -class ReadHelper { - public: - explicit ReadHelper(int bytes_to_read) - : buffer_(new char[bytes_to_read]), - bytes_to_read_(bytes_to_read), - bytes_read_(0) {} - - void RunWork(PlatformFile file, int64 offset) { - bytes_read_ = ReadPlatformFile(file, offset, buffer_.get(), bytes_to_read_); - } - - void Reply(const FileUtilProxy::ReadCallback& callback) { - if (!callback.is_null()) { - PlatformFileError error = - (bytes_read_ < 0) ? PLATFORM_FILE_ERROR_FAILED : PLATFORM_FILE_OK; - callback.Run(error, buffer_.get(), bytes_read_); - } - } - - private: - scoped_ptr buffer_; - int bytes_to_read_; - int bytes_read_; - DISALLOW_COPY_AND_ASSIGN(ReadHelper); -}; - -class WriteHelper { - public: - WriteHelper(const char* buffer, int bytes_to_write) - : buffer_(new char[bytes_to_write]), - bytes_to_write_(bytes_to_write), - bytes_written_(0) { - memcpy(buffer_.get(), buffer, bytes_to_write); - } - - void RunWork(PlatformFile file, int64 offset) { - bytes_written_ = WritePlatformFile(file, offset, buffer_.get(), - bytes_to_write_); - } - - void Reply(const FileUtilProxy::WriteCallback& callback) { - if (!callback.is_null()) { - PlatformFileError error = - (bytes_written_ < 0) ? PLATFORM_FILE_ERROR_FAILED : PLATFORM_FILE_OK; - callback.Run(error, bytes_written_); - } - } - - private: - scoped_ptr buffer_; - int bytes_to_write_; - int bytes_written_; - DISALLOW_COPY_AND_ASSIGN(WriteHelper); -}; - -PlatformFileError CreateOrOpenAdapter( - const FilePath& file_path, int file_flags, - PlatformFile* file_handle, bool* created) { - DCHECK(file_handle); - DCHECK(created); - if (!DirectoryExists(file_path.DirName())) { - // If its parent does not exist, should return NOT_FOUND error. - return PLATFORM_FILE_ERROR_NOT_FOUND; - } - PlatformFileError error = PLATFORM_FILE_OK; - *file_handle = CreatePlatformFile(file_path, file_flags, created, &error); - return error; -} - -PlatformFileError CloseAdapter(PlatformFile file_handle) { - if (!ClosePlatformFile(file_handle)) { - return PLATFORM_FILE_ERROR_FAILED; - } - return PLATFORM_FILE_OK; -} - -PlatformFileError DeleteAdapter(const FilePath& file_path, bool recursive) { - if (!PathExists(file_path)) { - return PLATFORM_FILE_ERROR_NOT_FOUND; - } - if (!base::DeleteFile(file_path, recursive)) { - if (!recursive && !file_util::IsDirectoryEmpty(file_path)) { - return PLATFORM_FILE_ERROR_NOT_EMPTY; - } - return PLATFORM_FILE_ERROR_FAILED; - } - return PLATFORM_FILE_OK; -} - -} // namespace - -// static -bool FileUtilProxy::CreateOrOpen( - TaskRunner* task_runner, - const FilePath& file_path, int file_flags, - const CreateOrOpenCallback& callback) { - return RelayCreateOrOpen( - task_runner, - base::Bind(&CreateOrOpenAdapter, file_path, file_flags), - base::Bind(&CloseAdapter), - callback); -} - -// static -bool FileUtilProxy::CreateTemporary( - TaskRunner* task_runner, - int additional_file_flags, - const CreateTemporaryCallback& callback) { - CreateTemporaryHelper* helper = new CreateTemporaryHelper(task_runner); - return task_runner->PostTaskAndReply( - FROM_HERE, - Bind(&CreateTemporaryHelper::RunWork, Unretained(helper), - additional_file_flags), - Bind(&CreateTemporaryHelper::Reply, Owned(helper), callback)); -} - -// static -bool FileUtilProxy::Close( - TaskRunner* task_runner, - base::PlatformFile file_handle, - const StatusCallback& callback) { - return RelayClose( - task_runner, - base::Bind(&CloseAdapter), - file_handle, callback); -} - -// Retrieves the information about a file. It is invalid to pass NULL for the -// callback. -bool FileUtilProxy::GetFileInfo( - TaskRunner* task_runner, - const FilePath& file_path, - const GetFileInfoCallback& callback) { - GetFileInfoHelper* helper = new GetFileInfoHelper; - return task_runner->PostTaskAndReply( - FROM_HERE, - Bind(&GetFileInfoHelper::RunWorkForFilePath, - Unretained(helper), file_path), - Bind(&GetFileInfoHelper::Reply, Owned(helper), callback)); -} - -// static -bool FileUtilProxy::GetFileInfoFromPlatformFile( - TaskRunner* task_runner, - PlatformFile file, - const GetFileInfoCallback& callback) { - GetFileInfoHelper* helper = new GetFileInfoHelper; - return task_runner->PostTaskAndReply( - FROM_HERE, - Bind(&GetFileInfoHelper::RunWorkForPlatformFile, - Unretained(helper), file), - Bind(&GetFileInfoHelper::Reply, Owned(helper), callback)); -} - -// static -bool FileUtilProxy::DeleteFile(TaskRunner* task_runner, - const FilePath& file_path, - bool recursive, - const StatusCallback& callback) { - return base::PostTaskAndReplyWithResult( - task_runner, FROM_HERE, - Bind(&DeleteAdapter, file_path, recursive), - callback); -} - -// static -bool FileUtilProxy::Read( - TaskRunner* task_runner, - PlatformFile file, - int64 offset, - int bytes_to_read, - const ReadCallback& callback) { - if (bytes_to_read < 0) { - return false; - } - ReadHelper* helper = new ReadHelper(bytes_to_read); - return task_runner->PostTaskAndReply( - FROM_HERE, - Bind(&ReadHelper::RunWork, Unretained(helper), file, offset), - Bind(&ReadHelper::Reply, Owned(helper), callback)); -} - -// static -bool FileUtilProxy::Write( - TaskRunner* task_runner, - PlatformFile file, - int64 offset, - const char* buffer, - int bytes_to_write, - const WriteCallback& callback) { - if (bytes_to_write <= 0 || buffer == NULL) { - return false; - } - WriteHelper* helper = new WriteHelper(buffer, bytes_to_write); - return task_runner->PostTaskAndReply( - FROM_HERE, - Bind(&WriteHelper::RunWork, Unretained(helper), file, offset), - Bind(&WriteHelper::Reply, Owned(helper), callback)); -} - -// static -bool FileUtilProxy::Touch( - TaskRunner* task_runner, - PlatformFile file, - const Time& last_access_time, - const Time& last_modified_time, - const StatusCallback& callback) { - return base::PostTaskAndReplyWithResult( - task_runner, - FROM_HERE, - Bind(&TouchPlatformFile, file, - last_access_time, last_modified_time), - Bind(&CallWithTranslatedParameter, callback)); -} - -// static -bool FileUtilProxy::Touch( - TaskRunner* task_runner, - const FilePath& file_path, - const Time& last_access_time, - const Time& last_modified_time, - const StatusCallback& callback) { - return base::PostTaskAndReplyWithResult( - task_runner, - FROM_HERE, - Bind(&file_util::TouchFile, file_path, - last_access_time, last_modified_time), - Bind(&CallWithTranslatedParameter, callback)); -} - -// static -bool FileUtilProxy::Truncate( - TaskRunner* task_runner, - PlatformFile file, - int64 length, - const StatusCallback& callback) { - return base::PostTaskAndReplyWithResult( - task_runner, - FROM_HERE, - Bind(&TruncatePlatformFile, file, length), - Bind(&CallWithTranslatedParameter, callback)); -} - -// static -bool FileUtilProxy::Flush( - TaskRunner* task_runner, - PlatformFile file, - const StatusCallback& callback) { - return base::PostTaskAndReplyWithResult( - task_runner, - FROM_HERE, - Bind(&FlushPlatformFile, file), - Bind(&CallWithTranslatedParameter, callback)); -} - -// static -bool FileUtilProxy::RelayCreateOrOpen( - TaskRunner* task_runner, - const CreateOrOpenTask& open_task, - const CloseTask& close_task, - const CreateOrOpenCallback& callback) { - CreateOrOpenHelper* helper = new CreateOrOpenHelper( - task_runner, close_task); - return task_runner->PostTaskAndReply( - FROM_HERE, - Bind(&CreateOrOpenHelper::RunWork, Unretained(helper), open_task), - Bind(&CreateOrOpenHelper::Reply, Owned(helper), callback)); -} - -// static -bool FileUtilProxy::RelayClose( - TaskRunner* task_runner, - const CloseTask& close_task, - PlatformFile file_handle, - const StatusCallback& callback) { - return base::PostTaskAndReplyWithResult( - task_runner, FROM_HERE, Bind(close_task, file_handle), callback); -} - -} // namespace base diff --git a/base/files/file_util_proxy.h b/base/files/file_util_proxy.h deleted file mode 100644 index bded161200..0000000000 --- a/base/files/file_util_proxy.h +++ /dev/null @@ -1,195 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef BASE_FILES_FILE_UTIL_PROXY_H_ -#define BASE_FILES_FILE_UTIL_PROXY_H_ - -#include "base/base_export.h" -#include "base/callback_forward.h" -#include "base/files/file_path.h" -#include "base/memory/ref_counted.h" -#include "base/platform_file.h" - -namespace tracked_objects { -class Location; -}; - -namespace base { - -class TaskRunner; -class Time; - -// This class provides asynchronous access to common file routines. -class BASE_EXPORT FileUtilProxy { - public: - // This callback is used by methods that report only an error code. It is - // valid to pass a null callback to any function that takes a StatusCallback, - // in which case the operation will complete silently. - typedef Callback StatusCallback; - - typedef Callback CreateOrOpenCallback; - typedef Callback CreateTemporaryCallback; - typedef Callback GetFileInfoCallback; - typedef Callback ReadCallback; - typedef Callback WriteCallback; - - typedef Callback CreateOrOpenTask; - typedef Callback CloseTask; - typedef Callback FileTask; - - // Creates or opens a file with the given flags. It is invalid to pass a null - // callback. If PLATFORM_FILE_CREATE is set in |file_flags| it always tries to - // create a new file at the given |file_path| and calls back with - // PLATFORM_FILE_ERROR_FILE_EXISTS if the |file_path| already exists. - // - // This returns false if task posting to |task_runner| has failed. - static bool CreateOrOpen(TaskRunner* task_runner, - const FilePath& file_path, - int file_flags, - const CreateOrOpenCallback& callback); - - // Creates a temporary file for writing. The path and an open file handle are - // returned. It is invalid to pass a null callback. The additional file flags - // will be added on top of the default file flags which are: - // base::PLATFORM_FILE_CREATE_ALWAYS - // base::PLATFORM_FILE_WRITE - // base::PLATFORM_FILE_TEMPORARY. - // Set |additional_file_flags| to 0 for synchronous writes and set to - // base::PLATFORM_FILE_ASYNC to support asynchronous file operations. - // - // This returns false if task posting to |task_runner| has failed. - static bool CreateTemporary( - TaskRunner* task_runner, - int additional_file_flags, - const CreateTemporaryCallback& callback); - - // Close the given file handle. - // This returns false if task posting to |task_runner| has failed. - static bool Close(TaskRunner* task_runner, - PlatformFile, - const StatusCallback& callback); - - // Retrieves the information about a file. It is invalid to pass a null - // callback. - // This returns false if task posting to |task_runner| has failed. - static bool GetFileInfo( - TaskRunner* task_runner, - const FilePath& file_path, - const GetFileInfoCallback& callback); - - // Does the same as GetFileInfo but takes PlatformFile instead of FilePath. - // This returns false if task posting to |task_runner| has failed. - static bool GetFileInfoFromPlatformFile( - TaskRunner* task_runner, - PlatformFile file, - const GetFileInfoCallback& callback); - - // Deletes a file or a directory. - // It is an error to delete a non-empty directory with recursive=false. - // This returns false if task posting to |task_runner| has failed. - static bool DeleteFile(TaskRunner* task_runner, - const FilePath& file_path, - bool recursive, - const StatusCallback& callback); - - // Reads from a file. On success, the file pointer is moved to position - // |offset + bytes_to_read| in the file. The callback can be null. - // - // This returns false if |bytes_to_read| is less than zero, or - // if task posting to |task_runner| has failed. - static bool Read( - TaskRunner* task_runner, - PlatformFile file, - int64 offset, - int bytes_to_read, - const ReadCallback& callback); - - // Writes to a file. If |offset| is greater than the length of the file, - // |false| is returned. On success, the file pointer is moved to position - // |offset + bytes_to_write| in the file. The callback can be null. - // |bytes_to_write| must be greater than zero. - // - // This returns false if |bytes_to_write| is less than or equal to zero, - // if |buffer| is NULL, or if task posting to |task_runner| has failed. - static bool Write( - TaskRunner* task_runner, - PlatformFile file, - int64 offset, - const char* buffer, - int bytes_to_write, - const WriteCallback& callback); - - // Touches a file. The callback can be null. - // This returns false if task posting to |task_runner| has failed. - static bool Touch( - TaskRunner* task_runner, - PlatformFile file, - const Time& last_access_time, - const Time& last_modified_time, - const StatusCallback& callback); - - // Touches a file. The callback can be null. - // This returns false if task posting to |task_runner| has failed. - static bool Touch( - TaskRunner* task_runner, - const FilePath& file_path, - const Time& last_access_time, - const Time& last_modified_time, - const StatusCallback& callback); - - // Truncates a file to the given length. If |length| is greater than the - // current length of the file, the file will be extended with zeroes. - // The callback can be null. - // This returns false if task posting to |task_runner| has failed. - static bool Truncate( - TaskRunner* task_runner, - PlatformFile file, - int64 length, - const StatusCallback& callback); - - // Truncates a file to the given length. If |length| is greater than the - // current length of the file, the file will be extended with zeroes. - // The callback can be null. - // This returns false if task posting to |task_runner| has failed. - static bool Truncate( - TaskRunner* task_runner, - const FilePath& path, - int64 length, - const StatusCallback& callback); - - // Flushes a file. The callback can be null. - // This returns false if task posting to |task_runner| has failed. - static bool Flush( - TaskRunner* task_runner, - PlatformFile file, - const StatusCallback& callback); - - // Relay helpers. - // They return false if posting a given task to |task_runner| has failed. - static bool RelayCreateOrOpen( - TaskRunner* task_runner, - const CreateOrOpenTask& open_task, - const CloseTask& close_task, - const CreateOrOpenCallback& callback); - static bool RelayClose( - TaskRunner* task_runner, - const CloseTask& close_task, - PlatformFile, - const StatusCallback& callback); - - private: - DISALLOW_IMPLICIT_CONSTRUCTORS(FileUtilProxy); -}; - -} // namespace base - -#endif // BASE_FILES_FILE_UTIL_PROXY_H_ diff --git a/base/files/file_util_proxy_unittest.cc b/base/files/file_util_proxy_unittest.cc deleted file mode 100644 index 3c67075f48..0000000000 --- a/base/files/file_util_proxy_unittest.cc +++ /dev/null @@ -1,411 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "base/files/file_util_proxy.h" - -#include - -#include "base/bind.h" -#include "base/file_util.h" -#include "base/files/scoped_temp_dir.h" -#include "base/logging.h" -#include "base/memory/weak_ptr.h" -#include "base/message_loop/message_loop.h" -#include "base/platform_file.h" -#include "base/threading/thread.h" -#include "testing/gtest/include/gtest/gtest.h" - -namespace base { - -class FileUtilProxyTest : public testing::Test { - public: - FileUtilProxyTest() - : message_loop_(MessageLoop::TYPE_IO), - file_thread_("FileUtilProxyTestFileThread"), - error_(PLATFORM_FILE_OK), - created_(false), - file_(kInvalidPlatformFileValue), - bytes_written_(-1), - weak_factory_(this) {} - - virtual void SetUp() OVERRIDE { - ASSERT_TRUE(dir_.CreateUniqueTempDir()); - ASSERT_TRUE(file_thread_.Start()); - } - - virtual void TearDown() OVERRIDE { - if (file_ != kInvalidPlatformFileValue) - ClosePlatformFile(file_); - } - - void DidFinish(PlatformFileError error) { - error_ = error; - MessageLoop::current()->QuitWhenIdle(); - } - - void DidCreateOrOpen(PlatformFileError error, - PassPlatformFile file, - bool created) { - error_ = error; - file_ = file.ReleaseValue(); - created_ = created; - MessageLoop::current()->QuitWhenIdle(); - } - - void DidCreateTemporary(PlatformFileError error, - PassPlatformFile file, - const FilePath& path) { - error_ = error; - file_ = file.ReleaseValue(); - path_ = path; - MessageLoop::current()->QuitWhenIdle(); - } - - void DidGetFileInfo(PlatformFileError error, - const PlatformFileInfo& file_info) { - error_ = error; - file_info_ = file_info; - MessageLoop::current()->QuitWhenIdle(); - } - - void DidRead(PlatformFileError error, - const char* data, - int bytes_read) { - error_ = error; - buffer_.resize(bytes_read); - memcpy(&buffer_[0], data, bytes_read); - MessageLoop::current()->QuitWhenIdle(); - } - - void DidWrite(PlatformFileError error, - int bytes_written) { - error_ = error; - bytes_written_ = bytes_written; - MessageLoop::current()->QuitWhenIdle(); - } - - protected: - PlatformFile GetTestPlatformFile(int flags) { - if (file_ != kInvalidPlatformFileValue) - return file_; - bool created; - PlatformFileError error; - file_ = CreatePlatformFile(test_path(), flags, &created, &error); - EXPECT_EQ(PLATFORM_FILE_OK, error); - EXPECT_NE(kInvalidPlatformFileValue, file_); - return file_; - } - - TaskRunner* file_task_runner() const { - return file_thread_.message_loop_proxy().get(); - } - const FilePath& test_dir_path() const { return dir_.path(); } - const FilePath test_path() const { return dir_.path().AppendASCII("test"); } - - MessageLoop message_loop_; - Thread file_thread_; - - ScopedTempDir dir_; - PlatformFileError error_; - bool created_; - PlatformFile file_; - FilePath path_; - PlatformFileInfo file_info_; - std::vector buffer_; - int bytes_written_; - WeakPtrFactory weak_factory_; -}; - -TEST_F(FileUtilProxyTest, CreateOrOpen_Create) { - FileUtilProxy::CreateOrOpen( - file_task_runner(), - test_path(), - PLATFORM_FILE_CREATE | PLATFORM_FILE_READ, - Bind(&FileUtilProxyTest::DidCreateOrOpen, weak_factory_.GetWeakPtr())); - MessageLoop::current()->Run(); - - EXPECT_EQ(PLATFORM_FILE_OK, error_); - EXPECT_TRUE(created_); - EXPECT_NE(kInvalidPlatformFileValue, file_); - EXPECT_TRUE(PathExists(test_path())); -} - -TEST_F(FileUtilProxyTest, CreateOrOpen_Open) { - // Creates a file. - file_util::WriteFile(test_path(), NULL, 0); - ASSERT_TRUE(PathExists(test_path())); - - // Opens the created file. - FileUtilProxy::CreateOrOpen( - file_task_runner(), - test_path(), - PLATFORM_FILE_OPEN | PLATFORM_FILE_READ, - Bind(&FileUtilProxyTest::DidCreateOrOpen, weak_factory_.GetWeakPtr())); - MessageLoop::current()->Run(); - - EXPECT_EQ(PLATFORM_FILE_OK, error_); - EXPECT_FALSE(created_); - EXPECT_NE(kInvalidPlatformFileValue, file_); -} - -TEST_F(FileUtilProxyTest, CreateOrOpen_OpenNonExistent) { - FileUtilProxy::CreateOrOpen( - file_task_runner(), - test_path(), - PLATFORM_FILE_OPEN | PLATFORM_FILE_READ, - Bind(&FileUtilProxyTest::DidCreateOrOpen, weak_factory_.GetWeakPtr())); - MessageLoop::current()->Run(); - EXPECT_EQ(PLATFORM_FILE_ERROR_NOT_FOUND, error_); - EXPECT_FALSE(created_); - EXPECT_EQ(kInvalidPlatformFileValue, file_); - EXPECT_FALSE(PathExists(test_path())); -} - -TEST_F(FileUtilProxyTest, Close) { - // Creates a file. - PlatformFile file = GetTestPlatformFile( - PLATFORM_FILE_CREATE | PLATFORM_FILE_WRITE); - -#if defined(OS_WIN) - // This fails on Windows if the file is not closed. - EXPECT_FALSE(base::Move(test_path(), - test_dir_path().AppendASCII("new"))); -#endif - - FileUtilProxy::Close( - file_task_runner(), - file, - Bind(&FileUtilProxyTest::DidFinish, weak_factory_.GetWeakPtr())); - MessageLoop::current()->Run(); - EXPECT_EQ(PLATFORM_FILE_OK, error_); - - // Now it should pass on all platforms. - EXPECT_TRUE(base::Move(test_path(), test_dir_path().AppendASCII("new"))); -} - -TEST_F(FileUtilProxyTest, CreateTemporary) { - FileUtilProxy::CreateTemporary( - file_task_runner(), 0 /* additional_file_flags */, - Bind(&FileUtilProxyTest::DidCreateTemporary, weak_factory_.GetWeakPtr())); - MessageLoop::current()->Run(); - EXPECT_EQ(PLATFORM_FILE_OK, error_); - EXPECT_TRUE(PathExists(path_)); - EXPECT_NE(kInvalidPlatformFileValue, file_); - - // The file should be writable. -#if defined(OS_WIN) - HANDLE hEvent = CreateEvent(NULL, FALSE, FALSE, NULL); - OVERLAPPED overlapped = {0}; - overlapped.hEvent = hEvent; - DWORD bytes_written; - if (!::WriteFile(file_, "test", 4, &bytes_written, &overlapped)) { - // Temporary file is created with ASYNC flag, so WriteFile may return 0 - // with ERROR_IO_PENDING. - EXPECT_EQ(ERROR_IO_PENDING, GetLastError()); - GetOverlappedResult(file_, &overlapped, &bytes_written, TRUE); - } - EXPECT_EQ(4, bytes_written); -#else - // On POSIX ASYNC flag does not affect synchronous read/write behavior. - EXPECT_EQ(4, WritePlatformFile(file_, 0, "test", 4)); -#endif - EXPECT_TRUE(ClosePlatformFile(file_)); - file_ = kInvalidPlatformFileValue; - - // Make sure the written data can be read from the returned path. - std::string data; - EXPECT_TRUE(file_util::ReadFileToString(path_, &data)); - EXPECT_EQ("test", data); - - // Make sure we can & do delete the created file to prevent leaks on the bots. - EXPECT_TRUE(base::DeleteFile(path_, false)); -} - -TEST_F(FileUtilProxyTest, GetFileInfo_File) { - // Setup. - ASSERT_EQ(4, file_util::WriteFile(test_path(), "test", 4)); - PlatformFileInfo expected_info; - file_util::GetFileInfo(test_path(), &expected_info); - - // Run. - FileUtilProxy::GetFileInfo( - file_task_runner(), - test_path(), - Bind(&FileUtilProxyTest::DidGetFileInfo, weak_factory_.GetWeakPtr())); - MessageLoop::current()->Run(); - - // Verify. - EXPECT_EQ(PLATFORM_FILE_OK, error_); - EXPECT_EQ(expected_info.size, file_info_.size); - EXPECT_EQ(expected_info.is_directory, file_info_.is_directory); - EXPECT_EQ(expected_info.is_symbolic_link, file_info_.is_symbolic_link); - EXPECT_EQ(expected_info.last_modified, file_info_.last_modified); - EXPECT_EQ(expected_info.last_accessed, file_info_.last_accessed); - EXPECT_EQ(expected_info.creation_time, file_info_.creation_time); -} - -TEST_F(FileUtilProxyTest, GetFileInfo_Directory) { - // Setup. - ASSERT_TRUE(file_util::CreateDirectory(test_path())); - PlatformFileInfo expected_info; - file_util::GetFileInfo(test_path(), &expected_info); - - // Run. - FileUtilProxy::GetFileInfo( - file_task_runner(), - test_path(), - Bind(&FileUtilProxyTest::DidGetFileInfo, weak_factory_.GetWeakPtr())); - MessageLoop::current()->Run(); - - // Verify. - EXPECT_EQ(PLATFORM_FILE_OK, error_); - EXPECT_EQ(expected_info.size, file_info_.size); - EXPECT_EQ(expected_info.is_directory, file_info_.is_directory); - EXPECT_EQ(expected_info.is_symbolic_link, file_info_.is_symbolic_link); - EXPECT_EQ(expected_info.last_modified, file_info_.last_modified); - EXPECT_EQ(expected_info.last_accessed, file_info_.last_accessed); - EXPECT_EQ(expected_info.creation_time, file_info_.creation_time); -} - -TEST_F(FileUtilProxyTest, Read) { - // Setup. - const char expected_data[] = "bleh"; - int expected_bytes = arraysize(expected_data); - ASSERT_EQ(expected_bytes, - file_util::WriteFile(test_path(), expected_data, expected_bytes)); - - // Run. - FileUtilProxy::Read( - file_task_runner(), - GetTestPlatformFile(PLATFORM_FILE_OPEN | PLATFORM_FILE_READ), - 0, // offset - 128, - Bind(&FileUtilProxyTest::DidRead, weak_factory_.GetWeakPtr())); - MessageLoop::current()->Run(); - - // Verify. - EXPECT_EQ(PLATFORM_FILE_OK, error_); - EXPECT_EQ(expected_bytes, static_cast(buffer_.size())); - for (size_t i = 0; i < buffer_.size(); ++i) { - EXPECT_EQ(expected_data[i], buffer_[i]); - } -} - -TEST_F(FileUtilProxyTest, WriteAndFlush) { - const char data[] = "foo!"; - int data_bytes = ARRAYSIZE_UNSAFE(data); - PlatformFile file = GetTestPlatformFile( - PLATFORM_FILE_CREATE | PLATFORM_FILE_WRITE); - - FileUtilProxy::Write( - file_task_runner(), - file, - 0, // offset - data, - data_bytes, - Bind(&FileUtilProxyTest::DidWrite, weak_factory_.GetWeakPtr())); - MessageLoop::current()->Run(); - EXPECT_EQ(PLATFORM_FILE_OK, error_); - EXPECT_EQ(data_bytes, bytes_written_); - - // Flush the written data. (So that the following read should always - // succeed. On some platforms it may work with or without this flush.) - FileUtilProxy::Flush( - file_task_runner(), - file, - Bind(&FileUtilProxyTest::DidFinish, weak_factory_.GetWeakPtr())); - MessageLoop::current()->Run(); - EXPECT_EQ(PLATFORM_FILE_OK, error_); - - // Verify the written data. - char buffer[10]; - EXPECT_EQ(data_bytes, file_util::ReadFile(test_path(), buffer, data_bytes)); - for (int i = 0; i < data_bytes; ++i) { - EXPECT_EQ(data[i], buffer[i]); - } -} - -TEST_F(FileUtilProxyTest, Touch) { - Time last_accessed_time = Time::Now() - TimeDelta::FromDays(12345); - Time last_modified_time = Time::Now() - TimeDelta::FromHours(98765); - - FileUtilProxy::Touch( - file_task_runner(), - GetTestPlatformFile(PLATFORM_FILE_CREATE | - PLATFORM_FILE_WRITE | - PLATFORM_FILE_WRITE_ATTRIBUTES), - last_accessed_time, - last_modified_time, - Bind(&FileUtilProxyTest::DidFinish, weak_factory_.GetWeakPtr())); - MessageLoop::current()->Run(); - EXPECT_EQ(PLATFORM_FILE_OK, error_); - - PlatformFileInfo info; - file_util::GetFileInfo(test_path(), &info); - - // The returned values may only have the seconds precision, so we cast - // the double values to int here. - EXPECT_EQ(static_cast(last_modified_time.ToDoubleT()), - static_cast(info.last_modified.ToDoubleT())); - EXPECT_EQ(static_cast(last_accessed_time.ToDoubleT()), - static_cast(info.last_accessed.ToDoubleT())); -} - -TEST_F(FileUtilProxyTest, Truncate_Shrink) { - // Setup. - const char kTestData[] = "0123456789"; - ASSERT_EQ(10, file_util::WriteFile(test_path(), kTestData, 10)); - PlatformFileInfo info; - file_util::GetFileInfo(test_path(), &info); - ASSERT_EQ(10, info.size); - - // Run. - FileUtilProxy::Truncate( - file_task_runner(), - GetTestPlatformFile(PLATFORM_FILE_OPEN | PLATFORM_FILE_WRITE), - 7, - Bind(&FileUtilProxyTest::DidFinish, weak_factory_.GetWeakPtr())); - MessageLoop::current()->Run(); - - // Verify. - file_util::GetFileInfo(test_path(), &info); - ASSERT_EQ(7, info.size); - - char buffer[7]; - EXPECT_EQ(7, file_util::ReadFile(test_path(), buffer, 7)); - int i = 0; - for (; i < 7; ++i) - EXPECT_EQ(kTestData[i], buffer[i]); -} - -TEST_F(FileUtilProxyTest, Truncate_Expand) { - // Setup. - const char kTestData[] = "9876543210"; - ASSERT_EQ(10, file_util::WriteFile(test_path(), kTestData, 10)); - PlatformFileInfo info; - file_util::GetFileInfo(test_path(), &info); - ASSERT_EQ(10, info.size); - - // Run. - FileUtilProxy::Truncate( - file_task_runner(), - GetTestPlatformFile(PLATFORM_FILE_OPEN | PLATFORM_FILE_WRITE), - 53, - Bind(&FileUtilProxyTest::DidFinish, weak_factory_.GetWeakPtr())); - MessageLoop::current()->Run(); - - // Verify. - file_util::GetFileInfo(test_path(), &info); - ASSERT_EQ(53, info.size); - - char buffer[53]; - EXPECT_EQ(53, file_util::ReadFile(test_path(), buffer, 53)); - int i = 0; - for (; i < 10; ++i) - EXPECT_EQ(kTestData[i], buffer[i]); - for (; i < 53; ++i) - EXPECT_EQ(0, buffer[i]); -} - -} // namespace base diff --git a/base/files/important_file_writer.cc b/base/files/important_file_writer.cc deleted file mode 100644 index d88498506b..0000000000 --- a/base/files/important_file_writer.cc +++ /dev/null @@ -1,167 +0,0 @@ -// Copyright (c) 2011 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "base/files/important_file_writer.h" - -#include - -#include - -#include "base/bind.h" -#include "base/critical_closure.h" -#include "base/file_util.h" -#include "base/files/file_path.h" -#include "base/logging.h" -#include "base/metrics/histogram.h" -#include "base/strings/string_number_conversions.h" -#include "base/task_runner.h" -#include "base/threading/thread.h" -#include "base/time/time.h" - -namespace base { - -namespace { - -const int kDefaultCommitIntervalMs = 10000; - -enum TempFileFailure { - FAILED_CREATING, - FAILED_OPENING, - FAILED_CLOSING, - FAILED_WRITING, - FAILED_RENAMING, - TEMP_FILE_FAILURE_MAX -}; - -void LogFailure(const FilePath& path, TempFileFailure failure_code, - const std::string& message) { - UMA_HISTOGRAM_ENUMERATION("ImportantFile.TempFileFailures", failure_code, - TEMP_FILE_FAILURE_MAX); - DPLOG(WARNING) << "temp file failure: " << path.value().c_str() - << " : " << message; -} - -} // namespace - -// static -bool ImportantFileWriter::WriteFileAtomically(const FilePath& path, - const std::string& data) { - // Write the data to a temp file then rename to avoid data loss if we crash - // while writing the file. Ensure that the temp file is on the same volume - // as target file, so it can be moved in one step, and that the temp file - // is securely created. - FilePath tmp_file_path; - if (!file_util::CreateTemporaryFileInDir(path.DirName(), &tmp_file_path)) { - LogFailure(path, FAILED_CREATING, "could not create temporary file"); - return false; - } - - int flags = PLATFORM_FILE_OPEN | PLATFORM_FILE_WRITE; - PlatformFile tmp_file = - CreatePlatformFile(tmp_file_path, flags, NULL, NULL); - if (tmp_file == kInvalidPlatformFileValue) { - LogFailure(path, FAILED_OPENING, "could not open temporary file"); - return false; - } - - // If this happens in the wild something really bad is going on. - CHECK_LE(data.length(), static_cast(kint32max)); - int bytes_written = WritePlatformFile( - tmp_file, 0, data.data(), static_cast(data.length())); - FlushPlatformFile(tmp_file); // Ignore return value. - - if (!ClosePlatformFile(tmp_file)) { - LogFailure(path, FAILED_CLOSING, "failed to close temporary file"); - base::DeleteFile(tmp_file_path, false); - return false; - } - - if (bytes_written < static_cast(data.length())) { - LogFailure(path, FAILED_WRITING, "error writing, bytes_written=" + - IntToString(bytes_written)); - base::DeleteFile(tmp_file_path, false); - return false; - } - - if (!base::ReplaceFile(tmp_file_path, path, NULL)) { - LogFailure(path, FAILED_RENAMING, "could not rename temporary file"); - base::DeleteFile(tmp_file_path, false); - return false; - } - - return true; -} - -ImportantFileWriter::ImportantFileWriter( - const FilePath& path, base::SequencedTaskRunner* task_runner) - : path_(path), - task_runner_(task_runner), - serializer_(NULL), - commit_interval_(TimeDelta::FromMilliseconds( - kDefaultCommitIntervalMs)) { - DCHECK(CalledOnValidThread()); - DCHECK(task_runner_.get()); -} - -ImportantFileWriter::~ImportantFileWriter() { - // We're usually a member variable of some other object, which also tends - // to be our serializer. It may not be safe to call back to the parent object - // being destructed. - DCHECK(!HasPendingWrite()); -} - -bool ImportantFileWriter::HasPendingWrite() const { - DCHECK(CalledOnValidThread()); - return timer_.IsRunning(); -} - -void ImportantFileWriter::WriteNow(const std::string& data) { - DCHECK(CalledOnValidThread()); - if (data.length() > static_cast(kint32max)) { - NOTREACHED(); - return; - } - - if (HasPendingWrite()) - timer_.Stop(); - - if (!task_runner_->PostTask( - FROM_HERE, - MakeCriticalClosure( - Bind(IgnoreResult(&ImportantFileWriter::WriteFileAtomically), - path_, data)))) { - // Posting the task to background message loop is not expected - // to fail, but if it does, avoid losing data and just hit the disk - // on the current thread. - NOTREACHED(); - - WriteFileAtomically(path_, data); - } -} - -void ImportantFileWriter::ScheduleWrite(DataSerializer* serializer) { - DCHECK(CalledOnValidThread()); - - DCHECK(serializer); - serializer_ = serializer; - - if (!timer_.IsRunning()) { - timer_.Start(FROM_HERE, commit_interval_, this, - &ImportantFileWriter::DoScheduledWrite); - } -} - -void ImportantFileWriter::DoScheduledWrite() { - DCHECK(serializer_); - std::string data; - if (serializer_->SerializeData(&data)) { - WriteNow(data); - } else { - DLOG(WARNING) << "failed to serialize data to be saved in " - << path_.value().c_str(); - } - serializer_ = NULL; -} - -} // namespace base diff --git a/base/files/important_file_writer.h b/base/files/important_file_writer.h deleted file mode 100644 index ba1c745a4e..0000000000 --- a/base/files/important_file_writer.h +++ /dev/null @@ -1,121 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef BASE_FILES_IMPORTANT_FILE_WRITER_H_ -#define BASE_FILES_IMPORTANT_FILE_WRITER_H_ - -#include - -#include "base/base_export.h" -#include "base/basictypes.h" -#include "base/files/file_path.h" -#include "base/memory/ref_counted.h" -#include "base/threading/non_thread_safe.h" -#include "base/time/time.h" -#include "base/timer/timer.h" - -namespace base { - -class SequencedTaskRunner; -class Thread; - -// Helper to ensure that a file won't be corrupted by the write (for example on -// application crash). Consider a naive way to save an important file F: -// -// 1. Open F for writing, truncating it. -// 2. Write new data to F. -// -// It's good when it works, but it gets very bad if step 2. doesn't complete. -// It can be caused by a crash, a computer hang, or a weird I/O error. And you -// end up with a broken file. -// -// To be safe, we don't start with writing directly to F. Instead, we write to -// to a temporary file. Only after that write is successful, we rename the -// temporary file to target filename. -// -// If you want to know more about this approach and ext3/ext4 fsync issues, see -// http://valhenson.livejournal.com/37921.html -class BASE_EXPORT ImportantFileWriter : public NonThreadSafe { - public: - // Used by ScheduleSave to lazily provide the data to be saved. Allows us - // to also batch data serializations. - class BASE_EXPORT DataSerializer { - public: - // Should put serialized string in |data| and return true on successful - // serialization. Will be called on the same thread on which - // ImportantFileWriter has been created. - virtual bool SerializeData(std::string* data) = 0; - - protected: - virtual ~DataSerializer() {} - }; - - // Save |data| to |path| in an atomic manner (see the class comment above). - // Blocks and writes data on the current thread. - static bool WriteFileAtomically(const FilePath& path, - const std::string& data); - - // Initialize the writer. - // |path| is the name of file to write. - // |task_runner| is the SequencedTaskRunner instance where on which we will - // execute file I/O operations. - // All non-const methods, ctor and dtor must be called on the same thread. - ImportantFileWriter(const FilePath& path, - base::SequencedTaskRunner* task_runner); - - // You have to ensure that there are no pending writes at the moment - // of destruction. - ~ImportantFileWriter(); - - const FilePath& path() const { return path_; } - - // Returns true if there is a scheduled write pending which has not yet - // been started. - bool HasPendingWrite() const; - - // Save |data| to target filename. Does not block. If there is a pending write - // scheduled by ScheduleWrite, it is cancelled. - void WriteNow(const std::string& data); - - // Schedule a save to target filename. Data will be serialized and saved - // to disk after the commit interval. If another ScheduleWrite is issued - // before that, only one serialization and write to disk will happen, and - // the most recent |serializer| will be used. This operation does not block. - // |serializer| should remain valid through the lifetime of - // ImportantFileWriter. - void ScheduleWrite(DataSerializer* serializer); - - // Serialize data pending to be saved and execute write on backend thread. - void DoScheduledWrite(); - - TimeDelta commit_interval() const { - return commit_interval_; - } - - void set_commit_interval(const TimeDelta& interval) { - commit_interval_ = interval; - } - - private: - // Path being written to. - const FilePath path_; - - // TaskRunner for the thread on which file I/O can be done. - const scoped_refptr task_runner_; - - // Timer used to schedule commit after ScheduleWrite. - OneShotTimer timer_; - - // Serializer which will provide the data to be saved. - DataSerializer* serializer_; - - // Time delta after which scheduled data will be written to disk. - TimeDelta commit_interval_; - - DISALLOW_COPY_AND_ASSIGN(ImportantFileWriter); -}; - -} // namespace base - -#endif // BASE_FILES_IMPORTANT_FILE_WRITER_H_ diff --git a/base/files/important_file_writer_unittest.cc b/base/files/important_file_writer_unittest.cc deleted file mode 100644 index e8f3d122c6..0000000000 --- a/base/files/important_file_writer_unittest.cc +++ /dev/null @@ -1,122 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "base/files/important_file_writer.h" - -#include "base/compiler_specific.h" -#include "base/file_util.h" -#include "base/files/file_path.h" -#include "base/files/scoped_temp_dir.h" -#include "base/logging.h" -#include "base/message_loop/message_loop.h" -#include "base/run_loop.h" -#include "base/threading/thread.h" -#include "base/time/time.h" -#include "testing/gtest/include/gtest/gtest.h" - -namespace base { - -namespace { - -std::string GetFileContent(const FilePath& path) { - std::string content; - if (!file_util::ReadFileToString(path, &content)) { - NOTREACHED(); - } - return content; -} - -class DataSerializer : public ImportantFileWriter::DataSerializer { - public: - explicit DataSerializer(const std::string& data) : data_(data) { - } - - virtual bool SerializeData(std::string* output) OVERRIDE { - output->assign(data_); - return true; - } - - private: - const std::string data_; -}; - -} // namespace - -class ImportantFileWriterTest : public testing::Test { - public: - ImportantFileWriterTest() { } - virtual void SetUp() { - ASSERT_TRUE(temp_dir_.CreateUniqueTempDir()); - file_ = temp_dir_.path().AppendASCII("test-file"); - } - - protected: - FilePath file_; - MessageLoop loop_; - - private: - ScopedTempDir temp_dir_; -}; - -TEST_F(ImportantFileWriterTest, Basic) { - ImportantFileWriter writer(file_, MessageLoopProxy::current().get()); - EXPECT_FALSE(PathExists(writer.path())); - writer.WriteNow("foo"); - RunLoop().RunUntilIdle(); - - ASSERT_TRUE(PathExists(writer.path())); - EXPECT_EQ("foo", GetFileContent(writer.path())); -} - -TEST_F(ImportantFileWriterTest, ScheduleWrite) { - ImportantFileWriter writer(file_, MessageLoopProxy::current().get()); - writer.set_commit_interval(TimeDelta::FromMilliseconds(25)); - EXPECT_FALSE(writer.HasPendingWrite()); - DataSerializer serializer("foo"); - writer.ScheduleWrite(&serializer); - EXPECT_TRUE(writer.HasPendingWrite()); - MessageLoop::current()->PostDelayedTask( - FROM_HERE, - MessageLoop::QuitWhenIdleClosure(), - TimeDelta::FromMilliseconds(100)); - MessageLoop::current()->Run(); - EXPECT_FALSE(writer.HasPendingWrite()); - ASSERT_TRUE(PathExists(writer.path())); - EXPECT_EQ("foo", GetFileContent(writer.path())); -} - -TEST_F(ImportantFileWriterTest, DoScheduledWrite) { - ImportantFileWriter writer(file_, MessageLoopProxy::current().get()); - EXPECT_FALSE(writer.HasPendingWrite()); - DataSerializer serializer("foo"); - writer.ScheduleWrite(&serializer); - EXPECT_TRUE(writer.HasPendingWrite()); - writer.DoScheduledWrite(); - MessageLoop::current()->PostDelayedTask( - FROM_HERE, - MessageLoop::QuitWhenIdleClosure(), - TimeDelta::FromMilliseconds(100)); - MessageLoop::current()->Run(); - EXPECT_FALSE(writer.HasPendingWrite()); - ASSERT_TRUE(PathExists(writer.path())); - EXPECT_EQ("foo", GetFileContent(writer.path())); -} - -TEST_F(ImportantFileWriterTest, BatchingWrites) { - ImportantFileWriter writer(file_, MessageLoopProxy::current().get()); - writer.set_commit_interval(TimeDelta::FromMilliseconds(25)); - DataSerializer foo("foo"), bar("bar"), baz("baz"); - writer.ScheduleWrite(&foo); - writer.ScheduleWrite(&bar); - writer.ScheduleWrite(&baz); - MessageLoop::current()->PostDelayedTask( - FROM_HERE, - MessageLoop::QuitWhenIdleClosure(), - TimeDelta::FromMilliseconds(100)); - MessageLoop::current()->Run(); - ASSERT_TRUE(PathExists(writer.path())); - EXPECT_EQ("baz", GetFileContent(writer.path())); -} - -} // namespace base diff --git a/base/files/memory_mapped_file.cc b/base/files/memory_mapped_file.cc deleted file mode 100644 index a48ec0ceb2..0000000000 --- a/base/files/memory_mapped_file.cc +++ /dev/null @@ -1,58 +0,0 @@ -// Copyright 2013 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "base/files/memory_mapped_file.h" - -#include "base/files/file_path.h" -#include "base/logging.h" - -namespace base { - -MemoryMappedFile::~MemoryMappedFile() { - CloseHandles(); -} - -bool MemoryMappedFile::Initialize(const FilePath& file_name) { - if (IsValid()) - return false; - - if (!MapFileToMemory(file_name)) { - CloseHandles(); - return false; - } - - return true; -} - -bool MemoryMappedFile::Initialize(PlatformFile file) { - if (IsValid()) - return false; - - file_ = file; - - if (!MapFileToMemoryInternal()) { - CloseHandles(); - return false; - } - - return true; -} - -bool MemoryMappedFile::IsValid() const { - return data_ != NULL; -} - -bool MemoryMappedFile::MapFileToMemory(const FilePath& file_name) { - file_ = CreatePlatformFile(file_name, PLATFORM_FILE_OPEN | PLATFORM_FILE_READ, - NULL, NULL); - - if (file_ == kInvalidPlatformFileValue) { - DLOG(ERROR) << "Couldn't open " << file_name.AsUTF8Unsafe(); - return false; - } - - return MapFileToMemoryInternal(); -} - -} // namespace base diff --git a/base/files/memory_mapped_file.h b/base/files/memory_mapped_file.h deleted file mode 100644 index 6df1bad635..0000000000 --- a/base/files/memory_mapped_file.h +++ /dev/null @@ -1,76 +0,0 @@ -// Copyright 2013 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef BASE_FILES_MEMORY_MAPPED_FILE_H_ -#define BASE_FILES_MEMORY_MAPPED_FILE_H_ - -#include "base/base_export.h" -#include "base/basictypes.h" -#include "base/platform_file.h" -#include "build/build_config.h" - -#if defined(OS_WIN) -#include -#endif - -namespace base { - -class FilePath; - -class BASE_EXPORT MemoryMappedFile { - public: - // The default constructor sets all members to invalid/null values. - MemoryMappedFile(); - ~MemoryMappedFile(); - - // Opens an existing file and maps it into memory. Access is restricted to - // read only. If this object already points to a valid memory mapped file - // then this method will fail and return false. If it cannot open the file, - // the file does not exist, or the memory mapping fails, it will return false. - // Later we may want to allow the user to specify access. - bool Initialize(const FilePath& file_name); - // As above, but works with an already-opened file. MemoryMappedFile will take - // ownership of |file| and close it when done. - bool Initialize(PlatformFile file); - -#if defined(OS_WIN) - // Opens an existing file and maps it as an image section. Please refer to - // the Initialize function above for additional information. - bool InitializeAsImageSection(const FilePath& file_name); -#endif // OS_WIN - - const uint8* data() const { return data_; } - size_t length() const { return length_; } - - // Is file_ a valid file handle that points to an open, memory mapped file? - bool IsValid() const; - - private: - // Open the given file and pass it to MapFileToMemoryInternal(). - bool MapFileToMemory(const FilePath& file_name); - - // Map the file to memory, set data_ to that memory address. Return true on - // success, false on any kind of failure. This is a helper for Initialize(). - bool MapFileToMemoryInternal(); - - // Closes all open handles. Later we may want to make this public. - void CloseHandles(); - -#if defined(OS_WIN) - // MapFileToMemoryInternal calls this function. It provides the ability to - // pass in flags which control the mapped section. - bool MapFileToMemoryInternalEx(int flags); - - HANDLE file_mapping_; -#endif - PlatformFile file_; - uint8* data_; - size_t length_; - - DISALLOW_COPY_AND_ASSIGN(MemoryMappedFile); -}; - -} // namespace base - -#endif // BASE_FILES_MEMORY_MAPPED_FILE_H_ diff --git a/base/files/memory_mapped_file_posix.cc b/base/files/memory_mapped_file_posix.cc deleted file mode 100644 index 38b271691c..0000000000 --- a/base/files/memory_mapped_file_posix.cc +++ /dev/null @@ -1,54 +0,0 @@ -// Copyright 2013 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "base/files/memory_mapped_file.h" - -#include -#include -#include - -#include "base/logging.h" -#include "base/posix/eintr_wrapper.h" -#include "base/threading/thread_restrictions.h" - -namespace base { - -MemoryMappedFile::MemoryMappedFile() - : file_(kInvalidPlatformFileValue), - data_(NULL), - length_(0) { -} - -bool MemoryMappedFile::MapFileToMemoryInternal() { - ThreadRestrictions::AssertIOAllowed(); - - struct stat file_stat; - if (fstat(file_, &file_stat) == kInvalidPlatformFileValue) { - DLOG(ERROR) << "Couldn't fstat " << file_ << ", errno " << errno; - return false; - } - length_ = file_stat.st_size; - - data_ = static_cast( - mmap(NULL, length_, PROT_READ, MAP_SHARED, file_, 0)); - if (data_ == MAP_FAILED) - DLOG(ERROR) << "Couldn't mmap " << file_ << ", errno " << errno; - - return data_ != MAP_FAILED; -} - -void MemoryMappedFile::CloseHandles() { - ThreadRestrictions::AssertIOAllowed(); - - if (data_ != NULL) - munmap(data_, length_); - if (file_ != kInvalidPlatformFileValue) - ignore_result(HANDLE_EINTR(close(file_))); - - data_ = NULL; - length_ = 0; - file_ = kInvalidPlatformFileValue; -} - -} // namespace base diff --git a/base/files/memory_mapped_file_win.cc b/base/files/memory_mapped_file_win.cc deleted file mode 100644 index 694212950d..0000000000 --- a/base/files/memory_mapped_file_win.cc +++ /dev/null @@ -1,87 +0,0 @@ -// Copyright 2013 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "base/files/memory_mapped_file.h" - -#include "base/files/file_path.h" -#include "base/logging.h" -#include "base/metrics/histogram.h" -#include "base/strings/string16.h" -#include "base/threading/thread_restrictions.h" - -namespace base { - -MemoryMappedFile::MemoryMappedFile() - : file_(INVALID_HANDLE_VALUE), - file_mapping_(INVALID_HANDLE_VALUE), - data_(NULL), - length_(INVALID_FILE_SIZE) { -} - -bool MemoryMappedFile::InitializeAsImageSection(const FilePath& file_name) { - if (IsValid()) - return false; - file_ = CreatePlatformFile(file_name, PLATFORM_FILE_OPEN | PLATFORM_FILE_READ, - NULL, NULL); - - if (file_ == kInvalidPlatformFileValue) { - DLOG(ERROR) << "Couldn't open " << file_name.AsUTF8Unsafe(); - return false; - } - - if (!MapFileToMemoryInternalEx(SEC_IMAGE)) { - CloseHandles(); - return false; - } - - return true; -} - -bool MemoryMappedFile::MapFileToMemoryInternal() { - return MapFileToMemoryInternalEx(0); -} - -bool MemoryMappedFile::MapFileToMemoryInternalEx(int flags) { - ThreadRestrictions::AssertIOAllowed(); - - if (file_ == INVALID_HANDLE_VALUE) - return false; - - length_ = ::GetFileSize(file_, NULL); - if (length_ == INVALID_FILE_SIZE) - return false; - - file_mapping_ = ::CreateFileMapping(file_, NULL, PAGE_READONLY | flags, - 0, 0, NULL); - if (!file_mapping_) { - // According to msdn, system error codes are only reserved up to 15999. - // http://msdn.microsoft.com/en-us/library/ms681381(v=VS.85).aspx. - UMA_HISTOGRAM_ENUMERATION("MemoryMappedFile.CreateFileMapping", - logging::GetLastSystemErrorCode(), 16000); - return false; - } - - data_ = static_cast( - ::MapViewOfFile(file_mapping_, FILE_MAP_READ, 0, 0, 0)); - if (!data_) { - UMA_HISTOGRAM_ENUMERATION("MemoryMappedFile.MapViewOfFile", - logging::GetLastSystemErrorCode(), 16000); - } - return data_ != NULL; -} - -void MemoryMappedFile::CloseHandles() { - if (data_) - ::UnmapViewOfFile(data_); - if (file_mapping_ != INVALID_HANDLE_VALUE) - ::CloseHandle(file_mapping_); - if (file_ != INVALID_HANDLE_VALUE) - ::CloseHandle(file_); - - data_ = NULL; - file_mapping_ = file_ = INVALID_HANDLE_VALUE; - length_ = INVALID_FILE_SIZE; -} - -} // namespace base diff --git a/base/files/scoped_platform_file_closer.cc b/base/files/scoped_platform_file_closer.cc deleted file mode 100644 index 44f67521b8..0000000000 --- a/base/files/scoped_platform_file_closer.cc +++ /dev/null @@ -1,16 +0,0 @@ -// Copyright 2013 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "base/files/scoped_platform_file_closer.h" - -namespace base { -namespace internal { - -void PlatformFileCloser::operator()(PlatformFile* file) const { - if (file && *file != kInvalidPlatformFileValue) - ClosePlatformFile(*file); -} - -} // namespace internal -} // namespace base diff --git a/base/files/scoped_platform_file_closer.h b/base/files/scoped_platform_file_closer.h deleted file mode 100644 index 8fe4a28511..0000000000 --- a/base/files/scoped_platform_file_closer.h +++ /dev/null @@ -1,26 +0,0 @@ -// Copyright 2013 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef BASE_FILES_SCOPED_PLATFORM_FILE_CLOSER_H_ -#define BASE_FILES_SCOPED_PLATFORM_FILE_CLOSER_H_ - -#include "base/memory/scoped_ptr.h" -#include "base/platform_file.h" - -namespace base { - -namespace internal { - -struct BASE_EXPORT PlatformFileCloser { - void operator()(PlatformFile* file) const; -}; - -} // namespace internal - -typedef scoped_ptr - ScopedPlatformFileCloser; - -} // namespace base - -#endif // BASE_FILES_SCOPED_PLATFORM_FILE_CLOSER_H_ diff --git a/base/files/scoped_temp_dir.cc b/base/files/scoped_temp_dir.cc deleted file mode 100644 index 497799e9f7..0000000000 --- a/base/files/scoped_temp_dir.cc +++ /dev/null @@ -1,85 +0,0 @@ -// Copyright (c) 2011 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "base/files/scoped_temp_dir.h" - -#include "base/file_util.h" -#include "base/logging.h" - -namespace base { - -ScopedTempDir::ScopedTempDir() { -} - -ScopedTempDir::~ScopedTempDir() { - if (!path_.empty() && !Delete()) - DLOG(WARNING) << "Could not delete temp dir in dtor."; -} - -bool ScopedTempDir::CreateUniqueTempDir() { - if (!path_.empty()) - return false; - - // This "scoped_dir" prefix is only used on Windows and serves as a template - // for the unique name. - if (!file_util::CreateNewTempDirectory(FILE_PATH_LITERAL("scoped_dir"), - &path_)) - return false; - - return true; -} - -bool ScopedTempDir::CreateUniqueTempDirUnderPath(const FilePath& base_path) { - if (!path_.empty()) - return false; - - // If |base_path| does not exist, create it. - if (!file_util::CreateDirectory(base_path)) - return false; - - // Create a new, uniquely named directory under |base_path|. - if (!file_util::CreateTemporaryDirInDir( - base_path, - FILE_PATH_LITERAL("scoped_dir_"), - &path_)) - return false; - - return true; -} - -bool ScopedTempDir::Set(const FilePath& path) { - if (!path_.empty()) - return false; - - if (!DirectoryExists(path) && !file_util::CreateDirectory(path)) - return false; - - path_ = path; - return true; -} - -bool ScopedTempDir::Delete() { - if (path_.empty()) - return false; - - bool ret = base::DeleteFile(path_, true); - if (ret) { - // We only clear the path if deleted the directory. - path_.clear(); - } - - return ret; -} - -FilePath ScopedTempDir::Take() { - FilePath ret = path_; - path_ = FilePath(); - return ret; -} - -bool ScopedTempDir::IsValid() const { - return !path_.empty() && DirectoryExists(path_); -} - -} // namespace base diff --git a/base/files/scoped_temp_dir.h b/base/files/scoped_temp_dir.h deleted file mode 100644 index 5f63e09cff..0000000000 --- a/base/files/scoped_temp_dir.h +++ /dev/null @@ -1,62 +0,0 @@ -// Copyright (c) 2011 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef BASE_FILES_SCOPED_TEMP_DIR_H_ -#define BASE_FILES_SCOPED_TEMP_DIR_H_ - -// An object representing a temporary / scratch directory that should be cleaned -// up (recursively) when this object goes out of scope. Note that since -// deletion occurs during the destructor, no further error handling is possible -// if the directory fails to be deleted. As a result, deletion is not -// guaranteed by this class. -// -// Multiple calls to the methods which establish a temporary directory -// (CreateUniqueTempDir, CreateUniqueTempDirUnderPath, and Set) must have -// intervening calls to Delete or Take, or the calls will fail. - -#include "base/base_export.h" -#include "base/files/file_path.h" - -namespace base { - -class BASE_EXPORT ScopedTempDir { - public: - // No directory is owned/created initially. - ScopedTempDir(); - - // Recursively delete path. - ~ScopedTempDir(); - - // Creates a unique directory in TempPath, and takes ownership of it. - // See file_util::CreateNewTemporaryDirectory. - bool CreateUniqueTempDir() WARN_UNUSED_RESULT; - - // Creates a unique directory under a given path, and takes ownership of it. - bool CreateUniqueTempDirUnderPath(const FilePath& path) WARN_UNUSED_RESULT; - - // Takes ownership of directory at |path|, creating it if necessary. - // Don't call multiple times unless Take() has been called first. - bool Set(const FilePath& path) WARN_UNUSED_RESULT; - - // Deletes the temporary directory wrapped by this object. - bool Delete() WARN_UNUSED_RESULT; - - // Caller takes ownership of the temporary directory so it won't be destroyed - // when this object goes out of scope. - FilePath Take(); - - const FilePath& path() const { return path_; } - - // Returns true if path_ is non-empty and exists. - bool IsValid() const; - - private: - FilePath path_; - - DISALLOW_COPY_AND_ASSIGN(ScopedTempDir); -}; - -} // namespace base - -#endif // BASE_FILES_SCOPED_TEMP_DIR_H_ diff --git a/base/files/scoped_temp_dir_unittest.cc b/base/files/scoped_temp_dir_unittest.cc deleted file mode 100644 index 0c9131c3a8..0000000000 --- a/base/files/scoped_temp_dir_unittest.cc +++ /dev/null @@ -1,117 +0,0 @@ -// Copyright (c) 2011 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include - -#include "base/file_util.h" -#include "base/files/scoped_temp_dir.h" -#include "base/platform_file.h" -#include "testing/gtest/include/gtest/gtest.h" - -namespace base { - -TEST(ScopedTempDir, FullPath) { - FilePath test_path; - file_util::CreateNewTempDirectory(FILE_PATH_LITERAL("scoped_temp_dir"), - &test_path); - - // Against an existing dir, it should get destroyed when leaving scope. - EXPECT_TRUE(DirectoryExists(test_path)); - { - ScopedTempDir dir; - EXPECT_TRUE(dir.Set(test_path)); - EXPECT_TRUE(dir.IsValid()); - } - EXPECT_FALSE(DirectoryExists(test_path)); - - { - ScopedTempDir dir; - EXPECT_TRUE(dir.Set(test_path)); - // Now the dir doesn't exist, so ensure that it gets created. - EXPECT_TRUE(DirectoryExists(test_path)); - // When we call Release(), it shouldn't get destroyed when leaving scope. - FilePath path = dir.Take(); - EXPECT_EQ(path.value(), test_path.value()); - EXPECT_FALSE(dir.IsValid()); - } - EXPECT_TRUE(DirectoryExists(test_path)); - - // Clean up. - { - ScopedTempDir dir; - EXPECT_TRUE(dir.Set(test_path)); - } - EXPECT_FALSE(DirectoryExists(test_path)); -} - -TEST(ScopedTempDir, TempDir) { - // In this case, just verify that a directory was created and that it's a - // child of TempDir. - FilePath test_path; - { - ScopedTempDir dir; - EXPECT_TRUE(dir.CreateUniqueTempDir()); - test_path = dir.path(); - EXPECT_TRUE(DirectoryExists(test_path)); - FilePath tmp_dir; - EXPECT_TRUE(file_util::GetTempDir(&tmp_dir)); - EXPECT_TRUE(test_path.value().find(tmp_dir.value()) != std::string::npos); - } - EXPECT_FALSE(DirectoryExists(test_path)); -} - -TEST(ScopedTempDir, UniqueTempDirUnderPath) { - // Create a path which will contain a unique temp path. - FilePath base_path; - ASSERT_TRUE(file_util::CreateNewTempDirectory(FILE_PATH_LITERAL("base_dir"), - &base_path)); - - FilePath test_path; - { - ScopedTempDir dir; - EXPECT_TRUE(dir.CreateUniqueTempDirUnderPath(base_path)); - test_path = dir.path(); - EXPECT_TRUE(DirectoryExists(test_path)); - EXPECT_TRUE(base_path.IsParent(test_path)); - EXPECT_TRUE(test_path.value().find(base_path.value()) != std::string::npos); - } - EXPECT_FALSE(DirectoryExists(test_path)); - base::DeleteFile(base_path, true); -} - -TEST(ScopedTempDir, MultipleInvocations) { - ScopedTempDir dir; - EXPECT_TRUE(dir.CreateUniqueTempDir()); - EXPECT_FALSE(dir.CreateUniqueTempDir()); - EXPECT_TRUE(dir.Delete()); - EXPECT_TRUE(dir.CreateUniqueTempDir()); - EXPECT_FALSE(dir.CreateUniqueTempDir()); - ScopedTempDir other_dir; - EXPECT_TRUE(other_dir.Set(dir.Take())); - EXPECT_TRUE(dir.CreateUniqueTempDir()); - EXPECT_FALSE(dir.CreateUniqueTempDir()); - EXPECT_FALSE(other_dir.CreateUniqueTempDir()); -} - -#if defined(OS_WIN) -TEST(ScopedTempDir, LockedTempDir) { - ScopedTempDir dir; - EXPECT_TRUE(dir.CreateUniqueTempDir()); - int file_flags = base::PLATFORM_FILE_CREATE_ALWAYS | - base::PLATFORM_FILE_WRITE; - base::PlatformFileError error_code = base::PLATFORM_FILE_OK; - FilePath file_path(dir.path().Append(FILE_PATH_LITERAL("temp"))); - base::PlatformFile file = base::CreatePlatformFile(file_path, file_flags, - NULL, &error_code); - EXPECT_NE(base::kInvalidPlatformFileValue, file); - EXPECT_EQ(base::PLATFORM_FILE_OK, error_code); - EXPECT_FALSE(dir.Delete()); // We should not be able to delete. - EXPECT_FALSE(dir.path().empty()); // We should still have a valid path. - EXPECT_TRUE(base::ClosePlatformFile(file)); - // Now, we should be able to delete. - EXPECT_TRUE(dir.Delete()); -} -#endif // defined(OS_WIN) - -} // namespace base diff --git a/base/float_util.h b/base/float_util.h deleted file mode 100644 index 90273106cd..0000000000 --- a/base/float_util.h +++ /dev/null @@ -1,36 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef BASE_FLOAT_UTIL_H_ -#define BASE_FLOAT_UTIL_H_ - -#include "build/build_config.h" - -#include - -#include - -namespace base { - -template -inline bool IsFinite(const Float& number) { -#if defined(OS_POSIX) - return std::isfinite(number) != 0; -#elif defined(OS_WIN) - return _finite(number) != 0; -#endif -} - -template -inline bool IsNaN(const Float& number) { -#if defined(OS_POSIX) - return std::isnan(number) != 0; -#elif defined(OS_WIN) - return _isnan(number) != 0; -#endif -} - -} // namespace base - -#endif // BASE_FLOAT_UTIL_H_ diff --git a/base/format_macros.h b/base/format_macros.h deleted file mode 100644 index 466d79be73..0000000000 --- a/base/format_macros.h +++ /dev/null @@ -1,73 +0,0 @@ -// Copyright (c) 2009 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef BASE_FORMAT_MACROS_H_ -#define BASE_FORMAT_MACROS_H_ - -// This file defines the format macros for some integer types. - -// To print a 64-bit value in a portable way: -// int64_t value; -// printf("xyz:%" PRId64, value); -// The "d" in the macro corresponds to %d; you can also use PRIu64 etc. -// -// For wide strings, prepend "Wide" to the macro: -// int64_t value; -// StringPrintf(L"xyz: %" WidePRId64, value); -// -// To print a size_t value in a portable way: -// size_t size; -// printf("xyz: %" PRIuS, size); -// The "u" in the macro corresponds to %u, and S is for "size". - -#include "build/build_config.h" - -#if defined(OS_POSIX) - -#if (defined(_INTTYPES_H) || defined(_INTTYPES_H_)) && !defined(PRId64) -#error "inttypes.h has already been included before this header file, but " -#error "without __STDC_FORMAT_MACROS defined." -#endif - -#if !defined(__STDC_FORMAT_MACROS) -#define __STDC_FORMAT_MACROS -#endif - -#include - -// GCC will concatenate wide and narrow strings correctly, so nothing needs to -// be done here. -#define WidePRId64 PRId64 -#define WidePRIu64 PRIu64 -#define WidePRIx64 PRIx64 - -#if !defined(PRIuS) -#define PRIuS "zu" -#endif - -#else // OS_WIN - -#if !defined(PRId64) -#define PRId64 "I64d" -#endif - -#if !defined(PRIu64) -#define PRIu64 "I64u" -#endif - -#if !defined(PRIx64) -#define PRIx64 "I64x" -#endif - -#define WidePRId64 L"I64d" -#define WidePRIu64 L"I64u" -#define WidePRIx64 L"I64x" - -#if !defined(PRIuS) -#define PRIuS "Iu" -#endif - -#endif - -#endif // BASE_FORMAT_MACROS_H_ diff --git a/base/glibc-x86-32.base_untrusted.source_list.gypcmd b/base/glibc-x86-32.base_untrusted.source_list.gypcmd deleted file mode 100644 index 8dbe0ca926..0000000000 --- a/base/glibc-x86-32.base_untrusted.source_list.gypcmd +++ /dev/null @@ -1,353 +0,0 @@ -../build/build_config.h -third_party/dmg_fp/dmg_fp.h -third_party/dmg_fp/g_fmt.cc -third_party/dmg_fp/dtoa_wrapper.cc -third_party/icu/icu_utf.cc -third_party/icu/icu_utf.h -third_party/nspr/prcpucfg.h -third_party/nspr/prcpucfg_freebsd.h -third_party/nspr/prcpucfg_nacl.h -third_party/nspr/prcpucfg_openbsd.h -third_party/nspr/prcpucfg_solaris.h -third_party/nspr/prtime.cc -third_party/nspr/prtime.h -third_party/nspr/prtypes.h -third_party/xdg_mime/xdgmime.h -allocator/allocator_extension.cc -allocator/allocator_extension.h -at_exit.cc -at_exit.h -atomic_ref_count.h -atomic_sequence_num.h -atomicops.h -atomicops_internals_gcc.h -atomicops_internals_tsan.h -atomicops_internals_x86_gcc.h -atomicops_internals_x86_msvc.h -base_export.h -base_paths.h -base_paths_android.h -base_paths_posix.cc -base_paths_posix.h -base_switches.h -base64.cc -base64.h -basictypes.h -bind.h -bind_helpers.cc -bind_helpers.h -bind_internal.h -bits.h -build_time.cc -build_time.h -callback.h -callback_helpers.h -callback_internal.cc -callback_internal.h -cancelable_callback.h -command_line.cc -command_line.h -compiler_specific.h -containers/hash_tables.h -containers/linked_list.h -containers/mru_cache.h -containers/small_map.h -containers/stack_container.h -cpu.h -critical_closure.h -debug/alias.cc -debug/alias.h -debug/crash_logging.cc -debug/crash_logging.h -debug/debugger.cc -debug/debugger.h -debug/debugger_posix.cc -debug/leak_annotations.h -debug/leak_tracker.h -debug/profiler.cc -debug/profiler.h -debug/stack_trace.cc -debug/stack_trace.h -debug/trace_event.h -debug/trace_event_impl.cc -debug/trace_event_impl.h -debug/trace_event_impl_constants.cc -debug/trace_event_memory.cc -debug/trace_event_memory.h -deferred_sequenced_task_runner.cc -deferred_sequenced_task_runner.h -environment.cc -environment.h -file_descriptor_posix.h -file_util.h -file_version_info.h -files/dir_reader_fallback.h -files/dir_reader_posix.h -files/file_enumerator.cc -files/file_enumerator.h -files/file_path.cc -files/file_path.h -files/file_path_constants.cc -files/file_path_watcher.cc -files/file_path_watcher.h -files/file_path_watcher_stub.cc -files/file_util_proxy.h -files/important_file_writer.h -files/important_file_writer.cc -files/memory_mapped_file.cc -files/memory_mapped_file.h -files/memory_mapped_file_posix.cc -files/scoped_platform_file_closer.cc -files/scoped_platform_file_closer.h -files/scoped_temp_dir.h -float_util.h -format_macros.h -gtest_prod_util.h -guid.cc -guid.h -guid_posix.cc -hash.cc -hash.h -id_map.h -ini_parser.cc -ini_parser.h -json/json_file_value_serializer.cc -json/json_file_value_serializer.h -json/json_parser.cc -json/json_parser.h -json/json_reader.cc -json/json_reader.h -json/json_string_value_serializer.cc -json/json_string_value_serializer.h -json/json_value_converter.h -json/json_writer.cc -json/json_writer.h -json/string_escape.cc -json/string_escape.h -lazy_instance.cc -lazy_instance.h -location.cc -location.h -logging.cc -logging.h -memory/aligned_memory.cc -memory/aligned_memory.h -memory/discardable_memory.cc -memory/discardable_memory.h -memory/linked_ptr.h -memory/manual_constructor.h -memory/memory_pressure_listener.cc -memory/memory_pressure_listener.h -memory/raw_scoped_refptr_mismatch_checker.h -memory/ref_counted.cc -memory/ref_counted.h -memory/ref_counted_delete_on_message_loop.h -memory/ref_counted_memory.cc -memory/ref_counted_memory.h -memory/scoped_handle.h -memory/scoped_open_process.h -memory/scoped_policy.h -memory/scoped_ptr.h -memory/scoped_vector.h -memory/shared_memory.h -memory/shared_memory_nacl.cc -memory/singleton.cc -memory/singleton.h -memory/weak_ptr.cc -memory/weak_ptr.h -message_loop/incoming_task_queue.cc -message_loop/incoming_task_queue.h -message_loop/message_loop.cc -message_loop/message_loop.h -message_loop/message_loop_proxy.cc -message_loop/message_loop_proxy.h -message_loop/message_loop_proxy_impl.cc -message_loop/message_loop_proxy_impl.h -message_loop/message_pump.cc -message_loop/message_pump.h -message_loop/message_pump_android.h -message_loop/message_pump_default.cc -message_loop/message_pump_default.h -move.h -native_library.h -observer_list.h -observer_list_threadsafe.h -os_compat_android.h -os_compat_nacl.cc -os_compat_nacl.h -path_service.h -pending_task.cc -pending_task.h -pickle.cc -pickle.h -platform_file.cc -platform_file.h -platform_file_posix.cc -port.h -posix/eintr_wrapper.h -posix/global_descriptors.cc -posix/global_descriptors.h -power_monitor/power_monitor.cc -power_monitor/power_monitor.h -power_monitor/power_monitor_device_source_android.h -power_monitor/power_monitor_device_source.cc -power_monitor/power_monitor_device_source.h -power_monitor/power_monitor_device_source_posix.cc -power_monitor/power_monitor_source.cc -power_monitor/power_monitor_source.h -power_monitor/power_observer.h -process/kill.cc -process/kill.h -process/launch.h -process/memory.h -process/process.h -process/process_handle_posix.cc -process/process_info.h -process/process_iterator.cc -process/process_iterator.h -process/process_metrics.h -profiler/scoped_profile.cc -profiler/scoped_profile.h -profiler/alternate_timer.cc -profiler/alternate_timer.h -profiler/tracked_time.cc -profiler/tracked_time.h -rand_util.cc -rand_util.h -rand_util_nacl.cc -run_loop.cc -run_loop.h -safe_numerics.h -safe_strerror_posix.cc -safe_strerror_posix.h -scoped_native_library.h -sequence_checker.h -sequence_checker_impl.cc -sequence_checker_impl.h -sequenced_task_runner.cc -sequenced_task_runner.h -sequenced_task_runner_helpers.h -sha1.h -sha1_portable.cc -single_thread_task_runner.h -stl_util.h -strings/latin1_string_conversions.cc -strings/latin1_string_conversions.h -strings/nullable_string16.cc -strings/nullable_string16.h -strings/string16.cc -strings/string16.h -strings/string_number_conversions.cc -strings/string_split.cc -strings/string_split.h -strings/string_number_conversions.h -strings/string_piece.cc -strings/string_piece.h -strings/string_tokenizer.h -strings/string_util.cc -strings/string_util.h -strings/string_util_constants.cc -strings/string_util_posix.h -strings/stringize_macros.h -strings/stringprintf.cc -strings/stringprintf.h -strings/sys_string_conversions.h -strings/sys_string_conversions_posix.cc -strings/utf_offset_string_conversions.cc -strings/utf_offset_string_conversions.h -strings/utf_string_conversion_utils.cc -strings/utf_string_conversion_utils.h -strings/utf_string_conversions.cc -strings/utf_string_conversions.h -supports_user_data.cc -supports_user_data.h -synchronization/cancellation_flag.cc -synchronization/cancellation_flag.h -synchronization/condition_variable.h -synchronization/condition_variable_posix.cc -synchronization/lock.cc -synchronization/lock.h -synchronization/lock_impl.h -synchronization/lock_impl_posix.cc -synchronization/spin_wait.h -synchronization/waitable_event.h -synchronization/waitable_event_posix.cc -synchronization/waitable_event_watcher.h -synchronization/waitable_event_watcher_posix.cc -system_monitor/system_monitor.cc -system_monitor/system_monitor.h -sys_byteorder.h -sys_info.cc -sys_info.h -task_runner.cc -task_runner.h -task_runner_util.h -template_util.h -thread_task_runner_handle.cc -thread_task_runner_handle.h -threading/non_thread_safe.h -threading/non_thread_safe_impl.cc -threading/non_thread_safe_impl.h -threading/platform_thread.h -threading/platform_thread_linux.cc -threading/platform_thread_posix.cc -threading/post_task_and_reply_impl.cc -threading/post_task_and_reply_impl.h -threading/sequenced_worker_pool.cc -threading/sequenced_worker_pool.h -threading/simple_thread.cc -threading/simple_thread.h -threading/thread.cc -threading/thread.h -threading/thread_checker.h -threading/thread_checker_impl.cc -threading/thread_checker_impl.h -threading/thread_collision_warner.cc -threading/thread_collision_warner.h -threading/thread_id_name_manager.cc -threading/thread_id_name_manager.h -threading/thread_local.h -threading/thread_local_posix.cc -threading/thread_local_storage.h -threading/thread_local_storage_posix.cc -threading/thread_restrictions.h -threading/thread_restrictions.cc -threading/watchdog.cc -threading/watchdog.h -threading/worker_pool.h -threading/worker_pool.cc -threading/worker_pool_posix.cc -threading/worker_pool_posix.h -time/clock.cc -time/clock.h -time/default_clock.cc -time/default_clock.h -time/default_tick_clock.cc -time/default_tick_clock.h -time/tick_clock.cc -time/tick_clock.h -time/time.cc -time/time.h -time/time_posix.cc -timer/hi_res_timer_manager_posix.cc -timer/hi_res_timer_manager.h -timer/timer.cc -timer/timer.h -tracked_objects.cc -tracked_objects.h -tracking_info.cc -tracking_info.h -tuple.h -values.cc -values.h -value_conversions.cc -value_conversions.h -version.cc -version.h -vlog.cc -vlog.h -base_switches.cc -base_switches.h -strings/string16.cc -sync_socket_nacl.cc -time/time_posix.cc diff --git a/base/glibc-x86-64.base_untrusted.source_list.gypcmd b/base/glibc-x86-64.base_untrusted.source_list.gypcmd deleted file mode 100644 index 8dbe0ca926..0000000000 --- a/base/glibc-x86-64.base_untrusted.source_list.gypcmd +++ /dev/null @@ -1,353 +0,0 @@ -../build/build_config.h -third_party/dmg_fp/dmg_fp.h -third_party/dmg_fp/g_fmt.cc -third_party/dmg_fp/dtoa_wrapper.cc -third_party/icu/icu_utf.cc -third_party/icu/icu_utf.h -third_party/nspr/prcpucfg.h -third_party/nspr/prcpucfg_freebsd.h -third_party/nspr/prcpucfg_nacl.h -third_party/nspr/prcpucfg_openbsd.h -third_party/nspr/prcpucfg_solaris.h -third_party/nspr/prtime.cc -third_party/nspr/prtime.h -third_party/nspr/prtypes.h -third_party/xdg_mime/xdgmime.h -allocator/allocator_extension.cc -allocator/allocator_extension.h -at_exit.cc -at_exit.h -atomic_ref_count.h -atomic_sequence_num.h -atomicops.h -atomicops_internals_gcc.h -atomicops_internals_tsan.h -atomicops_internals_x86_gcc.h -atomicops_internals_x86_msvc.h -base_export.h -base_paths.h -base_paths_android.h -base_paths_posix.cc -base_paths_posix.h -base_switches.h -base64.cc -base64.h -basictypes.h -bind.h -bind_helpers.cc -bind_helpers.h -bind_internal.h -bits.h -build_time.cc -build_time.h -callback.h -callback_helpers.h -callback_internal.cc -callback_internal.h -cancelable_callback.h -command_line.cc -command_line.h -compiler_specific.h -containers/hash_tables.h -containers/linked_list.h -containers/mru_cache.h -containers/small_map.h -containers/stack_container.h -cpu.h -critical_closure.h -debug/alias.cc -debug/alias.h -debug/crash_logging.cc -debug/crash_logging.h -debug/debugger.cc -debug/debugger.h -debug/debugger_posix.cc -debug/leak_annotations.h -debug/leak_tracker.h -debug/profiler.cc -debug/profiler.h -debug/stack_trace.cc -debug/stack_trace.h -debug/trace_event.h -debug/trace_event_impl.cc -debug/trace_event_impl.h -debug/trace_event_impl_constants.cc -debug/trace_event_memory.cc -debug/trace_event_memory.h -deferred_sequenced_task_runner.cc -deferred_sequenced_task_runner.h -environment.cc -environment.h -file_descriptor_posix.h -file_util.h -file_version_info.h -files/dir_reader_fallback.h -files/dir_reader_posix.h -files/file_enumerator.cc -files/file_enumerator.h -files/file_path.cc -files/file_path.h -files/file_path_constants.cc -files/file_path_watcher.cc -files/file_path_watcher.h -files/file_path_watcher_stub.cc -files/file_util_proxy.h -files/important_file_writer.h -files/important_file_writer.cc -files/memory_mapped_file.cc -files/memory_mapped_file.h -files/memory_mapped_file_posix.cc -files/scoped_platform_file_closer.cc -files/scoped_platform_file_closer.h -files/scoped_temp_dir.h -float_util.h -format_macros.h -gtest_prod_util.h -guid.cc -guid.h -guid_posix.cc -hash.cc -hash.h -id_map.h -ini_parser.cc -ini_parser.h -json/json_file_value_serializer.cc -json/json_file_value_serializer.h -json/json_parser.cc -json/json_parser.h -json/json_reader.cc -json/json_reader.h -json/json_string_value_serializer.cc -json/json_string_value_serializer.h -json/json_value_converter.h -json/json_writer.cc -json/json_writer.h -json/string_escape.cc -json/string_escape.h -lazy_instance.cc -lazy_instance.h -location.cc -location.h -logging.cc -logging.h -memory/aligned_memory.cc -memory/aligned_memory.h -memory/discardable_memory.cc -memory/discardable_memory.h -memory/linked_ptr.h -memory/manual_constructor.h -memory/memory_pressure_listener.cc -memory/memory_pressure_listener.h -memory/raw_scoped_refptr_mismatch_checker.h -memory/ref_counted.cc -memory/ref_counted.h -memory/ref_counted_delete_on_message_loop.h -memory/ref_counted_memory.cc -memory/ref_counted_memory.h -memory/scoped_handle.h -memory/scoped_open_process.h -memory/scoped_policy.h -memory/scoped_ptr.h -memory/scoped_vector.h -memory/shared_memory.h -memory/shared_memory_nacl.cc -memory/singleton.cc -memory/singleton.h -memory/weak_ptr.cc -memory/weak_ptr.h -message_loop/incoming_task_queue.cc -message_loop/incoming_task_queue.h -message_loop/message_loop.cc -message_loop/message_loop.h -message_loop/message_loop_proxy.cc -message_loop/message_loop_proxy.h -message_loop/message_loop_proxy_impl.cc -message_loop/message_loop_proxy_impl.h -message_loop/message_pump.cc -message_loop/message_pump.h -message_loop/message_pump_android.h -message_loop/message_pump_default.cc -message_loop/message_pump_default.h -move.h -native_library.h -observer_list.h -observer_list_threadsafe.h -os_compat_android.h -os_compat_nacl.cc -os_compat_nacl.h -path_service.h -pending_task.cc -pending_task.h -pickle.cc -pickle.h -platform_file.cc -platform_file.h -platform_file_posix.cc -port.h -posix/eintr_wrapper.h -posix/global_descriptors.cc -posix/global_descriptors.h -power_monitor/power_monitor.cc -power_monitor/power_monitor.h -power_monitor/power_monitor_device_source_android.h -power_monitor/power_monitor_device_source.cc -power_monitor/power_monitor_device_source.h -power_monitor/power_monitor_device_source_posix.cc -power_monitor/power_monitor_source.cc -power_monitor/power_monitor_source.h -power_monitor/power_observer.h -process/kill.cc -process/kill.h -process/launch.h -process/memory.h -process/process.h -process/process_handle_posix.cc -process/process_info.h -process/process_iterator.cc -process/process_iterator.h -process/process_metrics.h -profiler/scoped_profile.cc -profiler/scoped_profile.h -profiler/alternate_timer.cc -profiler/alternate_timer.h -profiler/tracked_time.cc -profiler/tracked_time.h -rand_util.cc -rand_util.h -rand_util_nacl.cc -run_loop.cc -run_loop.h -safe_numerics.h -safe_strerror_posix.cc -safe_strerror_posix.h -scoped_native_library.h -sequence_checker.h -sequence_checker_impl.cc -sequence_checker_impl.h -sequenced_task_runner.cc -sequenced_task_runner.h -sequenced_task_runner_helpers.h -sha1.h -sha1_portable.cc -single_thread_task_runner.h -stl_util.h -strings/latin1_string_conversions.cc -strings/latin1_string_conversions.h -strings/nullable_string16.cc -strings/nullable_string16.h -strings/string16.cc -strings/string16.h -strings/string_number_conversions.cc -strings/string_split.cc -strings/string_split.h -strings/string_number_conversions.h -strings/string_piece.cc -strings/string_piece.h -strings/string_tokenizer.h -strings/string_util.cc -strings/string_util.h -strings/string_util_constants.cc -strings/string_util_posix.h -strings/stringize_macros.h -strings/stringprintf.cc -strings/stringprintf.h -strings/sys_string_conversions.h -strings/sys_string_conversions_posix.cc -strings/utf_offset_string_conversions.cc -strings/utf_offset_string_conversions.h -strings/utf_string_conversion_utils.cc -strings/utf_string_conversion_utils.h -strings/utf_string_conversions.cc -strings/utf_string_conversions.h -supports_user_data.cc -supports_user_data.h -synchronization/cancellation_flag.cc -synchronization/cancellation_flag.h -synchronization/condition_variable.h -synchronization/condition_variable_posix.cc -synchronization/lock.cc -synchronization/lock.h -synchronization/lock_impl.h -synchronization/lock_impl_posix.cc -synchronization/spin_wait.h -synchronization/waitable_event.h -synchronization/waitable_event_posix.cc -synchronization/waitable_event_watcher.h -synchronization/waitable_event_watcher_posix.cc -system_monitor/system_monitor.cc -system_monitor/system_monitor.h -sys_byteorder.h -sys_info.cc -sys_info.h -task_runner.cc -task_runner.h -task_runner_util.h -template_util.h -thread_task_runner_handle.cc -thread_task_runner_handle.h -threading/non_thread_safe.h -threading/non_thread_safe_impl.cc -threading/non_thread_safe_impl.h -threading/platform_thread.h -threading/platform_thread_linux.cc -threading/platform_thread_posix.cc -threading/post_task_and_reply_impl.cc -threading/post_task_and_reply_impl.h -threading/sequenced_worker_pool.cc -threading/sequenced_worker_pool.h -threading/simple_thread.cc -threading/simple_thread.h -threading/thread.cc -threading/thread.h -threading/thread_checker.h -threading/thread_checker_impl.cc -threading/thread_checker_impl.h -threading/thread_collision_warner.cc -threading/thread_collision_warner.h -threading/thread_id_name_manager.cc -threading/thread_id_name_manager.h -threading/thread_local.h -threading/thread_local_posix.cc -threading/thread_local_storage.h -threading/thread_local_storage_posix.cc -threading/thread_restrictions.h -threading/thread_restrictions.cc -threading/watchdog.cc -threading/watchdog.h -threading/worker_pool.h -threading/worker_pool.cc -threading/worker_pool_posix.cc -threading/worker_pool_posix.h -time/clock.cc -time/clock.h -time/default_clock.cc -time/default_clock.h -time/default_tick_clock.cc -time/default_tick_clock.h -time/tick_clock.cc -time/tick_clock.h -time/time.cc -time/time.h -time/time_posix.cc -timer/hi_res_timer_manager_posix.cc -timer/hi_res_timer_manager.h -timer/timer.cc -timer/timer.h -tracked_objects.cc -tracked_objects.h -tracking_info.cc -tracking_info.h -tuple.h -values.cc -values.h -value_conversions.cc -value_conversions.h -version.cc -version.h -vlog.cc -vlog.h -base_switches.cc -base_switches.h -strings/string16.cc -sync_socket_nacl.cc -time/time_posix.cc diff --git a/base/gmock_unittest.cc b/base/gmock_unittest.cc deleted file mode 100644 index 855380a975..0000000000 --- a/base/gmock_unittest.cc +++ /dev/null @@ -1,137 +0,0 @@ -// Copyright (c) 2009 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. -// -// This test is a simple sanity check to make sure gmock is able to build/link -// correctly. It just instantiates a mock object and runs through a couple of -// the basic mock features. - -#include "testing/gmock/include/gmock/gmock.h" -#include "testing/gtest/include/gtest/gtest.h" - -// Gmock matchers and actions that we use below. -using testing::AnyOf; -using testing::Eq; -using testing::Return; -using testing::SetArgumentPointee; -using testing::WithArg; -using testing::_; - -namespace { - -// Simple class that we can mock out the behavior for. Everything is virtual -// for easy mocking. -class SampleClass { - public: - SampleClass() {} - virtual ~SampleClass() {} - - virtual int ReturnSomething() { - return -1; - } - - virtual void ReturnNothingConstly() const { - } - - virtual void OutputParam(int* a) { - } - - virtual int ReturnSecond(int a, int b) { - return b; - } -}; - -// Declare a mock for the class. -class MockSampleClass : public SampleClass { - public: - MOCK_METHOD0(ReturnSomething, int()); - MOCK_CONST_METHOD0(ReturnNothingConstly, void()); - MOCK_METHOD1(OutputParam, void(int* a)); - MOCK_METHOD2(ReturnSecond, int(int a, int b)); -}; - -// Create a couple of custom actions. Custom actions can be used for adding -// more complex behavior into your mock...though if you start needing these, ask -// if you're asking your mock to do too much. -ACTION(ReturnVal) { - // Return the first argument received. - return arg0; -} -ACTION(ReturnSecond) { - // Returns the second argument. This basically implemetns ReturnSecond. - return arg1; -} - -TEST(GmockTest, SimpleMatchAndActions) { - // Basic test of some simple gmock matchers, actions, and cardinality - // expectations. - MockSampleClass mock; - - EXPECT_CALL(mock, ReturnSomething()) - .WillOnce(Return(1)) - .WillOnce(Return(2)) - .WillOnce(Return(3)); - EXPECT_EQ(1, mock.ReturnSomething()); - EXPECT_EQ(2, mock.ReturnSomething()); - EXPECT_EQ(3, mock.ReturnSomething()); - - EXPECT_CALL(mock, ReturnNothingConstly()).Times(2); - mock.ReturnNothingConstly(); - mock.ReturnNothingConstly(); -} - -TEST(GmockTest, AssignArgument) { - // Capture an argument for examination. - MockSampleClass mock; - - EXPECT_CALL(mock, OutputParam(_)) - .WillRepeatedly(SetArgumentPointee<0>(5)); - - int arg = 0; - mock.OutputParam(&arg); - EXPECT_EQ(5, arg); -} - -TEST(GmockTest, SideEffects) { - // Capture an argument for examination. - MockSampleClass mock; - - EXPECT_CALL(mock, OutputParam(_)) - .WillRepeatedly(SetArgumentPointee<0>(5)); - - int arg = 0; - mock.OutputParam(&arg); - EXPECT_EQ(5, arg); -} - -TEST(GmockTest, CustomAction_ReturnSecond) { - // Test a mock of the ReturnSecond behavior using an action that provides an - // alternate implementation of the function. Danger here though, this is - // starting to add too much behavior of the mock, which means the mock - // implementation might start to have bugs itself. - MockSampleClass mock; - - EXPECT_CALL(mock, ReturnSecond(_, AnyOf(Eq(4), Eq(5)))) - .WillRepeatedly(ReturnSecond()); - EXPECT_EQ(4, mock.ReturnSecond(-1, 4)); - EXPECT_EQ(5, mock.ReturnSecond(0, 5)); - EXPECT_EQ(4, mock.ReturnSecond(0xdeadbeef, 4)); - EXPECT_EQ(4, mock.ReturnSecond(112358, 4)); - EXPECT_EQ(5, mock.ReturnSecond(1337, 5)); -} - -TEST(GmockTest, CustomAction_ReturnVal) { - // Alternate implemention of ReturnSecond using a more general custom action, - // and a WithArg adapter to bridge the interfaces. - MockSampleClass mock; - - EXPECT_CALL(mock, ReturnSecond(_, AnyOf(Eq(4), Eq(5)))) - .WillRepeatedly(WithArg<1>(ReturnVal())); - EXPECT_EQ(4, mock.ReturnSecond(-1, 4)); - EXPECT_EQ(5, mock.ReturnSecond(0, 5)); - EXPECT_EQ(4, mock.ReturnSecond(0xdeadbeef, 4)); - EXPECT_EQ(4, mock.ReturnSecond(112358, 4)); - EXPECT_EQ(5, mock.ReturnSecond(1337, 5)); -} - -} // namespace diff --git a/base/gtest_prod_util.h b/base/gtest_prod_util.h deleted file mode 100644 index 3289e6301d..0000000000 --- a/base/gtest_prod_util.h +++ /dev/null @@ -1,66 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef BASE_GTEST_PROD_UTIL_H_ -#define BASE_GTEST_PROD_UTIL_H_ - -#include "testing/gtest/include/gtest/gtest_prod.h" - -// This is a wrapper for gtest's FRIEND_TEST macro that friends -// test with all possible prefixes. This is very helpful when changing the test -// prefix, because the friend declarations don't need to be updated. -// -// Example usage: -// -// class MyClass { -// private: -// void MyMethod(); -// FRIEND_TEST_ALL_PREFIXES(MyClassTest, MyMethod); -// }; -#define FRIEND_TEST_ALL_PREFIXES(test_case_name, test_name) \ - FRIEND_TEST(test_case_name, test_name); \ - FRIEND_TEST(test_case_name, DISABLED_##test_name); \ - FRIEND_TEST(test_case_name, FLAKY_##test_name) - -// C++ compilers will refuse to compile the following code: -// -// namespace foo { -// class MyClass { -// private: -// FRIEND_TEST_ALL_PREFIXES(MyClassTest, TestMethod); -// bool private_var; -// }; -// } // namespace foo -// -// class MyClassTest::TestMethod() { -// foo::MyClass foo_class; -// foo_class.private_var = true; -// } -// -// Unless you forward declare MyClassTest::TestMethod outside of namespace foo. -// Use FORWARD_DECLARE_TEST to do so for all possible prefixes. -// -// Example usage: -// -// FORWARD_DECLARE_TEST(MyClassTest, TestMethod); -// -// namespace foo { -// class MyClass { -// private: -// FRIEND_TEST_ALL_PREFIXES(::MyClassTest, TestMethod); // NOTE use of :: -// bool private_var; -// }; -// } // namespace foo -// -// class MyClassTest::TestMethod() { -// foo::MyClass foo_class; -// foo_class.private_var = true; -// } - -#define FORWARD_DECLARE_TEST(test_case_name, test_name) \ - class test_case_name##_##test_name##_Test; \ - class test_case_name##_##DISABLED_##test_name##_Test; \ - class test_case_name##_##FLAKY_##test_name##_Test - -#endif // BASE_GTEST_PROD_UTIL_H_ diff --git a/base/guid.cc b/base/guid.cc deleted file mode 100644 index 657383fc24..0000000000 --- a/base/guid.cc +++ /dev/null @@ -1,32 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "base/guid.h" - -#include "base/rand_util.h" -#include "base/strings/stringprintf.h" - -namespace base { - -bool IsValidGUID(const std::string& guid) { - const size_t kGUIDLength = 36U; - if (guid.length() != kGUIDLength) - return false; - - std::string hexchars = "0123456789ABCDEF"; - for (uint32 i = 0; i < guid.length(); ++i) { - char current = guid[i]; - if (i == 8 || i == 13 || i == 18 || i == 23) { - if (current != '-') - return false; - } else { - if (hexchars.find(current) == std::string::npos) - return false; - } - } - - return true; -} - -} // namespace guid diff --git a/base/guid.h b/base/guid.h deleted file mode 100644 index 468b65ff61..0000000000 --- a/base/guid.h +++ /dev/null @@ -1,32 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef BASE_GUID_H_ -#define BASE_GUID_H_ - -#include - -#include "base/base_export.h" -#include "base/basictypes.h" -#include "build/build_config.h" - -namespace base { - -// Generate a 128-bit random GUID of the form: "%08X-%04X-%04X-%04X-%012llX". -// If GUID generation fails an empty string is returned. -// The POSIX implementation uses psuedo random number generation to create -// the GUID. The Windows implementation uses system services. -BASE_EXPORT std::string GenerateGUID(); - -// Returns true if the input string conforms to the GUID format. -BASE_EXPORT bool IsValidGUID(const std::string& guid); - -#if defined(OS_POSIX) -// For unit testing purposes only. Do not use outside of tests. -BASE_EXPORT std::string RandomDataToGUIDString(const uint64 bytes[2]); -#endif - -} // namespace guid - -#endif // BASE_GUID_H_ diff --git a/base/guid_posix.cc b/base/guid_posix.cc deleted file mode 100644 index 1b6d56fdea..0000000000 --- a/base/guid_posix.cc +++ /dev/null @@ -1,28 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "base/guid.h" - -#include "base/rand_util.h" -#include "base/strings/stringprintf.h" - -namespace base { - -std::string GenerateGUID() { - uint64 sixteen_bytes[2] = { base::RandUint64(), base::RandUint64() }; - return RandomDataToGUIDString(sixteen_bytes); -} - -// TODO(cmasone): Once we're comfortable this works, migrate Windows code to -// use this as well. -std::string RandomDataToGUIDString(const uint64 bytes[2]) { - return StringPrintf("%08X-%04X-%04X-%04X-%012llX", - static_cast(bytes[0] >> 32), - static_cast((bytes[0] >> 16) & 0x0000ffff), - static_cast(bytes[0] & 0x0000ffff), - static_cast(bytes[1] >> 48), - bytes[1] & 0x0000ffffffffffffULL); -} - -} // namespace guid diff --git a/base/guid_unittest.cc b/base/guid_unittest.cc deleted file mode 100644 index 18c04a9d33..0000000000 --- a/base/guid_unittest.cc +++ /dev/null @@ -1,42 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "base/guid.h" - -#include - -#include "testing/gtest/include/gtest/gtest.h" - -#if defined(OS_POSIX) -TEST(GUIDTest, GUIDGeneratesAllZeroes) { - uint64 bytes[] = { 0, 0 }; - std::string clientid = base::RandomDataToGUIDString(bytes); - EXPECT_EQ("00000000-0000-0000-0000-000000000000", clientid); -} - -TEST(GUIDTest, GUIDGeneratesCorrectly) { - uint64 bytes[] = { 0x0123456789ABCDEFULL, 0xFEDCBA9876543210ULL }; - std::string clientid = base::RandomDataToGUIDString(bytes); - EXPECT_EQ("01234567-89AB-CDEF-FEDC-BA9876543210", clientid); -} -#endif - -TEST(GUIDTest, GUIDCorrectlyFormatted) { - const int kIterations = 10; - for (int it = 0; it < kIterations; ++it) { - std::string guid = base::GenerateGUID(); - EXPECT_TRUE(base::IsValidGUID(guid)); - } -} - -TEST(GUIDTest, GUIDBasicUniqueness) { - const int kIterations = 10; - for (int it = 0; it < kIterations; ++it) { - std::string guid1 = base::GenerateGUID(); - std::string guid2 = base::GenerateGUID(); - EXPECT_EQ(36U, guid1.length()); - EXPECT_EQ(36U, guid2.length()); - EXPECT_NE(guid1, guid2); - } -} diff --git a/base/guid_win.cc b/base/guid_win.cc deleted file mode 100644 index cdb860a0b9..0000000000 --- a/base/guid_win.cc +++ /dev/null @@ -1,38 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "base/guid.h" - -#include - -#include -#include - -#include "base/basictypes.h" -#include "base/logging.h" -#include "base/strings/string_util.h" -#include "base/strings/utf_string_conversions.h" - -namespace base { - -std::string GenerateGUID() { - const int kGUIDSize = 39; - - GUID guid; - HRESULT guid_result = CoCreateGuid(&guid); - DCHECK(SUCCEEDED(guid_result)); - if (!SUCCEEDED(guid_result)) - return std::string(); - - std::wstring guid_string; - int result = StringFromGUID2(guid, - WriteInto(&guid_string, kGUIDSize), kGUIDSize); - DCHECK(result == kGUIDSize); - if (result != kGUIDSize) - return std::string(); - - return WideToUTF8(guid_string.substr(1, guid_string.length() - 2)); -} - -} // namespace guid diff --git a/base/hash.cc b/base/hash.cc deleted file mode 100644 index 2c87065045..0000000000 --- a/base/hash.cc +++ /dev/null @@ -1,73 +0,0 @@ -// From http://www.azillionmonkeys.com/qed/hash.html - -#include "base/hash.h" - -typedef uint32 uint32_t; -typedef uint16 uint16_t; - -namespace base { - -#undef get16bits -#if (defined(__GNUC__) && defined(__i386__)) || defined(__WATCOMC__) \ - || defined(_MSC_VER) || defined (__BORLANDC__) || defined (__TURBOC__) -#define get16bits(d) (*((const uint16_t *) (d))) -#endif - -#if !defined (get16bits) -#define get16bits(d) ((((uint32_t)(((const uint8_t *)(d))[1])) << 8)\ - +(uint32_t)(((const uint8_t *)(d))[0]) ) -#endif - -uint32 SuperFastHash(const char * data, int len) { - uint32_t hash = len, tmp; - int rem; - - if (len <= 0 || data == NULL) - return 0; - - rem = len & 3; - len >>= 2; - - /* Main loop */ - for (; len > 0; len--) { - hash += get16bits(data); - tmp = (get16bits(data + 2) << 11) ^ hash; - hash = (hash << 16) ^ tmp; - data += 2 * sizeof(uint16_t); - hash += hash >> 11; - } - - /* Handle end cases */ - switch (rem) { - case 3: - hash += get16bits(data); - hash ^= hash << 16; - - // Treat the final character as signed. This ensures all platforms behave - // consistently with the original x86 code. - hash ^= static_cast(data[sizeof(uint16_t)]) << 18; - hash += hash >> 11; - break; - case 2: - hash += get16bits(data); - hash ^= hash << 11; - hash += hash >> 17; - break; - case 1: - hash += static_cast(*data); - hash ^= hash << 10; - hash += hash >> 1; - } - - /* Force "avalanching" of final 127 bits */ - hash ^= hash << 3; - hash += hash >> 5; - hash ^= hash << 4; - hash += hash >> 17; - hash ^= hash << 25; - hash += hash >> 6; - - return hash; -} - -} // namespace base diff --git a/base/hash.h b/base/hash.h deleted file mode 100644 index cf8ea3a26e..0000000000 --- a/base/hash.h +++ /dev/null @@ -1,31 +0,0 @@ -// Copyright (c) 2011 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef BASE_HASH_H_ -#define BASE_HASH_H_ - -#include - -#include "base/base_export.h" -#include "base/basictypes.h" - -namespace base { - -// From http://www.azillionmonkeys.com/qed/hash.html -// This is the hash used on WebCore/platform/stringhash -BASE_EXPORT uint32 SuperFastHash(const char * data, int len); - -inline uint32 Hash(const char* key, size_t length) { - return SuperFastHash(key, static_cast(length)); -} - -inline uint32 Hash(const std::string& key) { - if (key.empty()) - return 0; - return SuperFastHash(key.data(), static_cast(key.size())); -} - -} // namespace base - -#endif // BASE_HASH_H_ diff --git a/base/i18n/OWNERS b/base/i18n/OWNERS deleted file mode 100644 index d717b8dabb..0000000000 --- a/base/i18n/OWNERS +++ /dev/null @@ -1 +0,0 @@ -jshin@chromium.org diff --git a/base/i18n/base_i18n_export.h b/base/i18n/base_i18n_export.h deleted file mode 100644 index e8a2adda17..0000000000 --- a/base/i18n/base_i18n_export.h +++ /dev/null @@ -1,29 +0,0 @@ -// Copyright (c) 2011 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef BASE_I18N_BASE_I18N_EXPORT_H_ -#define BASE_I18N_BASE_I18N_EXPORT_H_ - -#if defined(COMPONENT_BUILD) -#if defined(WIN32) - -#if defined(BASE_I18N_IMPLEMENTATION) -#define BASE_I18N_EXPORT __declspec(dllexport) -#else -#define BASE_I18N_EXPORT __declspec(dllimport) -#endif // defined(BASE_I18N_IMPLEMENTATION) - -#else // defined(WIN32) -#if defined(BASE_I18N_IMPLEMENTATION) -#define BASE_I18N_EXPORT __attribute__((visibility("default"))) -#else -#define BASE_I18N_EXPORT -#endif -#endif - -#else // defined(COMPONENT_BUILD) -#define BASE_I18N_EXPORT -#endif - -#endif // BASE_I18N_BASE_I18N_EXPORT_H_ diff --git a/base/i18n/bidi_line_iterator.cc b/base/i18n/bidi_line_iterator.cc deleted file mode 100644 index e81a36b77a..0000000000 --- a/base/i18n/bidi_line_iterator.cc +++ /dev/null @@ -1,60 +0,0 @@ -// Copyright (c) 2011 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "base/i18n/bidi_line_iterator.h" - -#include "base/logging.h" - -namespace base { -namespace i18n { - -BiDiLineIterator::BiDiLineIterator() : bidi_(NULL) { -} - -BiDiLineIterator::~BiDiLineIterator() { - if (bidi_) { - ubidi_close(bidi_); - bidi_ = NULL; - } -} - -bool BiDiLineIterator::Open(const string16& text, - bool right_to_left, - bool url) { - DCHECK(!bidi_); - UErrorCode error = U_ZERO_ERROR; - bidi_ = ubidi_openSized(static_cast(text.length()), 0, &error); - if (U_FAILURE(error)) - return false; - if (right_to_left && url) - ubidi_setReorderingMode(bidi_, UBIDI_REORDER_RUNS_ONLY); - ubidi_setPara(bidi_, text.data(), static_cast(text.length()), - right_to_left ? UBIDI_DEFAULT_RTL : UBIDI_DEFAULT_LTR, - NULL, &error); - return (U_SUCCESS(error) == TRUE); -} - -int BiDiLineIterator::CountRuns() { - DCHECK(bidi_ != NULL); - UErrorCode error = U_ZERO_ERROR; - const int runs = ubidi_countRuns(bidi_, &error); - return U_SUCCESS(error) ? runs : 0; -} - -UBiDiDirection BiDiLineIterator::GetVisualRun(int index, - int* start, - int* length) { - DCHECK(bidi_ != NULL); - return ubidi_getVisualRun(bidi_, index, start, length); -} - -void BiDiLineIterator::GetLogicalRun(int start, - int* end, - UBiDiLevel* level) { - DCHECK(bidi_ != NULL); - ubidi_getLogicalRun(bidi_, start, end, level); -} - -} // namespace i18n -} // namespace base diff --git a/base/i18n/bidi_line_iterator.h b/base/i18n/bidi_line_iterator.h deleted file mode 100644 index d5a2a077d7..0000000000 --- a/base/i18n/bidi_line_iterator.h +++ /dev/null @@ -1,46 +0,0 @@ -// Copyright (c) 2011 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef BASE_I18N_BIDI_LINE_ITERATOR_H_ -#define BASE_I18N_BIDI_LINE_ITERATOR_H_ - -#include "base/basictypes.h" -#include "base/i18n/base_i18n_export.h" -#include "base/strings/string16.h" -#include "third_party/icu/source/common/unicode/ubidi.h" - -namespace base { -namespace i18n { - -// A simple wrapper class for the bidirectional iterator of ICU. -// This class uses the bidirectional iterator of ICU to split a line of -// bidirectional texts into visual runs in its display order. -class BASE_I18N_EXPORT BiDiLineIterator { - public: - BiDiLineIterator(); - ~BiDiLineIterator(); - - // Initializes the bidirectional iterator with the specified text. Returns - // whether initialization succeeded. - bool Open(const string16& text, bool right_to_left, bool url); - - // Returns the number of visual runs in the text, or zero on error. - int CountRuns(); - - // Gets the logical offset, length, and direction of the specified visual run. - UBiDiDirection GetVisualRun(int index, int* start, int* length); - - // Given a start position, figure out where the run ends (and the BiDiLevel). - void GetLogicalRun(int start, int* end, UBiDiLevel* level); - - private: - UBiDi* bidi_; - - DISALLOW_COPY_AND_ASSIGN(BiDiLineIterator); -}; - -} // namespace i18n -} // namespace base - -#endif // BASE_I18N_BIDI_LINE_ITERATOR_H_ diff --git a/base/i18n/break_iterator.cc b/base/i18n/break_iterator.cc deleted file mode 100644 index 2c4d466973..0000000000 --- a/base/i18n/break_iterator.cc +++ /dev/null @@ -1,126 +0,0 @@ -// Copyright (c) 2011 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "base/i18n/break_iterator.h" - -#include "base/logging.h" -#include "third_party/icu/source/common/unicode/ubrk.h" -#include "third_party/icu/source/common/unicode/uchar.h" -#include "third_party/icu/source/common/unicode/ustring.h" - -namespace base { -namespace i18n { - -const size_t npos = -1; - -BreakIterator::BreakIterator(const string16& str, BreakType break_type) - : iter_(NULL), - string_(str), - break_type_(break_type), - prev_(npos), - pos_(0) { -} - -BreakIterator::~BreakIterator() { - if (iter_) - ubrk_close(static_cast(iter_)); -} - -bool BreakIterator::Init() { - UErrorCode status = U_ZERO_ERROR; - UBreakIteratorType break_type; - switch (break_type_) { - case BREAK_CHARACTER: - break_type = UBRK_CHARACTER; - break; - case BREAK_WORD: - break_type = UBRK_WORD; - break; - case BREAK_LINE: - case BREAK_NEWLINE: - break_type = UBRK_LINE; - break; - default: - NOTREACHED() << "invalid break_type_"; - return false; - } - iter_ = ubrk_open(break_type, NULL, - string_.data(), static_cast(string_.size()), - &status); - if (U_FAILURE(status)) { - NOTREACHED() << "ubrk_open failed"; - return false; - } - // Move the iterator to the beginning of the string. - ubrk_first(static_cast(iter_)); - return true; -} - -bool BreakIterator::Advance() { - int32_t pos; - int32_t status; - prev_ = pos_; - switch (break_type_) { - case BREAK_CHARACTER: - case BREAK_WORD: - case BREAK_LINE: - pos = ubrk_next(static_cast(iter_)); - if (pos == UBRK_DONE) { - pos_ = npos; - return false; - } - pos_ = static_cast(pos); - return true; - case BREAK_NEWLINE: - do { - pos = ubrk_next(static_cast(iter_)); - if (pos == UBRK_DONE) - break; - pos_ = static_cast(pos); - status = ubrk_getRuleStatus(static_cast(iter_)); - } while (status >= UBRK_LINE_SOFT && status < UBRK_LINE_SOFT_LIMIT); - if (pos == UBRK_DONE && prev_ == pos_) { - pos_ = npos; - return false; - } - return true; - default: - NOTREACHED() << "invalid break_type_"; - return false; - } -} - -bool BreakIterator::IsWord() const { - int32_t status = ubrk_getRuleStatus(static_cast(iter_)); - return (break_type_ == BREAK_WORD && status != UBRK_WORD_NONE); -} - -bool BreakIterator::IsEndOfWord(size_t position) const { - if (break_type_ != BREAK_WORD) - return false; - - UBreakIterator* iter = static_cast(iter_); - UBool boundary = ubrk_isBoundary(iter, static_cast(position)); - int32_t status = ubrk_getRuleStatus(iter); - return (!!boundary && status != UBRK_WORD_NONE); -} - -bool BreakIterator::IsStartOfWord(size_t position) const { - if (break_type_ != BREAK_WORD) - return false; - - UBreakIterator* iter = static_cast(iter_); - UBool boundary = ubrk_isBoundary(iter, static_cast(position)); - ubrk_next(iter); - int32_t next_status = ubrk_getRuleStatus(iter); - return (!!boundary && next_status != UBRK_WORD_NONE); -} - -string16 BreakIterator::GetString() const { - DCHECK(prev_ != npos && pos_ != npos); - return string_.substr(prev_, pos_ - prev_); -} - -} // namespace i18n -} // namespace base diff --git a/base/i18n/break_iterator.h b/base/i18n/break_iterator.h deleted file mode 100644 index 96bdeaa9b3..0000000000 --- a/base/i18n/break_iterator.h +++ /dev/null @@ -1,131 +0,0 @@ -// Copyright (c) 2011 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef BASE_I18N_BREAK_ITERATOR_H_ -#define BASE_I18N_BREAK_ITERATOR_H_ - -#include "base/basictypes.h" -#include "base/i18n/base_i18n_export.h" -#include "base/strings/string16.h" - -// The BreakIterator class iterates through the words, word breaks, and -// line breaks in a UTF-16 string. -// -// It provides several modes, BREAK_WORD, BREAK_LINE, and BREAK_NEWLINE, -// which modify how characters are aggregated into the returned string. -// -// Under BREAK_WORD mode, once a word is encountered any non-word -// characters are not included in the returned string (e.g. in the -// UTF-16 equivalent of the string " foo bar! ", the word breaks are at -// the periods in ". .foo. .bar.!. ."). -// Note that Chinese/Japanese/Thai do not use spaces between words so that -// boundaries can fall in the middle of a continuous run of non-space / -// non-punctuation characters. -// -// Under BREAK_LINE mode, once a line breaking opportunity is encountered, -// any non-word characters are included in the returned string, breaking -// only when a space-equivalent character or a line breaking opportunity -// is encountered (e.g. in the UTF16-equivalent of the string " foo bar! ", -// the breaks are at the periods in ". .foo .bar! ."). -// -// Note that lines can be broken at any character/syllable/grapheme cluster -// boundary in Chinese/Japanese/Korean and at word boundaries in Thai -// (Thai does not use spaces between words). Therefore, this is NOT the same -// as breaking only at space-equivalent characters where its former -// name (BREAK_SPACE) implied. -// -// Under BREAK_NEWLINE mode, all characters are included in the returned -// string, breking only when a newline-equivalent character is encountered -// (eg. in the UTF-16 equivalent of the string "foo\nbar!\n\n", the line -// breaks are at the periods in ".foo\n.bar\n.\n."). -// -// To extract the words from a string, move a BREAK_WORD BreakIterator -// through the string and test whether IsWord() is true. E.g., -// BreakIterator iter(str, BreakIterator::BREAK_WORD); -// if (!iter.Init()) -// return false; -// while (iter.Advance()) { -// if (iter.IsWord()) { -// // Region [iter.prev(), iter.pos()) contains a word. -// VLOG(1) << "word: " << iter.GetString(); -// } -// } - -namespace base { -namespace i18n { - -class BASE_I18N_EXPORT BreakIterator { - public: - enum BreakType { - BREAK_WORD, - BREAK_LINE, - // TODO(jshin): Remove this after reviewing call sites. - // If call sites really need break only on space-like characters - // implement it separately. - BREAK_SPACE = BREAK_LINE, - BREAK_NEWLINE, - BREAK_CHARACTER, - }; - - // Requires |str| to live as long as the BreakIterator does. - BreakIterator(const string16& str, BreakType break_type); - ~BreakIterator(); - - // Init() must be called before any of the iterators are valid. - // Returns false if ICU failed to initialize. - bool Init(); - - // Advance to the next break. Returns false if we've run past the end of - // the string. (Note that the very last "break" is after the final - // character in the string, and when we advance to that position it's the - // last time Advance() returns true.) - bool Advance(); - - // Under BREAK_WORD mode, returns true if the break we just hit is the - // end of a word. (Otherwise, the break iterator just skipped over e.g. - // whitespace or punctuation.) Under BREAK_LINE and BREAK_NEWLINE modes, - // this distinction doesn't apply and it always retuns false. - bool IsWord() const; - - // Under BREAK_WORD mode, returns true if |position| is at the end of word or - // at the start of word. It always retuns false under BREAK_LINE and - // BREAK_NEWLINE modes. - bool IsEndOfWord(size_t position) const; - bool IsStartOfWord(size_t position) const; - - // Returns the string between prev() and pos(). - // Advance() must have been called successfully at least once for pos() to - // have advanced to somewhere useful. - string16 GetString() const; - - // Returns the value of pos() returned before Advance() was last called. - size_t prev() const { return prev_; } - - // Returns the current break position within the string, - // or BreakIterator::npos when done. - size_t pos() const { return pos_; } - - private: - // ICU iterator, avoiding ICU ubrk.h dependence. - // This is actually an ICU UBreakiterator* type, which turns out to be - // a typedef for a void* in the ICU headers. Using void* directly prevents - // callers from needing access to the ICU public headers directory. - void* iter_; - - // The string we're iterating over. - const string16& string_; - - // The breaking style (word/space/newline). - BreakType break_type_; - - // Previous and current iterator positions. - size_t prev_, pos_; - - DISALLOW_COPY_AND_ASSIGN(BreakIterator); -}; - -} // namespace i18n -} // namespace base - -#endif // BASE_I18N_BREAK_ITERATOR_H_ diff --git a/base/i18n/break_iterator_unittest.cc b/base/i18n/break_iterator_unittest.cc deleted file mode 100644 index 6dcae18460..0000000000 --- a/base/i18n/break_iterator_unittest.cc +++ /dev/null @@ -1,338 +0,0 @@ -// Copyright (c) 2011 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "base/i18n/break_iterator.h" - -#include "base/strings/string_piece.h" -#include "base/strings/stringprintf.h" -#include "base/strings/utf_string_conversions.h" -#include "testing/gtest/include/gtest/gtest.h" - -namespace base { -namespace i18n { - -TEST(BreakIteratorTest, BreakWordEmpty) { - string16 empty; - BreakIterator iter(empty, BreakIterator::BREAK_WORD); - ASSERT_TRUE(iter.Init()); - EXPECT_FALSE(iter.Advance()); - EXPECT_FALSE(iter.IsWord()); - EXPECT_FALSE(iter.Advance()); // Test unexpected advance after end. - EXPECT_FALSE(iter.IsWord()); -} - -TEST(BreakIteratorTest, BreakWord) { - string16 space(UTF8ToUTF16(" ")); - string16 str(UTF8ToUTF16(" foo bar! \npouet boom")); - BreakIterator iter(str, BreakIterator::BREAK_WORD); - ASSERT_TRUE(iter.Init()); - EXPECT_TRUE(iter.Advance()); - EXPECT_FALSE(iter.IsWord()); - EXPECT_EQ(space, iter.GetString()); - EXPECT_TRUE(iter.Advance()); - EXPECT_TRUE(iter.IsWord()); - EXPECT_EQ(UTF8ToUTF16("foo"), iter.GetString()); - EXPECT_TRUE(iter.Advance()); - EXPECT_FALSE(iter.IsWord()); - EXPECT_EQ(space, iter.GetString()); - EXPECT_TRUE(iter.Advance()); - EXPECT_TRUE(iter.IsWord()); - EXPECT_EQ(UTF8ToUTF16("bar"), iter.GetString()); - EXPECT_TRUE(iter.Advance()); - EXPECT_FALSE(iter.IsWord()); - EXPECT_EQ(UTF8ToUTF16("!"), iter.GetString()); - EXPECT_TRUE(iter.Advance()); - EXPECT_FALSE(iter.IsWord()); - EXPECT_EQ(space, iter.GetString()); - EXPECT_TRUE(iter.Advance()); - EXPECT_FALSE(iter.IsWord()); - EXPECT_EQ(UTF8ToUTF16("\n"), iter.GetString()); - EXPECT_TRUE(iter.Advance()); - EXPECT_TRUE(iter.IsWord()); - EXPECT_EQ(UTF8ToUTF16("pouet"), iter.GetString()); - EXPECT_TRUE(iter.Advance()); - EXPECT_FALSE(iter.IsWord()); - EXPECT_EQ(space, iter.GetString()); - EXPECT_TRUE(iter.Advance()); - EXPECT_TRUE(iter.IsWord()); - EXPECT_EQ(UTF8ToUTF16("boom"), iter.GetString()); - EXPECT_FALSE(iter.Advance()); - EXPECT_FALSE(iter.IsWord()); - EXPECT_FALSE(iter.Advance()); // Test unexpected advance after end. - EXPECT_FALSE(iter.IsWord()); -} - -TEST(BreakIteratorTest, BreakWide16) { - // Two greek words separated by space. - const string16 str(WideToUTF16( - L"\x03a0\x03b1\x03b3\x03ba\x03cc\x03c3\x03bc\x03b9" - L"\x03bf\x03c2\x0020\x0399\x03c3\x03c4\x03cc\x03c2")); - const string16 word1(str.substr(0, 10)); - const string16 word2(str.substr(11, 5)); - BreakIterator iter(str, BreakIterator::BREAK_WORD); - ASSERT_TRUE(iter.Init()); - EXPECT_TRUE(iter.Advance()); - EXPECT_TRUE(iter.IsWord()); - EXPECT_EQ(word1, iter.GetString()); - EXPECT_TRUE(iter.Advance()); - EXPECT_FALSE(iter.IsWord()); - EXPECT_EQ(UTF8ToUTF16(" "), iter.GetString()); - EXPECT_TRUE(iter.Advance()); - EXPECT_TRUE(iter.IsWord()); - EXPECT_EQ(word2, iter.GetString()); - EXPECT_FALSE(iter.Advance()); - EXPECT_FALSE(iter.IsWord()); - EXPECT_FALSE(iter.Advance()); // Test unexpected advance after end. - EXPECT_FALSE(iter.IsWord()); -} - -TEST(BreakIteratorTest, BreakWide32) { - // U+1D49C MATHEMATICAL SCRIPT CAPITAL A - const char* very_wide_char = "\xF0\x9D\x92\x9C"; - const string16 str( - UTF8ToUTF16(base::StringPrintf("%s a", very_wide_char))); - const string16 very_wide_word(str.substr(0, 2)); - - BreakIterator iter(str, BreakIterator::BREAK_WORD); - ASSERT_TRUE(iter.Init()); - EXPECT_TRUE(iter.Advance()); - EXPECT_TRUE(iter.IsWord()); - EXPECT_EQ(very_wide_word, iter.GetString()); - EXPECT_TRUE(iter.Advance()); - EXPECT_FALSE(iter.IsWord()); - EXPECT_EQ(UTF8ToUTF16(" "), iter.GetString()); - EXPECT_TRUE(iter.Advance()); - EXPECT_TRUE(iter.IsWord()); - EXPECT_EQ(UTF8ToUTF16("a"), iter.GetString()); - EXPECT_FALSE(iter.Advance()); - EXPECT_FALSE(iter.IsWord()); - EXPECT_FALSE(iter.Advance()); // Test unexpected advance after end. - EXPECT_FALSE(iter.IsWord()); -} - -TEST(BreakIteratorTest, BreakSpaceEmpty) { - string16 empty; - BreakIterator iter(empty, BreakIterator::BREAK_SPACE); - ASSERT_TRUE(iter.Init()); - EXPECT_FALSE(iter.Advance()); - EXPECT_FALSE(iter.IsWord()); - EXPECT_FALSE(iter.Advance()); // Test unexpected advance after end. - EXPECT_FALSE(iter.IsWord()); -} - -TEST(BreakIteratorTest, BreakSpace) { - string16 str(UTF8ToUTF16(" foo bar! \npouet boom")); - BreakIterator iter(str, BreakIterator::BREAK_SPACE); - ASSERT_TRUE(iter.Init()); - EXPECT_TRUE(iter.Advance()); - EXPECT_FALSE(iter.IsWord()); - EXPECT_EQ(UTF8ToUTF16(" "), iter.GetString()); - EXPECT_TRUE(iter.Advance()); - EXPECT_FALSE(iter.IsWord()); - EXPECT_EQ(UTF8ToUTF16("foo "), iter.GetString()); - EXPECT_TRUE(iter.Advance()); - EXPECT_FALSE(iter.IsWord()); - EXPECT_EQ(UTF8ToUTF16("bar! \n"), iter.GetString()); - EXPECT_TRUE(iter.Advance()); - EXPECT_FALSE(iter.IsWord()); - EXPECT_EQ(UTF8ToUTF16("pouet "), iter.GetString()); - EXPECT_TRUE(iter.Advance()); - EXPECT_FALSE(iter.IsWord()); - EXPECT_EQ(UTF8ToUTF16("boom"), iter.GetString()); - EXPECT_FALSE(iter.Advance()); - EXPECT_FALSE(iter.IsWord()); - EXPECT_FALSE(iter.Advance()); // Test unexpected advance after end. - EXPECT_FALSE(iter.IsWord()); -} - -TEST(BreakIteratorTest, BreakSpaceSP) { - string16 str(UTF8ToUTF16(" foo bar! \npouet boom ")); - BreakIterator iter(str, BreakIterator::BREAK_SPACE); - ASSERT_TRUE(iter.Init()); - EXPECT_TRUE(iter.Advance()); - EXPECT_FALSE(iter.IsWord()); - EXPECT_EQ(UTF8ToUTF16(" "), iter.GetString()); - EXPECT_TRUE(iter.Advance()); - EXPECT_FALSE(iter.IsWord()); - EXPECT_EQ(UTF8ToUTF16("foo "), iter.GetString()); - EXPECT_TRUE(iter.Advance()); - EXPECT_FALSE(iter.IsWord()); - EXPECT_EQ(UTF8ToUTF16("bar! \n"), iter.GetString()); - EXPECT_TRUE(iter.Advance()); - EXPECT_FALSE(iter.IsWord()); - EXPECT_EQ(UTF8ToUTF16("pouet "), iter.GetString()); - EXPECT_TRUE(iter.Advance()); - EXPECT_FALSE(iter.IsWord()); - EXPECT_EQ(UTF8ToUTF16("boom "), iter.GetString()); - EXPECT_FALSE(iter.Advance()); - EXPECT_FALSE(iter.IsWord()); - EXPECT_FALSE(iter.Advance()); // Test unexpected advance after end. - EXPECT_FALSE(iter.IsWord()); -} - -TEST(BreakIteratorTest, BreakSpacekWide16) { - // Two Greek words. - const string16 str(WideToUTF16( - L"\x03a0\x03b1\x03b3\x03ba\x03cc\x03c3\x03bc\x03b9" - L"\x03bf\x03c2\x0020\x0399\x03c3\x03c4\x03cc\x03c2")); - const string16 word1(str.substr(0, 11)); - const string16 word2(str.substr(11, 5)); - BreakIterator iter(str, BreakIterator::BREAK_SPACE); - ASSERT_TRUE(iter.Init()); - EXPECT_TRUE(iter.Advance()); - EXPECT_FALSE(iter.IsWord()); - EXPECT_EQ(word1, iter.GetString()); - EXPECT_TRUE(iter.Advance()); - EXPECT_FALSE(iter.IsWord()); - EXPECT_EQ(word2, iter.GetString()); - EXPECT_FALSE(iter.Advance()); - EXPECT_FALSE(iter.IsWord()); - EXPECT_FALSE(iter.Advance()); // Test unexpected advance after end. - EXPECT_FALSE(iter.IsWord()); -} - -TEST(BreakIteratorTest, BreakSpaceWide32) { - // U+1D49C MATHEMATICAL SCRIPT CAPITAL A - const char* very_wide_char = "\xF0\x9D\x92\x9C"; - const string16 str( - UTF8ToUTF16(base::StringPrintf("%s a", very_wide_char))); - const string16 very_wide_word(str.substr(0, 3)); - - BreakIterator iter(str, BreakIterator::BREAK_SPACE); - ASSERT_TRUE(iter.Init()); - EXPECT_TRUE(iter.Advance()); - EXPECT_FALSE(iter.IsWord()); - EXPECT_EQ(very_wide_word, iter.GetString()); - EXPECT_TRUE(iter.Advance()); - EXPECT_FALSE(iter.IsWord()); - EXPECT_EQ(UTF8ToUTF16("a"), iter.GetString()); - EXPECT_FALSE(iter.Advance()); - EXPECT_FALSE(iter.IsWord()); - EXPECT_FALSE(iter.Advance()); // Test unexpected advance after end. - EXPECT_FALSE(iter.IsWord()); -} - -TEST(BreakIteratorTest, BreakLineEmpty) { - string16 empty; - BreakIterator iter(empty, BreakIterator::BREAK_NEWLINE); - ASSERT_TRUE(iter.Init()); - EXPECT_FALSE(iter.Advance()); - EXPECT_FALSE(iter.IsWord()); - EXPECT_FALSE(iter.Advance()); // Test unexpected advance after end. - EXPECT_FALSE(iter.IsWord()); -} - -TEST(BreakIteratorTest, BreakLine) { - string16 nl(UTF8ToUTF16("\n")); - string16 str(UTF8ToUTF16("\nfoo bar!\n\npouet boom")); - BreakIterator iter(str, BreakIterator::BREAK_NEWLINE); - ASSERT_TRUE(iter.Init()); - EXPECT_TRUE(iter.Advance()); - EXPECT_FALSE(iter.IsWord()); - EXPECT_EQ(nl, iter.GetString()); - EXPECT_TRUE(iter.Advance()); - EXPECT_FALSE(iter.IsWord()); - EXPECT_EQ(UTF8ToUTF16("foo bar!\n"), iter.GetString()); - EXPECT_TRUE(iter.Advance()); - EXPECT_FALSE(iter.IsWord()); - EXPECT_EQ(nl, iter.GetString()); - EXPECT_TRUE(iter.Advance()); - EXPECT_FALSE(iter.IsWord()); - EXPECT_EQ(UTF8ToUTF16("pouet boom"), iter.GetString()); - EXPECT_FALSE(iter.Advance()); - EXPECT_FALSE(iter.IsWord()); - EXPECT_FALSE(iter.Advance()); // Test unexpected advance after end. - EXPECT_FALSE(iter.IsWord()); -} - -TEST(BreakIteratorTest, BreakLineNL) { - string16 nl(UTF8ToUTF16("\n")); - string16 str(UTF8ToUTF16("\nfoo bar!\n\npouet boom\n")); - BreakIterator iter(str, BreakIterator::BREAK_NEWLINE); - ASSERT_TRUE(iter.Init()); - EXPECT_TRUE(iter.Advance()); - EXPECT_FALSE(iter.IsWord()); - EXPECT_EQ(nl, iter.GetString()); - EXPECT_TRUE(iter.Advance()); - EXPECT_FALSE(iter.IsWord()); - EXPECT_EQ(UTF8ToUTF16("foo bar!\n"), iter.GetString()); - EXPECT_TRUE(iter.Advance()); - EXPECT_FALSE(iter.IsWord()); - EXPECT_EQ(nl, iter.GetString()); - EXPECT_TRUE(iter.Advance()); - EXPECT_FALSE(iter.IsWord()); - EXPECT_EQ(UTF8ToUTF16("pouet boom\n"), iter.GetString()); - EXPECT_FALSE(iter.Advance()); - EXPECT_FALSE(iter.IsWord()); - EXPECT_FALSE(iter.Advance()); // Test unexpected advance after end. - EXPECT_FALSE(iter.IsWord()); -} - -TEST(BreakIteratorTest, BreakLineWide16) { - // Two Greek words separated by newline. - const string16 str(WideToUTF16( - L"\x03a0\x03b1\x03b3\x03ba\x03cc\x03c3\x03bc\x03b9" - L"\x03bf\x03c2\x000a\x0399\x03c3\x03c4\x03cc\x03c2")); - const string16 line1(str.substr(0, 11)); - const string16 line2(str.substr(11, 5)); - BreakIterator iter(str, BreakIterator::BREAK_NEWLINE); - ASSERT_TRUE(iter.Init()); - EXPECT_TRUE(iter.Advance()); - EXPECT_FALSE(iter.IsWord()); - EXPECT_EQ(line1, iter.GetString()); - EXPECT_TRUE(iter.Advance()); - EXPECT_FALSE(iter.IsWord()); - EXPECT_EQ(line2, iter.GetString()); - EXPECT_FALSE(iter.Advance()); - EXPECT_FALSE(iter.IsWord()); - EXPECT_FALSE(iter.Advance()); // Test unexpected advance after end. - EXPECT_FALSE(iter.IsWord()); -} - -TEST(BreakIteratorTest, BreakLineWide32) { - // U+1D49C MATHEMATICAL SCRIPT CAPITAL A - const char* very_wide_char = "\xF0\x9D\x92\x9C"; - const string16 str( - UTF8ToUTF16(base::StringPrintf("%s\na", very_wide_char))); - const string16 very_wide_line(str.substr(0, 3)); - BreakIterator iter(str, BreakIterator::BREAK_NEWLINE); - ASSERT_TRUE(iter.Init()); - EXPECT_TRUE(iter.Advance()); - EXPECT_FALSE(iter.IsWord()); - EXPECT_EQ(very_wide_line, iter.GetString()); - EXPECT_TRUE(iter.Advance()); - EXPECT_FALSE(iter.IsWord()); - EXPECT_EQ(UTF8ToUTF16("a"), iter.GetString()); - EXPECT_FALSE(iter.Advance()); - EXPECT_FALSE(iter.IsWord()); - EXPECT_FALSE(iter.Advance()); // Test unexpected advance after end. - EXPECT_FALSE(iter.IsWord()); -} - -TEST(BreakIteratorTest, BreakCharacter) { - static const wchar_t* kCharacters[] = { - // An English word consisting of four ASCII characters. - L"w", L"o", L"r", L"d", L" ", - // A Hindi word (which means "Hindi") consisting of three Devanagari - // characters. - L"\x0939\x093F", L"\x0928\x094D", L"\x0926\x0940", L" ", - // A Thai word (which means "feel") consisting of three Thai characters. - L"\x0E23\x0E39\x0E49", L"\x0E2A\x0E36", L"\x0E01", L" ", - }; - std::vector characters; - string16 text; - for (size_t i = 0; i < arraysize(kCharacters); ++i) { - characters.push_back(WideToUTF16(kCharacters[i])); - text.append(characters.back()); - } - BreakIterator iter(text, BreakIterator::BREAK_CHARACTER); - ASSERT_TRUE(iter.Init()); - for (size_t i = 0; i < arraysize(kCharacters); ++i) { - EXPECT_TRUE(iter.Advance()); - EXPECT_EQ(characters[i], iter.GetString()); - } -} - -} // namespace i18n -} // namespace base diff --git a/base/i18n/case_conversion.cc b/base/i18n/case_conversion.cc deleted file mode 100644 index 5debc2ec8d..0000000000 --- a/base/i18n/case_conversion.cc +++ /dev/null @@ -1,26 +0,0 @@ -// Copyright (c) 2011 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "base/i18n/case_conversion.h" - -#include "base/strings/string16.h" -#include "third_party/icu/source/common/unicode/unistr.h" - -namespace base { -namespace i18n { - -string16 ToLower(const StringPiece16& string) { - icu::UnicodeString unicode_string(string.data(), string.size()); - unicode_string.toLower(); - return string16(unicode_string.getBuffer(), unicode_string.length()); -} - -string16 ToUpper(const StringPiece16& string) { - icu::UnicodeString unicode_string(string.data(), string.size()); - unicode_string.toUpper(); - return string16(unicode_string.getBuffer(), unicode_string.length()); -} - -} // namespace i18n -} // namespace base diff --git a/base/i18n/case_conversion.h b/base/i18n/case_conversion.h deleted file mode 100644 index 5d538ccf1d..0000000000 --- a/base/i18n/case_conversion.h +++ /dev/null @@ -1,24 +0,0 @@ -// Copyright (c) 2011 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef BASE_I18N_CASE_CONVERSION_H_ -#define BASE_I18N_CASE_CONVERSION_H_ - -#include "base/i18n/base_i18n_export.h" -#include "base/strings/string16.h" -#include "base/strings/string_piece.h" - -namespace base { -namespace i18n { - -// Returns the lower case equivalent of string. Uses ICU's default locale. -BASE_I18N_EXPORT string16 ToLower(const StringPiece16& string); - -// Returns the upper case equivalent of string. Uses ICU's default locale. -BASE_I18N_EXPORT string16 ToUpper(const StringPiece16& string); - -} // namespace i18n -} // namespace base - -#endif // BASE_I18N_CASE_CONVERSION_H_ diff --git a/base/i18n/case_conversion_unittest.cc b/base/i18n/case_conversion_unittest.cc deleted file mode 100644 index 2139bbe7b3..0000000000 --- a/base/i18n/case_conversion_unittest.cc +++ /dev/null @@ -1,26 +0,0 @@ -// Copyright (c) 2011 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "base/i18n/case_conversion.h" -#include "base/strings/utf_string_conversions.h" -#include "testing/gtest/include/gtest/gtest.h" - -namespace { - -// Test upper and lower case string conversion. -TEST(CaseConversionTest, UpperLower) { - string16 mixed(ASCIIToUTF16("Text with UPPer & lowER casE.")); - const string16 expected_lower(ASCIIToUTF16("text with upper & lower case.")); - const string16 expected_upper(ASCIIToUTF16("TEXT WITH UPPER & LOWER CASE.")); - - string16 result = base::i18n::ToLower(mixed); - EXPECT_EQ(expected_lower, result); - - result = base::i18n::ToUpper(mixed); - EXPECT_EQ(expected_upper, result); -} - -// TODO(jshin): More tests are needed, especially with non-ASCII characters. - -} // namespace diff --git a/base/i18n/char_iterator.cc b/base/i18n/char_iterator.cc deleted file mode 100644 index 25efc51869..0000000000 --- a/base/i18n/char_iterator.cc +++ /dev/null @@ -1,82 +0,0 @@ -// Copyright (c) 2011 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "base/i18n/char_iterator.h" - -#include "third_party/icu/source/common/unicode/utf8.h" -#include "third_party/icu/source/common/unicode/utf16.h" - -namespace base { -namespace i18n { - -UTF8CharIterator::UTF8CharIterator(const std::string* str) - : str_(reinterpret_cast(str->data())), - len_(str->size()), - array_pos_(0), - next_pos_(0), - char_pos_(0), - char_(0) { - if (len_) - U8_NEXT(str_, next_pos_, len_, char_); -} - -UTF8CharIterator::~UTF8CharIterator() { -} - -bool UTF8CharIterator::Advance() { - if (array_pos_ >= len_) - return false; - - array_pos_ = next_pos_; - char_pos_++; - if (next_pos_ < len_) - U8_NEXT(str_, next_pos_, len_, char_); - - return true; -} - -UTF16CharIterator::UTF16CharIterator(const string16* str) - : str_(reinterpret_cast(str->data())), - len_(str->size()), - array_pos_(0), - next_pos_(0), - char_pos_(0), - char_(0) { - if (len_) - ReadChar(); -} - -UTF16CharIterator::UTF16CharIterator(const char16* str, size_t str_len) - : str_(str), - len_(str_len), - array_pos_(0), - next_pos_(0), - char_pos_(0), - char_(0) { - if (len_) - ReadChar(); -} - -UTF16CharIterator::~UTF16CharIterator() { -} - -bool UTF16CharIterator::Advance() { - if (array_pos_ >= len_) - return false; - - array_pos_ = next_pos_; - char_pos_++; - if (next_pos_ < len_) - ReadChar(); - - return true; -} - -void UTF16CharIterator::ReadChar() { - // This is actually a huge macro, so is worth having in a separate function. - U16_NEXT(str_, next_pos_, len_, char_); -} - -} // namespace i18n -} // namespace base diff --git a/base/i18n/char_iterator.h b/base/i18n/char_iterator.h deleted file mode 100644 index 46928b37d0..0000000000 --- a/base/i18n/char_iterator.h +++ /dev/null @@ -1,130 +0,0 @@ -// Copyright (c) 2011 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef BASE_I18N_CHAR_ITERATOR_H_ -#define BASE_I18N_CHAR_ITERATOR_H_ - -#include - -#include "base/basictypes.h" -#include "base/i18n/base_i18n_export.h" -#include "base/strings/string16.h" - -// The CharIterator classes iterate through the characters in UTF8 and -// UTF16 strings. Example usage: -// -// UTF8CharIterator iter(&str); -// while (!iter.End()) { -// VLOG(1) << iter.get(); -// iter.Advance(); -// } - -#if defined(OS_WIN) -typedef unsigned char uint8_t; -#endif - -namespace base { -namespace i18n { - -class BASE_I18N_EXPORT UTF8CharIterator { - public: - // Requires |str| to live as long as the UTF8CharIterator does. - explicit UTF8CharIterator(const std::string* str); - ~UTF8CharIterator(); - - // Return the starting array index of the current character within the - // string. - int32 array_pos() const { return array_pos_; } - - // Return the logical index of the current character, independent of the - // number of bytes each character takes. - int32 char_pos() const { return char_pos_; } - - // Return the current char. - int32 get() const { return char_; } - - // Returns true if we're at the end of the string. - bool end() const { return array_pos_ == len_; } - - // Advance to the next actual character. Returns false if we're at the - // end of the string. - bool Advance(); - - private: - // The string we're iterating over. - const uint8_t* str_; - - // The length of the encoded string. - int32 len_; - - // Array index. - int32 array_pos_; - - // The next array index. - int32 next_pos_; - - // Character index. - int32 char_pos_; - - // The current character. - int32 char_; - - DISALLOW_COPY_AND_ASSIGN(UTF8CharIterator); -}; - -class BASE_I18N_EXPORT UTF16CharIterator { - public: - // Requires |str| to live as long as the UTF16CharIterator does. - explicit UTF16CharIterator(const string16* str); - UTF16CharIterator(const char16* str, size_t str_len); - ~UTF16CharIterator(); - - // Return the starting array index of the current character within the - // string. - int32 array_pos() const { return array_pos_; } - - // Return the logical index of the current character, independent of the - // number of codewords each character takes. - int32 char_pos() const { return char_pos_; } - - // Return the current char. - int32 get() const { return char_; } - - // Returns true if we're at the end of the string. - bool end() const { return array_pos_ == len_; } - - // Advance to the next actual character. Returns false if we're at the - // end of the string. - bool Advance(); - - private: - // Fills in the current character we found and advances to the next - // character, updating all flags as necessary. - void ReadChar(); - - // The string we're iterating over. - const char16* str_; - - // The length of the encoded string. - int32 len_; - - // Array index. - int32 array_pos_; - - // The next array index. - int32 next_pos_; - - // Character index. - int32 char_pos_; - - // The current character. - int32 char_; - - DISALLOW_COPY_AND_ASSIGN(UTF16CharIterator); -}; - -} // namespace i18n -} // namespace base - -#endif // BASE_I18N_CHAR_ITERATOR_H_ diff --git a/base/i18n/char_iterator_unittest.cc b/base/i18n/char_iterator_unittest.cc deleted file mode 100644 index 0cf8e6c07d..0000000000 --- a/base/i18n/char_iterator_unittest.cc +++ /dev/null @@ -1,101 +0,0 @@ -// Copyright (c) 2011 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "base/i18n/char_iterator.h" - -#include "base/strings/utf_string_conversions.h" -#include "testing/gtest/include/gtest/gtest.h" - -namespace base { -namespace i18n { - -TEST(CharIteratorsTest, TestUTF8) { - std::string empty; - UTF8CharIterator empty_iter(&empty); - ASSERT_TRUE(empty_iter.end()); - ASSERT_EQ(0, empty_iter.array_pos()); - ASSERT_EQ(0, empty_iter.char_pos()); - ASSERT_FALSE(empty_iter.Advance()); - - std::string str("s\303\273r"); // [u with circumflex] - UTF8CharIterator iter(&str); - ASSERT_FALSE(iter.end()); - ASSERT_EQ(0, iter.array_pos()); - ASSERT_EQ(0, iter.char_pos()); - ASSERT_EQ('s', iter.get()); - ASSERT_TRUE(iter.Advance()); - - ASSERT_FALSE(iter.end()); - ASSERT_EQ(1, iter.array_pos()); - ASSERT_EQ(1, iter.char_pos()); - ASSERT_EQ(251, iter.get()); - ASSERT_TRUE(iter.Advance()); - - ASSERT_FALSE(iter.end()); - ASSERT_EQ(3, iter.array_pos()); - ASSERT_EQ(2, iter.char_pos()); - ASSERT_EQ('r', iter.get()); - ASSERT_TRUE(iter.Advance()); - - ASSERT_TRUE(iter.end()); - ASSERT_EQ(4, iter.array_pos()); - ASSERT_EQ(3, iter.char_pos()); - - // Don't care what it returns, but this shouldn't crash - iter.get(); - - ASSERT_FALSE(iter.Advance()); -} - -TEST(CharIteratorsTest, TestUTF16) { - string16 empty = UTF8ToUTF16(""); - UTF16CharIterator empty_iter(&empty); - ASSERT_TRUE(empty_iter.end()); - ASSERT_EQ(0, empty_iter.array_pos()); - ASSERT_EQ(0, empty_iter.char_pos()); - ASSERT_FALSE(empty_iter.Advance()); - - // This test string contains 4 characters: - // x - // u with circumflex - 2 bytes in UTF8, 1 codeword in UTF16 - // math double-struck A - 4 bytes in UTF8, 2 codewords in UTF16 - // z - string16 str = UTF8ToUTF16("x\303\273\360\235\224\270z"); - UTF16CharIterator iter(&str); - ASSERT_FALSE(iter.end()); - ASSERT_EQ(0, iter.array_pos()); - ASSERT_EQ(0, iter.char_pos()); - ASSERT_EQ('x', iter.get()); - ASSERT_TRUE(iter.Advance()); - - ASSERT_FALSE(iter.end()); - ASSERT_EQ(1, iter.array_pos()); - ASSERT_EQ(1, iter.char_pos()); - ASSERT_EQ(251, iter.get()); - ASSERT_TRUE(iter.Advance()); - - ASSERT_FALSE(iter.end()); - ASSERT_EQ(2, iter.array_pos()); - ASSERT_EQ(2, iter.char_pos()); - ASSERT_EQ(120120, iter.get()); - ASSERT_TRUE(iter.Advance()); - - ASSERT_FALSE(iter.end()); - ASSERT_EQ(4, iter.array_pos()); - ASSERT_EQ(3, iter.char_pos()); - ASSERT_EQ('z', iter.get()); - ASSERT_TRUE(iter.Advance()); - - ASSERT_TRUE(iter.end()); - ASSERT_EQ(5, iter.array_pos()); - ASSERT_EQ(4, iter.char_pos()); - - // Don't care what it returns, but this shouldn't crash - iter.get(); - - ASSERT_FALSE(iter.Advance()); -} - -} // namespace i18n -} // namespace base diff --git a/base/i18n/file_util_icu.cc b/base/i18n/file_util_icu.cc deleted file mode 100644 index 4b2ca3ac0b..0000000000 --- a/base/i18n/file_util_icu.cc +++ /dev/null @@ -1,170 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -// File utilities that use the ICU library go in this file. - -#include "base/i18n/file_util_icu.h" - -#include "base/files/file_path.h" -#include "base/i18n/icu_string_conversions.h" -#include "base/i18n/string_compare.h" -#include "base/logging.h" -#include "base/memory/scoped_ptr.h" -#include "base/memory/singleton.h" -#include "base/strings/string_util.h" -#include "base/strings/sys_string_conversions.h" -#include "base/strings/utf_string_conversions.h" -#include "build/build_config.h" -#include "third_party/icu/source/common/unicode/uniset.h" -#include "third_party/icu/source/i18n/unicode/coll.h" - -namespace { - -class IllegalCharacters { - public: - static IllegalCharacters* GetInstance() { - return Singleton::get(); - } - - bool contains(UChar32 ucs4) { - return !!set->contains(ucs4); - } - - bool containsNone(const string16 &s) { - return !!set->containsNone(icu::UnicodeString(s.c_str(), s.size())); - } - - private: - friend class Singleton; - friend struct DefaultSingletonTraits; - - IllegalCharacters(); - ~IllegalCharacters() { } - - scoped_ptr set; - - DISALLOW_COPY_AND_ASSIGN(IllegalCharacters); -}; - -IllegalCharacters::IllegalCharacters() { - UErrorCode status = U_ZERO_ERROR; - // Control characters, formatting characters, non-characters, and - // some printable ASCII characters regarded as dangerous ('"*/:<>?\\'). - // See http://blogs.msdn.com/michkap/archive/2006/11/03/941420.aspx - // and http://msdn2.microsoft.com/en-us/library/Aa365247.aspx - // TODO(jungshik): Revisit the set. ZWJ and ZWNJ are excluded because they - // are legitimate in Arabic and some S/SE Asian scripts. However, when used - // elsewhere, they can be confusing/problematic. - // Also, consider wrapping the set with our Singleton class to create and - // freeze it only once. Note that there's a trade-off between memory and - // speed. -#if defined(WCHAR_T_IS_UTF16) - set.reset(new icu::UnicodeSet(icu::UnicodeString( - L"[[\"*/:<>?\\\\|][:Cc:][:Cf:] - [\u200c\u200d]]"), status)); -#else - set.reset(new icu::UnicodeSet(UNICODE_STRING_SIMPLE( - "[[\"*/:<>?\\\\|][:Cc:][:Cf:] - [\\u200c\\u200d]]").unescape(), - status)); -#endif - DCHECK(U_SUCCESS(status)); - // Add non-characters. If this becomes a performance bottleneck by - // any chance, do not add these to |set| and change IsFilenameLegal() - // to check |ucs4 & 0xFFFEu == 0xFFFEu|, in addiition to calling - // containsNone(). - set->add(0xFDD0, 0xFDEF); - for (int i = 0; i <= 0x10; ++i) { - int plane_base = 0x10000 * i; - set->add(plane_base + 0xFFFE, plane_base + 0xFFFF); - } - set->freeze(); -} - -} // namespace - -namespace file_util { - -bool IsFilenameLegal(const string16& file_name) { - return IllegalCharacters::GetInstance()->containsNone(file_name); -} - -void ReplaceIllegalCharactersInPath(base::FilePath::StringType* file_name, - char replace_char) { - DCHECK(file_name); - - DCHECK(!(IllegalCharacters::GetInstance()->contains(replace_char))); - - // Remove leading and trailing whitespace. - TrimWhitespace(*file_name, TRIM_ALL, file_name); - - IllegalCharacters* illegal = IllegalCharacters::GetInstance(); - int cursor = 0; // The ICU macros expect an int. - while (cursor < static_cast(file_name->size())) { - int char_begin = cursor; - uint32 code_point; -#if defined(OS_MACOSX) - // Mac uses UTF-8 encoding for filenames. - U8_NEXT(file_name->data(), cursor, static_cast(file_name->length()), - code_point); -#elif defined(OS_WIN) - // Windows uses UTF-16 encoding for filenames. - U16_NEXT(file_name->data(), cursor, static_cast(file_name->length()), - code_point); -#elif defined(OS_POSIX) - // Linux doesn't actually define an encoding. It basically allows anything - // except for a few special ASCII characters. - unsigned char cur_char = static_cast((*file_name)[cursor++]); - if (cur_char >= 0x80) - continue; - code_point = cur_char; -#else - NOTREACHED(); -#endif - - if (illegal->contains(code_point)) { - file_name->replace(char_begin, cursor - char_begin, 1, replace_char); - // We just made the potentially multi-byte/word char into one that only - // takes one byte/word, so need to adjust the cursor to point to the next - // character again. - cursor = char_begin + 1; - } - } -} - -bool LocaleAwareCompareFilenames(const base::FilePath& a, - const base::FilePath& b) { - UErrorCode error_code = U_ZERO_ERROR; - // Use the default collator. The default locale should have been properly - // set by the time this constructor is called. - scoped_ptr collator(icu::Collator::createInstance(error_code)); - DCHECK(U_SUCCESS(error_code)); - // Make it case-sensitive. - collator->setStrength(icu::Collator::TERTIARY); - -#if defined(OS_WIN) - return base::i18n::CompareString16WithCollator(collator.get(), - WideToUTF16(a.value()), WideToUTF16(b.value())) == UCOL_LESS; - -#elif defined(OS_POSIX) - // On linux, the file system encoding is not defined. We assume - // SysNativeMBToWide takes care of it. - return base::i18n::CompareString16WithCollator(collator.get(), - WideToUTF16(base::SysNativeMBToWide(a.value().c_str())), - WideToUTF16(base::SysNativeMBToWide(b.value().c_str()))) == UCOL_LESS; -#else - #error Not implemented on your system -#endif -} - -void NormalizeFileNameEncoding(base::FilePath* file_name) { -#if defined(OS_CHROMEOS) - std::string normalized_str; - if (base::ConvertToUtf8AndNormalize(file_name->BaseName().value(), - base::kCodepageUTF8, - &normalized_str)) { - *file_name = file_name->DirName().Append(base::FilePath(normalized_str)); - } -#endif -} - -} // namespace diff --git a/base/i18n/file_util_icu.h b/base/i18n/file_util_icu.h deleted file mode 100644 index 7f246c7f1c..0000000000 --- a/base/i18n/file_util_icu.h +++ /dev/null @@ -1,43 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef BASE_I18N_FILE_UTIL_ICU_H_ -#define BASE_I18N_FILE_UTIL_ICU_H_ - -// File utilities that use the ICU library go in this file. - -#include "base/files/file_path.h" -#include "base/i18n/base_i18n_export.h" -#include "base/strings/string16.h" - -namespace file_util { - -// Returns true if file_name does not have any illegal character. The input -// param has the same restriction as that for ReplaceIllegalCharacters. -BASE_I18N_EXPORT bool IsFilenameLegal(const string16& file_name); - -// Replaces characters in 'file_name' that are illegal for file names with -// 'replace_char'. 'file_name' must not be a full or relative path, but just the -// file name component (since slashes are considered illegal). Any leading or -// trailing whitespace in 'file_name' is removed. -// Example: -// file_name == "bad:file*name?.txt", changed to: "bad-file-name-.txt" when -// 'replace_char' is '-'. -BASE_I18N_EXPORT void ReplaceIllegalCharactersInPath( - base::FilePath::StringType* file_name, - char replace_char); - -// Compares two filenames using the current locale information. This can be -// used to sort directory listings. It behaves like "operator<" for use in -// std::sort. -BASE_I18N_EXPORT bool LocaleAwareCompareFilenames(const base::FilePath& a, - const base::FilePath& b); - -// Calculates the canonical file-system representation of |file_name| base name. -// Modifies |file_name| in place. No-op if not on ChromeOS. -BASE_I18N_EXPORT void NormalizeFileNameEncoding(base::FilePath* file_name); - -} // namespace file_util - -#endif // BASE_I18N_FILE_UTIL_ICU_H_ diff --git a/base/i18n/file_util_icu_unittest.cc b/base/i18n/file_util_icu_unittest.cc deleted file mode 100644 index e3af9adf94..0000000000 --- a/base/i18n/file_util_icu_unittest.cc +++ /dev/null @@ -1,107 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "base/i18n/file_util_icu.h" - -#include "base/file_util.h" -#include "base/strings/utf_string_conversions.h" -#include "testing/gtest/include/gtest/gtest.h" -#include "testing/platform_test.h" - -// file_util winds up using autoreleased objects on the Mac, so this needs -// to be a PlatformTest -class FileUtilICUTest : public PlatformTest { -}; - -#if defined(OS_POSIX) && !defined(OS_MACOSX) - -// Linux disallows some evil ASCII characters, but passes all non-ASCII. -static const struct goodbad_pair { - const char* bad_name; - const char* good_name; -} kIllegalCharacterCases[] = { - {"bad*file:name?.jpg", "bad-file-name-.jpg"}, - {"**********::::.txt", "--------------.txt"}, - {"\xe9\xf0zzzz.\xff", "\xe9\xf0zzzz.\xff"}, -}; - -TEST_F(FileUtilICUTest, ReplaceIllegalCharacersInPathLinuxTest) { - for (size_t i = 0; i < arraysize(kIllegalCharacterCases); ++i) { - std::string bad_name(kIllegalCharacterCases[i].bad_name); - file_util::ReplaceIllegalCharactersInPath(&bad_name, '-'); - EXPECT_EQ(kIllegalCharacterCases[i].good_name, bad_name); - } -} - -#else - -// For Mac & Windows, which both do Unicode validation on filenames. These -// characters are given as wide strings since its more convenient to specify -// unicode characters. For Mac they should be converted to UTF-8. -static const struct goodbad_pair { - const wchar_t* bad_name; - const wchar_t* good_name; -} kIllegalCharacterCases[] = { - {L"bad*file:name?.jpg", L"bad-file-name-.jpg"}, - {L"**********::::.txt", L"--------------.txt"}, - // We can't use UCNs (universal character names) for C0/C1 characters and - // U+007F, but \x escape is interpreted by MSVC and gcc as we intend. - {L"bad\x0003\x0091 file\u200E\u200Fname.png", L"bad-- file--name.png"}, -#if defined(OS_WIN) - {L"bad*file\\name.jpg", L"bad-file-name.jpg"}, - {L"\t bad*file\\name/.jpg ", L"bad-file-name-.jpg"}, -#elif defined(OS_MACOSX) - {L"bad*file?name.jpg", L"bad-file-name.jpg"}, - {L"\t bad*file?name/.jpg ", L"bad-file-name-.jpg"}, -#endif - {L"this_file_name is okay!.mp3", L"this_file_name is okay!.mp3"}, - {L"\u4E00\uAC00.mp3", L"\u4E00\uAC00.mp3"}, - {L"\u0635\u200C\u0644.mp3", L"\u0635\u200C\u0644.mp3"}, - {L"\U00010330\U00010331.mp3", L"\U00010330\U00010331.mp3"}, - // Unassigned codepoints are ok. - {L"\u0378\U00040001.mp3", L"\u0378\U00040001.mp3"}, - // Non-characters are not allowed. - {L"bad\uFFFFfile\U0010FFFEname.jpg ", L"bad-file-name.jpg"}, - {L"bad\uFDD0file\uFDEFname.jpg ", L"bad-file-name.jpg"}, -}; - -TEST_F(FileUtilICUTest, ReplaceIllegalCharactersInPathTest) { - for (size_t i = 0; i < arraysize(kIllegalCharacterCases); ++i) { -#if defined(OS_WIN) - std::wstring bad_name(kIllegalCharacterCases[i].bad_name); - file_util::ReplaceIllegalCharactersInPath(&bad_name, '-'); - EXPECT_EQ(kIllegalCharacterCases[i].good_name, bad_name); -#elif defined(OS_MACOSX) - std::string bad_name(WideToUTF8(kIllegalCharacterCases[i].bad_name)); - file_util::ReplaceIllegalCharactersInPath(&bad_name, '-'); - EXPECT_EQ(WideToUTF8(kIllegalCharacterCases[i].good_name), bad_name); -#endif - } -} - -#endif - -#if defined(OS_CHROMEOS) -static const struct normalize_name_encoding_test_cases { - const char* original_path; - const char* normalized_path; -} kNormalizeFileNameEncodingTestCases[] = { - { "foo_na\xcc\x88me.foo", "foo_n\xc3\xa4me.foo"}, - { "foo_dir_na\xcc\x88me/foo_na\xcc\x88me.foo", - "foo_dir_na\xcc\x88me/foo_n\xc3\xa4me.foo"}, - { "", ""}, - { "foo_dir_na\xcc\x88me/", "foo_dir_n\xc3\xa4me"} -}; - -TEST_F(FileUtilICUTest, NormalizeFileNameEncoding) { - for (size_t i = 0; i < arraysize(kNormalizeFileNameEncodingTestCases); i++) { - base::FilePath path(kNormalizeFileNameEncodingTestCases[i].original_path); - file_util::NormalizeFileNameEncoding(&path); - EXPECT_EQ( - base::FilePath(kNormalizeFileNameEncodingTestCases[i].normalized_path), - path); - } -} - -#endif diff --git a/base/i18n/i18n_constants.cc b/base/i18n/i18n_constants.cc deleted file mode 100644 index 9b8c571564..0000000000 --- a/base/i18n/i18n_constants.cc +++ /dev/null @@ -1,15 +0,0 @@ -// Copyright (c) 2011 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "base/i18n/i18n_constants.h" - -namespace base { - -const char kCodepageLatin1[] = "ISO-8859-1"; -const char kCodepageUTF8[] = "UTF-8"; -const char kCodepageUTF16BE[] = "UTF-16BE"; -const char kCodepageUTF16LE[] = "UTF-16LE"; - -} // namespace base - diff --git a/base/i18n/i18n_constants.h b/base/i18n/i18n_constants.h deleted file mode 100644 index c2de842da1..0000000000 --- a/base/i18n/i18n_constants.h +++ /dev/null @@ -1,20 +0,0 @@ -// Copyright (c) 2013 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef BASE_I18N_I18N_CONSTANTS_H_ -#define BASE_I18N_I18N_CONSTANTS_H_ - -#include "base/i18n/base_i18n_export.h" - -namespace base { - -// Names of codepages (charsets) understood by icu. -BASE_I18N_EXPORT extern const char kCodepageLatin1[]; // a.k.a. ISO 8859-1 -BASE_I18N_EXPORT extern const char kCodepageUTF8[]; -BASE_I18N_EXPORT extern const char kCodepageUTF16BE[]; -BASE_I18N_EXPORT extern const char kCodepageUTF16LE[]; - -} // namespace base - -#endif // BASE_I18N_I18N_CONSTANTS_H_ diff --git a/base/i18n/icu_encoding_detection.cc b/base/i18n/icu_encoding_detection.cc deleted file mode 100644 index ccd5cde209..0000000000 --- a/base/i18n/icu_encoding_detection.cc +++ /dev/null @@ -1,104 +0,0 @@ -// Copyright (c) 2011 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "base/i18n/icu_encoding_detection.h" - -#include - -#include "base/strings/string_util.h" -#include "third_party/icu/source/i18n/unicode/ucsdet.h" - -namespace base { - -bool DetectEncoding(const std::string& text, std::string* encoding) { - if (IsStringASCII(text)) { - *encoding = std::string(); - return true; - } - - UErrorCode status = U_ZERO_ERROR; - UCharsetDetector* detector = ucsdet_open(&status); - ucsdet_setText(detector, text.data(), static_cast(text.length()), - &status); - const UCharsetMatch* match = ucsdet_detect(detector, &status); - if (match == NULL) - return false; - const char* detected_encoding = ucsdet_getName(match, &status); - ucsdet_close(detector); - - if (U_FAILURE(status)) - return false; - - *encoding = detected_encoding; - return true; -} - -bool DetectAllEncodings(const std::string& text, - std::vector* encodings) { - UErrorCode status = U_ZERO_ERROR; - UCharsetDetector* detector = ucsdet_open(&status); - ucsdet_setText(detector, text.data(), static_cast(text.length()), - &status); - int matches_count = 0; - const UCharsetMatch** matches = ucsdet_detectAll(detector, - &matches_count, - &status); - if (U_FAILURE(status)) { - ucsdet_close(detector); - return false; - } - - // ICU has some heuristics for encoding detection, such that the more likely - // encodings should be returned first. However, it doesn't always return - // all encodings that properly decode |text|, so we'll append more encodings - // later. To make that efficient, keep track of encodings sniffed in this - // first phase. - std::set sniffed_encodings; - - encodings->clear(); - for (int i = 0; i < matches_count; i++) { - UErrorCode get_name_status = U_ZERO_ERROR; - const char* encoding_name = ucsdet_getName(matches[i], &get_name_status); - - // If we failed to get the encoding's name, ignore the error. - if (U_FAILURE(get_name_status)) - continue; - - int32_t confidence = ucsdet_getConfidence(matches[i], &get_name_status); - - // We also treat this error as non-fatal. - if (U_FAILURE(get_name_status)) - continue; - - // A confidence level >= 10 means that the encoding is expected to properly - // decode the text. Drop all encodings with lower confidence level. - if (confidence < 10) - continue; - - encodings->push_back(encoding_name); - sniffed_encodings.insert(encoding_name); - } - - // Append all encodings not included earlier, in arbitrary order. - // TODO(jshin): This shouldn't be necessary, possible ICU bug. - // See also http://crbug.com/65917. - UEnumeration* detectable_encodings = ucsdet_getAllDetectableCharsets(detector, - &status); - int detectable_count = uenum_count(detectable_encodings, &status); - for (int i = 0; i < detectable_count; i++) { - int name_length; - const char* name_raw = uenum_next(detectable_encodings, - &name_length, - &status); - std::string name(name_raw, name_length); - if (sniffed_encodings.find(name) == sniffed_encodings.end()) - encodings->push_back(name); - } - uenum_close(detectable_encodings); - - ucsdet_close(detector); - return !encodings->empty(); -} - -} // namespace base diff --git a/base/i18n/icu_encoding_detection.h b/base/i18n/icu_encoding_detection.h deleted file mode 100644 index 6d1e71ca2b..0000000000 --- a/base/i18n/icu_encoding_detection.h +++ /dev/null @@ -1,30 +0,0 @@ -// Copyright (c) 2011 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef BASE_I18N_ICU_ENCODING_DETECTION_H_ -#define BASE_I18N_ICU_ENCODING_DETECTION_H_ - -#include -#include - -#include "base/i18n/base_i18n_export.h" - -namespace base { - -// Detect encoding of |text| and put the name of encoding (as returned by ICU) -// in |encoding|. For ASCII texts |encoding| will be set to an empty string. -// Returns true on success. -BASE_I18N_EXPORT bool DetectEncoding(const std::string& text, - std::string* encoding); - -// Detect all possible encodings of |text| and put their names -// (as returned by ICU) in |encodings|. Returns true on success. -// Note: this function may return encodings that may fail to decode |text|, -// the caller is responsible for handling that. -BASE_I18N_EXPORT bool DetectAllEncodings(const std::string& text, - std::vector* encodings); - -} // namespace base - -#endif // BASE_I18N_ICU_ENCODING_DETECTION_H_ diff --git a/base/i18n/icu_string_conversions.cc b/base/i18n/icu_string_conversions.cc deleted file mode 100644 index 1530117f1e..0000000000 --- a/base/i18n/icu_string_conversions.cc +++ /dev/null @@ -1,292 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "base/i18n/icu_string_conversions.h" - -#include - -#include "base/basictypes.h" -#include "base/logging.h" -#include "base/memory/scoped_ptr.h" -#include "base/strings/string_util.h" -#include "base/strings/utf_string_conversions.h" -#include "third_party/icu/source/common/unicode/ucnv.h" -#include "third_party/icu/source/common/unicode/ucnv_cb.h" -#include "third_party/icu/source/common/unicode/ucnv_err.h" -#include "third_party/icu/source/common/unicode/unorm.h" -#include "third_party/icu/source/common/unicode/ustring.h" - -namespace base { - -namespace { -// ToUnicodeCallbackSubstitute() is based on UCNV_TO_U_CALLBACK_SUBSTITUTE -// in source/common/ucnv_err.c. - -// Copyright (c) 1995-2006 International Business Machines Corporation -// and others -// -// All rights reserved. -// - -// Permission is hereby granted, free of charge, to any person obtaining a -// copy of this software and associated documentation files (the "Software"), -// to deal in the Software without restriction, including without limitation -// the rights to use, copy, modify, merge, publish, distribute, and/or -// sell copies of the Software, and to permit persons to whom the Software -// is furnished to do so, provided that the above copyright notice(s) and -// this permission notice appear in all copies of the Software and that -// both the above copyright notice(s) and this permission notice appear in -// supporting documentation. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT -// OF THIRD PARTY RIGHTS. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR HOLDERS -// INCLUDED IN THIS NOTICE BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL INDIRECT -// OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS -// OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE -// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE -// OR PERFORMANCE OF THIS SOFTWARE. -// -// Except as contained in this notice, the name of a copyright holder -// shall not be used in advertising or otherwise to promote the sale, use -// or other dealings in this Software without prior written authorization -// of the copyright holder. - -// ___________________________________________________________________________ -// -// All trademarks and registered trademarks mentioned herein are the property -// of their respective owners. - -void ToUnicodeCallbackSubstitute(const void* context, - UConverterToUnicodeArgs *to_args, - const char* code_units, - int32_t length, - UConverterCallbackReason reason, - UErrorCode * err) { - static const UChar kReplacementChar = 0xFFFD; - if (reason <= UCNV_IRREGULAR) { - if (context == NULL || - (*(reinterpret_cast(context)) == 'i' && - reason == UCNV_UNASSIGNED)) { - *err = U_ZERO_ERROR; - ucnv_cbToUWriteUChars(to_args, &kReplacementChar, 1, 0, err); - } - // else the caller must have set the error code accordingly. - } - // else ignore the reset, close and clone calls. -} - -bool ConvertFromUTF16(UConverter* converter, const UChar* uchar_src, - int uchar_len, OnStringConversionError::Type on_error, - std::string* encoded) { - int encoded_max_length = UCNV_GET_MAX_BYTES_FOR_STRING(uchar_len, - ucnv_getMaxCharSize(converter)); - encoded->resize(encoded_max_length); - - UErrorCode status = U_ZERO_ERROR; - - // Setup our error handler. - switch (on_error) { - case OnStringConversionError::FAIL: - ucnv_setFromUCallBack(converter, UCNV_FROM_U_CALLBACK_STOP, 0, - NULL, NULL, &status); - break; - case OnStringConversionError::SKIP: - case OnStringConversionError::SUBSTITUTE: - ucnv_setFromUCallBack(converter, UCNV_FROM_U_CALLBACK_SKIP, 0, - NULL, NULL, &status); - break; - default: - NOTREACHED(); - } - - // ucnv_fromUChars returns size not including terminating null - int actual_size = ucnv_fromUChars(converter, &(*encoded)[0], - encoded_max_length, uchar_src, uchar_len, &status); - encoded->resize(actual_size); - ucnv_close(converter); - if (U_SUCCESS(status)) - return true; - encoded->clear(); // Make sure the output is empty on error. - return false; -} - -// Set up our error handler for ToUTF-16 converters -void SetUpErrorHandlerForToUChars(OnStringConversionError::Type on_error, - UConverter* converter, UErrorCode* status) { - switch (on_error) { - case OnStringConversionError::FAIL: - ucnv_setToUCallBack(converter, UCNV_TO_U_CALLBACK_STOP, 0, - NULL, NULL, status); - break; - case OnStringConversionError::SKIP: - ucnv_setToUCallBack(converter, UCNV_TO_U_CALLBACK_SKIP, 0, - NULL, NULL, status); - break; - case OnStringConversionError::SUBSTITUTE: - ucnv_setToUCallBack(converter, ToUnicodeCallbackSubstitute, 0, - NULL, NULL, status); - break; - default: - NOTREACHED(); - } -} - -inline UConverterType utf32_platform_endian() { -#if U_IS_BIG_ENDIAN - return UCNV_UTF32_BigEndian; -#else - return UCNV_UTF32_LittleEndian; -#endif -} - -} // namespace - -// Codepage <-> Wide/UTF-16 --------------------------------------------------- - -bool UTF16ToCodepage(const string16& utf16, - const char* codepage_name, - OnStringConversionError::Type on_error, - std::string* encoded) { - encoded->clear(); - - UErrorCode status = U_ZERO_ERROR; - UConverter* converter = ucnv_open(codepage_name, &status); - if (!U_SUCCESS(status)) - return false; - - return ConvertFromUTF16(converter, utf16.c_str(), - static_cast(utf16.length()), on_error, encoded); -} - -bool CodepageToUTF16(const std::string& encoded, - const char* codepage_name, - OnStringConversionError::Type on_error, - string16* utf16) { - utf16->clear(); - - UErrorCode status = U_ZERO_ERROR; - UConverter* converter = ucnv_open(codepage_name, &status); - if (!U_SUCCESS(status)) - return false; - - // Even in the worst case, the maximum length in 2-byte units of UTF-16 - // output would be at most the same as the number of bytes in input. There - // is no single-byte encoding in which a character is mapped to a - // non-BMP character requiring two 2-byte units. - // - // Moreover, non-BMP characters in legacy multibyte encodings - // (e.g. EUC-JP, GB18030) take at least 2 bytes. The only exceptions are - // BOCU and SCSU, but we don't care about them. - size_t uchar_max_length = encoded.length() + 1; - - SetUpErrorHandlerForToUChars(on_error, converter, &status); - scoped_ptr buffer(new char16[uchar_max_length]); - int actual_size = ucnv_toUChars(converter, buffer.get(), - static_cast(uchar_max_length), encoded.data(), - static_cast(encoded.length()), &status); - ucnv_close(converter); - if (!U_SUCCESS(status)) { - utf16->clear(); // Make sure the output is empty on error. - return false; - } - - utf16->assign(buffer.get(), actual_size); - return true; -} - -bool WideToCodepage(const std::wstring& wide, - const char* codepage_name, - OnStringConversionError::Type on_error, - std::string* encoded) { -#if defined(WCHAR_T_IS_UTF16) - return UTF16ToCodepage(wide, codepage_name, on_error, encoded); -#elif defined(WCHAR_T_IS_UTF32) - encoded->clear(); - - UErrorCode status = U_ZERO_ERROR; - UConverter* converter = ucnv_open(codepage_name, &status); - if (!U_SUCCESS(status)) - return false; - - int utf16_len; - // When wchar_t is wider than UChar (16 bits), transform |wide| into a - // UChar* string. Size the UChar* buffer to be large enough to hold twice - // as many UTF-16 code units (UChar's) as there are Unicode code points, - // in case each code points translates to a UTF-16 surrogate pair, - // and leave room for a NUL terminator. - std::vector utf16(wide.length() * 2 + 1); - u_strFromUTF32(&utf16[0], utf16.size(), &utf16_len, - reinterpret_cast(wide.c_str()), - wide.length(), &status); - DCHECK(U_SUCCESS(status)) << "failed to convert wstring to UChar*"; - - return ConvertFromUTF16(converter, &utf16[0], utf16_len, on_error, encoded); -#endif // defined(WCHAR_T_IS_UTF32) -} - -bool CodepageToWide(const std::string& encoded, - const char* codepage_name, - OnStringConversionError::Type on_error, - std::wstring* wide) { -#if defined(WCHAR_T_IS_UTF16) - return CodepageToUTF16(encoded, codepage_name, on_error, wide); -#elif defined(WCHAR_T_IS_UTF32) - wide->clear(); - - UErrorCode status = U_ZERO_ERROR; - UConverter* converter = ucnv_open(codepage_name, &status); - if (!U_SUCCESS(status)) - return false; - - // The maximum length in 4 byte unit of UTF-32 output would be - // at most the same as the number of bytes in input. In the worst - // case of GB18030 (excluding escaped-based encodings like ISO-2022-JP), - // this can be 4 times larger than actually needed. - size_t wchar_max_length = encoded.length() + 1; - - SetUpErrorHandlerForToUChars(on_error, converter, &status); - scoped_ptr buffer(new wchar_t[wchar_max_length]); - int actual_size = ucnv_toAlgorithmic(utf32_platform_endian(), converter, - reinterpret_cast(buffer.get()), - static_cast(wchar_max_length) * sizeof(wchar_t), encoded.data(), - static_cast(encoded.length()), &status); - ucnv_close(converter); - if (!U_SUCCESS(status)) { - wide->clear(); // Make sure the output is empty on error. - return false; - } - - // actual_size is # of bytes. - wide->assign(buffer.get(), actual_size / sizeof(wchar_t)); - return true; -#endif // defined(WCHAR_T_IS_UTF32) -} - -bool ConvertToUtf8AndNormalize(const std::string& text, - const std::string& charset, - std::string* result) { - result->clear(); - string16 utf16; - if (!CodepageToUTF16( - text, charset.c_str(), OnStringConversionError::FAIL, &utf16)) - return false; - - UErrorCode status = U_ZERO_ERROR; - size_t max_length = utf16.length() + 1; - string16 normalized_utf16; - scoped_ptr buffer(new char16[max_length]); - int actual_length = unorm_normalize( - utf16.c_str(), utf16.length(), UNORM_NFC, 0, - buffer.get(), static_cast(max_length), &status); - if (!U_SUCCESS(status)) - return false; - normalized_utf16.assign(buffer.get(), actual_length); - - return UTF16ToUTF8(normalized_utf16.data(), - normalized_utf16.length(), result); -} - -} // namespace base diff --git a/base/i18n/icu_string_conversions.h b/base/i18n/icu_string_conversions.h deleted file mode 100644 index fd2ae46c52..0000000000 --- a/base/i18n/icu_string_conversions.h +++ /dev/null @@ -1,70 +0,0 @@ -// Copyright (c) 2011 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef BASE_I18N_ICU_STRING_CONVERSIONS_H_ -#define BASE_I18N_ICU_STRING_CONVERSIONS_H_ - -#include - -#include "base/i18n/base_i18n_export.h" -#include "base/i18n/i18n_constants.h" -#include "base/strings/string16.h" - -namespace base { - -// Defines the error handling modes of UTF16ToCodepage, CodepageToUTF16, -// WideToCodepage and CodepageToWide. -class OnStringConversionError { - public: - enum Type { - // The function will return failure. The output buffer will be empty. - FAIL, - - // The offending characters are skipped and the conversion will proceed as - // if they did not exist. - SKIP, - - // When converting to Unicode, the offending byte sequences are substituted - // by Unicode replacement character (U+FFFD). When converting from Unicode, - // this is the same as SKIP. - SUBSTITUTE, - }; - - private: - OnStringConversionError(); -}; - -// Converts between UTF-16 strings and the encoding specified. If the -// encoding doesn't exist or the encoding fails (when on_error is FAIL), -// returns false. -BASE_I18N_EXPORT bool UTF16ToCodepage(const string16& utf16, - const char* codepage_name, - OnStringConversionError::Type on_error, - std::string* encoded); -BASE_I18N_EXPORT bool CodepageToUTF16(const std::string& encoded, - const char* codepage_name, - OnStringConversionError::Type on_error, - string16* utf16); - -// Converts between wide strings and the encoding specified. If the -// encoding doesn't exist or the encoding fails (when on_error is FAIL), -// returns false. -BASE_I18N_EXPORT bool WideToCodepage(const std::wstring& wide, - const char* codepage_name, - OnStringConversionError::Type on_error, - std::string* encoded); -BASE_I18N_EXPORT bool CodepageToWide(const std::string& encoded, - const char* codepage_name, - OnStringConversionError::Type on_error, - std::wstring* wide); - -// Converts from any codepage to UTF-8 and ensures the resulting UTF-8 is -// normalized. -BASE_I18N_EXPORT bool ConvertToUtf8AndNormalize(const std::string& text, - const std::string& charset, - std::string* result); - -} // namespace base - -#endif // BASE_I18N_ICU_STRING_CONVERSIONS_H_ diff --git a/base/i18n/icu_string_conversions_unittest.cc b/base/i18n/icu_string_conversions_unittest.cc deleted file mode 100644 index 62e055ea6f..0000000000 --- a/base/i18n/icu_string_conversions_unittest.cc +++ /dev/null @@ -1,386 +0,0 @@ -// Copyright (c) 2011 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include -#include - -#include -#include - -#include "base/basictypes.h" -#include "base/format_macros.h" -#include "base/i18n/icu_string_conversions.h" -#include "base/logging.h" -#include "base/strings/string_piece.h" -#include "base/strings/stringprintf.h" -#include "base/strings/utf_string_conversions.h" -#include "testing/gtest/include/gtest/gtest.h" - -namespace base { - -namespace { - -// Given a null-terminated string of wchar_t with each wchar_t representing -// a UTF-16 code unit, returns a string16 made up of wchar_t's in the input. -// Each wchar_t should be <= 0xFFFF and a non-BMP character (> U+FFFF) -// should be represented as a surrogate pair (two UTF-16 units) -// *even* where wchar_t is 32-bit (Linux and Mac). -// -// This is to help write tests for functions with string16 params until -// the C++ 0x UTF-16 literal is well-supported by compilers. -string16 BuildString16(const wchar_t* s) { -#if defined(WCHAR_T_IS_UTF16) - return string16(s); -#elif defined(WCHAR_T_IS_UTF32) - string16 u16; - while (*s != 0) { - DCHECK_LE(static_cast(*s), 0xFFFFu); - u16.push_back(*s++); - } - return u16; -#endif -} - -const wchar_t* const kConvertRoundtripCases[] = { - L"Google Video", - // "网页 图片 资讯更多 »" - L"\x7f51\x9875\x0020\x56fe\x7247\x0020\x8d44\x8baf\x66f4\x591a\x0020\x00bb", - // "Παγκόσμιος Ιστός" - L"\x03a0\x03b1\x03b3\x03ba\x03cc\x03c3\x03bc\x03b9" - L"\x03bf\x03c2\x0020\x0399\x03c3\x03c4\x03cc\x03c2", - // "Поиск страниц на русском" - L"\x041f\x043e\x0438\x0441\x043a\x0020\x0441\x0442" - L"\x0440\x0430\x043d\x0438\x0446\x0020\x043d\x0430" - L"\x0020\x0440\x0443\x0441\x0441\x043a\x043e\x043c", - // "전체서비스" - L"\xc804\xccb4\xc11c\xbe44\xc2a4", - - // Test characters that take more than 16 bits. This will depend on whether - // wchar_t is 16 or 32 bits. -#if defined(WCHAR_T_IS_UTF16) - L"\xd800\xdf00", - // ????? (Mathematical Alphanumeric Symbols (U+011d40 - U+011d44 : A,B,C,D,E) - L"\xd807\xdd40\xd807\xdd41\xd807\xdd42\xd807\xdd43\xd807\xdd44", -#elif defined(WCHAR_T_IS_UTF32) - L"\x10300", - // ????? (Mathematical Alphanumeric Symbols (U+011d40 - U+011d44 : A,B,C,D,E) - L"\x11d40\x11d41\x11d42\x11d43\x11d44", -#endif -}; - -} // namespace - -TEST(ICUStringConversionsTest, ConvertCodepageUTF8) { - // Make sure WideToCodepage works like WideToUTF8. - for (size_t i = 0; i < arraysize(kConvertRoundtripCases); ++i) { - SCOPED_TRACE(base::StringPrintf("Test[%" PRIuS "]: %ls", - i, kConvertRoundtripCases[i])); - - std::string expected(WideToUTF8(kConvertRoundtripCases[i])); - std::string utf8; - EXPECT_TRUE(WideToCodepage(kConvertRoundtripCases[i], kCodepageUTF8, - OnStringConversionError::SKIP, &utf8)); - EXPECT_EQ(expected, utf8); - } -} - -// kConverterCodepageCases is not comprehensive. There are a number of cases -// to add if we really want to have a comprehensive coverage of various -// codepages and their 'idiosyncrasies'. Currently, the only implementation -// for CodepageTo* and *ToCodepage uses ICU, which has a very extensive -// set of tests for the charset conversion. So, we can get away with a -// relatively small number of cases listed below. -// -// Note about |u16_wide| in the following struct. -// On Windows, the field is always identical to |wide|. On Mac and Linux, -// it's identical as long as there's no character outside the -// BMP (<= U+FFFF). When there is, it is different from |wide| and -// is not a real wide string (UTF-32 string) in that each wchar_t in -// the string is a UTF-16 code unit zero-extended to be 32-bit -// even when the code unit belongs to a surrogate pair. -// For instance, a Unicode string (U+0041 U+010000) is represented as -// L"\x0041\xD800\xDC00" instead of L"\x0041\x10000". -// To avoid the clutter, |u16_wide| will be set to NULL -// if it's identical to |wide| on *all* platforms. - -static const struct { - const char* codepage_name; - const char* encoded; - OnStringConversionError::Type on_error; - bool success; - const wchar_t* wide; - const wchar_t* u16_wide; -} kConvertCodepageCases[] = { - // Test a case where the input cannot be decoded, using SKIP, FAIL - // and SUBSTITUTE error handling rules. "A7 41" is valid, but "A6" isn't. - {"big5", - "\xA7\x41\xA6", - OnStringConversionError::FAIL, - false, - L"", - NULL}, - {"big5", - "\xA7\x41\xA6", - OnStringConversionError::SKIP, - true, - L"\x4F60", - NULL}, - {"big5", - "\xA7\x41\xA6", - OnStringConversionError::SUBSTITUTE, - true, - L"\x4F60\xFFFD", - NULL}, - // Arabic (ISO-8859) - {"iso-8859-6", - "\xC7\xEE\xE4\xD3\xF1\xEE\xE4\xC7\xE5\xEF" " " - "\xD9\xEE\xE4\xEE\xEA\xF2\xE3\xEF\xE5\xF2", - OnStringConversionError::FAIL, - true, - L"\x0627\x064E\x0644\x0633\x0651\x064E\x0644\x0627\x0645\x064F" L" " - L"\x0639\x064E\x0644\x064E\x064A\x0652\x0643\x064F\x0645\x0652", - NULL}, - // Chinese Simplified (GB2312) - {"gb2312", - "\xC4\xE3\xBA\xC3", - OnStringConversionError::FAIL, - true, - L"\x4F60\x597D", - NULL}, - // Chinese (GB18030) : 4 byte sequences mapped to BMP characters - {"gb18030", - "\x81\x30\x84\x36\xA1\xA7", - OnStringConversionError::FAIL, - true, - L"\x00A5\x00A8", - NULL}, - // Chinese (GB18030) : A 4 byte sequence mapped to plane 2 (U+20000) - {"gb18030", - "\x95\x32\x82\x36\xD2\xBB", - OnStringConversionError::FAIL, - true, -#if defined(WCHAR_T_IS_UTF16) - L"\xD840\xDC00\x4E00", -#elif defined(WCHAR_T_IS_UTF32) - L"\x20000\x4E00", -#endif - L"\xD840\xDC00\x4E00"}, - {"big5", - "\xA7\x41\xA6\x6E", - OnStringConversionError::FAIL, - true, - L"\x4F60\x597D", - NULL}, - // Greek (ISO-8859) - {"iso-8859-7", - "\xE3\xE5\xE9\xDC" " " "\xF3\xEF\xF5", - OnStringConversionError::FAIL, - true, - L"\x03B3\x03B5\x03B9\x03AC" L" " L"\x03C3\x03BF\x03C5", - NULL}, - // Hebrew (Windows) - {"windows-1255", - "\xF9\xD1\xC8\xEC\xE5\xC9\xED", - OnStringConversionError::FAIL, - true, - L"\x05E9\x05C1\x05B8\x05DC\x05D5\x05B9\x05DD", - NULL}, - // Hindi Devanagari (ISCII) - {"iscii-dev", - "\xEF\x42" "\xC6\xCC\xD7\xE8\xB3\xDA\xCF", - OnStringConversionError::FAIL, - true, - L"\x0928\x092E\x0938\x094D\x0915\x093E\x0930", - NULL}, - // Korean (EUC) - {"euc-kr", - "\xBE\xC8\xB3\xE7\xC7\xCF\xBC\xBC\xBF\xE4", - OnStringConversionError::FAIL, - true, - L"\xC548\xB155\xD558\xC138\xC694", - NULL}, - // Japanese (EUC) - {"euc-jp", - "\xA4\xB3\xA4\xF3\xA4\xCB\xA4\xC1\xA4\xCF\xB0\xEC\x8F\xB0\xA1\x8E\xA6", - OnStringConversionError::FAIL, - true, - L"\x3053\x3093\x306B\x3061\x306F\x4E00\x4E02\xFF66", - NULL}, - // Japanese (ISO-2022) - {"iso-2022-jp", - "\x1B$B" "\x24\x33\x24\x73\x24\x4B\x24\x41\x24\x4F\x30\x6C" "\x1B(B" - "ab" "\x1B(J" "\x5C\x7E#$" "\x1B(B", - OnStringConversionError::FAIL, - true, - L"\x3053\x3093\x306B\x3061\x306F\x4E00" L"ab\x00A5\x203E#$", - NULL}, - // Japanese (Shift-JIS) - {"sjis", - "\x82\xB1\x82\xF1\x82\xC9\x82\xBF\x82\xCD\x88\xEA\xA6", - OnStringConversionError::FAIL, - true, - L"\x3053\x3093\x306B\x3061\x306F\x4E00\xFF66", - NULL}, - // Russian (KOI8) - {"koi8-r", - "\xDA\xC4\xD2\xC1\xD7\xD3\xD4\xD7\xD5\xCA\xD4\xC5", - OnStringConversionError::FAIL, - true, - L"\x0437\x0434\x0440\x0430\x0432\x0441\x0442\x0432" - L"\x0443\x0439\x0442\x0435", - NULL}, - // Thai (windows-874) - {"windows-874", - "\xCA\xC7\xD1\xCA\xB4\xD5" "\xA4\xC3\xD1\xBA", - OnStringConversionError::FAIL, - true, - L"\x0E2A\x0E27\x0E31\x0E2A\x0E14\x0E35" - L"\x0E04\x0E23\x0e31\x0E1A", - NULL}, - // Empty text - {"iscii-dev", - "", - OnStringConversionError::FAIL, - true, - L"", - NULL}, -}; - -TEST(ICUStringConversionsTest, ConvertBetweenCodepageAndWide) { - for (size_t i = 0; i < ARRAYSIZE_UNSAFE(kConvertCodepageCases); ++i) { - SCOPED_TRACE(base::StringPrintf( - "Test[%" PRIuS "]: ", i, - kConvertCodepageCases[i].encoded, - kConvertCodepageCases[i].codepage_name)); - - std::wstring wide; - bool success = CodepageToWide(kConvertCodepageCases[i].encoded, - kConvertCodepageCases[i].codepage_name, - kConvertCodepageCases[i].on_error, - &wide); - EXPECT_EQ(kConvertCodepageCases[i].success, success); - EXPECT_EQ(kConvertCodepageCases[i].wide, wide); - - // When decoding was successful and nothing was skipped, we also check the - // reverse conversion. Not all conversions are round-trippable, but - // kConverterCodepageCases does not have any one-way conversion at the - // moment. - if (success && - kConvertCodepageCases[i].on_error == - OnStringConversionError::FAIL) { - std::string encoded; - success = WideToCodepage(wide, kConvertCodepageCases[i].codepage_name, - kConvertCodepageCases[i].on_error, &encoded); - EXPECT_EQ(kConvertCodepageCases[i].success, success); - EXPECT_EQ(kConvertCodepageCases[i].encoded, encoded); - } - } - - // The above cases handled codepage->wide errors, but not wide->codepage. - // Test that here. - std::string encoded("Temp data"); // Make sure the string gets cleared. - - // First test going to an encoding that can not represent that character. - EXPECT_FALSE(WideToCodepage(L"Chinese\xff27", "iso-8859-1", - OnStringConversionError::FAIL, &encoded)); - EXPECT_TRUE(encoded.empty()); - EXPECT_TRUE(WideToCodepage(L"Chinese\xff27", "iso-8859-1", - OnStringConversionError::SKIP, &encoded)); - EXPECT_STREQ("Chinese", encoded.c_str()); - // From Unicode, SUBSTITUTE is the same as SKIP for now. - EXPECT_TRUE(WideToCodepage(L"Chinese\xff27", "iso-8859-1", - OnStringConversionError::SUBSTITUTE, - &encoded)); - EXPECT_STREQ("Chinese", encoded.c_str()); - -#if defined(WCHAR_T_IS_UTF16) - // When we're in UTF-16 mode, test an invalid UTF-16 character in the input. - EXPECT_FALSE(WideToCodepage(L"a\xd800z", "iso-8859-1", - OnStringConversionError::FAIL, &encoded)); - EXPECT_TRUE(encoded.empty()); - EXPECT_TRUE(WideToCodepage(L"a\xd800z", "iso-8859-1", - OnStringConversionError::SKIP, &encoded)); - EXPECT_STREQ("az", encoded.c_str()); -#endif // WCHAR_T_IS_UTF16 - - // Invalid characters should fail. - EXPECT_TRUE(WideToCodepage(L"a\xffffz", "iso-8859-1", - OnStringConversionError::SKIP, &encoded)); - EXPECT_STREQ("az", encoded.c_str()); - - // Invalid codepages should fail. - EXPECT_FALSE(WideToCodepage(L"Hello, world", "awesome-8571-2", - OnStringConversionError::SKIP, &encoded)); -} - -TEST(ICUStringConversionsTest, ConvertBetweenCodepageAndUTF16) { - for (size_t i = 0; i < ARRAYSIZE_UNSAFE(kConvertCodepageCases); ++i) { - SCOPED_TRACE(base::StringPrintf( - "Test[%" PRIuS "]: ", i, - kConvertCodepageCases[i].encoded, - kConvertCodepageCases[i].codepage_name)); - - string16 utf16; - bool success = CodepageToUTF16(kConvertCodepageCases[i].encoded, - kConvertCodepageCases[i].codepage_name, - kConvertCodepageCases[i].on_error, - &utf16); - string16 utf16_expected; - if (kConvertCodepageCases[i].u16_wide == NULL) - utf16_expected = BuildString16(kConvertCodepageCases[i].wide); - else - utf16_expected = BuildString16(kConvertCodepageCases[i].u16_wide); - EXPECT_EQ(kConvertCodepageCases[i].success, success); - EXPECT_EQ(utf16_expected, utf16); - - // When decoding was successful and nothing was skipped, we also check the - // reverse conversion. See also the corresponding comment in - // ConvertBetweenCodepageAndWide. - if (success && - kConvertCodepageCases[i].on_error == OnStringConversionError::FAIL) { - std::string encoded; - success = UTF16ToCodepage(utf16, kConvertCodepageCases[i].codepage_name, - kConvertCodepageCases[i].on_error, &encoded); - EXPECT_EQ(kConvertCodepageCases[i].success, success); - EXPECT_EQ(kConvertCodepageCases[i].encoded, encoded); - } - } -} - -static const struct { - const char* encoded; - const char* codepage_name; - bool expected_success; - const char* expected_value; -} kConvertAndNormalizeCases[] = { - {"foo-\xe4.html", "iso-8859-1", true, "foo-\xc3\xa4.html"}, - {"foo-\xe4.html", "iso-8859-7", true, "foo-\xce\xb4.html"}, - {"foo-\xe4.html", "foo-bar", false, ""}, - {"foo-\xff.html", "ascii", false, ""}, - {"foo.html", "ascii", true, "foo.html"}, - {"foo-a\xcc\x88.html", "utf-8", true, "foo-\xc3\xa4.html"}, - {"\x95\x32\x82\x36\xD2\xBB", "gb18030", true, "\xF0\xA0\x80\x80\xE4\xB8\x80"}, - {"\xA7\x41\xA6\x6E", "big5", true, "\xE4\xBD\xA0\xE5\xA5\xBD"}, - // Windows-1258 does have a combining character at xD2 (which is U+0309). - // The sequence of (U+00E2, U+0309) is also encoded as U+1EA9. - {"foo\xE2\xD2", "windows-1258", true, "foo\xE1\xBA\xA9"}, - {"", "iso-8859-1", true, ""}, -}; -TEST(ICUStringConversionsTest, ConvertToUtf8AndNormalize) { - std::string result; - for (size_t i = 0; i < ARRAYSIZE_UNSAFE(kConvertAndNormalizeCases); ++i) { - SCOPED_TRACE(base::StringPrintf( - "Test[%" PRIuS "]: ", i, - kConvertAndNormalizeCases[i].encoded, - kConvertAndNormalizeCases[i].codepage_name)); - - bool success = ConvertToUtf8AndNormalize( - kConvertAndNormalizeCases[i].encoded, - kConvertAndNormalizeCases[i].codepage_name, &result); - EXPECT_EQ(kConvertAndNormalizeCases[i].expected_success, success); - EXPECT_EQ(kConvertAndNormalizeCases[i].expected_value, result); - } -} - -} // namespace base diff --git a/base/i18n/icu_util.cc b/base/i18n/icu_util.cc deleted file mode 100644 index 76016d0ce6..0000000000 --- a/base/i18n/icu_util.cc +++ /dev/null @@ -1,135 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "base/i18n/icu_util.h" - -#include "build/build_config.h" - -#if defined(OS_WIN) -#include -#endif - -#include - -#include "base/files/file_path.h" -#include "base/files/memory_mapped_file.h" -#include "base/logging.h" -#include "base/path_service.h" -#include "base/strings/string_util.h" -#include "base/strings/sys_string_conversions.h" -#include "third_party/icu/source/common/unicode/putil.h" -#include "third_party/icu/source/common/unicode/udata.h" - -#if defined(OS_MACOSX) -#include "base/mac/foundation_util.h" -#endif - -#define ICU_UTIL_DATA_FILE 0 -#define ICU_UTIL_DATA_SHARED 1 -#define ICU_UTIL_DATA_STATIC 2 - -#ifndef ICU_UTIL_DATA_IMPL - -#if defined(OS_WIN) -#define ICU_UTIL_DATA_IMPL ICU_UTIL_DATA_SHARED -#elif defined(OS_IOS) -#define ICU_UTIL_DATA_IMPL ICU_UTIL_DATA_FILE -#else -#define ICU_UTIL_DATA_IMPL ICU_UTIL_DATA_STATIC -#endif - -#endif // ICU_UTIL_DATA_IMPL - -#if ICU_UTIL_DATA_IMPL == ICU_UTIL_DATA_FILE -#define ICU_UTIL_DATA_FILE_NAME "icudt" U_ICU_VERSION_SHORT "l.dat" -#elif ICU_UTIL_DATA_IMPL == ICU_UTIL_DATA_SHARED -#define ICU_UTIL_DATA_SYMBOL "icudt" U_ICU_VERSION_SHORT "_dat" -#if defined(OS_WIN) -#define ICU_UTIL_DATA_SHARED_MODULE_NAME "icudt.dll" -#endif -#endif - -using base::FilePath; - -namespace icu_util { - -bool Initialize() { -#ifndef NDEBUG - // Assert that we are not called more than once. Even though calling this - // function isn't harmful (ICU can handle it), being called twice probably - // indicates a programming error. - static bool called_once = false; - DCHECK(!called_once); - called_once = true; -#endif - -#if (ICU_UTIL_DATA_IMPL == ICU_UTIL_DATA_SHARED) - // We expect to find the ICU data module alongside the current module. - FilePath data_path; - PathService::Get(base::DIR_MODULE, &data_path); - data_path = data_path.AppendASCII(ICU_UTIL_DATA_SHARED_MODULE_NAME); - - HMODULE module = LoadLibrary(data_path.value().c_str()); - if (!module) { - DLOG(ERROR) << "Failed to load " << ICU_UTIL_DATA_SHARED_MODULE_NAME; - return false; - } - - FARPROC addr = GetProcAddress(module, ICU_UTIL_DATA_SYMBOL); - if (!addr) { - DLOG(ERROR) << ICU_UTIL_DATA_SYMBOL << ": not found in " - << ICU_UTIL_DATA_SHARED_MODULE_NAME; - return false; - } - - UErrorCode err = U_ZERO_ERROR; - udata_setCommonData(reinterpret_cast(addr), &err); - return err == U_ZERO_ERROR; -#elif (ICU_UTIL_DATA_IMPL == ICU_UTIL_DATA_STATIC) - // Mac/Linux bundle the ICU data in. - return true; -#elif (ICU_UTIL_DATA_IMPL == ICU_UTIL_DATA_FILE) -#if !defined(OS_MACOSX) - // For now, expect the data file to be alongside the executable. - // This is sufficient while we work on unit tests, but will eventually - // likely live in a data directory. - FilePath data_path; - bool path_ok = PathService::Get(base::DIR_EXE, &data_path); - DCHECK(path_ok); - u_setDataDirectory(data_path.value().c_str()); - // Only look for the packaged data file; - // the default behavior is to look for individual files. - UErrorCode err = U_ZERO_ERROR; - udata_setFileAccess(UDATA_ONLY_PACKAGES, &err); - return err == U_ZERO_ERROR; -#else - // If the ICU data directory is set, ICU won't actually load the data until - // it is needed. This can fail if the process is sandboxed at that time. - // Instead, Mac maps the file in and hands off the data so the sandbox won't - // cause any problems. - - // Chrome doesn't normally shut down ICU, so the mapped data shouldn't ever - // be released. - CR_DEFINE_STATIC_LOCAL(base::MemoryMappedFile, mapped_file, ()); - if (!mapped_file.IsValid()) { - // Assume it is in the framework bundle's Resources directory. - FilePath data_path = - base::mac::PathForFrameworkBundleResource(CFSTR(ICU_UTIL_DATA_FILE_NAME)); - if (data_path.empty()) { - DLOG(ERROR) << ICU_UTIL_DATA_FILE_NAME << " not found in bundle"; - return false; - } - if (!mapped_file.Initialize(data_path)) { - DLOG(ERROR) << "Couldn't mmap " << data_path.value(); - return false; - } - } - UErrorCode err = U_ZERO_ERROR; - udata_setCommonData(const_cast(mapped_file.data()), &err); - return err == U_ZERO_ERROR; -#endif // OS check -#endif -} - -} // namespace icu_util diff --git a/base/i18n/icu_util.h b/base/i18n/icu_util.h deleted file mode 100644 index f6356f1bb6..0000000000 --- a/base/i18n/icu_util.h +++ /dev/null @@ -1,18 +0,0 @@ -// Copyright (c) 2011 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef BASE_I18N_ICU_UTIL_H_ -#define BASE_I18N_ICU_UTIL_H_ - -#include "base/i18n/base_i18n_export.h" - -namespace icu_util { - -// Call this function to load ICU's data tables for the current process. This -// function should be called before ICU is used. -BASE_I18N_EXPORT bool Initialize(); - -} // namespace icu_util - -#endif // BASE_I18N_ICU_UTIL_H_ diff --git a/base/i18n/icu_util_nacl_win64.cc b/base/i18n/icu_util_nacl_win64.cc deleted file mode 100644 index 6e0bb6b2f2..0000000000 --- a/base/i18n/icu_util_nacl_win64.cc +++ /dev/null @@ -1,13 +0,0 @@ -// Copyright (c) 2009 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "base/i18n/icu_util.h" - -namespace icu_util { - -bool Initialize() { - return true; -} - -} // namespace icu_util diff --git a/base/i18n/number_formatting.cc b/base/i18n/number_formatting.cc deleted file mode 100644 index 47aa14cab2..0000000000 --- a/base/i18n/number_formatting.cc +++ /dev/null @@ -1,87 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "base/i18n/number_formatting.h" - -#include "base/format_macros.h" -#include "base/lazy_instance.h" -#include "base/logging.h" -#include "base/memory/scoped_ptr.h" -#include "base/strings/string_util.h" -#include "base/strings/stringprintf.h" -#include "base/strings/utf_string_conversions.h" -#include "third_party/icu/source/common/unicode/ustring.h" -#include "third_party/icu/source/i18n/unicode/numfmt.h" - -namespace base { - -namespace { - -// A simple wrapper around icu::NumberFormat that allows for resetting it -// (as LazyInstance does not). -struct NumberFormatWrapper { - NumberFormatWrapper() { - Reset(); - } - - void Reset() { - // There's no ICU call to destroy a NumberFormat object other than - // operator delete, so use the default Delete, which calls operator delete. - // This can cause problems if a different allocator is used by this file - // than by ICU. - UErrorCode status = U_ZERO_ERROR; - number_format.reset(icu::NumberFormat::createInstance(status)); - DCHECK(U_SUCCESS(status)); - } - - scoped_ptr number_format; -}; - -LazyInstance g_number_format_int = - LAZY_INSTANCE_INITIALIZER; -LazyInstance g_number_format_float = - LAZY_INSTANCE_INITIALIZER; - -} // namespace - -string16 FormatNumber(int64 number) { - icu::NumberFormat* number_format = - g_number_format_int.Get().number_format.get(); - - if (!number_format) { - // As a fallback, just return the raw number in a string. - return UTF8ToUTF16(StringPrintf("%" PRId64, number)); - } - icu::UnicodeString ustr; - number_format->format(number, ustr); - - return string16(ustr.getBuffer(), static_cast(ustr.length())); -} - -string16 FormatDouble(double number, int fractional_digits) { - icu::NumberFormat* number_format = - g_number_format_float.Get().number_format.get(); - - if (!number_format) { - // As a fallback, just return the raw number in a string. - return UTF8ToUTF16(StringPrintf("%f", number)); - } - number_format->setMaximumFractionDigits(fractional_digits); - number_format->setMinimumFractionDigits(fractional_digits); - icu::UnicodeString ustr; - number_format->format(number, ustr); - - return string16(ustr.getBuffer(), static_cast(ustr.length())); -} - -namespace testing { - -void ResetFormatters() { - g_number_format_int.Get().Reset(); - g_number_format_float.Get().Reset(); -} - -} // namespace testing - -} // namespace base diff --git a/base/i18n/number_formatting.h b/base/i18n/number_formatting.h deleted file mode 100644 index 556f9c24d2..0000000000 --- a/base/i18n/number_formatting.h +++ /dev/null @@ -1,34 +0,0 @@ -// Copyright (c) 2011 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef BASE_I18N_NUMBER_FORMATTING_H_ -#define BASE_I18N_NUMBER_FORMATTING_H_ - -#include "base/basictypes.h" -#include "base/i18n/base_i18n_export.h" -#include "base/strings/string16.h" - -namespace base { - -// Return a number formatted with separators in the user's locale. -// Ex: FormatNumber(1234567) -// => "1,234,567" in English, "1.234.567" in German -BASE_I18N_EXPORT string16 FormatNumber(int64 number); - -// Return a number formatted with separators in the user's locale. -// Ex: FormatDouble(1234567.8, 1) -// => "1,234,567.8" in English, "1.234.567,8" in German -BASE_I18N_EXPORT string16 FormatDouble(double number, int fractional_digits); - -namespace testing { - -// Causes cached formatters to be discarded and recreated. Only useful for -// testing. -BASE_I18N_EXPORT void ResetFormatters(); - -} // namespace testing - -} // namespace base - -#endif // BASE_I18N_NUMBER_FORMATTING_H_ diff --git a/base/i18n/number_formatting_unittest.cc b/base/i18n/number_formatting_unittest.cc deleted file mode 100644 index da6397df8a..0000000000 --- a/base/i18n/number_formatting_unittest.cc +++ /dev/null @@ -1,88 +0,0 @@ -// Copyright (c) 2011 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include - -#include "base/i18n/number_formatting.h" -#include "base/i18n/rtl.h" -#include "base/strings/utf_string_conversions.h" -#include "testing/gtest/include/gtest/gtest.h" - -namespace base { -namespace { - -TEST(NumberFormattingTest, FormatNumber) { - static const struct { - int64 number; - const char* expected_english; - const char* expected_german; - } cases[] = { - {0, "0", "0"}, - {1024, "1,024", "1.024"}, - {std::numeric_limits::max(), - "9,223,372,036,854,775,807", "9.223.372.036.854.775.807"}, - {std::numeric_limits::min(), - "-9,223,372,036,854,775,808", "-9.223.372.036.854.775.808"}, - {-42, "-42", "-42"}, - }; - - for (size_t i = 0; i < ARRAYSIZE_UNSAFE(cases); ++i) { - i18n::SetICUDefaultLocale("en"); - testing::ResetFormatters(); - EXPECT_EQ(cases[i].expected_english, - UTF16ToUTF8(FormatNumber(cases[i].number))); - i18n::SetICUDefaultLocale("de"); - testing::ResetFormatters(); - EXPECT_EQ(cases[i].expected_german, - UTF16ToUTF8(FormatNumber(cases[i].number))); - } -} - -TEST(NumberFormattingTest, FormatDouble) { - static const struct { - double number; - int frac_digits; - const char* expected_english; - const char* expected_german; - } cases[] = { - {0.0, 0, "0", "0"}, -#if !defined(OS_ANDROID) - // Bionic can't printf negative zero correctly. - {-0.0, 4, "-0.0000", "-0,0000"}, -#endif - {1024.2, 0, "1,024", "1.024"}, - {-1024.223, 2, "-1,024.22", "-1.024,22"}, - {std::numeric_limits::max(), 6, - "179,769,313,486,232,000,000,000,000,000,000,000,000,000,000,000,000," - "000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000," - "000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000," - "000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000," - "000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000," - "000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000," - "000.000000", - "179.769.313.486.232.000.000.000.000.000.000.000.000.000.000.000.000." - "000.000.000.000.000.000.000.000.000.000.000.000.000.000.000.000.000." - "000.000.000.000.000.000.000.000.000.000.000.000.000.000.000.000.000." - "000.000.000.000.000.000.000.000.000.000.000.000.000.000.000.000.000." - "000.000.000.000.000.000.000.000.000.000.000.000.000.000.000.000.000." - "000.000.000.000.000.000.000.000.000.000.000.000.000.000.000.000.000." - "000,000000"}, - {std::numeric_limits::min(), 2, "0.00", "0,00"}, - {-42.7, 3, "-42.700", "-42,700"}, - }; - - for (size_t i = 0; i < ARRAYSIZE_UNSAFE(cases); ++i) { - i18n::SetICUDefaultLocale("en"); - testing::ResetFormatters(); - EXPECT_EQ(cases[i].expected_english, - UTF16ToUTF8(FormatDouble(cases[i].number, cases[i].frac_digits))); - i18n::SetICUDefaultLocale("de"); - testing::ResetFormatters(); - EXPECT_EQ(cases[i].expected_german, - UTF16ToUTF8(FormatDouble(cases[i].number, cases[i].frac_digits))); - } -} - -} // namespace -} // namespace base diff --git a/base/i18n/rtl.cc b/base/i18n/rtl.cc deleted file mode 100644 index d9818e800e..0000000000 --- a/base/i18n/rtl.cc +++ /dev/null @@ -1,383 +0,0 @@ -// Copyright (c) 2011 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "base/i18n/rtl.h" - -#include "base/files/file_path.h" -#include "base/logging.h" -#include "base/strings/string_util.h" -#include "base/strings/sys_string_conversions.h" -#include "base/strings/utf_string_conversions.h" -#include "third_party/icu/source/common/unicode/locid.h" -#include "third_party/icu/source/common/unicode/uchar.h" -#include "third_party/icu/source/common/unicode/uscript.h" -#include "third_party/icu/source/i18n/unicode/coll.h" - -#if defined(TOOLKIT_GTK) -#include -#endif - -namespace { - -// Extract language, country and variant, but ignore keywords. For example, -// en-US, ca@valencia, ca-ES@valencia. -std::string GetLocaleString(const icu::Locale& locale) { - const char* language = locale.getLanguage(); - const char* country = locale.getCountry(); - const char* variant = locale.getVariant(); - - std::string result = - (language != NULL && *language != '\0') ? language : "und"; - - if (country != NULL && *country != '\0') { - result += '-'; - result += country; - } - - if (variant != NULL && *variant != '\0') { - std::string variant_str(variant); - StringToLowerASCII(&variant_str); - result += '@' + variant_str; - } - - return result; -} - -// Returns LEFT_TO_RIGHT or RIGHT_TO_LEFT if |character| has strong -// directionality, returns UNKNOWN_DIRECTION if it doesn't. Please refer to -// http://unicode.org/reports/tr9/ for more information. -base::i18n::TextDirection GetCharacterDirection(UChar32 character) { - // Now that we have the character, we use ICU in order to query for the - // appropriate Unicode BiDi character type. - int32_t property = u_getIntPropertyValue(character, UCHAR_BIDI_CLASS); - if ((property == U_RIGHT_TO_LEFT) || - (property == U_RIGHT_TO_LEFT_ARABIC) || - (property == U_RIGHT_TO_LEFT_EMBEDDING) || - (property == U_RIGHT_TO_LEFT_OVERRIDE)) { - return base::i18n::RIGHT_TO_LEFT; - } else if ((property == U_LEFT_TO_RIGHT) || - (property == U_LEFT_TO_RIGHT_EMBEDDING) || - (property == U_LEFT_TO_RIGHT_OVERRIDE)) { - return base::i18n::LEFT_TO_RIGHT; - } - return base::i18n::UNKNOWN_DIRECTION; -} - -} // namespace - -namespace base { -namespace i18n { - -// Represents the locale-specific ICU text direction. -static TextDirection g_icu_text_direction = UNKNOWN_DIRECTION; - -// Convert the ICU default locale to a string. -std::string GetConfiguredLocale() { - return GetLocaleString(icu::Locale::getDefault()); -} - -// Convert the ICU canonicalized locale to a string. -std::string GetCanonicalLocale(const char* locale) { - return GetLocaleString(icu::Locale::createCanonical(locale)); -} - -// Convert Chrome locale name to ICU locale name -std::string ICULocaleName(const std::string& locale_string) { - // If not Spanish, just return it. - if (locale_string.substr(0, 2) != "es") - return locale_string; - // Expand es to es-ES. - if (LowerCaseEqualsASCII(locale_string, "es")) - return "es-ES"; - // Map es-419 (Latin American Spanish) to es-FOO depending on the system - // locale. If it's es-RR other than es-ES, map to es-RR. Otherwise, map - // to es-MX (the most populous in Spanish-speaking Latin America). - if (LowerCaseEqualsASCII(locale_string, "es-419")) { - const icu::Locale& locale = icu::Locale::getDefault(); - std::string language = locale.getLanguage(); - const char* country = locale.getCountry(); - if (LowerCaseEqualsASCII(language, "es") && - !LowerCaseEqualsASCII(country, "es")) { - language += '-'; - language += country; - return language; - } - return "es-MX"; - } - // Currently, Chrome has only "es" and "es-419", but later we may have - // more specific "es-RR". - return locale_string; -} - -void SetICUDefaultLocale(const std::string& locale_string) { - icu::Locale locale(ICULocaleName(locale_string).c_str()); - UErrorCode error_code = U_ZERO_ERROR; - icu::Locale::setDefault(locale, error_code); - // This return value is actually bogus because Locale object is - // an ID and setDefault seems to always succeed (regardless of the - // presence of actual locale data). However, - // it does not hurt to have it as a sanity check. - DCHECK(U_SUCCESS(error_code)); - g_icu_text_direction = UNKNOWN_DIRECTION; -} - -bool IsRTL() { -#if defined(TOOLKIT_GTK) - GtkTextDirection gtk_dir = gtk_widget_get_default_direction(); - return gtk_dir == GTK_TEXT_DIR_RTL; -#else - return ICUIsRTL(); -#endif -} - -bool ICUIsRTL() { - if (g_icu_text_direction == UNKNOWN_DIRECTION) { - const icu::Locale& locale = icu::Locale::getDefault(); - g_icu_text_direction = GetTextDirectionForLocale(locale.getName()); - } - return g_icu_text_direction == RIGHT_TO_LEFT; -} - -TextDirection GetTextDirectionForLocale(const char* locale_name) { - UErrorCode status = U_ZERO_ERROR; - ULayoutType layout_dir = uloc_getCharacterOrientation(locale_name, &status); - DCHECK(U_SUCCESS(status)); - // Treat anything other than RTL as LTR. - return (layout_dir != ULOC_LAYOUT_RTL) ? LEFT_TO_RIGHT : RIGHT_TO_LEFT; -} - -TextDirection GetFirstStrongCharacterDirection(const string16& text) { - const UChar* string = text.c_str(); - size_t length = text.length(); - size_t position = 0; - while (position < length) { - UChar32 character; - size_t next_position = position; - U16_NEXT(string, next_position, length, character); - TextDirection direction = GetCharacterDirection(character); - if (direction != UNKNOWN_DIRECTION) - return direction; - position = next_position; - } - return LEFT_TO_RIGHT; -} - -TextDirection GetStringDirection(const string16& text) { - const UChar* string = text.c_str(); - size_t length = text.length(); - size_t position = 0; - - TextDirection result(UNKNOWN_DIRECTION); - while (position < length) { - UChar32 character; - size_t next_position = position; - U16_NEXT(string, next_position, length, character); - TextDirection direction = GetCharacterDirection(character); - if (direction != UNKNOWN_DIRECTION) { - if (result != UNKNOWN_DIRECTION && result != direction) - return UNKNOWN_DIRECTION; - result = direction; - } - position = next_position; - } - - // Handle the case of a string not containing any strong directionality - // characters defaulting to LEFT_TO_RIGHT. - if (result == UNKNOWN_DIRECTION) - return LEFT_TO_RIGHT; - - return result; -} - -#if defined(OS_WIN) -bool AdjustStringForLocaleDirection(string16* text) { - if (!IsRTL() || text->empty()) - return false; - - // Marking the string as LTR if the locale is RTL and the string does not - // contain strong RTL characters. Otherwise, mark the string as RTL. - bool has_rtl_chars = StringContainsStrongRTLChars(*text); - if (!has_rtl_chars) - WrapStringWithLTRFormatting(text); - else - WrapStringWithRTLFormatting(text); - - return true; -} - -bool UnadjustStringForLocaleDirection(string16* text) { - if (!IsRTL() || text->empty()) - return false; - - *text = StripWrappingBidiControlCharacters(*text); - return true; -} -#else -bool AdjustStringForLocaleDirection(string16* text) { - // On OS X & GTK the directionality of a label is determined by the first - // strongly directional character. - // However, we want to make sure that in an LTR-language-UI all strings are - // left aligned and vice versa. - // A problem can arise if we display a string which starts with user input. - // User input may be of the opposite directionality to the UI. So the whole - // string will be displayed in the opposite directionality, e.g. if we want to - // display in an LTR UI [such as US English]: - // - // EMAN_NOISNETXE is now installed. - // - // Since EXTENSION_NAME begins with a strong RTL char, the label's - // directionality will be set to RTL and the string will be displayed visually - // as: - // - // .is now installed EMAN_NOISNETXE - // - // In order to solve this issue, we prepend an LRM to the string. An LRM is a - // strongly directional LTR char. - // We also append an LRM at the end, which ensures that we're in an LTR - // context. - - // Unlike Windows, Linux and OS X can correctly display RTL glyphs out of the - // box so there is no issue with displaying zero-width bidi control characters - // on any system. Thus no need for the !IsRTL() check here. - if (text->empty()) - return false; - - bool ui_direction_is_rtl = IsRTL(); - - bool has_rtl_chars = StringContainsStrongRTLChars(*text); - if (!ui_direction_is_rtl && has_rtl_chars) { - WrapStringWithRTLFormatting(text); - text->insert(0U, 1U, kLeftToRightMark); - text->push_back(kLeftToRightMark); - } else if (ui_direction_is_rtl && has_rtl_chars) { - WrapStringWithRTLFormatting(text); - text->insert(0U, 1U, kRightToLeftMark); - text->push_back(kRightToLeftMark); - } else if (ui_direction_is_rtl) { - WrapStringWithLTRFormatting(text); - text->insert(0U, 1U, kRightToLeftMark); - text->push_back(kRightToLeftMark); - } else { - return false; - } - - return true; -} - -bool UnadjustStringForLocaleDirection(string16* text) { - if (text->empty()) - return false; - - size_t begin_index = 0; - char16 begin = text->at(begin_index); - if (begin == kLeftToRightMark || - begin == kRightToLeftMark) { - ++begin_index; - } - - size_t end_index = text->length() - 1; - char16 end = text->at(end_index); - if (end == kLeftToRightMark || - end == kRightToLeftMark) { - --end_index; - } - - string16 unmarked_text = - text->substr(begin_index, end_index - begin_index + 1); - *text = StripWrappingBidiControlCharacters(unmarked_text); - return true; -} - -#endif // !OS_WIN - -bool StringContainsStrongRTLChars(const string16& text) { - const UChar* string = text.c_str(); - size_t length = text.length(); - size_t position = 0; - while (position < length) { - UChar32 character; - size_t next_position = position; - U16_NEXT(string, next_position, length, character); - - // Now that we have the character, we use ICU in order to query for the - // appropriate Unicode BiDi character type. - int32_t property = u_getIntPropertyValue(character, UCHAR_BIDI_CLASS); - if ((property == U_RIGHT_TO_LEFT) || (property == U_RIGHT_TO_LEFT_ARABIC)) - return true; - - position = next_position; - } - - return false; -} - -void WrapStringWithLTRFormatting(string16* text) { - if (text->empty()) - return; - - // Inserting an LRE (Left-To-Right Embedding) mark as the first character. - text->insert(0U, 1U, kLeftToRightEmbeddingMark); - - // Inserting a PDF (Pop Directional Formatting) mark as the last character. - text->push_back(kPopDirectionalFormatting); -} - -void WrapStringWithRTLFormatting(string16* text) { - if (text->empty()) - return; - - // Inserting an RLE (Right-To-Left Embedding) mark as the first character. - text->insert(0U, 1U, kRightToLeftEmbeddingMark); - - // Inserting a PDF (Pop Directional Formatting) mark as the last character. - text->push_back(kPopDirectionalFormatting); -} - -void WrapPathWithLTRFormatting(const FilePath& path, - string16* rtl_safe_path) { - // Wrap the overall path with LRE-PDF pair which essentialy marks the - // string as a Left-To-Right string. - // Inserting an LRE (Left-To-Right Embedding) mark as the first character. - rtl_safe_path->push_back(kLeftToRightEmbeddingMark); -#if defined(OS_MACOSX) - rtl_safe_path->append(UTF8ToUTF16(path.value())); -#elif defined(OS_WIN) - rtl_safe_path->append(path.value()); -#else // defined(OS_POSIX) && !defined(OS_MACOSX) - std::wstring wide_path = base::SysNativeMBToWide(path.value()); - rtl_safe_path->append(WideToUTF16(wide_path)); -#endif - // Inserting a PDF (Pop Directional Formatting) mark as the last character. - rtl_safe_path->push_back(kPopDirectionalFormatting); -} - -string16 GetDisplayStringInLTRDirectionality(const string16& text) { - // Always wrap the string in RTL UI (it may be appended to RTL string). - // Also wrap strings with an RTL first strong character direction in LTR UI. - if (IsRTL() || GetFirstStrongCharacterDirection(text) == RIGHT_TO_LEFT) { - string16 text_mutable(text); - WrapStringWithLTRFormatting(&text_mutable); - return text_mutable; - } - return text; -} - -string16 StripWrappingBidiControlCharacters(const string16& text) { - if (text.empty()) - return text; - size_t begin_index = 0; - char16 begin = text[begin_index]; - if (begin == kLeftToRightEmbeddingMark || - begin == kRightToLeftEmbeddingMark || - begin == kLeftToRightOverride || - begin == kRightToLeftOverride) - ++begin_index; - size_t end_index = text.length() - 1; - if (text[end_index] == kPopDirectionalFormatting) - --end_index; - return text.substr(begin_index, end_index - begin_index + 1); -} - -} // namespace i18n -} // namespace base diff --git a/base/i18n/rtl.h b/base/i18n/rtl.h deleted file mode 100644 index c80d2f8577..0000000000 --- a/base/i18n/rtl.h +++ /dev/null @@ -1,147 +0,0 @@ -// Copyright (c) 2011 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef BASE_I18N_RTL_H_ -#define BASE_I18N_RTL_H_ - -#include - -#include "base/compiler_specific.h" -#include "base/i18n/base_i18n_export.h" -#include "base/strings/string16.h" -#include "build/build_config.h" - -namespace base { - -class FilePath; - -namespace i18n { - -const char16 kRightToLeftMark = 0x200F; -const char16 kLeftToRightMark = 0x200E; -const char16 kLeftToRightEmbeddingMark = 0x202A; -const char16 kRightToLeftEmbeddingMark = 0x202B; -const char16 kPopDirectionalFormatting = 0x202C; -const char16 kLeftToRightOverride = 0x202D; -const char16 kRightToLeftOverride = 0x202E; - -// Locale.java mirrored this enum TextDirection. Please keep in sync. -enum TextDirection { - UNKNOWN_DIRECTION = 0, - RIGHT_TO_LEFT = 1, - LEFT_TO_RIGHT = 2, - TEXT_DIRECTION_NUM_DIRECTIONS = 3, -}; - -// Get the locale that the currently running process has been configured to use. -// The return value is of the form language[-country] (e.g., en-US) where the -// language is the 2 or 3 letter code from ISO-639. -BASE_I18N_EXPORT std::string GetConfiguredLocale(); - -// Canonicalize a string (eg. a POSIX locale string) to a Chrome locale name. -BASE_I18N_EXPORT std::string GetCanonicalLocale(const char* locale); - -// Sets the default locale of ICU. -// Once the application locale of Chrome in GetApplicationLocale is determined, -// the default locale of ICU need to be changed to match the application locale -// so that ICU functions work correctly in a locale-dependent manner. -// This is handy in that we don't have to call GetApplicationLocale() -// everytime we call locale-dependent ICU APIs as long as we make sure -// that this is called before any locale-dependent API is called. -BASE_I18N_EXPORT void SetICUDefaultLocale(const std::string& locale_string); - -// Returns true if the application text direction is right-to-left. -BASE_I18N_EXPORT bool IsRTL(); - -// Returns whether the text direction for the default ICU locale is RTL. This -// assumes that SetICUDefaultLocale has been called to set the default locale to -// the UI locale of Chrome. -// NOTE: Generally, you should call IsRTL() instead of this. -BASE_I18N_EXPORT bool ICUIsRTL(); - -// Returns the text direction for |locale_name|. -BASE_I18N_EXPORT TextDirection GetTextDirectionForLocale( - const char* locale_name); - -// Given the string in |text|, returns the directionality of the first -// character with strong directionality in the string. If no character in the -// text has strong directionality, LEFT_TO_RIGHT is returned. The Bidi -// character types L, LRE, LRO, R, AL, RLE, and RLO are considered as strong -// directionality characters. Please refer to http://unicode.org/reports/tr9/ -// for more information. -BASE_I18N_EXPORT TextDirection GetFirstStrongCharacterDirection( - const string16& text); - -// Given the string in |text|, returns LEFT_TO_RIGHT or RIGHT_TO_LEFT if all the -// strong directionality characters in the string are of the same -// directionality. It returns UNKNOWN_DIRECTION if the string contains a mix of -// LTR and RTL strong directionality characters. Defaults to LEFT_TO_RIGHT if -// the string does not contain directionality characters. Please refer to -// http://unicode.org/reports/tr9/ for more information. -BASE_I18N_EXPORT TextDirection GetStringDirection(const string16& text); - -// Given the string in |text|, this function modifies the string in place with -// the appropriate Unicode formatting marks that mark the string direction -// (either left-to-right or right-to-left). The function checks both the current -// locale and the contents of the string in order to determine the direction of -// the returned string. The function returns true if the string in |text| was -// properly adjusted. -// -// Certain LTR strings are not rendered correctly when the context is RTL. For -// example, the string "Foo!" will appear as "!Foo" if it is rendered as is in -// an RTL context. Calling this function will make sure the returned localized -// string is always treated as a right-to-left string. This is done by -// inserting certain Unicode formatting marks into the returned string. -// -// ** Notes about the Windows version of this function: -// TODO(idana) bug 6806: this function adjusts the string in question only -// if the current locale is right-to-left. The function does not take care of -// the opposite case (an RTL string displayed in an LTR context) since -// adjusting the string involves inserting Unicode formatting characters that -// Windows does not handle well unless right-to-left language support is -// installed. Since the English version of Windows doesn't have right-to-left -// language support installed by default, inserting the direction Unicode mark -// results in Windows displaying squares. -BASE_I18N_EXPORT bool AdjustStringForLocaleDirection(string16* text); - -// Undoes the actions of the above function (AdjustStringForLocaleDirection). -BASE_I18N_EXPORT bool UnadjustStringForLocaleDirection(string16* text); - -// Returns true if the string contains at least one character with strong right -// to left directionality; that is, a character with either R or AL Unicode -// BiDi character type. -BASE_I18N_EXPORT bool StringContainsStrongRTLChars(const string16& text); - -// Wraps a string with an LRE-PDF pair which essentialy marks the string as a -// Left-To-Right string. Doing this is useful in order to make sure LTR -// strings are rendered properly in an RTL context. -BASE_I18N_EXPORT void WrapStringWithLTRFormatting(string16* text); - -// Wraps a string with an RLE-PDF pair which essentialy marks the string as a -// Right-To-Left string. Doing this is useful in order to make sure RTL -// strings are rendered properly in an LTR context. -BASE_I18N_EXPORT void WrapStringWithRTLFormatting(string16* text); - -// Wraps file path to get it to display correctly in RTL UI. All filepaths -// should be passed through this function before display in UI for RTL locales. -BASE_I18N_EXPORT void WrapPathWithLTRFormatting(const FilePath& path, - string16* rtl_safe_path); - -// Return the string in |text| wrapped with LRE (Left-To-Right Embedding) and -// PDF (Pop Directional Formatting) marks, if needed for UI display purposes. -BASE_I18N_EXPORT string16 GetDisplayStringInLTRDirectionality( - const string16& text) WARN_UNUSED_RESULT; - -// Strip the beginning (U+202A..U+202B, U+202D..U+202E) and/or ending (U+202C) -// explicit bidi control characters from |text|, if there are any. Otherwise, -// return the text itself. Explicit bidi control characters display and have -// semantic effect. They can be deleted so they might not always appear in a -// pair. -BASE_I18N_EXPORT string16 StripWrappingBidiControlCharacters( - const string16& text) WARN_UNUSED_RESULT; - -} // namespace i18n -} // namespace base - -#endif // BASE_I18N_RTL_H_ diff --git a/base/i18n/rtl_unittest.cc b/base/i18n/rtl_unittest.cc deleted file mode 100644 index 58772b0583..0000000000 --- a/base/i18n/rtl_unittest.cc +++ /dev/null @@ -1,385 +0,0 @@ -// Copyright (c) 2011 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "base/i18n/rtl.h" - -#include - -#include "base/files/file_path.h" -#include "base/strings/string_util.h" -#include "base/strings/sys_string_conversions.h" -#include "base/strings/utf_string_conversions.h" -#include "testing/gtest/include/gtest/gtest.h" -#include "testing/platform_test.h" -#include "third_party/icu/source/i18n/unicode/usearch.h" - -#if defined(TOOLKIT_GTK) -#include -#endif - -namespace base { -namespace i18n { - -namespace { - -// A test utility function to set the application default text direction. -void SetRTL(bool rtl) { - // Override the current locale/direction. - SetICUDefaultLocale(rtl ? "he" : "en"); -#if defined(TOOLKIT_GTK) - // Do the same for GTK, which does not rely on the ICU default locale. - gtk_widget_set_default_direction(rtl ? GTK_TEXT_DIR_RTL : GTK_TEXT_DIR_LTR); -#endif - EXPECT_EQ(rtl, IsRTL()); -} - -} // namespace - -class RTLTest : public PlatformTest { -}; - -TEST_F(RTLTest, GetFirstStrongCharacterDirection) { - struct { - const wchar_t* text; - TextDirection direction; - } cases[] = { - // Test pure LTR string. - { L"foo bar", LEFT_TO_RIGHT }, - // Test bidi string in which the first character with strong directionality - // is a character with type L. - { L"foo \x05d0 bar", LEFT_TO_RIGHT }, - // Test bidi string in which the first character with strong directionality - // is a character with type R. - { L"\x05d0 foo bar", RIGHT_TO_LEFT }, - // Test bidi string which starts with a character with weak directionality - // and in which the first character with strong directionality is a - // character with type L. - { L"!foo \x05d0 bar", LEFT_TO_RIGHT }, - // Test bidi string which starts with a character with weak directionality - // and in which the first character with strong directionality is a - // character with type R. - { L",\x05d0 foo bar", RIGHT_TO_LEFT }, - // Test bidi string in which the first character with strong directionality - // is a character with type LRE. - { L"\x202a \x05d0 foo bar", LEFT_TO_RIGHT }, - // Test bidi string in which the first character with strong directionality - // is a character with type LRO. - { L"\x202d \x05d0 foo bar", LEFT_TO_RIGHT }, - // Test bidi string in which the first character with strong directionality - // is a character with type RLE. - { L"\x202b foo \x05d0 bar", RIGHT_TO_LEFT }, - // Test bidi string in which the first character with strong directionality - // is a character with type RLO. - { L"\x202e foo \x05d0 bar", RIGHT_TO_LEFT }, - // Test bidi string in which the first character with strong directionality - // is a character with type AL. - { L"\x0622 foo \x05d0 bar", RIGHT_TO_LEFT }, - // Test a string without strong directionality characters. - { L",!.{}", LEFT_TO_RIGHT }, - // Test empty string. - { L"", LEFT_TO_RIGHT }, - // Test characters in non-BMP (e.g. Phoenician letters. Please refer to - // http://demo.icu-project.org/icu-bin/ubrowse?scr=151&b=10910 for more - // information). - { -#if defined(WCHAR_T_IS_UTF32) - L" ! \x10910" L"abc 123", -#elif defined(WCHAR_T_IS_UTF16) - L" ! \xd802\xdd10" L"abc 123", -#else -#error wchar_t should be either UTF-16 or UTF-32 -#endif - RIGHT_TO_LEFT }, - { -#if defined(WCHAR_T_IS_UTF32) - L" ! \x10401" L"abc 123", -#elif defined(WCHAR_T_IS_UTF16) - L" ! \xd801\xdc01" L"abc 123", -#else -#error wchar_t should be either UTF-16 or UTF-32 -#endif - LEFT_TO_RIGHT }, - }; - - for (size_t i = 0; i < ARRAYSIZE_UNSAFE(cases); ++i) - EXPECT_EQ(cases[i].direction, - GetFirstStrongCharacterDirection(WideToUTF16(cases[i].text))); -} - -TEST_F(RTLTest, GetStringDirection) { - struct { - const wchar_t* text; - TextDirection direction; - } cases[] = { - // Test pure LTR string. - { L"foobar", LEFT_TO_RIGHT }, - { L".foobar", LEFT_TO_RIGHT }, - { L"foo, bar", LEFT_TO_RIGHT }, - // Test pure LTR with strong directionality characters of type LRE. - { L"\x202a\x202a", LEFT_TO_RIGHT }, - { L".\x202a\x202a", LEFT_TO_RIGHT }, - { L"\x202a, \x202a", LEFT_TO_RIGHT }, - // Test pure LTR with strong directionality characters of type LRO. - { L"\x202d\x202d", LEFT_TO_RIGHT }, - { L".\x202d\x202d", LEFT_TO_RIGHT }, - { L"\x202d, \x202d", LEFT_TO_RIGHT }, - // Test pure LTR with various types of strong directionality characters. - { L"foo \x202a\x202d", LEFT_TO_RIGHT }, - { L".\x202d foo \x202a", LEFT_TO_RIGHT }, - { L"\x202a, \x202d foo", LEFT_TO_RIGHT }, - // Test pure RTL with strong directionality characters of type R. - { L"\x05d0\x05d0", RIGHT_TO_LEFT }, - { L".\x05d0\x05d0", RIGHT_TO_LEFT }, - { L"\x05d0, \x05d0", RIGHT_TO_LEFT }, - // Test pure RTL with strong directionality characters of type RLE. - { L"\x202b\x202b", RIGHT_TO_LEFT }, - { L".\x202b\x202b", RIGHT_TO_LEFT }, - { L"\x202b, \x202b", RIGHT_TO_LEFT }, - // Test pure RTL with strong directionality characters of type RLO. - { L"\x202e\x202e", RIGHT_TO_LEFT }, - { L".\x202e\x202e", RIGHT_TO_LEFT }, - { L"\x202e, \x202e", RIGHT_TO_LEFT }, - // Test pure RTL with strong directionality characters of type AL. - { L"\x0622\x0622", RIGHT_TO_LEFT }, - { L".\x0622\x0622", RIGHT_TO_LEFT }, - { L"\x0622, \x0622", RIGHT_TO_LEFT }, - // Test pure RTL with various types of strong directionality characters. - { L"\x05d0\x202b\x202e\x0622", RIGHT_TO_LEFT }, - { L".\x202b\x202e\x0622\x05d0", RIGHT_TO_LEFT }, - { L"\x0622\x202e, \x202b\x05d0", RIGHT_TO_LEFT }, - // Test bidi strings. - { L"foo \x05d0 bar", UNKNOWN_DIRECTION }, - { L"\x202b foo bar", UNKNOWN_DIRECTION }, - { L"!foo \x0622 bar", UNKNOWN_DIRECTION }, - { L"\x202a\x202b", UNKNOWN_DIRECTION }, - { L"\x202e\x202d", UNKNOWN_DIRECTION }, - { L"\x0622\x202a", UNKNOWN_DIRECTION }, - { L"\x202d\x05d0", UNKNOWN_DIRECTION }, - // Test a string without strong directionality characters. - { L",!.{}", LEFT_TO_RIGHT }, - // Test empty string. - { L"", LEFT_TO_RIGHT }, - { -#if defined(WCHAR_T_IS_UTF32) - L" ! \x10910" L"abc 123", -#elif defined(WCHAR_T_IS_UTF16) - L" ! \xd802\xdd10" L"abc 123", -#else -#error wchar_t should be either UTF-16 or UTF-32 -#endif - UNKNOWN_DIRECTION }, - { -#if defined(WCHAR_T_IS_UTF32) - L" ! \x10401" L"abc 123", -#elif defined(WCHAR_T_IS_UTF16) - L" ! \xd801\xdc01" L"abc 123", -#else -#error wchar_t should be either UTF-16 or UTF-32 -#endif - LEFT_TO_RIGHT }, - }; - - for (size_t i = 0; i < ARRAYSIZE_UNSAFE(cases); ++i) - EXPECT_EQ(cases[i].direction, - GetStringDirection(WideToUTF16(cases[i].text))); -} - -TEST_F(RTLTest, WrapPathWithLTRFormatting) { - const wchar_t* cases[] = { - // Test common path, such as "c:\foo\bar". - L"c:/foo/bar", - // Test path with file name, such as "c:\foo\bar\test.jpg". - L"c:/foo/bar/test.jpg", - // Test path ending with punctuation, such as "c:\(foo)\bar.". - L"c:/(foo)/bar.", - // Test path ending with separator, such as "c:\foo\bar\". - L"c:/foo/bar/", - // Test path with RTL character. - L"c:/\x05d0", - // Test path with 2 level RTL directory names. - L"c:/\x05d0/\x0622", - // Test path with mixed RTL/LTR directory names and ending with punctuation. - L"c:/\x05d0/\x0622/(foo)/b.a.r.", - // Test path without driver name, such as "/foo/bar/test/jpg". - L"/foo/bar/test.jpg", - // Test path start with current directory, such as "./foo". - L"./foo", - // Test path start with parent directory, such as "../foo/bar.jpg". - L"../foo/bar.jpg", - // Test absolute path, such as "//foo/bar.jpg". - L"//foo/bar.jpg", - // Test path with mixed RTL/LTR directory names. - L"c:/foo/\x05d0/\x0622/\x05d1.jpg", - // Test empty path. - L"" - }; - - for (size_t i = 0; i < arraysize(cases); ++i) { - FilePath path; -#if defined(OS_WIN) - std::wstring win_path(cases[i]); - std::replace(win_path.begin(), win_path.end(), '/', '\\'); - path = FilePath(win_path); - std::wstring wrapped_expected = - std::wstring(L"\x202a") + win_path + L"\x202c"; -#else - path = FilePath(base::SysWideToNativeMB(cases[i])); - std::wstring wrapped_expected = - std::wstring(L"\x202a") + cases[i] + L"\x202c"; -#endif - string16 localized_file_path_string; - WrapPathWithLTRFormatting(path, &localized_file_path_string); - - std::wstring wrapped_actual = UTF16ToWide(localized_file_path_string); - EXPECT_EQ(wrapped_expected, wrapped_actual); - } -} - -TEST_F(RTLTest, WrapString) { - const wchar_t* cases[] = { - L" . ", - L"abc", - L"a" L"\x5d0\x5d1", - L"a" L"\x5d1" L"b", - L"\x5d0\x5d1\x5d2", - L"\x5d0\x5d1" L"a", - L"\x5d0" L"a" L"\x5d1", - }; - - const bool was_rtl = IsRTL(); - - for (size_t i = 0; i < 2; ++i) { - // Toggle the application default text direction (to try each direction). - SetRTL(!IsRTL()); - - string16 empty; - WrapStringWithLTRFormatting(&empty); - EXPECT_TRUE(empty.empty()); - WrapStringWithRTLFormatting(&empty); - EXPECT_TRUE(empty.empty()); - - for (size_t i = 0; i < arraysize(cases); ++i) { - string16 input = WideToUTF16(cases[i]); - string16 ltr_wrap = input; - WrapStringWithLTRFormatting(<r_wrap); - EXPECT_EQ(ltr_wrap[0], kLeftToRightEmbeddingMark); - EXPECT_EQ(ltr_wrap.substr(1, ltr_wrap.length() - 2), input); - EXPECT_EQ(ltr_wrap[ltr_wrap.length() -1], kPopDirectionalFormatting); - - string16 rtl_wrap = input; - WrapStringWithRTLFormatting(&rtl_wrap); - EXPECT_EQ(rtl_wrap[0], kRightToLeftEmbeddingMark); - EXPECT_EQ(rtl_wrap.substr(1, rtl_wrap.length() - 2), input); - EXPECT_EQ(rtl_wrap[rtl_wrap.length() -1], kPopDirectionalFormatting); - } - } - - EXPECT_EQ(was_rtl, IsRTL()); -} - -TEST_F(RTLTest, GetDisplayStringInLTRDirectionality) { - struct { - const wchar_t* path; - bool wrap_ltr; - bool wrap_rtl; - } cases[] = { - { L"test", false, true }, - { L"test.html", false, true }, - { L"\x05d0\x05d1\x05d2", true, true }, - { L"\x05d0\x05d1\x05d2.txt", true, true }, - { L"\x05d0" L"abc", true, true }, - { L"\x05d0" L"abc.txt", true, true }, - { L"abc\x05d0\x05d1", false, true }, - { L"abc\x05d0\x05d1.jpg", false, true }, - }; - - const bool was_rtl = IsRTL(); - - for (size_t i = 0; i < 2; ++i) { - // Toggle the application default text direction (to try each direction). - SetRTL(!IsRTL()); - for (size_t i = 0; i < ARRAYSIZE_UNSAFE(cases); ++i) { - string16 input = WideToUTF16(cases[i].path); - string16 output = GetDisplayStringInLTRDirectionality(input); - // Test the expected wrapping behavior for the current UI directionality. - if (IsRTL() ? cases[i].wrap_rtl : cases[i].wrap_ltr) - EXPECT_NE(output, input); - else - EXPECT_EQ(output, input); - } - } - - EXPECT_EQ(was_rtl, IsRTL()); -} - -TEST_F(RTLTest, GetTextDirection) { - EXPECT_EQ(RIGHT_TO_LEFT, GetTextDirectionForLocale("ar")); - EXPECT_EQ(RIGHT_TO_LEFT, GetTextDirectionForLocale("ar_EG")); - EXPECT_EQ(RIGHT_TO_LEFT, GetTextDirectionForLocale("he")); - EXPECT_EQ(RIGHT_TO_LEFT, GetTextDirectionForLocale("he_IL")); - // iw is an obsolete code for Hebrew. - EXPECT_EQ(RIGHT_TO_LEFT, GetTextDirectionForLocale("iw")); - // Although we're not yet localized to Farsi and Urdu, we - // do have the text layout direction information for them. - EXPECT_EQ(RIGHT_TO_LEFT, GetTextDirectionForLocale("fa")); - EXPECT_EQ(RIGHT_TO_LEFT, GetTextDirectionForLocale("ur")); -#if 0 - // Enable these when we include the minimal locale data for Azerbaijani - // written in Arabic and Dhivehi. At the moment, our copy of - // ICU data does not have entries for them. - EXPECT_EQ(RIGHT_TO_LEFT, GetTextDirectionForLocale("az_Arab")); - // Dhivehi that uses Thaana script. - EXPECT_EQ(RIGHT_TO_LEFT, GetTextDirectionForLocale("dv")); -#endif - EXPECT_EQ(LEFT_TO_RIGHT, GetTextDirectionForLocale("en")); - // Chinese in China with '-'. - EXPECT_EQ(LEFT_TO_RIGHT, GetTextDirectionForLocale("zh-CN")); - // Filipino : 3-letter code - EXPECT_EQ(LEFT_TO_RIGHT, GetTextDirectionForLocale("fil")); - // Russian - EXPECT_EQ(LEFT_TO_RIGHT, GetTextDirectionForLocale("ru")); - // Japanese that uses multiple scripts - EXPECT_EQ(LEFT_TO_RIGHT, GetTextDirectionForLocale("ja")); -} - -TEST_F(RTLTest, UnadjustStringForLocaleDirection) { - // These test strings are borrowed from WrapPathWithLTRFormatting - const wchar_t* cases[] = { - L"foo bar", - L"foo \x05d0 bar", - L"\x05d0 foo bar", - L"!foo \x05d0 bar", - L",\x05d0 foo bar", - L"\x202a \x05d0 foo bar", - L"\x202d \x05d0 foo bar", - L"\x202b foo \x05d0 bar", - L"\x202e foo \x05d0 bar", - L"\x0622 foo \x05d0 bar", - }; - - const bool was_rtl = IsRTL(); - - for (size_t i = 0; i < 2; ++i) { - // Toggle the application default text direction (to try each direction). - SetRTL(!IsRTL()); - - for (size_t i = 0; i < arraysize(cases); ++i) { - string16 test_case = WideToUTF16(cases[i]); - string16 adjusted_string = test_case; - - if (!AdjustStringForLocaleDirection(&adjusted_string)) - continue; - - EXPECT_NE(test_case, adjusted_string); - EXPECT_TRUE(UnadjustStringForLocaleDirection(&adjusted_string)); - EXPECT_EQ(test_case, adjusted_string) << " for test case [" << test_case - << "] with IsRTL() == " << IsRTL(); - } - } - - EXPECT_EQ(was_rtl, IsRTL()); -} - -} // namespace i18n -} // namespace base diff --git a/base/i18n/string_compare.cc b/base/i18n/string_compare.cc deleted file mode 100644 index 1ac7284359..0000000000 --- a/base/i18n/string_compare.cc +++ /dev/null @@ -1,29 +0,0 @@ -// Copyright (c) 2013 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "base/i18n/string_compare.h" - -#include "base/logging.h" -#include "base/strings/utf_string_conversions.h" - -namespace base { -namespace i18n { - -// Compares the character data stored in two different string16 strings by -// specified Collator instance. -UCollationResult CompareString16WithCollator(const icu::Collator* collator, - const string16& lhs, - const string16& rhs) { - DCHECK(collator); - UErrorCode error = U_ZERO_ERROR; - UCollationResult result = collator->compare( - static_cast(lhs.c_str()), static_cast(lhs.length()), - static_cast(rhs.c_str()), static_cast(rhs.length()), - error); - DCHECK(U_SUCCESS(error)); - return result; -} - -} // namespace i18n -} // namespace base diff --git a/base/i18n/string_compare.h b/base/i18n/string_compare.h deleted file mode 100644 index f0f3e297f0..0000000000 --- a/base/i18n/string_compare.h +++ /dev/null @@ -1,28 +0,0 @@ -// Copyright (c) 2013 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef BASE_I18N_STRING_COMPARE_H_ -#define BASE_I18N_STRING_COMPARE_H_ - -#include -#include -#include - -#include "base/i18n/base_i18n_export.h" -#include "base/strings/string16.h" -#include "third_party/icu/source/i18n/unicode/coll.h" - -namespace base { -namespace i18n { - -// Compares the two strings using the specified collator. -BASE_I18N_EXPORT UCollationResult CompareString16WithCollator( - const icu::Collator* collator, - const string16& lhs, - const string16& rhs); - -} // namespace i18n -} // namespace base - -#endif // BASE_I18N_STRING_COMPARATOR_H_ diff --git a/base/i18n/string_search.cc b/base/i18n/string_search.cc deleted file mode 100644 index 121dfce586..0000000000 --- a/base/i18n/string_search.cc +++ /dev/null @@ -1,80 +0,0 @@ -// Copyright (c) 2011 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "base/i18n/string_search.h" -#include "base/logging.h" - -#include "third_party/icu/source/i18n/unicode/usearch.h" - -namespace base { -namespace i18n { - -FixedPatternStringSearchIgnoringCaseAndAccents:: -FixedPatternStringSearchIgnoringCaseAndAccents(const string16& find_this) - : find_this_(find_this) { - // usearch_open requires a valid string argument to be searched, even if we - // want to set it by usearch_setText afterwards. So, supplying a dummy text. - const string16& dummy = find_this_; - - UErrorCode status = U_ZERO_ERROR; - search_ = usearch_open(find_this_.data(), find_this_.size(), - dummy.data(), dummy.size(), - uloc_getDefault(), - NULL, // breakiter - &status); - if (U_SUCCESS(status)) { - UCollator* collator = usearch_getCollator(search_); - ucol_setStrength(collator, UCOL_PRIMARY); - usearch_reset(search_); - } -} - -FixedPatternStringSearchIgnoringCaseAndAccents:: -~FixedPatternStringSearchIgnoringCaseAndAccents() { - if (search_) - usearch_close(search_); -} - -bool FixedPatternStringSearchIgnoringCaseAndAccents::Search( - const string16& in_this, size_t* match_index, size_t* match_length) { - UErrorCode status = U_ZERO_ERROR; - usearch_setText(search_, in_this.data(), in_this.size(), &status); - - // Default to basic substring search if usearch fails. According to - // http://icu-project.org/apiref/icu4c/usearch_8h.html, usearch_open will fail - // if either |find_this| or |in_this| are empty. In either case basic - // substring search will give the correct return value. - if (!U_SUCCESS(status)) { - size_t index = in_this.find(find_this_); - if (index == string16::npos) { - return false; - } else { - if (match_index) - *match_index = index; - if (match_length) - *match_length = find_this_.size(); - return true; - } - } - - int32_t index = usearch_first(search_, &status); - if (!U_SUCCESS(status) || index == USEARCH_DONE) - return false; - if (match_index) - *match_index = static_cast(index); - if (match_length) - *match_length = static_cast(usearch_getMatchedLength(search_)); - return true; -} - -bool StringSearchIgnoringCaseAndAccents(const string16& find_this, - const string16& in_this, - size_t* match_index, - size_t* match_length) { - return FixedPatternStringSearchIgnoringCaseAndAccents(find_this).Search( - in_this, match_index, match_length); -} - -} // namespace i18n -} // namespace base diff --git a/base/i18n/string_search.h b/base/i18n/string_search.h deleted file mode 100644 index 138606f8c6..0000000000 --- a/base/i18n/string_search.h +++ /dev/null @@ -1,53 +0,0 @@ -// Copyright (c) 2011 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef BASE_I18N_STRING_SEARCH_H_ -#define BASE_I18N_STRING_SEARCH_H_ - -#include "base/i18n/base_i18n_export.h" -#include "base/strings/string16.h" - -struct UStringSearch; - -namespace base { -namespace i18n { - -// Returns true if |in_this| contains |find_this|. If |match_index| or -// |match_length| are non-NULL, they are assigned the start position and total -// length of the match. -// -// Only differences between base letters are taken into consideration. Case and -// accent differences are ignored. Please refer to 'primary level' in -// http://userguide.icu-project.org/collation/concepts for additional details. -BASE_I18N_EXPORT - bool StringSearchIgnoringCaseAndAccents(const string16& find_this, - const string16& in_this, - size_t* match_index, - size_t* match_length); - -// This class is for speeding up multiple StringSearchIgnoringCaseAndAccents() -// with the same |find_this| argument. |find_this| is passed as the constructor -// argument, and precomputation for searching is done only at that timing. -class BASE_I18N_EXPORT FixedPatternStringSearchIgnoringCaseAndAccents { - public: - explicit FixedPatternStringSearchIgnoringCaseAndAccents( - const string16& find_this); - ~FixedPatternStringSearchIgnoringCaseAndAccents(); - - // Returns true if |in_this| contains |find_this|. If |match_index| or - // |match_length| are non-NULL, they are assigned the start position and total - // length of the match. - bool Search(const string16& in_this, - size_t* match_index, - size_t* match_length); - - private: - string16 find_this_; - UStringSearch* search_; -}; - -} // namespace i18n -} // namespace base - -#endif // BASE_I18N_STRING_SEARCH_H_ diff --git a/base/i18n/string_search_unittest.cc b/base/i18n/string_search_unittest.cc deleted file mode 100644 index 9419b267cb..0000000000 --- a/base/i18n/string_search_unittest.cc +++ /dev/null @@ -1,226 +0,0 @@ -// Copyright (c) 2011 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include - -#include "base/i18n/rtl.h" -#include "base/i18n/string_search.h" -#include "base/strings/string16.h" -#include "base/strings/utf_string_conversions.h" -#include "testing/gtest/include/gtest/gtest.h" -#include "third_party/icu/source/i18n/unicode/usearch.h" - -namespace base { -namespace i18n { - -// Note on setting default locale for testing: The current default locale on -// the Mac trybot is en_US_POSIX, with which primary-level collation strength -// string search is case-sensitive, when normally it should be -// case-insensitive. In other locales (including en_US which English speakers -// in the U.S. use), this search would be case-insensitive as expected. - -TEST(StringSearchTest, ASCII) { - std::string default_locale(uloc_getDefault()); - bool locale_is_posix = (default_locale == "en_US_POSIX"); - if (locale_is_posix) - SetICUDefaultLocale("en_US"); - - size_t index = 0; - size_t length = 0; - - EXPECT_TRUE(StringSearchIgnoringCaseAndAccents( - ASCIIToUTF16("hello"), ASCIIToUTF16("hello world"), &index, &length)); - EXPECT_EQ(0U, index); - EXPECT_EQ(5U, length); - - EXPECT_FALSE(StringSearchIgnoringCaseAndAccents( - ASCIIToUTF16("h e l l o"), ASCIIToUTF16("h e l l o"), - &index, &length)); - - EXPECT_TRUE(StringSearchIgnoringCaseAndAccents( - ASCIIToUTF16("aabaaa"), ASCIIToUTF16("aaabaabaaa"), &index, &length)); - EXPECT_EQ(4U, index); - EXPECT_EQ(6U, length); - - EXPECT_FALSE(StringSearchIgnoringCaseAndAccents( - ASCIIToUTF16("searching within empty string"), string16(), - &index, &length)); - - EXPECT_TRUE(StringSearchIgnoringCaseAndAccents( - string16(), ASCIIToUTF16("searching for empty string"), &index, &length)); - EXPECT_EQ(0U, index); - EXPECT_EQ(0U, length); - - EXPECT_TRUE(StringSearchIgnoringCaseAndAccents( - ASCIIToUTF16("case insensitivity"), ASCIIToUTF16("CaSe InSeNsItIvItY"), - &index, &length)); - EXPECT_EQ(0U, index); - EXPECT_EQ(18U, length); - - if (locale_is_posix) - SetICUDefaultLocale(default_locale.data()); -} - -TEST(StringSearchTest, UnicodeLocaleIndependent) { - // Base characters - const string16 e_base = WideToUTF16(L"e"); - const string16 E_base = WideToUTF16(L"E"); - const string16 a_base = WideToUTF16(L"a"); - - // Composed characters - const string16 e_with_acute_accent = WideToUTF16(L"\u00e9"); - const string16 E_with_acute_accent = WideToUTF16(L"\u00c9"); - const string16 e_with_grave_accent = WideToUTF16(L"\u00e8"); - const string16 E_with_grave_accent = WideToUTF16(L"\u00c8"); - const string16 a_with_acute_accent = WideToUTF16(L"\u00e1"); - - // Decomposed characters - const string16 e_with_acute_combining_mark = WideToUTF16(L"e\u0301"); - const string16 E_with_acute_combining_mark = WideToUTF16(L"E\u0301"); - const string16 e_with_grave_combining_mark = WideToUTF16(L"e\u0300"); - const string16 E_with_grave_combining_mark = WideToUTF16(L"E\u0300"); - const string16 a_with_acute_combining_mark = WideToUTF16(L"a\u0301"); - - std::string default_locale(uloc_getDefault()); - bool locale_is_posix = (default_locale == "en_US_POSIX"); - if (locale_is_posix) - SetICUDefaultLocale("en_US"); - - size_t index = 0; - size_t length = 0; - - EXPECT_TRUE(StringSearchIgnoringCaseAndAccents( - e_base, e_with_acute_accent, &index, &length)); - EXPECT_EQ(0U, index); - EXPECT_EQ(e_with_acute_accent.size(), length); - - EXPECT_TRUE(StringSearchIgnoringCaseAndAccents( - e_with_acute_accent, e_base, &index, &length)); - EXPECT_EQ(0U, index); - EXPECT_EQ(e_base.size(), length); - - EXPECT_TRUE(StringSearchIgnoringCaseAndAccents( - e_base, e_with_acute_combining_mark, &index, &length)); - EXPECT_EQ(0U, index); - EXPECT_EQ(e_with_acute_combining_mark.size(), length); - - EXPECT_TRUE(StringSearchIgnoringCaseAndAccents( - e_with_acute_combining_mark, e_base, &index, &length)); - EXPECT_EQ(0U, index); - EXPECT_EQ(e_base.size(), length); - - EXPECT_TRUE(StringSearchIgnoringCaseAndAccents( - e_with_acute_combining_mark, e_with_acute_accent, - &index, &length)); - EXPECT_EQ(0U, index); - EXPECT_EQ(e_with_acute_accent.size(), length); - - EXPECT_TRUE(StringSearchIgnoringCaseAndAccents( - e_with_acute_accent, e_with_acute_combining_mark, - &index, &length)); - EXPECT_EQ(0U, index); - EXPECT_EQ(e_with_acute_combining_mark.size(), length); - - EXPECT_TRUE(StringSearchIgnoringCaseAndAccents( - e_with_acute_combining_mark, e_with_grave_combining_mark, - &index, &length)); - EXPECT_EQ(0U, index); - EXPECT_EQ(e_with_grave_combining_mark.size(), length); - - EXPECT_TRUE(StringSearchIgnoringCaseAndAccents( - e_with_grave_combining_mark, e_with_acute_combining_mark, - &index, &length)); - EXPECT_EQ(0U, index); - EXPECT_EQ(e_with_acute_combining_mark.size(), length); - - EXPECT_TRUE(StringSearchIgnoringCaseAndAccents( - e_with_acute_combining_mark, e_with_grave_accent, &index, &length)); - EXPECT_EQ(0U, index); - EXPECT_EQ(e_with_grave_accent.size(), length); - - EXPECT_TRUE(StringSearchIgnoringCaseAndAccents( - e_with_grave_accent, e_with_acute_combining_mark, &index, &length)); - EXPECT_EQ(0U, index); - EXPECT_EQ(e_with_acute_combining_mark.size(), length); - - EXPECT_TRUE(StringSearchIgnoringCaseAndAccents( - E_with_acute_accent, e_with_acute_accent, &index, &length)); - EXPECT_EQ(0U, index); - EXPECT_EQ(e_with_acute_accent.size(), length); - - EXPECT_TRUE(StringSearchIgnoringCaseAndAccents( - E_with_grave_accent, e_with_acute_accent, &index, &length)); - EXPECT_EQ(0U, index); - EXPECT_EQ(e_with_acute_accent.size(), length); - - EXPECT_TRUE(StringSearchIgnoringCaseAndAccents( - E_with_acute_combining_mark, e_with_grave_accent, &index, &length)); - EXPECT_EQ(0U, index); - EXPECT_EQ(e_with_grave_accent.size(), length); - - EXPECT_TRUE(StringSearchIgnoringCaseAndAccents( - E_with_grave_combining_mark, e_with_acute_accent, &index, &length)); - EXPECT_EQ(0U, index); - EXPECT_EQ(e_with_acute_accent.size(), length); - - EXPECT_TRUE(StringSearchIgnoringCaseAndAccents( - E_base, e_with_grave_accent, &index, &length)); - EXPECT_EQ(0U, index); - EXPECT_EQ(e_with_grave_accent.size(), length); - - EXPECT_FALSE(StringSearchIgnoringCaseAndAccents( - a_with_acute_accent, e_with_acute_accent, &index, &length)); - - EXPECT_FALSE(StringSearchIgnoringCaseAndAccents( - a_with_acute_combining_mark, e_with_acute_combining_mark, - &index, &length)); - - if (locale_is_posix) - SetICUDefaultLocale(default_locale.data()); -} - -TEST(StringSearchTest, UnicodeLocaleDependent) { - // Base characters - const string16 a_base = WideToUTF16(L"a"); - - // Composed characters - const string16 a_with_ring = WideToUTF16(L"\u00e5"); - - EXPECT_TRUE(StringSearchIgnoringCaseAndAccents( - a_base, a_with_ring, NULL, NULL)); - - const char* default_locale = uloc_getDefault(); - SetICUDefaultLocale("da"); - - EXPECT_FALSE(StringSearchIgnoringCaseAndAccents( - a_base, a_with_ring, NULL, NULL)); - - SetICUDefaultLocale(default_locale); -} - -TEST(StringSearchTest, FixedPatternMultipleSearch) { - std::string default_locale(uloc_getDefault()); - bool locale_is_posix = (default_locale == "en_US_POSIX"); - if (locale_is_posix) - SetICUDefaultLocale("en_US"); - - size_t index = 0; - size_t length = 0; - - // Search "hello" over multiple texts. - FixedPatternStringSearchIgnoringCaseAndAccents query(ASCIIToUTF16("hello")); - EXPECT_TRUE(query.Search(ASCIIToUTF16("12hello34"), &index, &length)); - EXPECT_EQ(2U, index); - EXPECT_EQ(5U, length); - EXPECT_FALSE(query.Search(ASCIIToUTF16("bye"), &index, &length)); - EXPECT_TRUE(query.Search(ASCIIToUTF16("hELLo"), &index, &length)); - EXPECT_EQ(0U, index); - EXPECT_EQ(5U, length); - - if (locale_is_posix) - SetICUDefaultLocale(default_locale.data()); -} - -} // namespace i18n -} // namespace base diff --git a/base/i18n/time_formatting.cc b/base/i18n/time_formatting.cc deleted file mode 100644 index 3973dd2508..0000000000 --- a/base/i18n/time_formatting.cc +++ /dev/null @@ -1,164 +0,0 @@ -// Copyright (c) 2011 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "base/i18n/time_formatting.h" - -#include "base/logging.h" -#include "base/memory/scoped_ptr.h" -#include "base/strings/utf_string_conversions.h" -#include "base/time/time.h" -#include "third_party/icu/source/i18n/unicode/datefmt.h" -#include "third_party/icu/source/i18n/unicode/dtptngen.h" -#include "third_party/icu/source/i18n/unicode/smpdtfmt.h" - -using base::Time; - -namespace { - -string16 TimeFormat(const icu::DateFormat* formatter, - const Time& time) { - DCHECK(formatter); - icu::UnicodeString date_string; - - formatter->format(static_cast(time.ToDoubleT() * 1000), date_string); - return string16(date_string.getBuffer(), - static_cast(date_string.length())); -} - -string16 TimeFormatWithoutAmPm(const icu::DateFormat* formatter, - const Time& time) { - DCHECK(formatter); - icu::UnicodeString time_string; - - icu::FieldPosition ampm_field(icu::DateFormat::kAmPmField); - formatter->format( - static_cast(time.ToDoubleT() * 1000), time_string, ampm_field); - int ampm_length = ampm_field.getEndIndex() - ampm_field.getBeginIndex(); - if (ampm_length) { - int begin = ampm_field.getBeginIndex(); - // Doesn't include any spacing before the field. - if (begin) - begin--; - time_string.removeBetween(begin, ampm_field.getEndIndex()); - } - return string16(time_string.getBuffer(), - static_cast(time_string.length())); -} - -} // namespace - -namespace base { - -string16 TimeFormatTimeOfDay(const Time& time) { - // We can omit the locale parameter because the default should match - // Chrome's application locale. - scoped_ptr formatter( - icu::DateFormat::createTimeInstance(icu::DateFormat::kShort)); - return TimeFormat(formatter.get(), time); -} - -string16 TimeFormatTimeOfDayWithHourClockType(const Time& time, - HourClockType type, - AmPmClockType ampm) { - // Just redirect to the normal function if the default type matches the - // given type. - HourClockType default_type = GetHourClockType(); - if (default_type == type && (type == k24HourClock || ampm == kKeepAmPm)) { - return TimeFormatTimeOfDay(time); - } - - // Generate a locale-dependent format pattern. The generator will take - // care of locale-dependent formatting issues like which separator to - // use (some locales use '.' instead of ':'), and where to put the am/pm - // marker. - UErrorCode status = U_ZERO_ERROR; - scoped_ptr generator( - icu::DateTimePatternGenerator::createInstance(status)); - DCHECK(U_SUCCESS(status)); - const char* base_pattern = (type == k12HourClock ? "ahm" : "Hm"); - icu::UnicodeString generated_pattern = - generator->getBestPattern(icu::UnicodeString(base_pattern), status); - DCHECK(U_SUCCESS(status)); - - // Then, format the time using the generated pattern. - icu::SimpleDateFormat formatter(generated_pattern, status); - DCHECK(U_SUCCESS(status)); - if (ampm == kKeepAmPm) { - return TimeFormat(&formatter, time); - } else { - return TimeFormatWithoutAmPm(&formatter, time); - } -} - -string16 TimeFormatShortDate(const Time& time) { - scoped_ptr formatter( - icu::DateFormat::createDateInstance(icu::DateFormat::kMedium)); - return TimeFormat(formatter.get(), time); -} - -string16 TimeFormatShortDateNumeric(const Time& time) { - scoped_ptr formatter( - icu::DateFormat::createDateInstance(icu::DateFormat::kShort)); - return TimeFormat(formatter.get(), time); -} - -string16 TimeFormatShortDateAndTime(const Time& time) { - scoped_ptr formatter( - icu::DateFormat::createDateTimeInstance(icu::DateFormat::kShort)); - return TimeFormat(formatter.get(), time); -} - -string16 TimeFormatFriendlyDateAndTime(const Time& time) { - scoped_ptr formatter( - icu::DateFormat::createDateTimeInstance(icu::DateFormat::kFull)); - return TimeFormat(formatter.get(), time); -} - -string16 TimeFormatFriendlyDate(const Time& time) { - scoped_ptr formatter(icu::DateFormat::createDateInstance( - icu::DateFormat::kFull)); - return TimeFormat(formatter.get(), time); -} - -HourClockType GetHourClockType() { - // TODO(satorux,jshin): Rework this with ures_getByKeyWithFallback() - // once it becomes public. The short time format can be found at - // "calendar/gregorian/DateTimePatterns/3" in the resources. - scoped_ptr formatter( - static_cast( - icu::DateFormat::createTimeInstance(icu::DateFormat::kShort))); - // Retrieve the short time format. - icu::UnicodeString pattern_unicode; - formatter->toPattern(pattern_unicode); - - // Determine what hour clock type the current locale uses, by checking - // "a" (am/pm marker) in the short time format. This is reliable as "a" - // is used by all of 12-hour clock formats, but not any of 24-hour clock - // formats, as shown below. - // - // % grep -A4 DateTimePatterns third_party/icu/source/data/locales/*.txt | - // grep -B1 -- -- |grep -v -- '--' | - // perl -nle 'print $1 if /^\S+\s+"(.*)"/' |sort -u - // - // H.mm - // H:mm - // HH.mm - // HH:mm - // a h:mm - // ah:mm - // ahh:mm - // h-mm a - // h:mm a - // hh:mm a - // - // See http://userguide.icu-project.org/formatparse/datetime for details - // about the date/time format syntax. - if (pattern_unicode.indexOf('a') == -1) { - return k24HourClock; - } else { - return k12HourClock; - } -} - -} // namespace base diff --git a/base/i18n/time_formatting.h b/base/i18n/time_formatting.h deleted file mode 100644 index 226d1a91a2..0000000000 --- a/base/i18n/time_formatting.h +++ /dev/null @@ -1,66 +0,0 @@ -// Copyright (c) 2011 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -// Basic time formatting methods. These methods use the current locale -// formatting for displaying the time. - -#ifndef BASE_I18N_TIME_FORMATTING_H_ -#define BASE_I18N_TIME_FORMATTING_H_ - -#include "base/i18n/base_i18n_export.h" -#include "base/strings/string16.h" - -namespace base { - -class Time; - -// Argument type used to specify the hour clock type. -enum HourClockType { - k12HourClock, // Uses 1-12. e.g., "3:07 PM" - k24HourClock, // Uses 0-23. e.g., "15:07" -}; - -// Argument type used to specify whether or not to include AM/PM sign. -enum AmPmClockType { - kDropAmPm, // Drops AM/PM sign. e.g., "3:07" - kKeepAmPm, // Keeps AM/PM sign. e.g., "3:07 PM" -}; - -// Returns the time of day, e.g., "3:07 PM". -BASE_I18N_EXPORT string16 TimeFormatTimeOfDay(const Time& time); - -// Returns the time of day in the specified hour clock type. e.g. -// "3:07 PM" (type == k12HourClock, ampm == kKeepAmPm). -// "3:07" (type == k12HourClock, ampm == kDropAmPm). -// "15:07" (type == k24HourClock). -BASE_I18N_EXPORT string16 TimeFormatTimeOfDayWithHourClockType( - const Time& time, - HourClockType type, - AmPmClockType ampm); - -// Returns a shortened date, e.g. "Nov 7, 2007" -BASE_I18N_EXPORT string16 TimeFormatShortDate(const Time& time); - -// Returns a numeric date such as 12/13/52. -BASE_I18N_EXPORT string16 TimeFormatShortDateNumeric(const Time& time); - -// Returns a numeric date and time such as "12/13/52 2:44:30 PM". -BASE_I18N_EXPORT string16 TimeFormatShortDateAndTime(const Time& time); - -// Formats a time in a friendly sentence format, e.g. -// "Monday, March 6, 2008 2:44:30 PM". -BASE_I18N_EXPORT string16 TimeFormatFriendlyDateAndTime(const Time& time); - -// Formats a time in a friendly sentence format, e.g. -// "Monday, March 6, 2008". -BASE_I18N_EXPORT string16 TimeFormatFriendlyDate(const Time& time); - -// Gets the hour clock type of the current locale. e.g. -// k12HourClock (en-US). -// k24HourClock (en-GB). -BASE_I18N_EXPORT HourClockType GetHourClockType(); - -} // namespace base - -#endif // BASE_I18N_TIME_FORMATTING_H_ diff --git a/base/i18n/time_formatting_unittest.cc b/base/i18n/time_formatting_unittest.cc deleted file mode 100644 index 03a3aa3ec7..0000000000 --- a/base/i18n/time_formatting_unittest.cc +++ /dev/null @@ -1,175 +0,0 @@ -// Copyright (c) 2011 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "base/i18n/time_formatting.h" - -#include "base/i18n/rtl.h" -#include "base/strings/utf_string_conversions.h" -#include "base/time/time.h" -#include "testing/gtest/include/gtest/gtest.h" -#include "third_party/icu/source/common/unicode/uversion.h" - -namespace base { -namespace { - -const Time::Exploded kTestDateTimeExploded = { - 2011, 4, 6, 30, // Sat, Apr 30, 2011 - 15, 42, 7, 0 // 15:42:07.000 -}; - -TEST(TimeFormattingTest, TimeFormatTimeOfDayDefault12h) { - // Test for a locale defaulted to 12h clock. - // As an instance, we use third_party/icu/source/data/locales/en.txt. - i18n::SetICUDefaultLocale("en_US"); - - Time time(Time::FromLocalExploded(kTestDateTimeExploded)); - string16 clock24h(ASCIIToUTF16("15:42")); - string16 clock12h_pm(ASCIIToUTF16("3:42 PM")); - string16 clock12h(ASCIIToUTF16("3:42")); - - // The default is 12h clock. - EXPECT_EQ(clock12h_pm, TimeFormatTimeOfDay(time)); - EXPECT_EQ(k12HourClock, GetHourClockType()); - // k{Keep,Drop}AmPm should not affect for 24h clock. - EXPECT_EQ(clock24h, - TimeFormatTimeOfDayWithHourClockType(time, - k24HourClock, - kKeepAmPm)); - EXPECT_EQ(clock24h, - TimeFormatTimeOfDayWithHourClockType(time, - k24HourClock, - kDropAmPm)); - // k{Keep,Drop}AmPm affects for 12h clock. - EXPECT_EQ(clock12h_pm, - TimeFormatTimeOfDayWithHourClockType(time, - k12HourClock, - kKeepAmPm)); - EXPECT_EQ(clock12h, - TimeFormatTimeOfDayWithHourClockType(time, - k12HourClock, - kDropAmPm)); -} - -TEST(TimeFormattingTest, TimeFormatTimeOfDayDefault24h) { - // Test for a locale defaulted to 24h clock. - // As an instance, we use third_party/icu/source/data/locales/en_GB.txt. - i18n::SetICUDefaultLocale("en_GB"); - - Time time(Time::FromLocalExploded(kTestDateTimeExploded)); - string16 clock24h(ASCIIToUTF16("15:42")); -#if U_ICU_VERSION_MAJOR_NUM >= 50 - string16 clock12h_pm(ASCIIToUTF16("3:42 pm")); -#else - // TODO(phajdan.jr): Clean up after bundled ICU gets updated to 50. - string16 clock12h_pm(ASCIIToUTF16("3:42 PM")); -#endif - string16 clock12h(ASCIIToUTF16("3:42")); - - // The default is 24h clock. - EXPECT_EQ(clock24h, TimeFormatTimeOfDay(time)); - EXPECT_EQ(k24HourClock, GetHourClockType()); - // k{Keep,Drop}AmPm should not affect for 24h clock. - EXPECT_EQ(clock24h, - TimeFormatTimeOfDayWithHourClockType(time, - k24HourClock, - kKeepAmPm)); - EXPECT_EQ(clock24h, - TimeFormatTimeOfDayWithHourClockType(time, - k24HourClock, - kDropAmPm)); - // k{Keep,Drop}AmPm affects for 12h clock. - EXPECT_EQ(clock12h_pm, - TimeFormatTimeOfDayWithHourClockType(time, - k12HourClock, - kKeepAmPm)); - EXPECT_EQ(clock12h, - TimeFormatTimeOfDayWithHourClockType(time, - k12HourClock, - kDropAmPm)); -} - -TEST(TimeFormattingTest, TimeFormatTimeOfDayJP) { - // Test for a locale that uses different mark than "AM" and "PM". - // As an instance, we use third_party/icu/source/data/locales/ja.txt. - i18n::SetICUDefaultLocale("ja_JP"); - - Time time(Time::FromLocalExploded(kTestDateTimeExploded)); - string16 clock24h(ASCIIToUTF16("15:42")); - string16 clock12h_pm(WideToUTF16(L"\x5348\x5f8c" L"3:42")); - string16 clock12h(ASCIIToUTF16("3:42")); - - // The default is 24h clock. - EXPECT_EQ(clock24h, TimeFormatTimeOfDay(time)); - EXPECT_EQ(k24HourClock, GetHourClockType()); - // k{Keep,Drop}AmPm should not affect for 24h clock. - EXPECT_EQ(clock24h, - TimeFormatTimeOfDayWithHourClockType(time, - k24HourClock, - kKeepAmPm)); - EXPECT_EQ(clock24h, - TimeFormatTimeOfDayWithHourClockType(time, - k24HourClock, - kDropAmPm)); - // k{Keep,Drop}AmPm affects for 12h clock. - EXPECT_EQ(clock12h_pm, - TimeFormatTimeOfDayWithHourClockType(time, - k12HourClock, - kKeepAmPm)); - EXPECT_EQ(clock12h, - TimeFormatTimeOfDayWithHourClockType(time, - k12HourClock, - kDropAmPm)); -} - -TEST(TimeFormattingTest, TimeFormatDateUS) { - // See third_party/icu/source/data/locales/en.txt. - // The date patterns are "EEEE, MMMM d, y", "MMM d, y", and "M/d/yy". - i18n::SetICUDefaultLocale("en_US"); - - Time time(Time::FromLocalExploded(kTestDateTimeExploded)); - - EXPECT_EQ(ASCIIToUTF16("Apr 30, 2011"), TimeFormatShortDate(time)); - EXPECT_EQ(ASCIIToUTF16("4/30/11"), TimeFormatShortDateNumeric(time)); - -#if U_ICU_VERSION_MAJOR_NUM >= 50 - EXPECT_EQ(ASCIIToUTF16("4/30/11, 3:42:07 PM"), - TimeFormatShortDateAndTime(time)); -#else - // TODO(phajdan.jr): Clean up after bundled ICU gets updated to 50. - EXPECT_EQ(ASCIIToUTF16("4/30/11 3:42:07 PM"), - TimeFormatShortDateAndTime(time)); -#endif - -#if U_ICU_VERSION_MAJOR_NUM >= 50 - EXPECT_EQ(ASCIIToUTF16("Saturday, April 30, 2011 at 3:42:07 PM"), - TimeFormatFriendlyDateAndTime(time)); -#else - // TODO(phajdan.jr): Clean up after bundled ICU gets updated to 50. - EXPECT_EQ(ASCIIToUTF16("Saturday, April 30, 2011 3:42:07 PM"), - TimeFormatFriendlyDateAndTime(time)); -#endif - - EXPECT_EQ(ASCIIToUTF16("Saturday, April 30, 2011"), - TimeFormatFriendlyDate(time)); -} - -TEST(TimeFormattingTest, TimeFormatDateGB) { - // See third_party/icu/source/data/locales/en_GB.txt. - // The date patterns are "EEEE, d MMMM y", "d MMM y", and "dd/MM/yyyy". - i18n::SetICUDefaultLocale("en_GB"); - - Time time(Time::FromLocalExploded(kTestDateTimeExploded)); - - EXPECT_EQ(ASCIIToUTF16("30 Apr 2011"), TimeFormatShortDate(time)); - EXPECT_EQ(ASCIIToUTF16("30/04/2011"), TimeFormatShortDateNumeric(time)); - EXPECT_EQ(ASCIIToUTF16("30/04/2011 15:42:07"), - TimeFormatShortDateAndTime(time)); - EXPECT_EQ(ASCIIToUTF16("Saturday, 30 April 2011 15:42:07"), - TimeFormatFriendlyDateAndTime(time)); - EXPECT_EQ(ASCIIToUTF16("Saturday, 30 April 2011"), - TimeFormatFriendlyDate(time)); -} - -} // namespace -} // namespace base diff --git a/base/id_map.h b/base/id_map.h deleted file mode 100644 index 27098d2976..0000000000 --- a/base/id_map.h +++ /dev/null @@ -1,257 +0,0 @@ -// Copyright (c) 2011 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef BASE_ID_MAP_H_ -#define BASE_ID_MAP_H_ - -#include - -#include "base/basictypes.h" -#include "base/containers/hash_tables.h" -#include "base/logging.h" -#include "base/threading/non_thread_safe.h" - -// Ownership semantics - own pointer means the pointer is deleted in Remove() -// & during destruction -enum IDMapOwnershipSemantics { - IDMapExternalPointer, - IDMapOwnPointer -}; - -// This object maintains a list of IDs that can be quickly converted to -// pointers to objects. It is implemented as a hash table, optimized for -// relatively small data sets (in the common case, there will be exactly one -// item in the list). -// -// Items can be inserted into the container with arbitrary ID, but the caller -// must ensure they are unique. Inserting IDs and relying on automatically -// generated ones is not allowed because they can collide. -// -// This class does not have a virtual destructor, do not inherit from it when -// ownership semantics are set to own because pointers will leak. -template -class IDMap : public base::NonThreadSafe { - private: - typedef int32 KeyType; - typedef base::hash_map HashTable; - - public: - IDMap() : iteration_depth_(0), next_id_(1), check_on_null_data_(false) { - // A number of consumers of IDMap create it on one thread but always access - // it from a different, but consitent, thread post-construction. - DetachFromThread(); - } - - ~IDMap() { - // Many IDMap's are static, and hence will be destroyed on the main thread. - // However, all the accesses may take place on another thread, such as the - // IO thread. Detaching again to clean this up. - DetachFromThread(); - Releaser::release_all(&data_); - } - - // Sets whether Add should CHECK if passed in NULL data. Default is false. - void set_check_on_null_data(bool value) { check_on_null_data_ = value; } - - // Adds a view with an automatically generated unique ID. See AddWithID. - KeyType Add(T* data) { - DCHECK(CalledOnValidThread()); - CHECK(!check_on_null_data_ || data); - KeyType this_id = next_id_; - DCHECK(data_.find(this_id) == data_.end()) << "Inserting duplicate item"; - data_[this_id] = data; - next_id_++; - return this_id; - } - - // Adds a new data member with the specified ID. The ID must not be in - // the list. The caller either must generate all unique IDs itself and use - // this function, or allow this object to generate IDs and call Add. These - // two methods may not be mixed, or duplicate IDs may be generated - void AddWithID(T* data, KeyType id) { - DCHECK(CalledOnValidThread()); - CHECK(!check_on_null_data_ || data); - DCHECK(data_.find(id) == data_.end()) << "Inserting duplicate item"; - data_[id] = data; - } - - void Remove(KeyType id) { - DCHECK(CalledOnValidThread()); - typename HashTable::iterator i = data_.find(id); - if (i == data_.end()) { - NOTREACHED() << "Attempting to remove an item not in the list"; - return; - } - - if (iteration_depth_ == 0) { - Releaser::release(i->second); - data_.erase(i); - } else { - removed_ids_.insert(id); - } - } - - void Clear() { - DCHECK(CalledOnValidThread()); - if (iteration_depth_ == 0) { - Releaser::release_all(&data_); - } else { - for (typename HashTable::iterator i = data_.begin(); - i != data_.end(); ++i) - removed_ids_.insert(i->first); - } - } - - bool IsEmpty() const { - DCHECK(CalledOnValidThread()); - return size() == 0u; - } - - T* Lookup(KeyType id) const { - DCHECK(CalledOnValidThread()); - typename HashTable::const_iterator i = data_.find(id); - if (i == data_.end()) - return NULL; - return i->second; - } - - size_t size() const { - DCHECK(CalledOnValidThread()); - return data_.size() - removed_ids_.size(); - } - -#if defined(UNIT_TEST) - int iteration_depth() const { - return iteration_depth_; - } -#endif // defined(UNIT_TEST) - - // It is safe to remove elements from the map during iteration. All iterators - // will remain valid. - template - class Iterator { - public: - Iterator(IDMap* map) - : map_(map), - iter_(map_->data_.begin()) { - Init(); - } - - Iterator(const Iterator& iter) - : map_(iter.map_), - iter_(iter.iter_) { - Init(); - } - - const Iterator& operator=(const Iterator& iter) { - map_ = iter.map; - iter_ = iter.iter; - Init(); - return *this; - } - - ~Iterator() { - DCHECK(map_->CalledOnValidThread()); - - // We're going to decrement iteration depth. Make sure it's greater than - // zero so that it doesn't become negative. - DCHECK_LT(0, map_->iteration_depth_); - - if (--map_->iteration_depth_ == 0) - map_->Compact(); - } - - bool IsAtEnd() const { - DCHECK(map_->CalledOnValidThread()); - return iter_ == map_->data_.end(); - } - - KeyType GetCurrentKey() const { - DCHECK(map_->CalledOnValidThread()); - return iter_->first; - } - - ReturnType* GetCurrentValue() const { - DCHECK(map_->CalledOnValidThread()); - return iter_->second; - } - - void Advance() { - DCHECK(map_->CalledOnValidThread()); - ++iter_; - SkipRemovedEntries(); - } - - private: - void Init() { - DCHECK(map_->CalledOnValidThread()); - ++map_->iteration_depth_; - SkipRemovedEntries(); - } - - void SkipRemovedEntries() { - while (iter_ != map_->data_.end() && - map_->removed_ids_.find(iter_->first) != - map_->removed_ids_.end()) { - ++iter_; - } - } - - IDMap* map_; - typename HashTable::const_iterator iter_; - }; - - typedef Iterator iterator; - typedef Iterator const_iterator; - - private: - - // The dummy parameter is there because C++ standard does not allow - // explicitly specialized templates inside classes - template struct Releaser { - static inline void release(T* ptr) {} - static inline void release_all(HashTable* table) {} - }; - - template struct Releaser { - static inline void release(T* ptr) { delete ptr;} - static inline void release_all(HashTable* table) { - for (typename HashTable::iterator i = table->begin(); - i != table->end(); ++i) { - delete i->second; - } - table->clear(); - } - }; - - void Compact() { - DCHECK_EQ(0, iteration_depth_); - for (std::set::const_iterator i = removed_ids_.begin(); - i != removed_ids_.end(); ++i) { - Remove(*i); - } - removed_ids_.clear(); - } - - // Keep track of how many iterators are currently iterating on us to safely - // handle removing items during iteration. - int iteration_depth_; - - // Keep set of IDs that should be removed after the outermost iteration has - // finished. This way we manage to not invalidate the iterator when an element - // is removed. - std::set removed_ids_; - - // The next ID that we will return from Add() - KeyType next_id_; - - HashTable data_; - - // See description above setter. - bool check_on_null_data_; - - DISALLOW_COPY_AND_ASSIGN(IDMap); -}; - -#endif // BASE_ID_MAP_H_ diff --git a/base/id_map_unittest.cc b/base/id_map_unittest.cc deleted file mode 100644 index 76d7c3ed4e..0000000000 --- a/base/id_map_unittest.cc +++ /dev/null @@ -1,335 +0,0 @@ -// Copyright (c) 2011 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "base/id_map.h" - -#include "testing/gtest/include/gtest/gtest.h" - -namespace { - -class TestObject { -}; - -class DestructorCounter { - public: - explicit DestructorCounter(int* counter) : counter_(counter) {} - ~DestructorCounter() { ++(*counter_); } - - private: - int* counter_; -}; - -TEST(IDMapTest, Basic) { - IDMap map; - EXPECT_TRUE(map.IsEmpty()); - EXPECT_EQ(0U, map.size()); - - TestObject obj1; - TestObject obj2; - - int32 id1 = map.Add(&obj1); - EXPECT_FALSE(map.IsEmpty()); - EXPECT_EQ(1U, map.size()); - EXPECT_EQ(&obj1, map.Lookup(id1)); - - int32 id2 = map.Add(&obj2); - EXPECT_FALSE(map.IsEmpty()); - EXPECT_EQ(2U, map.size()); - - EXPECT_EQ(&obj1, map.Lookup(id1)); - EXPECT_EQ(&obj2, map.Lookup(id2)); - - map.Remove(id1); - EXPECT_FALSE(map.IsEmpty()); - EXPECT_EQ(1U, map.size()); - - map.Remove(id2); - EXPECT_TRUE(map.IsEmpty()); - EXPECT_EQ(0U, map.size()); - - map.AddWithID(&obj1, 1); - map.AddWithID(&obj2, 2); - EXPECT_EQ(&obj1, map.Lookup(1)); - EXPECT_EQ(&obj2, map.Lookup(2)); - - EXPECT_EQ(0, map.iteration_depth()); -} - -TEST(IDMapTest, IteratorRemainsValidWhenRemovingCurrentElement) { - IDMap map; - - TestObject obj1; - TestObject obj2; - TestObject obj3; - - map.Add(&obj1); - map.Add(&obj2); - map.Add(&obj3); - - { - IDMap::const_iterator iter(&map); - - EXPECT_EQ(1, map.iteration_depth()); - - while (!iter.IsAtEnd()) { - map.Remove(iter.GetCurrentKey()); - iter.Advance(); - } - - // Test that while an iterator is still in scope, we get the map emptiness - // right (http://crbug.com/35571). - EXPECT_TRUE(map.IsEmpty()); - EXPECT_EQ(0U, map.size()); - } - - EXPECT_TRUE(map.IsEmpty()); - EXPECT_EQ(0U, map.size()); - - EXPECT_EQ(0, map.iteration_depth()); -} - -TEST(IDMapTest, IteratorRemainsValidWhenRemovingOtherElements) { - IDMap map; - - const int kCount = 5; - TestObject obj[kCount]; - int32 ids[kCount]; - - for (int i = 0; i < kCount; i++) - ids[i] = map.Add(&obj[i]); - - int counter = 0; - for (IDMap::const_iterator iter(&map); - !iter.IsAtEnd(); iter.Advance()) { - EXPECT_EQ(1, map.iteration_depth()); - - switch (counter) { - case 0: - EXPECT_EQ(ids[0], iter.GetCurrentKey()); - EXPECT_EQ(&obj[0], iter.GetCurrentValue()); - map.Remove(ids[1]); - break; - case 1: - EXPECT_EQ(ids[2], iter.GetCurrentKey()); - EXPECT_EQ(&obj[2], iter.GetCurrentValue()); - map.Remove(ids[3]); - break; - case 2: - EXPECT_EQ(ids[4], iter.GetCurrentKey()); - EXPECT_EQ(&obj[4], iter.GetCurrentValue()); - map.Remove(ids[0]); - break; - default: - FAIL() << "should not have that many elements"; - break; - } - - counter++; - } - - EXPECT_EQ(0, map.iteration_depth()); -} - -TEST(IDMapTest, CopyIterator) { - IDMap map; - - TestObject obj1; - TestObject obj2; - TestObject obj3; - - map.Add(&obj1); - map.Add(&obj2); - map.Add(&obj3); - - EXPECT_EQ(0, map.iteration_depth()); - - { - IDMap::const_iterator iter1(&map); - EXPECT_EQ(1, map.iteration_depth()); - - // Make sure that copying the iterator correctly increments - // map's iteration depth. - IDMap::const_iterator iter2(iter1); - EXPECT_EQ(2, map.iteration_depth()); - } - - // Make sure after destroying all iterators the map's iteration depth - // returns to initial state. - EXPECT_EQ(0, map.iteration_depth()); -} - -TEST(IDMapTest, AssignIterator) { - IDMap map; - - TestObject obj1; - TestObject obj2; - TestObject obj3; - - map.Add(&obj1); - map.Add(&obj2); - map.Add(&obj3); - - EXPECT_EQ(0, map.iteration_depth()); - - { - IDMap::const_iterator iter1(&map); - EXPECT_EQ(1, map.iteration_depth()); - - IDMap::const_iterator iter2(&map); - EXPECT_EQ(2, map.iteration_depth()); - - // Make sure that assigning the iterator correctly updates - // map's iteration depth (-1 for destruction, +1 for assignment). - EXPECT_EQ(2, map.iteration_depth()); - } - - // Make sure after destroying all iterators the map's iteration depth - // returns to initial state. - EXPECT_EQ(0, map.iteration_depth()); -} - -TEST(IDMapTest, IteratorRemainsValidWhenClearing) { - IDMap map; - - const int kCount = 5; - TestObject obj[kCount]; - int32 ids[kCount]; - - for (int i = 0; i < kCount; i++) - ids[i] = map.Add(&obj[i]); - - int counter = 0; - for (IDMap::const_iterator iter(&map); - !iter.IsAtEnd(); iter.Advance()) { - switch (counter) { - case 0: - EXPECT_EQ(ids[0], iter.GetCurrentKey()); - EXPECT_EQ(&obj[0], iter.GetCurrentValue()); - break; - case 1: - EXPECT_EQ(ids[1], iter.GetCurrentKey()); - EXPECT_EQ(&obj[1], iter.GetCurrentValue()); - map.Clear(); - EXPECT_TRUE(map.IsEmpty()); - EXPECT_EQ(0U, map.size()); - break; - default: - FAIL() << "should not have that many elements"; - break; - } - counter++; - } - - EXPECT_TRUE(map.IsEmpty()); - EXPECT_EQ(0U, map.size()); -} - -TEST(IDMapTest, OwningPointersDeletesThemOnRemove) { - const int kCount = 3; - - int external_del_count = 0; - DestructorCounter* external_obj[kCount]; - int map_external_ids[kCount]; - - int owned_del_count = 0; - DestructorCounter* owned_obj[kCount]; - int map_owned_ids[kCount]; - - IDMap map_external; - IDMap map_owned; - - for (int i = 0; i < kCount; ++i) { - external_obj[i] = new DestructorCounter(&external_del_count); - map_external_ids[i] = map_external.Add(external_obj[i]); - - owned_obj[i] = new DestructorCounter(&owned_del_count); - map_owned_ids[i] = map_owned.Add(owned_obj[i]); - } - - for (int i = 0; i < kCount; ++i) { - EXPECT_EQ(external_del_count, 0); - EXPECT_EQ(owned_del_count, i); - - map_external.Remove(map_external_ids[i]); - map_owned.Remove(map_owned_ids[i]); - } - - for (int i = 0; i < kCount; ++i) { - delete external_obj[i]; - } - - EXPECT_EQ(external_del_count, kCount); - EXPECT_EQ(owned_del_count, kCount); -} - -TEST(IDMapTest, OwningPointersDeletesThemOnClear) { - const int kCount = 3; - - int external_del_count = 0; - DestructorCounter* external_obj[kCount]; - - int owned_del_count = 0; - DestructorCounter* owned_obj[kCount]; - - IDMap map_external; - IDMap map_owned; - - for (int i = 0; i < kCount; ++i) { - external_obj[i] = new DestructorCounter(&external_del_count); - map_external.Add(external_obj[i]); - - owned_obj[i] = new DestructorCounter(&owned_del_count); - map_owned.Add(owned_obj[i]); - } - - EXPECT_EQ(external_del_count, 0); - EXPECT_EQ(owned_del_count, 0); - - map_external.Clear(); - map_owned.Clear(); - - EXPECT_EQ(external_del_count, 0); - EXPECT_EQ(owned_del_count, kCount); - - for (int i = 0; i < kCount; ++i) { - delete external_obj[i]; - } - - EXPECT_EQ(external_del_count, kCount); - EXPECT_EQ(owned_del_count, kCount); -} - -TEST(IDMapTest, OwningPointersDeletesThemOnDestruct) { - const int kCount = 3; - - int external_del_count = 0; - DestructorCounter* external_obj[kCount]; - - int owned_del_count = 0; - DestructorCounter* owned_obj[kCount]; - - { - IDMap map_external; - IDMap map_owned; - - for (int i = 0; i < kCount; ++i) { - external_obj[i] = new DestructorCounter(&external_del_count); - map_external.Add(external_obj[i]); - - owned_obj[i] = new DestructorCounter(&owned_del_count); - map_owned.Add(owned_obj[i]); - } - } - - EXPECT_EQ(external_del_count, 0); - - for (int i = 0; i < kCount; ++i) { - delete external_obj[i]; - } - - EXPECT_EQ(external_del_count, kCount); - EXPECT_EQ(owned_del_count, kCount); -} - -} // namespace diff --git a/base/ini_parser.cc b/base/ini_parser.cc deleted file mode 100644 index 7a2bd1c911..0000000000 --- a/base/ini_parser.cc +++ /dev/null @@ -1,66 +0,0 @@ -// Copyright 2013 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "base/ini_parser.h" - -#include "base/logging.h" -#include "base/strings/string_tokenizer.h" - -namespace base { - -INIParser::INIParser() : used_(false) {} - -INIParser::~INIParser() {} - -void INIParser::Parse(const std::string& content) { - DCHECK(!used_); - used_ = true; - base::StringTokenizer tokenizer(content, "\r\n"); - - std::string current_section; - while (tokenizer.GetNext()) { - std::string line = tokenizer.token(); - if (line.empty()) { - // Skips the empty line. - continue; - } - if (line[0] == '#' || line[0] == ';') { - // This line is a comment. - continue; - } - if (line[0] == '[') { - // It is a section header. - current_section = line.substr(1); - size_t end = current_section.rfind(']'); - if (end != std::string::npos) - current_section.erase(end); - } else { - std::string key, value; - size_t equal = line.find('='); - if (equal != std::string::npos) { - key = line.substr(0, equal); - value = line.substr(equal + 1); - HandleTriplet(current_section, key, value); - } - } - } -} - -DictionaryValueINIParser::DictionaryValueINIParser() {} - -DictionaryValueINIParser::~DictionaryValueINIParser() {} - -void DictionaryValueINIParser::HandleTriplet(const std::string& section, - const std::string& key, - const std::string& value) { - - // Checks whether the section and key contain a '.' character. - // Those sections and keys break DictionaryValue's path format when not - // using the *WithoutPathExpansion methods. - if (section.find('.') == std::string::npos && - key.find('.') == std::string::npos) - root_.SetString(section + "." + key, value); -} - -} // namespace base diff --git a/base/ini_parser.h b/base/ini_parser.h deleted file mode 100644 index 0aa7754d34..0000000000 --- a/base/ini_parser.h +++ /dev/null @@ -1,69 +0,0 @@ -// Copyright 2013 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef BASE_INI_PARSER_H_ -#define BASE_INI_PARSER_H_ - -#include - -#include "base/base_export.h" -#include "base/basictypes.h" -#include "base/values.h" - -namespace base { - -// Parses INI files in a string. Users should in inherit from this class. -// This is a very basic INI parser with these characteristics: -// - Ignores blank lines. -// - Ignores comment lines beginning with '#' or ';'. -// - Duplicate key names in the same section will simply cause repeated calls -// to HandleTriplet with the same |section| and |key| parameters. -// - No escape characters supported. -// - Global properties result in calls to HandleTriplet with an empty string in -// the |section| argument. -// - Section headers begin with a '[' character. It is recommended, but -// not required to close the header bracket with a ']' character. All -// characters after a closing ']' character is ignored. -// - Key value pairs are indicated with an '=' character. Whitespace is not -// ignored. Quoting is not supported. Everything before the first '=' -// is considered the |key|, and everything after is the |value|. -class BASE_EXPORT INIParser { - public: - INIParser(); - virtual ~INIParser(); - - // May only be called once per instance. - void Parse(const std::string& content); - - private: - virtual void HandleTriplet(const std::string& section, - const std::string& key, - const std::string& value) = 0; - - bool used_; -}; - -// Parsed values are stored as strings at the "section.key" path. Triplets with -// |section| or |key| parameters containing '.' are ignored. -class BASE_EXPORT DictionaryValueINIParser : public INIParser { - public: - DictionaryValueINIParser(); - virtual ~DictionaryValueINIParser(); - - const DictionaryValue& root() const { return root_; } - - private: - // INIParser implementation. - virtual void HandleTriplet(const std::string& section, - const std::string& key, - const std::string& value) OVERRIDE; - - DictionaryValue root_; - - DISALLOW_COPY_AND_ASSIGN(DictionaryValueINIParser); -}; - -} // namespace base - -#endif // BASE_INI_PARSER_H_ diff --git a/base/ini_parser_unittest.cc b/base/ini_parser_unittest.cc deleted file mode 100644 index ff90f6c8fc..0000000000 --- a/base/ini_parser_unittest.cc +++ /dev/null @@ -1,131 +0,0 @@ -// Copyright 2013 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include -#include - -#include "base/ini_parser.h" -#include "testing/gtest/include/gtest/gtest.h" - -namespace base { - -namespace { - -struct TestTriplet { - TestTriplet(const std::string& section, - const std::string& key, - const std::string& value) - : section(section), - key(key), - value(value) { - } - - std::string section; - std::string key; - std::string value; -}; - -class TestINIParser : public INIParser { - public: - explicit TestINIParser( - const std::vector& expected_triplets) - : expected_triplets_(expected_triplets), - pair_i_(0) { - } - virtual ~TestINIParser() {} - - size_t pair_i() { - return pair_i_; - } - - private: - virtual void HandleTriplet(const std::string& section, const std::string& key, - const std::string& value) OVERRIDE { - EXPECT_EQ(expected_triplets_[pair_i_].section, section); - EXPECT_EQ(expected_triplets_[pair_i_].key, key); - EXPECT_EQ(expected_triplets_[pair_i_].value, value); - ++pair_i_; - } - - std::vector expected_triplets_; - size_t pair_i_; -}; - -TEST(INIParserTest, BasicValid) { - std::vector expected_triplets; - expected_triplets.push_back(TestTriplet("section1", "key1", "value1")); - expected_triplets.push_back(TestTriplet("section1", "key2", "value2")); - expected_triplets.push_back(TestTriplet("section1", "key3", "value3")); - expected_triplets.push_back(TestTriplet("section2", "key4", "value4")); - expected_triplets.push_back(TestTriplet("section2", "key5", - "value=with=equals")); - expected_triplets.push_back(TestTriplet("section2", "key6", "value6")); - TestINIParser test_parser(expected_triplets); - - test_parser.Parse( - "[section1]\n" - "key1=value1\n" - "key2=value2\r\n" // Testing DOS "\r\n" line endings. - "key3=value3\n" - "[section2\n" // Testing omitted closing bracket. - "key4=value4\r" // Testing "\r" line endings. - "key5=value=with=equals\n" - "key6=value6"); // Testing omitted final line ending. -} - -TEST(INIParserTest, IgnoreBlankLinesAndComments) { - std::vector expected_triplets; - expected_triplets.push_back(TestTriplet("section1", "key1", "value1")); - expected_triplets.push_back(TestTriplet("section1", "key2", "value2")); - expected_triplets.push_back(TestTriplet("section1", "key3", "value3")); - expected_triplets.push_back(TestTriplet("section2", "key4", "value4")); - expected_triplets.push_back(TestTriplet("section2", "key5", "value5")); - expected_triplets.push_back(TestTriplet("section2", "key6", "value6")); - TestINIParser test_parser(expected_triplets); - - test_parser.Parse( - "\n" - "[section1]\n" - "key1=value1\n" - "\n" - "\n" - "key2=value2\n" - "key3=value3\n" - "\n" - ";Comment1" - "\n" - "[section2]\n" - "key4=value4\n" - "#Comment2\n" - "key5=value5\n" - "\n" - "key6=value6\n"); -} - -TEST(INIParserTest, DictionaryValueINIParser) { - DictionaryValueINIParser test_parser; - - test_parser.Parse( - "[section1]\n" - "key1=value1\n" - "key.2=value2\n" - "key3=va.lue3\n" - "[se.ction2]\n" - "key.4=value4\n" - "key5=value5\n"); - - const DictionaryValue& root = test_parser.root(); - std::string value; - EXPECT_TRUE(root.GetString("section1.key1", &value)); - EXPECT_EQ("value1", value); - EXPECT_FALSE(root.GetString("section1.key.2", &value)); - EXPECT_TRUE(root.GetString("section1.key3", &value)); - EXPECT_EQ("va.lue3", value); - EXPECT_FALSE(root.GetString("se.ction2.key.4", &value)); - EXPECT_FALSE(root.GetString("se.ction2.key5", &value)); -} - -} // namespace - -} // namespace base diff --git a/base/ios/OWNERS b/base/ios/OWNERS deleted file mode 100644 index 625640026f..0000000000 --- a/base/ios/OWNERS +++ /dev/null @@ -1,3 +0,0 @@ -qsr@chromium.org -rohitrao@chromium.org -stuartmorgan@chromium.org diff --git a/base/ios/device_util.h b/base/ios/device_util.h deleted file mode 100644 index fe4833dd36..0000000000 --- a/base/ios/device_util.h +++ /dev/null @@ -1,65 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef BASE_IOS_DEVICE_UTIL_H_ -#define BASE_IOS_DEVICE_UTIL_H_ - -#include - -namespace ios { -namespace device_util { - -// Returns the hardware version of the device the app is running on. -// -// The returned string is the string returned by sysctlbyname() with name -// "hw.machine". Possible (known) values include: -// -// iPhone1,1 -> iPhone 1G -// iPhone1,2 -> iPhone 3G -// iPhone2,1 -> iPhone 3GS -// iPhone3,1 -> iPhone 4/AT&T -// iPhone3,2 -> iPhone 4/Other Carrier? -// iPhone3,3 -> iPhone 4/Other Carrier? -// iPhone4,1 -> iPhone 4S -// -// iPod1,1 -> iPod touch 1G -// iPod2,1 -> iPod touch 2G -// iPod2,2 -> ? -// iPod3,1 -> iPod touch 3G -// iPod4,1 -> iPod touch 4G -// iPod5,1 -> ? -// -// iPad1,1 -> iPad 1G, WiFi -// iPad1,? -> iPad 1G, 3G <- needs 3G owner to test -// iPad2,1 -> iPad 2G, WiFi -// -// AppleTV2,1 -> AppleTV 2 -// -// i386 -> Simulator -// x86_64 -> Simulator -std::string GetPlatform(); - -// Returns true if the application is running on a high-ram device. (>=250M). -bool IsRunningOnHighRamDevice(); - -// Returns true if the device has only one core. -bool IsSingleCoreDevice(); - -// Returns the MAC address of the interface with name |interface_name|. -std::string GetMacAddress(const std::string& interface_name); - -// Returns a random UUID. -std::string GetRandomId(); - -// Returns an identifier for the device, using the given |salt|. A global -// identifier is generated the first time this method is called, and the salt -// is used to be able to generate distinct identifiers for the same device. If -// |salt| is NULL, a default value is used. Unless you are using this value for -// something that should be anonymous, you should probably pass NULL. -std::string GetDeviceIdentifier(const char* salt); - -} // namespace device_util -} // namespace ios - -#endif // BASE_IOS_DEVICE_UTIL_H_ diff --git a/base/ios/device_util.mm b/base/ios/device_util.mm deleted file mode 100644 index 96008332be..0000000000 --- a/base/ios/device_util.mm +++ /dev/null @@ -1,165 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "base/ios/device_util.h" - -#include -#import - -#include -#include -#include -#include -#include - -#include "base/ios/ios_util.h" -#include "base/logging.h" -#include "base/mac/scoped_cftyperef.h" -#include "base/memory/scoped_ptr.h" -#include "base/strings/string_util.h" -#include "base/strings/stringprintf.h" -#include "base/strings/sys_string_conversions.h" - -namespace { - -// Client ID key in the user preferences. -NSString* const kLegacyClientIdPreferenceKey = @"ChromiumClientID"; -NSString* const kClientIdPreferenceKey = @"ChromeClientID"; -// Current hardware type. This is used to detect that a device has been backed -// up and restored to another device, and allows regenerating a new device id. -NSString* const kHardwareTypePreferenceKey = @"ClientIDGenerationHardwareType"; -// Default salt for device ids. -const char kDefaultSalt[] = "Salt"; -// Zero UUID returned on buggy iOS devices. -NSString* const kZeroUUID = @"00000000-0000-0000-0000-000000000000"; - -NSString* GenerateClientId() { - NSUserDefaults* defaults = [NSUserDefaults standardUserDefaults]; - - // Try to migrate from legacy client id. - NSString* client_id = [defaults stringForKey:kLegacyClientIdPreferenceKey]; - - // Some iOS6 devices return a buggy identifierForVendor: - // http://openradar.appspot.com/12377282. If this is the case, revert to - // generating a new one. - if (!client_id || [client_id isEqualToString:kZeroUUID]) { - if (base::ios::IsRunningOnIOS6OrLater()) { - client_id = [[[UIDevice currentDevice] identifierForVendor] UUIDString]; - if ([client_id isEqualToString:kZeroUUID]) - client_id = base::SysUTF8ToNSString(ios::device_util::GetRandomId()); - } else { - client_id = base::SysUTF8ToNSString(ios::device_util::GetRandomId()); - } - } - return client_id; -} - -} // namespace - -namespace ios { -namespace device_util { - -std::string GetPlatform() { - std::string platform; - size_t size = 0; - sysctlbyname("hw.machine", NULL, &size, NULL, 0); - sysctlbyname("hw.machine", WriteInto(&platform, size), &size, NULL, 0); - return platform; -} - -bool IsRunningOnHighRamDevice() { - uint64_t memory_size = 0; - size_t size = sizeof(memory_size); - if (sysctlbyname("hw.memsize", &memory_size, &size, NULL, 0) == 0) { - // Anything >= 250M, call high ram. - return memory_size >= 250 * 1024 * 1024; - } - return false; -} - -bool IsSingleCoreDevice() { - uint64_t cpu_number = 0; - size_t sizes = sizeof(cpu_number); - sysctlbyname("hw.physicalcpu", &cpu_number, &sizes, NULL, 0); - return cpu_number == 1; -} - -std::string GetMacAddress(const std::string& interface_name) { - std::string mac_string; - struct ifaddrs* addresses; - if (getifaddrs(&addresses) == 0) { - for (struct ifaddrs* address = addresses; address; - address = address->ifa_next) { - if ((address->ifa_addr->sa_family == AF_LINK) && - strcmp(interface_name.c_str(), address->ifa_name) == 0) { - const struct sockaddr_dl* found_address_struct = - reinterpret_cast(address->ifa_addr); - - // |found_address_struct->sdl_data| contains the interface name followed - // by the interface address. The address part can be accessed based on - // the length of the name, that is, |found_address_struct->sdl_nlen|. - const unsigned char* found_address = - reinterpret_cast( - &found_address_struct->sdl_data[ - found_address_struct->sdl_nlen]); - - int found_address_length = found_address_struct->sdl_alen; - for (int i = 0; i < found_address_length; ++i) { - if (i != 0) - mac_string.push_back(':'); - base::StringAppendF(&mac_string, "%02X", found_address[i]); - } - break; - } - } - freeifaddrs(addresses); - } - return mac_string; -} - -std::string GetRandomId() { - base::ScopedCFTypeRef uuid_object( - CFUUIDCreate(kCFAllocatorDefault)); - base::ScopedCFTypeRef uuid_string( - CFUUIDCreateString(kCFAllocatorDefault, uuid_object)); - return base::SysCFStringRefToUTF8(uuid_string); -} - -std::string GetDeviceIdentifier(const char* salt) { - NSUserDefaults* defaults = [NSUserDefaults standardUserDefaults]; - - NSString* last_seen_hardware = - [defaults stringForKey:kHardwareTypePreferenceKey]; - NSString* current_hardware = base::SysUTF8ToNSString(GetPlatform()); - if (!last_seen_hardware) { - last_seen_hardware = current_hardware; - [defaults setObject:current_hardware forKey:kHardwareTypePreferenceKey]; - [defaults synchronize]; - } - - NSString* client_id = [defaults stringForKey:kClientIdPreferenceKey]; - - if (!client_id || ![last_seen_hardware isEqualToString:current_hardware]) { - client_id = GenerateClientId(); - [defaults setObject:client_id forKey:kClientIdPreferenceKey]; - [defaults setObject:current_hardware forKey:kHardwareTypePreferenceKey]; - [defaults synchronize]; - } - - NSData* hash_data = [[NSString stringWithFormat:@"%@%s", client_id, - salt ? salt : kDefaultSalt] dataUsingEncoding:NSUTF8StringEncoding]; - - unsigned char hash[CC_SHA256_DIGEST_LENGTH]; - CC_SHA256([hash_data bytes], [hash_data length], hash); - CFUUIDBytes* uuid_bytes = reinterpret_cast(hash); - - base::ScopedCFTypeRef uuid_object( - CFUUIDCreateFromUUIDBytes(kCFAllocatorDefault, *uuid_bytes)); - base::ScopedCFTypeRef device_id( - CFUUIDCreateString(kCFAllocatorDefault, uuid_object)); - return base::SysCFStringRefToUTF8(device_id); -} - -} // namespace device_util -} // namespace ios diff --git a/base/ios/device_util_unittest.mm b/base/ios/device_util_unittest.mm deleted file mode 100644 index c2aefe0f73..0000000000 --- a/base/ios/device_util_unittest.mm +++ /dev/null @@ -1,122 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#import - -#include "base/ios/device_util.h" -#include "base/ios/ios_util.h" -#include "base/strings/sys_string_conversions.h" -#include "testing/gtest/include/gtest/gtest.h" -#include "testing/gtest_mac.h" -#include "testing/platform_test.h" - -namespace { -// The behavior of most of these utility functions depends on what they are run -// on, so there is not much to unittest them. The APIs are run to make sure they -// don't choke. Additional checks are added for particular APIs when needed. - -typedef PlatformTest DeviceUtilTest; - -void CleanNSUserDefaultsForDeviceId() { - NSUserDefaults* defaults = [NSUserDefaults standardUserDefaults]; - [defaults removeObjectForKey:@"ChromeClientID"]; - [defaults removeObjectForKey:@"ChromiumClientID"]; - [defaults removeObjectForKey:@"ClientIDGenerationHardwareType"]; - [defaults synchronize]; -} - -TEST_F(DeviceUtilTest, GetPlatform) { - GTEST_ASSERT_GT(ios::device_util::GetPlatform().length(), 0U); -} - -TEST_F(DeviceUtilTest, IsRunningOnHighRamDevice) { - ios::device_util::IsRunningOnHighRamDevice(); -} - -TEST_F(DeviceUtilTest, IsSingleCoreDevice) { - ios::device_util::IsSingleCoreDevice(); -} - -TEST_F(DeviceUtilTest, GetMacAddress) { - GTEST_ASSERT_GT(ios::device_util::GetMacAddress("en0").length(), 0U); -} - -TEST_F(DeviceUtilTest, GetRandomId) { - GTEST_ASSERT_GT(ios::device_util::GetRandomId().length(), 0U); -} - -TEST_F(DeviceUtilTest, GetDeviceIdentifier) { - CleanNSUserDefaultsForDeviceId(); - - std::string default_id = ios::device_util::GetDeviceIdentifier(NULL); - std::string other_id = ios::device_util::GetDeviceIdentifier("ForTest"); - EXPECT_NE(default_id, other_id); - - CleanNSUserDefaultsForDeviceId(); - - std::string new_default_id = ios::device_util::GetDeviceIdentifier(NULL); - if (base::ios::IsRunningOnIOS6OrLater() && - ![[[[UIDevice currentDevice] identifierForVendor] UUIDString] - isEqualToString:@"00000000-0000-0000-0000-000000000000"]) { - EXPECT_EQ(default_id, new_default_id); - } else { - EXPECT_NE(default_id, new_default_id); - } - - CleanNSUserDefaultsForDeviceId(); -} - -TEST_F(DeviceUtilTest, CheckMigration) { - CleanNSUserDefaultsForDeviceId(); - - NSUserDefaults* defaults = [NSUserDefaults standardUserDefaults]; - [defaults setObject:@"10000000-0000-0000-0000-000000000000" - forKey:@"ChromeClientID"]; - [defaults synchronize]; - std::string expected_id = ios::device_util::GetDeviceIdentifier(NULL); - [defaults removeObjectForKey:@"ChromeClientID"]; - [defaults setObject:@"10000000-0000-0000-0000-000000000000" - forKey:@"ChromiumClientID"]; - [defaults synchronize]; - std::string new_id = ios::device_util::GetDeviceIdentifier(NULL); - EXPECT_EQ(expected_id, new_id); - - CleanNSUserDefaultsForDeviceId(); -} - -TEST_F(DeviceUtilTest, CheckMigrationFromZero) { - CleanNSUserDefaultsForDeviceId(); - - NSUserDefaults* defaults = [NSUserDefaults standardUserDefaults]; - [defaults setObject:@"00000000-0000-0000-0000-000000000000" - forKey:@"ChromeClientID"]; - [defaults synchronize]; - std::string zero_id = ios::device_util::GetDeviceIdentifier(NULL); - [defaults removeObjectForKey:@"ChromeClientID"]; - [defaults setObject:@"00000000-0000-0000-0000-000000000000" - forKey:@"ChromiumClientID"]; - [defaults synchronize]; - std::string new_id = ios::device_util::GetDeviceIdentifier(NULL); - EXPECT_NE(zero_id, new_id); - - CleanNSUserDefaultsForDeviceId(); -} - -TEST_F(DeviceUtilTest, CheckDeviceMigration) { - CleanNSUserDefaultsForDeviceId(); - - NSUserDefaults* defaults = [NSUserDefaults standardUserDefaults]; - [defaults setObject:@"10000000-0000-0000-0000-000000000000" - forKey:@"ChromeClientID"]; - [defaults synchronize]; - std::string base_id = ios::device_util::GetDeviceIdentifier(NULL); - [defaults setObject:@"Foo" forKey:@"ClientIDGenerationHardwareType"]; - [defaults synchronize]; - std::string new_id = ios::device_util::GetDeviceIdentifier(NULL); - EXPECT_NE(new_id, base_id); - - CleanNSUserDefaultsForDeviceId(); -} - -} // namespace diff --git a/base/ios/ios_util.h b/base/ios/ios_util.h deleted file mode 100644 index 7e2e621dfd..0000000000 --- a/base/ios/ios_util.h +++ /dev/null @@ -1,26 +0,0 @@ -// Copyright 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef BASE_IOS_IOS_UTIL_H_ -#define BASE_IOS_IOS_UTIL_H_ - -#include "base/base_export.h" -#include "base/basictypes.h" - -namespace base { -namespace ios { - -// Returns whether the operating system is iOS 6 or later. -BASE_EXPORT bool IsRunningOnIOS6OrLater(); - -// Returns whether the operating system is iOS 7 or later. -BASE_EXPORT bool IsRunningOnIOS7OrLater(); - -// Returns whether the operating system is at the given version or later. -BASE_EXPORT bool IsRunningOnOrLater(int32 major, int32 minor, int32 bug_fix); - -} // namespace ios -} // namespace base - -#endif // BASE_IOS_IOS_UTIL_H_ diff --git a/base/ios/ios_util.mm b/base/ios/ios_util.mm deleted file mode 100644 index a76911017f..0000000000 --- a/base/ios/ios_util.mm +++ /dev/null @@ -1,42 +0,0 @@ -// Copyright 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "base/ios/ios_util.h" - -#include "base/sys_info.h" - -namespace { -// Return a 3 elements array containing the major, minor and bug fix version of -// the OS. -const int32* OSVersionAsArray() { - int32* digits = new int32[3]; - base::SysInfo::OperatingSystemVersionNumbers( - &digits[0], &digits[1], &digits[2]); - return digits; -} -} // namespace - -namespace base { -namespace ios { - -bool IsRunningOnIOS6OrLater() { - return IsRunningOnOrLater(6, 0, 0); -} - -bool IsRunningOnIOS7OrLater() { - return IsRunningOnOrLater(7, 0, 0); -} - -bool IsRunningOnOrLater(int32 major, int32 minor, int32 bug_fix) { - static const int32* current_version = OSVersionAsArray(); - int32 version[] = { major, minor, bug_fix }; - for (size_t i = 0; i < arraysize(version); i++) { - if (current_version[i] != version[i]) - return current_version[i] > version[i]; - } - return true; -} - -} // namespace ios -} // namespace base diff --git a/base/ios/scoped_critical_action.h b/base/ios/scoped_critical_action.h deleted file mode 100644 index 660a83ad02..0000000000 --- a/base/ios/scoped_critical_action.h +++ /dev/null @@ -1,48 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef BASE_IOS_SCOPED_CRITICAL_ACTION_H_ -#define BASE_IOS_SCOPED_CRITICAL_ACTION_H_ - -#include "base/synchronization/lock.h" - -namespace base { -namespace ios { - -// This class attempts to allow the application to continue to run for a period -// of time after it transitions to the background. The construction of an -// instance of this class marks the beginning of a task that needs background -// running time when the application is moved to the background and the -// destruction marks the end of such a task. -// -// Note there is no guarantee that the task will continue to finish when the -// application is moved to the background. -// -// This class should be used at times where leaving a task unfinished might be -// detrimental to user experience. For example, it should be used to ensure that -// the application has enough time to save important data or at least attempt to -// save such data. -class ScopedCriticalAction { - public: - ScopedCriticalAction(); - ~ScopedCriticalAction(); - - private: - // Informs the OS that the background task has completed. - void EndBackgroundTask(); - - // |UIBackgroundTaskIdentifier| returned by - // |beginBackgroundTaskWithExpirationHandler:| when marking the beginning of - // a long-running background task. It is defined as an |unsigned int| instead - // of a |UIBackgroundTaskIdentifier| so this class can be used in .cc files. - unsigned int background_task_id_; - Lock background_task_id_lock_; - - DISALLOW_COPY_AND_ASSIGN(ScopedCriticalAction); -}; - -} // namespace ios -} // namespace base - -#endif // BASE_IOS_SCOPED_CRITICAL_ACTION_H_ diff --git a/base/ios/scoped_critical_action.mm b/base/ios/scoped_critical_action.mm deleted file mode 100644 index 734c0a215b..0000000000 --- a/base/ios/scoped_critical_action.mm +++ /dev/null @@ -1,54 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "base/ios/scoped_critical_action.h" - -#import - -#include "base/logging.h" -#include "base/synchronization/lock.h" - -namespace base { -namespace ios { - -// This implementation calls |beginBackgroundTaskWithExpirationHandler:| when -// instantiated and |endBackgroundTask:| when destroyed, creating a scope whose -// execution will continue (temporarily) even after the app is backgrounded. -ScopedCriticalAction::ScopedCriticalAction() { - background_task_id_ = [[UIApplication sharedApplication] - beginBackgroundTaskWithExpirationHandler:^{ - DLOG(WARNING) << "Background task with id " << background_task_id_ - << " expired."; - // Note if |endBackgroundTask:| is not called for each task before time - // expires, the system kills the application. - EndBackgroundTask(); - }]; - if (background_task_id_ == UIBackgroundTaskInvalid) { - DLOG(WARNING) << - "beginBackgroundTaskWithExpirationHandler: returned an invalid ID"; - } else { - VLOG(3) << "Beginning background task with id " << background_task_id_; - } -} - -ScopedCriticalAction::~ScopedCriticalAction() { - EndBackgroundTask(); -} - -void ScopedCriticalAction::EndBackgroundTask() { - UIBackgroundTaskIdentifier task_id; - { - AutoLock lock_scope(background_task_id_lock_); - if (background_task_id_ == UIBackgroundTaskInvalid) - return; - task_id = background_task_id_; - background_task_id_ = UIBackgroundTaskInvalid; - } - - VLOG(3) << "Ending background task with id " << task_id; - [[UIApplication sharedApplication] endBackgroundTask:task_id]; -} - -} // namespace ios -} // namespace base diff --git a/base/irt-x86-32.base_untrusted.source_list.gypcmd b/base/irt-x86-32.base_untrusted.source_list.gypcmd deleted file mode 100644 index 8dbe0ca926..0000000000 --- a/base/irt-x86-32.base_untrusted.source_list.gypcmd +++ /dev/null @@ -1,353 +0,0 @@ -../build/build_config.h -third_party/dmg_fp/dmg_fp.h -third_party/dmg_fp/g_fmt.cc -third_party/dmg_fp/dtoa_wrapper.cc -third_party/icu/icu_utf.cc -third_party/icu/icu_utf.h -third_party/nspr/prcpucfg.h -third_party/nspr/prcpucfg_freebsd.h -third_party/nspr/prcpucfg_nacl.h -third_party/nspr/prcpucfg_openbsd.h -third_party/nspr/prcpucfg_solaris.h -third_party/nspr/prtime.cc -third_party/nspr/prtime.h -third_party/nspr/prtypes.h -third_party/xdg_mime/xdgmime.h -allocator/allocator_extension.cc -allocator/allocator_extension.h -at_exit.cc -at_exit.h -atomic_ref_count.h -atomic_sequence_num.h -atomicops.h -atomicops_internals_gcc.h -atomicops_internals_tsan.h -atomicops_internals_x86_gcc.h -atomicops_internals_x86_msvc.h -base_export.h -base_paths.h -base_paths_android.h -base_paths_posix.cc -base_paths_posix.h -base_switches.h -base64.cc -base64.h -basictypes.h -bind.h -bind_helpers.cc -bind_helpers.h -bind_internal.h -bits.h -build_time.cc -build_time.h -callback.h -callback_helpers.h -callback_internal.cc -callback_internal.h -cancelable_callback.h -command_line.cc -command_line.h -compiler_specific.h -containers/hash_tables.h -containers/linked_list.h -containers/mru_cache.h -containers/small_map.h -containers/stack_container.h -cpu.h -critical_closure.h -debug/alias.cc -debug/alias.h -debug/crash_logging.cc -debug/crash_logging.h -debug/debugger.cc -debug/debugger.h -debug/debugger_posix.cc -debug/leak_annotations.h -debug/leak_tracker.h -debug/profiler.cc -debug/profiler.h -debug/stack_trace.cc -debug/stack_trace.h -debug/trace_event.h -debug/trace_event_impl.cc -debug/trace_event_impl.h -debug/trace_event_impl_constants.cc -debug/trace_event_memory.cc -debug/trace_event_memory.h -deferred_sequenced_task_runner.cc -deferred_sequenced_task_runner.h -environment.cc -environment.h -file_descriptor_posix.h -file_util.h -file_version_info.h -files/dir_reader_fallback.h -files/dir_reader_posix.h -files/file_enumerator.cc -files/file_enumerator.h -files/file_path.cc -files/file_path.h -files/file_path_constants.cc -files/file_path_watcher.cc -files/file_path_watcher.h -files/file_path_watcher_stub.cc -files/file_util_proxy.h -files/important_file_writer.h -files/important_file_writer.cc -files/memory_mapped_file.cc -files/memory_mapped_file.h -files/memory_mapped_file_posix.cc -files/scoped_platform_file_closer.cc -files/scoped_platform_file_closer.h -files/scoped_temp_dir.h -float_util.h -format_macros.h -gtest_prod_util.h -guid.cc -guid.h -guid_posix.cc -hash.cc -hash.h -id_map.h -ini_parser.cc -ini_parser.h -json/json_file_value_serializer.cc -json/json_file_value_serializer.h -json/json_parser.cc -json/json_parser.h -json/json_reader.cc -json/json_reader.h -json/json_string_value_serializer.cc -json/json_string_value_serializer.h -json/json_value_converter.h -json/json_writer.cc -json/json_writer.h -json/string_escape.cc -json/string_escape.h -lazy_instance.cc -lazy_instance.h -location.cc -location.h -logging.cc -logging.h -memory/aligned_memory.cc -memory/aligned_memory.h -memory/discardable_memory.cc -memory/discardable_memory.h -memory/linked_ptr.h -memory/manual_constructor.h -memory/memory_pressure_listener.cc -memory/memory_pressure_listener.h -memory/raw_scoped_refptr_mismatch_checker.h -memory/ref_counted.cc -memory/ref_counted.h -memory/ref_counted_delete_on_message_loop.h -memory/ref_counted_memory.cc -memory/ref_counted_memory.h -memory/scoped_handle.h -memory/scoped_open_process.h -memory/scoped_policy.h -memory/scoped_ptr.h -memory/scoped_vector.h -memory/shared_memory.h -memory/shared_memory_nacl.cc -memory/singleton.cc -memory/singleton.h -memory/weak_ptr.cc -memory/weak_ptr.h -message_loop/incoming_task_queue.cc -message_loop/incoming_task_queue.h -message_loop/message_loop.cc -message_loop/message_loop.h -message_loop/message_loop_proxy.cc -message_loop/message_loop_proxy.h -message_loop/message_loop_proxy_impl.cc -message_loop/message_loop_proxy_impl.h -message_loop/message_pump.cc -message_loop/message_pump.h -message_loop/message_pump_android.h -message_loop/message_pump_default.cc -message_loop/message_pump_default.h -move.h -native_library.h -observer_list.h -observer_list_threadsafe.h -os_compat_android.h -os_compat_nacl.cc -os_compat_nacl.h -path_service.h -pending_task.cc -pending_task.h -pickle.cc -pickle.h -platform_file.cc -platform_file.h -platform_file_posix.cc -port.h -posix/eintr_wrapper.h -posix/global_descriptors.cc -posix/global_descriptors.h -power_monitor/power_monitor.cc -power_monitor/power_monitor.h -power_monitor/power_monitor_device_source_android.h -power_monitor/power_monitor_device_source.cc -power_monitor/power_monitor_device_source.h -power_monitor/power_monitor_device_source_posix.cc -power_monitor/power_monitor_source.cc -power_monitor/power_monitor_source.h -power_monitor/power_observer.h -process/kill.cc -process/kill.h -process/launch.h -process/memory.h -process/process.h -process/process_handle_posix.cc -process/process_info.h -process/process_iterator.cc -process/process_iterator.h -process/process_metrics.h -profiler/scoped_profile.cc -profiler/scoped_profile.h -profiler/alternate_timer.cc -profiler/alternate_timer.h -profiler/tracked_time.cc -profiler/tracked_time.h -rand_util.cc -rand_util.h -rand_util_nacl.cc -run_loop.cc -run_loop.h -safe_numerics.h -safe_strerror_posix.cc -safe_strerror_posix.h -scoped_native_library.h -sequence_checker.h -sequence_checker_impl.cc -sequence_checker_impl.h -sequenced_task_runner.cc -sequenced_task_runner.h -sequenced_task_runner_helpers.h -sha1.h -sha1_portable.cc -single_thread_task_runner.h -stl_util.h -strings/latin1_string_conversions.cc -strings/latin1_string_conversions.h -strings/nullable_string16.cc -strings/nullable_string16.h -strings/string16.cc -strings/string16.h -strings/string_number_conversions.cc -strings/string_split.cc -strings/string_split.h -strings/string_number_conversions.h -strings/string_piece.cc -strings/string_piece.h -strings/string_tokenizer.h -strings/string_util.cc -strings/string_util.h -strings/string_util_constants.cc -strings/string_util_posix.h -strings/stringize_macros.h -strings/stringprintf.cc -strings/stringprintf.h -strings/sys_string_conversions.h -strings/sys_string_conversions_posix.cc -strings/utf_offset_string_conversions.cc -strings/utf_offset_string_conversions.h -strings/utf_string_conversion_utils.cc -strings/utf_string_conversion_utils.h -strings/utf_string_conversions.cc -strings/utf_string_conversions.h -supports_user_data.cc -supports_user_data.h -synchronization/cancellation_flag.cc -synchronization/cancellation_flag.h -synchronization/condition_variable.h -synchronization/condition_variable_posix.cc -synchronization/lock.cc -synchronization/lock.h -synchronization/lock_impl.h -synchronization/lock_impl_posix.cc -synchronization/spin_wait.h -synchronization/waitable_event.h -synchronization/waitable_event_posix.cc -synchronization/waitable_event_watcher.h -synchronization/waitable_event_watcher_posix.cc -system_monitor/system_monitor.cc -system_monitor/system_monitor.h -sys_byteorder.h -sys_info.cc -sys_info.h -task_runner.cc -task_runner.h -task_runner_util.h -template_util.h -thread_task_runner_handle.cc -thread_task_runner_handle.h -threading/non_thread_safe.h -threading/non_thread_safe_impl.cc -threading/non_thread_safe_impl.h -threading/platform_thread.h -threading/platform_thread_linux.cc -threading/platform_thread_posix.cc -threading/post_task_and_reply_impl.cc -threading/post_task_and_reply_impl.h -threading/sequenced_worker_pool.cc -threading/sequenced_worker_pool.h -threading/simple_thread.cc -threading/simple_thread.h -threading/thread.cc -threading/thread.h -threading/thread_checker.h -threading/thread_checker_impl.cc -threading/thread_checker_impl.h -threading/thread_collision_warner.cc -threading/thread_collision_warner.h -threading/thread_id_name_manager.cc -threading/thread_id_name_manager.h -threading/thread_local.h -threading/thread_local_posix.cc -threading/thread_local_storage.h -threading/thread_local_storage_posix.cc -threading/thread_restrictions.h -threading/thread_restrictions.cc -threading/watchdog.cc -threading/watchdog.h -threading/worker_pool.h -threading/worker_pool.cc -threading/worker_pool_posix.cc -threading/worker_pool_posix.h -time/clock.cc -time/clock.h -time/default_clock.cc -time/default_clock.h -time/default_tick_clock.cc -time/default_tick_clock.h -time/tick_clock.cc -time/tick_clock.h -time/time.cc -time/time.h -time/time_posix.cc -timer/hi_res_timer_manager_posix.cc -timer/hi_res_timer_manager.h -timer/timer.cc -timer/timer.h -tracked_objects.cc -tracked_objects.h -tracking_info.cc -tracking_info.h -tuple.h -values.cc -values.h -value_conversions.cc -value_conversions.h -version.cc -version.h -vlog.cc -vlog.h -base_switches.cc -base_switches.h -strings/string16.cc -sync_socket_nacl.cc -time/time_posix.cc diff --git a/base/irt-x86-64.base_untrusted.source_list.gypcmd b/base/irt-x86-64.base_untrusted.source_list.gypcmd deleted file mode 100644 index 8dbe0ca926..0000000000 --- a/base/irt-x86-64.base_untrusted.source_list.gypcmd +++ /dev/null @@ -1,353 +0,0 @@ -../build/build_config.h -third_party/dmg_fp/dmg_fp.h -third_party/dmg_fp/g_fmt.cc -third_party/dmg_fp/dtoa_wrapper.cc -third_party/icu/icu_utf.cc -third_party/icu/icu_utf.h -third_party/nspr/prcpucfg.h -third_party/nspr/prcpucfg_freebsd.h -third_party/nspr/prcpucfg_nacl.h -third_party/nspr/prcpucfg_openbsd.h -third_party/nspr/prcpucfg_solaris.h -third_party/nspr/prtime.cc -third_party/nspr/prtime.h -third_party/nspr/prtypes.h -third_party/xdg_mime/xdgmime.h -allocator/allocator_extension.cc -allocator/allocator_extension.h -at_exit.cc -at_exit.h -atomic_ref_count.h -atomic_sequence_num.h -atomicops.h -atomicops_internals_gcc.h -atomicops_internals_tsan.h -atomicops_internals_x86_gcc.h -atomicops_internals_x86_msvc.h -base_export.h -base_paths.h -base_paths_android.h -base_paths_posix.cc -base_paths_posix.h -base_switches.h -base64.cc -base64.h -basictypes.h -bind.h -bind_helpers.cc -bind_helpers.h -bind_internal.h -bits.h -build_time.cc -build_time.h -callback.h -callback_helpers.h -callback_internal.cc -callback_internal.h -cancelable_callback.h -command_line.cc -command_line.h -compiler_specific.h -containers/hash_tables.h -containers/linked_list.h -containers/mru_cache.h -containers/small_map.h -containers/stack_container.h -cpu.h -critical_closure.h -debug/alias.cc -debug/alias.h -debug/crash_logging.cc -debug/crash_logging.h -debug/debugger.cc -debug/debugger.h -debug/debugger_posix.cc -debug/leak_annotations.h -debug/leak_tracker.h -debug/profiler.cc -debug/profiler.h -debug/stack_trace.cc -debug/stack_trace.h -debug/trace_event.h -debug/trace_event_impl.cc -debug/trace_event_impl.h -debug/trace_event_impl_constants.cc -debug/trace_event_memory.cc -debug/trace_event_memory.h -deferred_sequenced_task_runner.cc -deferred_sequenced_task_runner.h -environment.cc -environment.h -file_descriptor_posix.h -file_util.h -file_version_info.h -files/dir_reader_fallback.h -files/dir_reader_posix.h -files/file_enumerator.cc -files/file_enumerator.h -files/file_path.cc -files/file_path.h -files/file_path_constants.cc -files/file_path_watcher.cc -files/file_path_watcher.h -files/file_path_watcher_stub.cc -files/file_util_proxy.h -files/important_file_writer.h -files/important_file_writer.cc -files/memory_mapped_file.cc -files/memory_mapped_file.h -files/memory_mapped_file_posix.cc -files/scoped_platform_file_closer.cc -files/scoped_platform_file_closer.h -files/scoped_temp_dir.h -float_util.h -format_macros.h -gtest_prod_util.h -guid.cc -guid.h -guid_posix.cc -hash.cc -hash.h -id_map.h -ini_parser.cc -ini_parser.h -json/json_file_value_serializer.cc -json/json_file_value_serializer.h -json/json_parser.cc -json/json_parser.h -json/json_reader.cc -json/json_reader.h -json/json_string_value_serializer.cc -json/json_string_value_serializer.h -json/json_value_converter.h -json/json_writer.cc -json/json_writer.h -json/string_escape.cc -json/string_escape.h -lazy_instance.cc -lazy_instance.h -location.cc -location.h -logging.cc -logging.h -memory/aligned_memory.cc -memory/aligned_memory.h -memory/discardable_memory.cc -memory/discardable_memory.h -memory/linked_ptr.h -memory/manual_constructor.h -memory/memory_pressure_listener.cc -memory/memory_pressure_listener.h -memory/raw_scoped_refptr_mismatch_checker.h -memory/ref_counted.cc -memory/ref_counted.h -memory/ref_counted_delete_on_message_loop.h -memory/ref_counted_memory.cc -memory/ref_counted_memory.h -memory/scoped_handle.h -memory/scoped_open_process.h -memory/scoped_policy.h -memory/scoped_ptr.h -memory/scoped_vector.h -memory/shared_memory.h -memory/shared_memory_nacl.cc -memory/singleton.cc -memory/singleton.h -memory/weak_ptr.cc -memory/weak_ptr.h -message_loop/incoming_task_queue.cc -message_loop/incoming_task_queue.h -message_loop/message_loop.cc -message_loop/message_loop.h -message_loop/message_loop_proxy.cc -message_loop/message_loop_proxy.h -message_loop/message_loop_proxy_impl.cc -message_loop/message_loop_proxy_impl.h -message_loop/message_pump.cc -message_loop/message_pump.h -message_loop/message_pump_android.h -message_loop/message_pump_default.cc -message_loop/message_pump_default.h -move.h -native_library.h -observer_list.h -observer_list_threadsafe.h -os_compat_android.h -os_compat_nacl.cc -os_compat_nacl.h -path_service.h -pending_task.cc -pending_task.h -pickle.cc -pickle.h -platform_file.cc -platform_file.h -platform_file_posix.cc -port.h -posix/eintr_wrapper.h -posix/global_descriptors.cc -posix/global_descriptors.h -power_monitor/power_monitor.cc -power_monitor/power_monitor.h -power_monitor/power_monitor_device_source_android.h -power_monitor/power_monitor_device_source.cc -power_monitor/power_monitor_device_source.h -power_monitor/power_monitor_device_source_posix.cc -power_monitor/power_monitor_source.cc -power_monitor/power_monitor_source.h -power_monitor/power_observer.h -process/kill.cc -process/kill.h -process/launch.h -process/memory.h -process/process.h -process/process_handle_posix.cc -process/process_info.h -process/process_iterator.cc -process/process_iterator.h -process/process_metrics.h -profiler/scoped_profile.cc -profiler/scoped_profile.h -profiler/alternate_timer.cc -profiler/alternate_timer.h -profiler/tracked_time.cc -profiler/tracked_time.h -rand_util.cc -rand_util.h -rand_util_nacl.cc -run_loop.cc -run_loop.h -safe_numerics.h -safe_strerror_posix.cc -safe_strerror_posix.h -scoped_native_library.h -sequence_checker.h -sequence_checker_impl.cc -sequence_checker_impl.h -sequenced_task_runner.cc -sequenced_task_runner.h -sequenced_task_runner_helpers.h -sha1.h -sha1_portable.cc -single_thread_task_runner.h -stl_util.h -strings/latin1_string_conversions.cc -strings/latin1_string_conversions.h -strings/nullable_string16.cc -strings/nullable_string16.h -strings/string16.cc -strings/string16.h -strings/string_number_conversions.cc -strings/string_split.cc -strings/string_split.h -strings/string_number_conversions.h -strings/string_piece.cc -strings/string_piece.h -strings/string_tokenizer.h -strings/string_util.cc -strings/string_util.h -strings/string_util_constants.cc -strings/string_util_posix.h -strings/stringize_macros.h -strings/stringprintf.cc -strings/stringprintf.h -strings/sys_string_conversions.h -strings/sys_string_conversions_posix.cc -strings/utf_offset_string_conversions.cc -strings/utf_offset_string_conversions.h -strings/utf_string_conversion_utils.cc -strings/utf_string_conversion_utils.h -strings/utf_string_conversions.cc -strings/utf_string_conversions.h -supports_user_data.cc -supports_user_data.h -synchronization/cancellation_flag.cc -synchronization/cancellation_flag.h -synchronization/condition_variable.h -synchronization/condition_variable_posix.cc -synchronization/lock.cc -synchronization/lock.h -synchronization/lock_impl.h -synchronization/lock_impl_posix.cc -synchronization/spin_wait.h -synchronization/waitable_event.h -synchronization/waitable_event_posix.cc -synchronization/waitable_event_watcher.h -synchronization/waitable_event_watcher_posix.cc -system_monitor/system_monitor.cc -system_monitor/system_monitor.h -sys_byteorder.h -sys_info.cc -sys_info.h -task_runner.cc -task_runner.h -task_runner_util.h -template_util.h -thread_task_runner_handle.cc -thread_task_runner_handle.h -threading/non_thread_safe.h -threading/non_thread_safe_impl.cc -threading/non_thread_safe_impl.h -threading/platform_thread.h -threading/platform_thread_linux.cc -threading/platform_thread_posix.cc -threading/post_task_and_reply_impl.cc -threading/post_task_and_reply_impl.h -threading/sequenced_worker_pool.cc -threading/sequenced_worker_pool.h -threading/simple_thread.cc -threading/simple_thread.h -threading/thread.cc -threading/thread.h -threading/thread_checker.h -threading/thread_checker_impl.cc -threading/thread_checker_impl.h -threading/thread_collision_warner.cc -threading/thread_collision_warner.h -threading/thread_id_name_manager.cc -threading/thread_id_name_manager.h -threading/thread_local.h -threading/thread_local_posix.cc -threading/thread_local_storage.h -threading/thread_local_storage_posix.cc -threading/thread_restrictions.h -threading/thread_restrictions.cc -threading/watchdog.cc -threading/watchdog.h -threading/worker_pool.h -threading/worker_pool.cc -threading/worker_pool_posix.cc -threading/worker_pool_posix.h -time/clock.cc -time/clock.h -time/default_clock.cc -time/default_clock.h -time/default_tick_clock.cc -time/default_tick_clock.h -time/tick_clock.cc -time/tick_clock.h -time/time.cc -time/time.h -time/time_posix.cc -timer/hi_res_timer_manager_posix.cc -timer/hi_res_timer_manager.h -timer/timer.cc -timer/timer.h -tracked_objects.cc -tracked_objects.h -tracking_info.cc -tracking_info.h -tuple.h -values.cc -values.h -value_conversions.cc -value_conversions.h -version.cc -version.h -vlog.cc -vlog.h -base_switches.cc -base_switches.h -strings/string16.cc -sync_socket_nacl.cc -time/time_posix.cc diff --git a/base/json/json_file_value_serializer.cc b/base/json/json_file_value_serializer.cc deleted file mode 100644 index 37371e8752..0000000000 --- a/base/json/json_file_value_serializer.cc +++ /dev/null @@ -1,99 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "base/json/json_file_value_serializer.h" - -#include "base/file_util.h" -#include "base/json/json_string_value_serializer.h" -#include "base/logging.h" - -using base::FilePath; - -const char* JSONFileValueSerializer::kAccessDenied = "Access denied."; -const char* JSONFileValueSerializer::kCannotReadFile = "Can't read file."; -const char* JSONFileValueSerializer::kFileLocked = "File locked."; -const char* JSONFileValueSerializer::kNoSuchFile = "File doesn't exist."; - -bool JSONFileValueSerializer::Serialize(const base::Value& root) { - return SerializeInternal(root, false); -} - -bool JSONFileValueSerializer::SerializeAndOmitBinaryValues( - const base::Value& root) { - return SerializeInternal(root, true); -} - -bool JSONFileValueSerializer::SerializeInternal(const base::Value& root, - bool omit_binary_values) { - std::string json_string; - JSONStringValueSerializer serializer(&json_string); - serializer.set_pretty_print(true); - bool result = omit_binary_values ? - serializer.SerializeAndOmitBinaryValues(root) : - serializer.Serialize(root); - if (!result) - return false; - - int data_size = static_cast(json_string.size()); - if (file_util::WriteFile(json_file_path_, - json_string.data(), - data_size) != data_size) - return false; - - return true; -} - -int JSONFileValueSerializer::ReadFileToString(std::string* json_string) { - DCHECK(json_string); - if (!file_util::ReadFileToString(json_file_path_, json_string)) { -#if defined(OS_WIN) - int error = ::GetLastError(); - if (error == ERROR_SHARING_VIOLATION || error == ERROR_LOCK_VIOLATION) { - return JSON_FILE_LOCKED; - } else if (error == ERROR_ACCESS_DENIED) { - return JSON_ACCESS_DENIED; - } -#endif - if (!base::PathExists(json_file_path_)) - return JSON_NO_SUCH_FILE; - else - return JSON_CANNOT_READ_FILE; - } - return JSON_NO_ERROR; -} - -const char* JSONFileValueSerializer::GetErrorMessageForCode(int error_code) { - switch (error_code) { - case JSON_NO_ERROR: - return ""; - case JSON_ACCESS_DENIED: - return kAccessDenied; - case JSON_CANNOT_READ_FILE: - return kCannotReadFile; - case JSON_FILE_LOCKED: - return kFileLocked; - case JSON_NO_SUCH_FILE: - return kNoSuchFile; - default: - NOTREACHED(); - return ""; - } -} - -base::Value* JSONFileValueSerializer::Deserialize(int* error_code, - std::string* error_str) { - std::string json_string; - int error = ReadFileToString(&json_string); - if (error != JSON_NO_ERROR) { - if (error_code) - *error_code = error; - if (error_str) - *error_str = GetErrorMessageForCode(error); - return NULL; - } - - JSONStringValueSerializer serializer(json_string); - serializer.set_allow_trailing_comma(allow_trailing_comma_); - return serializer.Deserialize(error_code, error_str); -} diff --git a/base/json/json_file_value_serializer.h b/base/json/json_file_value_serializer.h deleted file mode 100644 index 4a0c334871..0000000000 --- a/base/json/json_file_value_serializer.h +++ /dev/null @@ -1,88 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef BASE_JSON_JSON_FILE_VALUE_SERIALIZER_H_ -#define BASE_JSON_JSON_FILE_VALUE_SERIALIZER_H_ - -#include - -#include "base/base_export.h" -#include "base/basictypes.h" -#include "base/files/file_path.h" -#include "base/values.h" - -class BASE_EXPORT JSONFileValueSerializer : public base::ValueSerializer { - public: - // json_file_patch is the path of a file that will be source of the - // deserialization or the destination of the serialization. - // When deserializing, the file should exist, but when serializing, the - // serializer will attempt to create the file at the specified location. - explicit JSONFileValueSerializer(const base::FilePath& json_file_path) - : json_file_path_(json_file_path), - allow_trailing_comma_(false) {} - - virtual ~JSONFileValueSerializer() {} - - // DO NOT USE except in unit tests to verify the file was written properly. - // We should never serialize directly to a file since this will block the - // thread. Instead, serialize to a string and write to the file you want on - // the file thread. - // - // Attempt to serialize the data structure represented by Value into - // JSON. If the return value is true, the result will have been written - // into the file whose name was passed into the constructor. - virtual bool Serialize(const base::Value& root) OVERRIDE; - - // Equivalent to Serialize(root) except binary values are omitted from the - // output. - bool SerializeAndOmitBinaryValues(const base::Value& root); - - // Attempt to deserialize the data structure encoded in the file passed - // in to the constructor into a structure of Value objects. If the return - // value is NULL, and if |error_code| is non-null, |error_code| will - // contain an integer error code (either JsonFileError or JsonParseError). - // If |error_message| is non-null, it will be filled in with a formatted - // error message including the location of the error if appropriate. - // The caller takes ownership of the returned value. - virtual base::Value* Deserialize(int* error_code, - std::string* error_message) OVERRIDE; - - // This enum is designed to safely overlap with JSONReader::JsonParseError. - enum JsonFileError { - JSON_NO_ERROR = 0, - JSON_ACCESS_DENIED = 1000, - JSON_CANNOT_READ_FILE, - JSON_FILE_LOCKED, - JSON_NO_SUCH_FILE - }; - - // File-specific error messages that can be returned. - static const char* kAccessDenied; - static const char* kCannotReadFile; - static const char* kFileLocked; - static const char* kNoSuchFile; - - // Convert an error code into an error message. |error_code| is assumed to - // be a JsonFileError. - static const char* GetErrorMessageForCode(int error_code); - - void set_allow_trailing_comma(bool new_value) { - allow_trailing_comma_ = new_value; - } - - private: - bool SerializeInternal(const base::Value& root, bool omit_binary_values); - - base::FilePath json_file_path_; - bool allow_trailing_comma_; - - // A wrapper for file_util::ReadFileToString which returns a non-zero - // JsonFileError if there were file errors. - int ReadFileToString(std::string* json_string); - - DISALLOW_IMPLICIT_CONSTRUCTORS(JSONFileValueSerializer); -}; - -#endif // BASE_JSON_JSON_FILE_VALUE_SERIALIZER_H_ - diff --git a/base/json/json_parser.cc b/base/json/json_parser.cc deleted file mode 100644 index f1f43337c4..0000000000 --- a/base/json/json_parser.cc +++ /dev/null @@ -1,965 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "base/json/json_parser.h" - -#include "base/float_util.h" -#include "base/logging.h" -#include "base/memory/scoped_ptr.h" -#include "base/strings/string_number_conversions.h" -#include "base/strings/string_piece.h" -#include "base/strings/string_util.h" -#include "base/strings/stringprintf.h" -#include "base/strings/utf_string_conversion_utils.h" -#include "base/strings/utf_string_conversions.h" -#include "base/third_party/icu/icu_utf.h" -#include "base/values.h" - -namespace base { -namespace internal { - -namespace { - -const int kStackMaxDepth = 100; - -const int32 kExtendedASCIIStart = 0x80; - -// This and the class below are used to own the JSON input string for when -// string tokens are stored as StringPiece instead of std::string. This -// optimization avoids about 2/3rds of string memory copies. The constructor -// takes ownership of the input string. The real root value is Swap()ed into -// the new instance. -class DictionaryHiddenRootValue : public base::DictionaryValue { - public: - DictionaryHiddenRootValue(std::string* json, Value* root) : json_(json) { - DCHECK(root->IsType(Value::TYPE_DICTIONARY)); - DictionaryValue::Swap(static_cast(root)); - } - - virtual void Swap(DictionaryValue* other) OVERRIDE { - DVLOG(1) << "Swap()ing a DictionaryValue inefficiently."; - - // First deep copy to convert JSONStringValue to std::string and swap that - // copy with |other|, which contains the new contents of |this|. - scoped_ptr copy(DeepCopy()); - copy->Swap(other); - - // Then erase the contents of the current dictionary and swap in the - // new contents, originally from |other|. - Clear(); - json_.reset(); - DictionaryValue::Swap(copy.get()); - } - - // Not overriding DictionaryValue::Remove because it just calls through to - // the method below. - - virtual bool RemoveWithoutPathExpansion(const std::string& key, - scoped_ptr* out) OVERRIDE { - // If the caller won't take ownership of the removed value, just call up. - if (!out) - return DictionaryValue::RemoveWithoutPathExpansion(key, out); - - DVLOG(1) << "Remove()ing from a DictionaryValue inefficiently."; - - // Otherwise, remove the value while its still "owned" by this and copy it - // to convert any JSONStringValues to std::string. - scoped_ptr out_owned; - if (!DictionaryValue::RemoveWithoutPathExpansion(key, &out_owned)) - return false; - - out->reset(out_owned->DeepCopy()); - - return true; - } - - private: - scoped_ptr json_; - - DISALLOW_COPY_AND_ASSIGN(DictionaryHiddenRootValue); -}; - -class ListHiddenRootValue : public base::ListValue { - public: - ListHiddenRootValue(std::string* json, Value* root) : json_(json) { - DCHECK(root->IsType(Value::TYPE_LIST)); - ListValue::Swap(static_cast(root)); - } - - virtual void Swap(ListValue* other) OVERRIDE { - DVLOG(1) << "Swap()ing a ListValue inefficiently."; - - // First deep copy to convert JSONStringValue to std::string and swap that - // copy with |other|, which contains the new contents of |this|. - scoped_ptr copy(DeepCopy()); - copy->Swap(other); - - // Then erase the contents of the current list and swap in the new contents, - // originally from |other|. - Clear(); - json_.reset(); - ListValue::Swap(copy.get()); - } - - virtual bool Remove(size_t index, scoped_ptr* out) OVERRIDE { - // If the caller won't take ownership of the removed value, just call up. - if (!out) - return ListValue::Remove(index, out); - - DVLOG(1) << "Remove()ing from a ListValue inefficiently."; - - // Otherwise, remove the value while its still "owned" by this and copy it - // to convert any JSONStringValues to std::string. - scoped_ptr out_owned; - if (!ListValue::Remove(index, &out_owned)) - return false; - - out->reset(out_owned->DeepCopy()); - - return true; - } - - private: - scoped_ptr json_; - - DISALLOW_COPY_AND_ASSIGN(ListHiddenRootValue); -}; - -// A variant on StringValue that uses StringPiece instead of copying the string -// into the Value. This can only be stored in a child of hidden root (above), -// otherwise the referenced string will not be guaranteed to outlive it. -class JSONStringValue : public base::Value { - public: - explicit JSONStringValue(const base::StringPiece& piece) - : Value(TYPE_STRING), - string_piece_(piece) { - } - - // Overridden from base::Value: - virtual bool GetAsString(std::string* out_value) const OVERRIDE { - string_piece_.CopyToString(out_value); - return true; - } - virtual bool GetAsString(string16* out_value) const OVERRIDE { - *out_value = UTF8ToUTF16(string_piece_); - return true; - } - virtual Value* DeepCopy() const OVERRIDE { - return new StringValue(string_piece_.as_string()); - } - virtual bool Equals(const Value* other) const OVERRIDE { - std::string other_string; - return other->IsType(TYPE_STRING) && other->GetAsString(&other_string) && - StringPiece(other_string) == string_piece_; - } - - private: - // The location in the original input stream. - base::StringPiece string_piece_; - - DISALLOW_COPY_AND_ASSIGN(JSONStringValue); -}; - -// Simple class that checks for maximum recursion/"stack overflow." -class StackMarker { - public: - explicit StackMarker(int* depth) : depth_(depth) { - ++(*depth_); - DCHECK_LE(*depth_, kStackMaxDepth); - } - ~StackMarker() { - --(*depth_); - } - - bool IsTooDeep() const { - return *depth_ >= kStackMaxDepth; - } - - private: - int* const depth_; - - DISALLOW_COPY_AND_ASSIGN(StackMarker); -}; - -} // namespace - -JSONParser::JSONParser(int options) - : options_(options), - start_pos_(NULL), - pos_(NULL), - end_pos_(NULL), - index_(0), - stack_depth_(0), - line_number_(0), - index_last_line_(0), - error_code_(JSONReader::JSON_NO_ERROR), - error_line_(0), - error_column_(0) { -} - -JSONParser::~JSONParser() { -} - -Value* JSONParser::Parse(const StringPiece& input) { - scoped_ptr input_copy; - // If the children of a JSON root can be detached, then hidden roots cannot - // be used, so do not bother copying the input because StringPiece will not - // be used anywhere. - if (!(options_ & JSON_DETACHABLE_CHILDREN)) { - input_copy.reset(new std::string(input.as_string())); - start_pos_ = input_copy->data(); - } else { - start_pos_ = input.data(); - } - pos_ = start_pos_; - end_pos_ = start_pos_ + input.length(); - index_ = 0; - line_number_ = 1; - index_last_line_ = 0; - - error_code_ = JSONReader::JSON_NO_ERROR; - error_line_ = 0; - error_column_ = 0; - - // When the input JSON string starts with a UTF-8 Byte-Order-Mark - // <0xEF 0xBB 0xBF>, advance the start position to avoid the - // ParseNextToken function mis-treating a Unicode BOM as an invalid - // character and returning NULL. - if (CanConsume(3) && static_cast(*pos_) == 0xEF && - static_cast(*(pos_ + 1)) == 0xBB && - static_cast(*(pos_ + 2)) == 0xBF) { - NextNChars(3); - } - - // Parse the first and any nested tokens. - scoped_ptr root(ParseNextToken()); - if (!root.get()) - return NULL; - - // Make sure the input stream is at an end. - if (GetNextToken() != T_END_OF_INPUT) { - if (!CanConsume(1) || (NextChar() && GetNextToken() != T_END_OF_INPUT)) { - ReportError(JSONReader::JSON_UNEXPECTED_DATA_AFTER_ROOT, 1); - return NULL; - } - } - - // Dictionaries and lists can contain JSONStringValues, so wrap them in a - // hidden root. - if (!(options_ & JSON_DETACHABLE_CHILDREN)) { - if (root->IsType(Value::TYPE_DICTIONARY)) { - return new DictionaryHiddenRootValue(input_copy.release(), root.get()); - } else if (root->IsType(Value::TYPE_LIST)) { - return new ListHiddenRootValue(input_copy.release(), root.get()); - } else if (root->IsType(Value::TYPE_STRING)) { - // A string type could be a JSONStringValue, but because there's no - // corresponding HiddenRootValue, the memory will be lost. Deep copy to - // preserve it. - return root->DeepCopy(); - } - } - - // All other values can be returned directly. - return root.release(); -} - -JSONReader::JsonParseError JSONParser::error_code() const { - return error_code_; -} - -std::string JSONParser::GetErrorMessage() const { - return FormatErrorMessage(error_line_, error_column_, - JSONReader::ErrorCodeToString(error_code_)); -} - -// StringBuilder /////////////////////////////////////////////////////////////// - -JSONParser::StringBuilder::StringBuilder() - : pos_(NULL), - length_(0), - string_(NULL) { -} - -JSONParser::StringBuilder::StringBuilder(const char* pos) - : pos_(pos), - length_(0), - string_(NULL) { -} - -void JSONParser::StringBuilder::Swap(StringBuilder* other) { - std::swap(other->string_, string_); - std::swap(other->pos_, pos_); - std::swap(other->length_, length_); -} - -JSONParser::StringBuilder::~StringBuilder() { - delete string_; -} - -void JSONParser::StringBuilder::Append(const char& c) { - DCHECK_GE(c, 0); - DCHECK_LT(c, 128); - - if (string_) - string_->push_back(c); - else - ++length_; -} - -void JSONParser::StringBuilder::AppendString(const std::string& str) { - DCHECK(string_); - string_->append(str); -} - -void JSONParser::StringBuilder::Convert() { - if (string_) - return; - string_ = new std::string(pos_, length_); -} - -bool JSONParser::StringBuilder::CanBeStringPiece() const { - return !string_; -} - -StringPiece JSONParser::StringBuilder::AsStringPiece() { - if (string_) - return StringPiece(); - return StringPiece(pos_, length_); -} - -const std::string& JSONParser::StringBuilder::AsString() { - if (!string_) - Convert(); - return *string_; -} - -// JSONParser private ////////////////////////////////////////////////////////// - -inline bool JSONParser::CanConsume(int length) { - return pos_ + length <= end_pos_; -} - -const char* JSONParser::NextChar() { - DCHECK(CanConsume(1)); - ++index_; - ++pos_; - return pos_; -} - -void JSONParser::NextNChars(int n) { - DCHECK(CanConsume(n)); - index_ += n; - pos_ += n; -} - -JSONParser::Token JSONParser::GetNextToken() { - EatWhitespaceAndComments(); - if (!CanConsume(1)) - return T_END_OF_INPUT; - - switch (*pos_) { - case '{': - return T_OBJECT_BEGIN; - case '}': - return T_OBJECT_END; - case '[': - return T_ARRAY_BEGIN; - case ']': - return T_ARRAY_END; - case '"': - return T_STRING; - case '0': - case '1': - case '2': - case '3': - case '4': - case '5': - case '6': - case '7': - case '8': - case '9': - case '-': - return T_NUMBER; - case 't': - return T_BOOL_TRUE; - case 'f': - return T_BOOL_FALSE; - case 'n': - return T_NULL; - case ',': - return T_LIST_SEPARATOR; - case ':': - return T_OBJECT_PAIR_SEPARATOR; - default: - return T_INVALID_TOKEN; - } -} - -void JSONParser::EatWhitespaceAndComments() { - while (pos_ < end_pos_) { - switch (*pos_) { - case '\r': - case '\n': - index_last_line_ = index_; - // Don't increment line_number_ twice for "\r\n". - if (!(*pos_ == '\n' && pos_ > start_pos_ && *(pos_ - 1) == '\r')) - ++line_number_; - // Fall through. - case ' ': - case '\t': - NextChar(); - break; - case '/': - if (!EatComment()) - return; - break; - default: - return; - } - } -} - -bool JSONParser::EatComment() { - if (*pos_ != '/' || !CanConsume(1)) - return false; - - char next_char = *NextChar(); - if (next_char == '/') { - // Single line comment, read to newline. - while (CanConsume(1)) { - char next_char = *NextChar(); - if (next_char == '\n' || next_char == '\r') - return true; - } - } else if (next_char == '*') { - char previous_char = '\0'; - // Block comment, read until end marker. - while (CanConsume(1)) { - next_char = *NextChar(); - if (previous_char == '*' && next_char == '/') { - // EatWhitespaceAndComments will inspect pos_, which will still be on - // the last / of the comment, so advance once more (which may also be - // end of input). - NextChar(); - return true; - } - previous_char = next_char; - } - - // If the comment is unterminated, GetNextToken will report T_END_OF_INPUT. - } - - return false; -} - -Value* JSONParser::ParseNextToken() { - return ParseToken(GetNextToken()); -} - -Value* JSONParser::ParseToken(Token token) { - switch (token) { - case T_OBJECT_BEGIN: - return ConsumeDictionary(); - case T_ARRAY_BEGIN: - return ConsumeList(); - case T_STRING: - return ConsumeString(); - case T_NUMBER: - return ConsumeNumber(); - case T_BOOL_TRUE: - case T_BOOL_FALSE: - case T_NULL: - return ConsumeLiteral(); - default: - ReportError(JSONReader::JSON_UNEXPECTED_TOKEN, 1); - return NULL; - } -} - -Value* JSONParser::ConsumeDictionary() { - if (*pos_ != '{') { - ReportError(JSONReader::JSON_UNEXPECTED_TOKEN, 1); - return NULL; - } - - StackMarker depth_check(&stack_depth_); - if (depth_check.IsTooDeep()) { - ReportError(JSONReader::JSON_TOO_MUCH_NESTING, 1); - return NULL; - } - - scoped_ptr dict(new DictionaryValue); - - NextChar(); - Token token = GetNextToken(); - while (token != T_OBJECT_END) { - if (token != T_STRING) { - ReportError(JSONReader::JSON_UNQUOTED_DICTIONARY_KEY, 1); - return NULL; - } - - // First consume the key. - StringBuilder key; - if (!ConsumeStringRaw(&key)) { - return NULL; - } - - // Read the separator. - NextChar(); - token = GetNextToken(); - if (token != T_OBJECT_PAIR_SEPARATOR) { - ReportError(JSONReader::JSON_SYNTAX_ERROR, 1); - return NULL; - } - - // The next token is the value. Ownership transfers to |dict|. - NextChar(); - Value* value = ParseNextToken(); - if (!value) { - // ReportError from deeper level. - return NULL; - } - - dict->SetWithoutPathExpansion(key.AsString(), value); - - NextChar(); - token = GetNextToken(); - if (token == T_LIST_SEPARATOR) { - NextChar(); - token = GetNextToken(); - if (token == T_OBJECT_END && !(options_ & JSON_ALLOW_TRAILING_COMMAS)) { - ReportError(JSONReader::JSON_TRAILING_COMMA, 1); - return NULL; - } - } else if (token != T_OBJECT_END) { - ReportError(JSONReader::JSON_SYNTAX_ERROR, 0); - return NULL; - } - } - - return dict.release(); -} - -Value* JSONParser::ConsumeList() { - if (*pos_ != '[') { - ReportError(JSONReader::JSON_UNEXPECTED_TOKEN, 1); - return NULL; - } - - StackMarker depth_check(&stack_depth_); - if (depth_check.IsTooDeep()) { - ReportError(JSONReader::JSON_TOO_MUCH_NESTING, 1); - return NULL; - } - - scoped_ptr list(new ListValue); - - NextChar(); - Token token = GetNextToken(); - while (token != T_ARRAY_END) { - Value* item = ParseToken(token); - if (!item) { - // ReportError from deeper level. - return NULL; - } - - list->Append(item); - - NextChar(); - token = GetNextToken(); - if (token == T_LIST_SEPARATOR) { - NextChar(); - token = GetNextToken(); - if (token == T_ARRAY_END && !(options_ & JSON_ALLOW_TRAILING_COMMAS)) { - ReportError(JSONReader::JSON_TRAILING_COMMA, 1); - return NULL; - } - } else if (token != T_ARRAY_END) { - ReportError(JSONReader::JSON_SYNTAX_ERROR, 1); - return NULL; - } - } - - return list.release(); -} - -Value* JSONParser::ConsumeString() { - StringBuilder string; - if (!ConsumeStringRaw(&string)) - return NULL; - - // Create the Value representation, using a hidden root, if configured - // to do so, and if the string can be represented by StringPiece. - if (string.CanBeStringPiece() && !(options_ & JSON_DETACHABLE_CHILDREN)) { - return new JSONStringValue(string.AsStringPiece()); - } else { - if (string.CanBeStringPiece()) - string.Convert(); - return new StringValue(string.AsString()); - } -} - -bool JSONParser::ConsumeStringRaw(StringBuilder* out) { - if (*pos_ != '"') { - ReportError(JSONReader::JSON_UNEXPECTED_TOKEN, 1); - return false; - } - - // StringBuilder will internally build a StringPiece unless a UTF-16 - // conversion occurs, at which point it will perform a copy into a - // std::string. - StringBuilder string(NextChar()); - - int length = end_pos_ - start_pos_; - int32 next_char = 0; - - while (CanConsume(1)) { - pos_ = start_pos_ + index_; // CBU8_NEXT is postcrement. - CBU8_NEXT(start_pos_, index_, length, next_char); - if (next_char < 0 || !IsValidCharacter(next_char)) { - ReportError(JSONReader::JSON_UNSUPPORTED_ENCODING, 1); - return false; - } - - // If this character is an escape sequence... - if (next_char == '\\') { - // The input string will be adjusted (either by combining the two - // characters of an encoded escape sequence, or with a UTF conversion), - // so using StringPiece isn't possible -- force a conversion. - string.Convert(); - - if (!CanConsume(1)) { - ReportError(JSONReader::JSON_INVALID_ESCAPE, 0); - return false; - } - - switch (*NextChar()) { - // Allowed esape sequences: - case 'x': { // UTF-8 sequence. - // UTF-8 \x escape sequences are not allowed in the spec, but they - // are supported here for backwards-compatiblity with the old parser. - if (!CanConsume(2)) { - ReportError(JSONReader::JSON_INVALID_ESCAPE, 1); - return false; - } - - int hex_digit = 0; - if (!HexStringToInt(StringPiece(NextChar(), 2), &hex_digit)) { - ReportError(JSONReader::JSON_INVALID_ESCAPE, -1); - return false; - } - NextChar(); - - if (hex_digit < kExtendedASCIIStart) - string.Append(hex_digit); - else - DecodeUTF8(hex_digit, &string); - break; - } - case 'u': { // UTF-16 sequence. - // UTF units are of the form \uXXXX. - if (!CanConsume(5)) { // 5 being 'u' and four HEX digits. - ReportError(JSONReader::JSON_INVALID_ESCAPE, 0); - return false; - } - - // Skip the 'u'. - NextChar(); - - std::string utf8_units; - if (!DecodeUTF16(&utf8_units)) { - ReportError(JSONReader::JSON_INVALID_ESCAPE, -1); - return false; - } - - string.AppendString(utf8_units); - break; - } - case '"': - string.Append('"'); - break; - case '\\': - string.Append('\\'); - break; - case '/': - string.Append('/'); - break; - case 'b': - string.Append('\b'); - break; - case 'f': - string.Append('\f'); - break; - case 'n': - string.Append('\n'); - break; - case 'r': - string.Append('\r'); - break; - case 't': - string.Append('\t'); - break; - case 'v': // Not listed as valid escape sequence in the RFC. - string.Append('\v'); - break; - // All other escape squences are illegal. - default: - ReportError(JSONReader::JSON_INVALID_ESCAPE, 0); - return false; - } - } else if (next_char == '"') { - --index_; // Rewind by one because of CBU8_NEXT. - out->Swap(&string); - return true; - } else { - if (next_char < kExtendedASCIIStart) - string.Append(next_char); - else - DecodeUTF8(next_char, &string); - } - } - - ReportError(JSONReader::JSON_SYNTAX_ERROR, 0); - return false; -} - -// Entry is at the first X in \uXXXX. -bool JSONParser::DecodeUTF16(std::string* dest_string) { - if (!CanConsume(4)) - return false; - - // This is a 32-bit field because the shift operations in the - // conversion process below cause MSVC to error about "data loss." - // This only stores UTF-16 code units, though. - // Consume the UTF-16 code unit, which may be a high surrogate. - int code_unit16_high = 0; - if (!HexStringToInt(StringPiece(pos_, 4), &code_unit16_high)) - return false; - - // Only add 3, not 4, because at the end of this iteration, the parser has - // finished working with the last digit of the UTF sequence, meaning that - // the next iteration will advance to the next byte. - NextNChars(3); - - // Used to convert the UTF-16 code units to a code point and then to a UTF-8 - // code unit sequence. - char code_unit8[8] = { 0 }; - size_t offset = 0; - - // If this is a high surrogate, consume the next code unit to get the - // low surrogate. - if (CBU16_IS_SURROGATE(code_unit16_high)) { - // Make sure this is the high surrogate. If not, it's an encoding - // error. - if (!CBU16_IS_SURROGATE_LEAD(code_unit16_high)) - return false; - - // Make sure that the token has more characters to consume the - // lower surrogate. - if (!CanConsume(6)) // 6 being '\' 'u' and four HEX digits. - return false; - if (*NextChar() != '\\' || *NextChar() != 'u') - return false; - - NextChar(); // Read past 'u'. - int code_unit16_low = 0; - if (!HexStringToInt(StringPiece(pos_, 4), &code_unit16_low)) - return false; - - NextNChars(3); - - if (!CBU16_IS_TRAIL(code_unit16_low)) { - return false; - } - - uint32 code_point = CBU16_GET_SUPPLEMENTARY(code_unit16_high, - code_unit16_low); - offset = 0; - CBU8_APPEND_UNSAFE(code_unit8, offset, code_point); - } else { - // Not a surrogate. - DCHECK(CBU16_IS_SINGLE(code_unit16_high)); - CBU8_APPEND_UNSAFE(code_unit8, offset, code_unit16_high); - } - - dest_string->append(code_unit8); - return true; -} - -void JSONParser::DecodeUTF8(const int32& point, StringBuilder* dest) { - // Anything outside of the basic ASCII plane will need to be decoded from - // int32 to a multi-byte sequence. - if (point < kExtendedASCIIStart) { - dest->Append(point); - } else { - char utf8_units[4] = { 0 }; - int offset = 0; - CBU8_APPEND_UNSAFE(utf8_units, offset, point); - dest->Convert(); - // CBU8_APPEND_UNSAFE can overwrite up to 4 bytes, so utf8_units may not be - // zero terminated at this point. |offset| contains the correct length. - dest->AppendString(std::string(utf8_units, offset)); - } -} - -Value* JSONParser::ConsumeNumber() { - const char* num_start = pos_; - const int start_index = index_; - int end_index = start_index; - - if (*pos_ == '-') - NextChar(); - - if (!ReadInt(false)) { - ReportError(JSONReader::JSON_SYNTAX_ERROR, 1); - return NULL; - } - end_index = index_; - - // The optional fraction part. - if (*pos_ == '.') { - if (!CanConsume(1)) { - ReportError(JSONReader::JSON_SYNTAX_ERROR, 1); - return NULL; - } - NextChar(); - if (!ReadInt(true)) { - ReportError(JSONReader::JSON_SYNTAX_ERROR, 1); - return NULL; - } - end_index = index_; - } - - // Optional exponent part. - if (*pos_ == 'e' || *pos_ == 'E') { - NextChar(); - if (*pos_ == '-' || *pos_ == '+') - NextChar(); - if (!ReadInt(true)) { - ReportError(JSONReader::JSON_SYNTAX_ERROR, 1); - return NULL; - } - end_index = index_; - } - - // ReadInt is greedy because numbers have no easily detectable sentinel, - // so save off where the parser should be on exit (see Consume invariant at - // the top of the header), then make sure the next token is one which is - // valid. - const char* exit_pos = pos_ - 1; - int exit_index = index_ - 1; - - switch (GetNextToken()) { - case T_OBJECT_END: - case T_ARRAY_END: - case T_LIST_SEPARATOR: - case T_END_OF_INPUT: - break; - default: - ReportError(JSONReader::JSON_SYNTAX_ERROR, 1); - return NULL; - } - - pos_ = exit_pos; - index_ = exit_index; - - StringPiece num_string(num_start, end_index - start_index); - - int num_int; - if (StringToInt(num_string, &num_int)) - return new FundamentalValue(num_int); - - double num_double; - if (base::StringToDouble(num_string.as_string(), &num_double) && - IsFinite(num_double)) { - return new FundamentalValue(num_double); - } - - return NULL; -} - -bool JSONParser::ReadInt(bool allow_leading_zeros) { - char first = *pos_; - int len = 0; - - char c = first; - while (CanConsume(1) && IsAsciiDigit(c)) { - c = *NextChar(); - ++len; - } - - if (len == 0) - return false; - - if (!allow_leading_zeros && len > 1 && first == '0') - return false; - - return true; -} - -Value* JSONParser::ConsumeLiteral() { - switch (*pos_) { - case 't': { - const char* kTrueLiteral = "true"; - const int kTrueLen = static_cast(strlen(kTrueLiteral)); - if (!CanConsume(kTrueLen - 1) || - !StringsAreEqual(pos_, kTrueLiteral, kTrueLen)) { - ReportError(JSONReader::JSON_SYNTAX_ERROR, 1); - return NULL; - } - NextNChars(kTrueLen - 1); - return new FundamentalValue(true); - } - case 'f': { - const char* kFalseLiteral = "false"; - const int kFalseLen = static_cast(strlen(kFalseLiteral)); - if (!CanConsume(kFalseLen - 1) || - !StringsAreEqual(pos_, kFalseLiteral, kFalseLen)) { - ReportError(JSONReader::JSON_SYNTAX_ERROR, 1); - return NULL; - } - NextNChars(kFalseLen - 1); - return new FundamentalValue(false); - } - case 'n': { - const char* kNullLiteral = "null"; - const int kNullLen = static_cast(strlen(kNullLiteral)); - if (!CanConsume(kNullLen - 1) || - !StringsAreEqual(pos_, kNullLiteral, kNullLen)) { - ReportError(JSONReader::JSON_SYNTAX_ERROR, 1); - return NULL; - } - NextNChars(kNullLen - 1); - return Value::CreateNullValue(); - } - default: - ReportError(JSONReader::JSON_UNEXPECTED_TOKEN, 1); - return NULL; - } -} - -// static -bool JSONParser::StringsAreEqual(const char* one, const char* two, size_t len) { - return strncmp(one, two, len) == 0; -} - -void JSONParser::ReportError(JSONReader::JsonParseError code, - int column_adjust) { - error_code_ = code; - error_line_ = line_number_; - error_column_ = index_ - index_last_line_ + column_adjust; -} - -// static -std::string JSONParser::FormatErrorMessage(int line, int column, - const std::string& description) { - if (line || column) { - return StringPrintf("Line: %i, column: %i, %s", - line, column, description.c_str()); - } - return description; -} - -} // namespace internal -} // namespace base diff --git a/base/json/json_parser.h b/base/json/json_parser.h deleted file mode 100644 index b4d0b1bf97..0000000000 --- a/base/json/json_parser.h +++ /dev/null @@ -1,271 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef BASE_JSON_JSON_PARSER_H_ -#define BASE_JSON_JSON_PARSER_H_ - -#include - -#include "base/base_export.h" -#include "base/basictypes.h" -#include "base/compiler_specific.h" -#include "base/json/json_reader.h" -#include "base/strings/string_piece.h" - -#if !defined(OS_CHROMEOS) -#include "base/gtest_prod_util.h" -#endif - -namespace base { -class Value; -} - -#if defined(OS_CHROMEOS) -// Chromium and Chromium OS check out gtest to different places, so this is -// unable to compile on both if gtest_prod.h is included here. Instead, include -// its only contents -- this will need to be updated if the macro ever changes. -#define FRIEND_TEST(test_case_name, test_name)\ -friend class test_case_name##_##test_name##_Test - -#define FRIEND_TEST_ALL_PREFIXES(test_case_name, test_name) \ - FRIEND_TEST(test_case_name, test_name); \ - FRIEND_TEST(test_case_name, DISABLED_##test_name); \ - FRIEND_TEST(test_case_name, FLAKY_##test_name) -#endif // OS_CHROMEOS - -namespace base { -namespace internal { - -class JSONParserTest; - -// The implementation behind the JSONReader interface. This class is not meant -// to be used directly; it encapsulates logic that need not be exposed publicly. -// -// This parser guarantees O(n) time through the input string. It also optimizes -// base::StringValue by using StringPiece where possible when returning Value -// objects by using "hidden roots," discussed in the implementation. -// -// Iteration happens on the byte level, with the functions CanConsume and -// NextChar. The conversion from byte to JSON token happens without advancing -// the parser in GetNextToken/ParseToken, that is tokenization operates on -// the current parser position without advancing. -// -// Built on top of these are a family of Consume functions that iterate -// internally. Invariant: on entry of a Consume function, the parser is wound -// to the first byte of a valid JSON token. On exit, it is on the last byte -// of a token, such that the next iteration of the parser will be at the byte -// immediately following the token, which would likely be the first byte of the -// next token. -class BASE_EXPORT_PRIVATE JSONParser { - public: - explicit JSONParser(int options); - ~JSONParser(); - - // Parses the input string according to the set options and returns the - // result as a Value owned by the caller. - Value* Parse(const StringPiece& input); - - // Returns the error code. - JSONReader::JsonParseError error_code() const; - - // Returns the human-friendly error message. - std::string GetErrorMessage() const; - - private: - enum Token { - T_OBJECT_BEGIN, // { - T_OBJECT_END, // } - T_ARRAY_BEGIN, // [ - T_ARRAY_END, // ] - T_STRING, - T_NUMBER, - T_BOOL_TRUE, // true - T_BOOL_FALSE, // false - T_NULL, // null - T_LIST_SEPARATOR, // , - T_OBJECT_PAIR_SEPARATOR, // : - T_END_OF_INPUT, - T_INVALID_TOKEN, - }; - - // A helper class used for parsing strings. One optimization performed is to - // create base::Value with a StringPiece to avoid unnecessary std::string - // copies. This is not possible if the input string needs to be decoded from - // UTF-16 to UTF-8, or if an escape sequence causes characters to be skipped. - // This class centralizes that logic. - class StringBuilder { - public: - // Empty constructor. Used for creating a builder with which to Swap(). - StringBuilder(); - - // |pos| is the beginning of an input string, excluding the |"|. - explicit StringBuilder(const char* pos); - - ~StringBuilder(); - - // Swaps the contents of |other| with this. - void Swap(StringBuilder* other); - - // Either increases the |length_| of the string or copies the character if - // the StringBuilder has been converted. |c| must be in the basic ASCII - // plane; all other characters need to be in UTF-8 units, appended with - // AppendString below. - void Append(const char& c); - - // Appends a string to the std::string. Must be Convert()ed to use. - void AppendString(const std::string& str); - - // Converts the builder from its default StringPiece to a full std::string, - // performing a copy. Once a builder is converted, it cannot be made a - // StringPiece again. - void Convert(); - - // Returns whether the builder can be converted to a StringPiece. - bool CanBeStringPiece() const; - - // Returns the StringPiece representation. Returns an empty piece if it - // cannot be converted. - StringPiece AsStringPiece(); - - // Returns the builder as a std::string. - const std::string& AsString(); - - private: - // The beginning of the input string. - const char* pos_; - - // Number of bytes in |pos_| that make up the string being built. - size_t length_; - - // The copied string representation. NULL until Convert() is called. - // Strong. scoped_ptr has too much of an overhead here. - std::string* string_; - }; - - // Quick check that the stream has capacity to consume |length| more bytes. - bool CanConsume(int length); - - // The basic way to consume a single character in the stream. Consumes one - // byte of the input stream and returns a pointer to the rest of it. - const char* NextChar(); - - // Performs the equivalent of NextChar N times. - void NextNChars(int n); - - // Skips over whitespace and comments to find the next token in the stream. - // This does not advance the parser for non-whitespace or comment chars. - Token GetNextToken(); - - // Consumes whitespace characters and comments until the next non-that is - // encountered. - void EatWhitespaceAndComments(); - // Helper function that consumes a comment, assuming that the parser is - // currently wound to a '/'. - bool EatComment(); - - // Calls GetNextToken() and then ParseToken(). Caller owns the result. - Value* ParseNextToken(); - - // Takes a token that represents the start of a Value ("a structural token" - // in RFC terms) and consumes it, returning the result as an object the - // caller owns. - Value* ParseToken(Token token); - - // Assuming that the parser is currently wound to '{', this parses a JSON - // object into a DictionaryValue. - Value* ConsumeDictionary(); - - // Assuming that the parser is wound to '[', this parses a JSON list into a - // ListValue. - Value* ConsumeList(); - - // Calls through ConsumeStringRaw and wraps it in a value. - Value* ConsumeString(); - - // Assuming that the parser is wound to a double quote, this parses a string, - // decoding any escape sequences and converts UTF-16 to UTF-8. Returns true on - // success and Swap()s the result into |out|. Returns false on failure with - // error information set. - bool ConsumeStringRaw(StringBuilder* out); - // Helper function for ConsumeStringRaw() that consumes the next four or 10 - // bytes (parser is wound to the first character of a HEX sequence, with the - // potential for consuming another \uXXXX for a surrogate). Returns true on - // success and places the UTF8 code units in |dest_string|, and false on - // failure. - bool DecodeUTF16(std::string* dest_string); - // Helper function for ConsumeStringRaw() that takes a single code point, - // decodes it into UTF-8 units, and appends it to the given builder. The - // point must be valid. - void DecodeUTF8(const int32& point, StringBuilder* dest); - - // Assuming that the parser is wound to the start of a valid JSON number, - // this parses and converts it to either an int or double value. - Value* ConsumeNumber(); - // Helper that reads characters that are ints. Returns true if a number was - // read and false on error. - bool ReadInt(bool allow_leading_zeros); - - // Consumes the literal values of |true|, |false|, and |null|, assuming the - // parser is wound to the first character of any of those. - Value* ConsumeLiteral(); - - // Compares two string buffers of a given length. - static bool StringsAreEqual(const char* left, const char* right, size_t len); - - // Sets the error information to |code| at the current column, based on - // |index_| and |index_last_line_|, with an optional positive/negative - // adjustment by |column_adjust|. - void ReportError(JSONReader::JsonParseError code, int column_adjust); - - // Given the line and column number of an error, formats one of the error - // message contants from json_reader.h for human display. - static std::string FormatErrorMessage(int line, int column, - const std::string& description); - - // base::JSONParserOptions that control parsing. - int options_; - - // Pointer to the start of the input data. - const char* start_pos_; - - // Pointer to the current position in the input data. Equivalent to - // |start_pos_ + index_|. - const char* pos_; - - // Pointer to the last character of the input data. - const char* end_pos_; - - // The index in the input stream to which the parser is wound. - int index_; - - // The number of times the parser has recursed (current stack depth). - int stack_depth_; - - // The line number that the parser is at currently. - int line_number_; - - // The last value of |index_| on the previous line. - int index_last_line_; - - // Error information. - JSONReader::JsonParseError error_code_; - int error_line_; - int error_column_; - - friend class JSONParserTest; - FRIEND_TEST_ALL_PREFIXES(JSONParserTest, NextChar); - FRIEND_TEST_ALL_PREFIXES(JSONParserTest, ConsumeDictionary); - FRIEND_TEST_ALL_PREFIXES(JSONParserTest, ConsumeList); - FRIEND_TEST_ALL_PREFIXES(JSONParserTest, ConsumeString); - FRIEND_TEST_ALL_PREFIXES(JSONParserTest, ConsumeLiterals); - FRIEND_TEST_ALL_PREFIXES(JSONParserTest, ConsumeNumbers); - FRIEND_TEST_ALL_PREFIXES(JSONParserTest, ErrorMessages); - - DISALLOW_COPY_AND_ASSIGN(JSONParser); -}; - -} // namespace internal -} // namespace base - -#endif // BASE_JSON_JSON_PARSER_H_ diff --git a/base/json/json_parser_unittest.cc b/base/json/json_parser_unittest.cc deleted file mode 100644 index 74e2026301..0000000000 --- a/base/json/json_parser_unittest.cc +++ /dev/null @@ -1,319 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "base/json/json_parser.h" - -#include "base/json/json_reader.h" -#include "base/memory/scoped_ptr.h" -#include "base/values.h" -#include "testing/gtest/include/gtest/gtest.h" - -namespace base { -namespace internal { - -class JSONParserTest : public testing::Test { - public: - JSONParser* NewTestParser(const std::string& input) { - JSONParser* parser = new JSONParser(JSON_PARSE_RFC); - parser->start_pos_ = input.data(); - parser->pos_ = parser->start_pos_; - parser->end_pos_ = parser->start_pos_ + input.length(); - return parser; - } - - void TestLastThree(JSONParser* parser) { - EXPECT_EQ(',', *parser->NextChar()); - EXPECT_EQ('|', *parser->NextChar()); - EXPECT_EQ('\0', *parser->NextChar()); - EXPECT_EQ(parser->end_pos_, parser->pos_); - } -}; - -TEST_F(JSONParserTest, NextChar) { - std::string input("Hello world"); - scoped_ptr parser(NewTestParser(input)); - - EXPECT_EQ('H', *parser->pos_); - for (size_t i = 1; i < input.length(); ++i) { - EXPECT_EQ(input[i], *parser->NextChar()); - } - EXPECT_EQ(parser->end_pos_, parser->NextChar()); -} - -TEST_F(JSONParserTest, ConsumeString) { - std::string input("\"test\",|"); - scoped_ptr parser(NewTestParser(input)); - scoped_ptr value(parser->ConsumeString()); - EXPECT_EQ('"', *parser->pos_); - - TestLastThree(parser.get()); - - ASSERT_TRUE(value.get()); - std::string str; - EXPECT_TRUE(value->GetAsString(&str)); - EXPECT_EQ("test", str); -} - -TEST_F(JSONParserTest, ConsumeList) { - std::string input("[true, false],|"); - scoped_ptr parser(NewTestParser(input)); - scoped_ptr value(parser->ConsumeList()); - EXPECT_EQ(']', *parser->pos_); - - TestLastThree(parser.get()); - - ASSERT_TRUE(value.get()); - base::ListValue* list; - EXPECT_TRUE(value->GetAsList(&list)); - EXPECT_EQ(2u, list->GetSize()); -} - -TEST_F(JSONParserTest, ConsumeDictionary) { - std::string input("{\"abc\":\"def\"},|"); - scoped_ptr parser(NewTestParser(input)); - scoped_ptr value(parser->ConsumeDictionary()); - EXPECT_EQ('}', *parser->pos_); - - TestLastThree(parser.get()); - - ASSERT_TRUE(value.get()); - base::DictionaryValue* dict; - EXPECT_TRUE(value->GetAsDictionary(&dict)); - std::string str; - EXPECT_TRUE(dict->GetString("abc", &str)); - EXPECT_EQ("def", str); -} - -TEST_F(JSONParserTest, ConsumeLiterals) { - // Literal |true|. - std::string input("true,|"); - scoped_ptr parser(NewTestParser(input)); - scoped_ptr value(parser->ConsumeLiteral()); - EXPECT_EQ('e', *parser->pos_); - - TestLastThree(parser.get()); - - ASSERT_TRUE(value.get()); - bool bool_value = false; - EXPECT_TRUE(value->GetAsBoolean(&bool_value)); - EXPECT_TRUE(bool_value); - - // Literal |false|. - input = "false,|"; - parser.reset(NewTestParser(input)); - value.reset(parser->ConsumeLiteral()); - EXPECT_EQ('e', *parser->pos_); - - TestLastThree(parser.get()); - - ASSERT_TRUE(value.get()); - EXPECT_TRUE(value->GetAsBoolean(&bool_value)); - EXPECT_FALSE(bool_value); - - // Literal |null|. - input = "null,|"; - parser.reset(NewTestParser(input)); - value.reset(parser->ConsumeLiteral()); - EXPECT_EQ('l', *parser->pos_); - - TestLastThree(parser.get()); - - ASSERT_TRUE(value.get()); - EXPECT_TRUE(value->IsType(Value::TYPE_NULL)); -} - -TEST_F(JSONParserTest, ConsumeNumbers) { - // Integer. - std::string input("1234,|"); - scoped_ptr parser(NewTestParser(input)); - scoped_ptr value(parser->ConsumeNumber()); - EXPECT_EQ('4', *parser->pos_); - - TestLastThree(parser.get()); - - ASSERT_TRUE(value.get()); - int number_i; - EXPECT_TRUE(value->GetAsInteger(&number_i)); - EXPECT_EQ(1234, number_i); - - // Negative integer. - input = "-1234,|"; - parser.reset(NewTestParser(input)); - value.reset(parser->ConsumeNumber()); - EXPECT_EQ('4', *parser->pos_); - - TestLastThree(parser.get()); - - ASSERT_TRUE(value.get()); - EXPECT_TRUE(value->GetAsInteger(&number_i)); - EXPECT_EQ(-1234, number_i); - - // Double. - input = "12.34,|"; - parser.reset(NewTestParser(input)); - value.reset(parser->ConsumeNumber()); - EXPECT_EQ('4', *parser->pos_); - - TestLastThree(parser.get()); - - ASSERT_TRUE(value.get()); - double number_d; - EXPECT_TRUE(value->GetAsDouble(&number_d)); - EXPECT_EQ(12.34, number_d); - - // Scientific. - input = "42e3,|"; - parser.reset(NewTestParser(input)); - value.reset(parser->ConsumeNumber()); - EXPECT_EQ('3', *parser->pos_); - - TestLastThree(parser.get()); - - ASSERT_TRUE(value.get()); - EXPECT_TRUE(value->GetAsDouble(&number_d)); - EXPECT_EQ(42000, number_d); - - // Negative scientific. - input = "314159e-5,|"; - parser.reset(NewTestParser(input)); - value.reset(parser->ConsumeNumber()); - EXPECT_EQ('5', *parser->pos_); - - TestLastThree(parser.get()); - - ASSERT_TRUE(value.get()); - EXPECT_TRUE(value->GetAsDouble(&number_d)); - EXPECT_EQ(3.14159, number_d); - - // Positive scientific. - input = "0.42e+3,|"; - parser.reset(NewTestParser(input)); - value.reset(parser->ConsumeNumber()); - EXPECT_EQ('3', *parser->pos_); - - TestLastThree(parser.get()); - - ASSERT_TRUE(value.get()); - EXPECT_TRUE(value->GetAsDouble(&number_d)); - EXPECT_EQ(420, number_d); -} - -TEST_F(JSONParserTest, ErrorMessages) { - // Error strings should not be modified in case of success. - std::string error_message; - int error_code = 0; - scoped_ptr root; - root.reset(JSONReader::ReadAndReturnError("[42]", JSON_PARSE_RFC, - &error_code, &error_message)); - EXPECT_TRUE(error_message.empty()); - EXPECT_EQ(0, error_code); - - // Test line and column counting - const char big_json[] = "[\n0,\n1,\n2,\n3,4,5,6 7,\n8,\n9\n]"; - // error here ----------------------------------^ - root.reset(JSONReader::ReadAndReturnError(big_json, JSON_PARSE_RFC, - &error_code, &error_message)); - EXPECT_FALSE(root.get()); - EXPECT_EQ(JSONParser::FormatErrorMessage(5, 10, JSONReader::kSyntaxError), - error_message); - EXPECT_EQ(JSONReader::JSON_SYNTAX_ERROR, error_code); - - error_code = 0; - error_message = ""; - // Test line and column counting with "\r\n" line ending - const char big_json_crlf[] = - "[\r\n0,\r\n1,\r\n2,\r\n3,4,5,6 7,\r\n8,\r\n9\r\n]"; - // error here ----------------------^ - root.reset(JSONReader::ReadAndReturnError(big_json_crlf, JSON_PARSE_RFC, - &error_code, &error_message)); - EXPECT_FALSE(root.get()); - EXPECT_EQ(JSONParser::FormatErrorMessage(5, 10, JSONReader::kSyntaxError), - error_message); - EXPECT_EQ(JSONReader::JSON_SYNTAX_ERROR, error_code); - - // Test each of the error conditions - root.reset(JSONReader::ReadAndReturnError("{},{}", JSON_PARSE_RFC, - &error_code, &error_message)); - EXPECT_FALSE(root.get()); - EXPECT_EQ(JSONParser::FormatErrorMessage(1, 3, - JSONReader::kUnexpectedDataAfterRoot), error_message); - EXPECT_EQ(JSONReader::JSON_UNEXPECTED_DATA_AFTER_ROOT, error_code); - - std::string nested_json; - for (int i = 0; i < 101; ++i) { - nested_json.insert(nested_json.begin(), '['); - nested_json.append(1, ']'); - } - root.reset(JSONReader::ReadAndReturnError(nested_json, JSON_PARSE_RFC, - &error_code, &error_message)); - EXPECT_FALSE(root.get()); - EXPECT_EQ(JSONParser::FormatErrorMessage(1, 100, JSONReader::kTooMuchNesting), - error_message); - EXPECT_EQ(JSONReader::JSON_TOO_MUCH_NESTING, error_code); - - root.reset(JSONReader::ReadAndReturnError("[1,]", JSON_PARSE_RFC, - &error_code, &error_message)); - EXPECT_FALSE(root.get()); - EXPECT_EQ(JSONParser::FormatErrorMessage(1, 4, JSONReader::kTrailingComma), - error_message); - EXPECT_EQ(JSONReader::JSON_TRAILING_COMMA, error_code); - - root.reset(JSONReader::ReadAndReturnError("{foo:\"bar\"}", JSON_PARSE_RFC, - &error_code, &error_message)); - EXPECT_FALSE(root.get()); - EXPECT_EQ(JSONParser::FormatErrorMessage(1, 2, - JSONReader::kUnquotedDictionaryKey), error_message); - EXPECT_EQ(JSONReader::JSON_UNQUOTED_DICTIONARY_KEY, error_code); - - root.reset(JSONReader::ReadAndReturnError("{\"foo\":\"bar\",}", - JSON_PARSE_RFC, - &error_code, &error_message)); - EXPECT_FALSE(root.get()); - EXPECT_EQ(JSONParser::FormatErrorMessage(1, 14, JSONReader::kTrailingComma), - error_message); - - root.reset(JSONReader::ReadAndReturnError("[nu]", JSON_PARSE_RFC, - &error_code, &error_message)); - EXPECT_FALSE(root.get()); - EXPECT_EQ(JSONParser::FormatErrorMessage(1, 2, JSONReader::kSyntaxError), - error_message); - EXPECT_EQ(JSONReader::JSON_SYNTAX_ERROR, error_code); - - root.reset(JSONReader::ReadAndReturnError("[\"xxx\\xq\"]", JSON_PARSE_RFC, - &error_code, &error_message)); - EXPECT_FALSE(root.get()); - EXPECT_EQ(JSONParser::FormatErrorMessage(1, 7, JSONReader::kInvalidEscape), - error_message); - EXPECT_EQ(JSONReader::JSON_INVALID_ESCAPE, error_code); - - root.reset(JSONReader::ReadAndReturnError("[\"xxx\\uq\"]", JSON_PARSE_RFC, - &error_code, &error_message)); - EXPECT_FALSE(root.get()); - EXPECT_EQ(JSONParser::FormatErrorMessage(1, 7, JSONReader::kInvalidEscape), - error_message); - EXPECT_EQ(JSONReader::JSON_INVALID_ESCAPE, error_code); - - root.reset(JSONReader::ReadAndReturnError("[\"xxx\\q\"]", JSON_PARSE_RFC, - &error_code, &error_message)); - EXPECT_FALSE(root.get()); - EXPECT_EQ(JSONParser::FormatErrorMessage(1, 7, JSONReader::kInvalidEscape), - error_message); - EXPECT_EQ(JSONReader::JSON_INVALID_ESCAPE, error_code); -} - -TEST_F(JSONParserTest, Decode4ByteUtf8Char) { - // This test strings contains a 4 byte unicode character (a smiley!) that the - // reader should be able to handle (the character is \xf0\x9f\x98\x87). - const char kUtf8Data[] = - "[\"😇\",[],[],[],{\"google:suggesttype\":[]}]"; - std::string error_message; - int error_code = 0; - scoped_ptr root( - JSONReader::ReadAndReturnError(kUtf8Data, JSON_PARSE_RFC, &error_code, - &error_message)); - EXPECT_TRUE(root.get()) << error_message; -} - -} // namespace internal -} // namespace base diff --git a/base/json/json_reader.cc b/base/json/json_reader.cc deleted file mode 100644 index 593273ebd4..0000000000 --- a/base/json/json_reader.cc +++ /dev/null @@ -1,110 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "base/json/json_reader.h" - -#include "base/json/json_parser.h" -#include "base/logging.h" - -namespace base { - -const char* JSONReader::kInvalidEscape = - "Invalid escape sequence."; -const char* JSONReader::kSyntaxError = - "Syntax error."; -const char* JSONReader::kUnexpectedToken = - "Unexpected token."; -const char* JSONReader::kTrailingComma = - "Trailing comma not allowed."; -const char* JSONReader::kTooMuchNesting = - "Too much nesting."; -const char* JSONReader::kUnexpectedDataAfterRoot = - "Unexpected data after root element."; -const char* JSONReader::kUnsupportedEncoding = - "Unsupported encoding. JSON must be UTF-8."; -const char* JSONReader::kUnquotedDictionaryKey = - "Dictionary keys must be quoted."; - -JSONReader::JSONReader() - : parser_(new internal::JSONParser(JSON_PARSE_RFC)) { -} - -JSONReader::JSONReader(int options) - : parser_(new internal::JSONParser(options)) { -} - -JSONReader::~JSONReader() { -} - -// static -Value* JSONReader::Read(const StringPiece& json) { - internal::JSONParser parser(JSON_PARSE_RFC); - return parser.Parse(json); -} - -// static -Value* JSONReader::Read(const StringPiece& json, - int options) { - internal::JSONParser parser(options); - return parser.Parse(json); -} - -// static -Value* JSONReader::ReadAndReturnError(const StringPiece& json, - int options, - int* error_code_out, - std::string* error_msg_out) { - internal::JSONParser parser(options); - Value* root = parser.Parse(json); - if (root) - return root; - - if (error_code_out) - *error_code_out = parser.error_code(); - if (error_msg_out) - *error_msg_out = parser.GetErrorMessage(); - - return NULL; -} - -// static -std::string JSONReader::ErrorCodeToString(JsonParseError error_code) { - switch (error_code) { - case JSON_NO_ERROR: - return std::string(); - case JSON_INVALID_ESCAPE: - return kInvalidEscape; - case JSON_SYNTAX_ERROR: - return kSyntaxError; - case JSON_UNEXPECTED_TOKEN: - return kUnexpectedToken; - case JSON_TRAILING_COMMA: - return kTrailingComma; - case JSON_TOO_MUCH_NESTING: - return kTooMuchNesting; - case JSON_UNEXPECTED_DATA_AFTER_ROOT: - return kUnexpectedDataAfterRoot; - case JSON_UNSUPPORTED_ENCODING: - return kUnsupportedEncoding; - case JSON_UNQUOTED_DICTIONARY_KEY: - return kUnquotedDictionaryKey; - default: - NOTREACHED(); - return std::string(); - } -} - -Value* JSONReader::ReadToValue(const std::string& json) { - return parser_->Parse(json); -} - -JSONReader::JsonParseError JSONReader::error_code() const { - return parser_->error_code(); -} - -std::string JSONReader::GetErrorMessage() const { - return parser_->GetErrorMessage(); -} - -} // namespace base diff --git a/base/json/json_reader.h b/base/json/json_reader.h deleted file mode 100644 index e602846278..0000000000 --- a/base/json/json_reader.h +++ /dev/null @@ -1,135 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. -// -// A JSON parser. Converts strings of JSON into a Value object (see -// base/values.h). -// http://www.ietf.org/rfc/rfc4627.txt?number=4627 -// -// Known limitations/deviations from the RFC: -// - Only knows how to parse ints within the range of a signed 32 bit int and -// decimal numbers within a double. -// - Assumes input is encoded as UTF8. The spec says we should allow UTF-16 -// (BE or LE) and UTF-32 (BE or LE) as well. -// - We limit nesting to 100 levels to prevent stack overflow (this is allowed -// by the RFC). -// - A Unicode FAQ ("http://unicode.org/faq/utf_bom.html") writes a data -// stream may start with a Unicode Byte-Order-Mark (U+FEFF), i.e. the input -// UTF-8 string for the JSONReader::JsonToValue() function may start with a -// UTF-8 BOM (0xEF, 0xBB, 0xBF). -// To avoid the function from mis-treating a UTF-8 BOM as an invalid -// character, the function skips a Unicode BOM at the beginning of the -// Unicode string (converted from the input UTF-8 string) before parsing it. -// -// TODO(tc): Add a parsing option to to relax object keys being wrapped in -// double quotes -// TODO(tc): Add an option to disable comment stripping - -#ifndef BASE_JSON_JSON_READER_H_ -#define BASE_JSON_JSON_READER_H_ - -#include - -#include "base/base_export.h" -#include "base/basictypes.h" -#include "base/memory/scoped_ptr.h" -#include "base/strings/string_piece.h" - -namespace base { -class Value; - -namespace internal { -class JSONParser; -} -} - -namespace base { - -enum JSONParserOptions { - // Parses the input strictly according to RFC 4627, except for where noted - // above. - JSON_PARSE_RFC = 0, - - // Allows commas to exist after the last element in structures. - JSON_ALLOW_TRAILING_COMMAS = 1 << 0, - - // The parser can perform optimizations by placing hidden data in the root of - // the JSON object, which speeds up certain operations on children. However, - // if the child is Remove()d from root, it would result in use-after-free - // unless it is DeepCopy()ed or this option is used. - JSON_DETACHABLE_CHILDREN = 1 << 1, -}; - -class BASE_EXPORT JSONReader { - public: - // Error codes during parsing. - enum JsonParseError { - JSON_NO_ERROR = 0, - JSON_INVALID_ESCAPE, - JSON_SYNTAX_ERROR, - JSON_UNEXPECTED_TOKEN, - JSON_TRAILING_COMMA, - JSON_TOO_MUCH_NESTING, - JSON_UNEXPECTED_DATA_AFTER_ROOT, - JSON_UNSUPPORTED_ENCODING, - JSON_UNQUOTED_DICTIONARY_KEY, - }; - - // String versions of parse error codes. - static const char* kInvalidEscape; - static const char* kSyntaxError; - static const char* kUnexpectedToken; - static const char* kTrailingComma; - static const char* kTooMuchNesting; - static const char* kUnexpectedDataAfterRoot; - static const char* kUnsupportedEncoding; - static const char* kUnquotedDictionaryKey; - - // Constructs a reader with the default options, JSON_PARSE_RFC. - JSONReader(); - - // Constructs a reader with custom options. - explicit JSONReader(int options); - - ~JSONReader(); - - // Reads and parses |json|, returning a Value. The caller owns the returned - // instance. If |json| is not a properly formed JSON string, returns NULL. - static Value* Read(const StringPiece& json); - - // Reads and parses |json|, returning a Value owned by the caller. The - // parser respects the given |options|. If the input is not properly formed, - // returns NULL. - static Value* Read(const StringPiece& json, int options); - - // Reads and parses |json| like Read(). |error_code_out| and |error_msg_out| - // are optional. If specified and NULL is returned, they will be populated - // an error code and a formatted error message (including error location if - // appropriate). Otherwise, they will be unmodified. - static Value* ReadAndReturnError(const StringPiece& json, - int options, // JSONParserOptions - int* error_code_out, - std::string* error_msg_out); - - // Converts a JSON parse error code into a human readable message. - // Returns an empty string if error_code is JSON_NO_ERROR. - static std::string ErrorCodeToString(JsonParseError error_code); - - // Parses an input string into a Value that is owned by the caller. - Value* ReadToValue(const std::string& json); - - // Returns the error code if the last call to ReadToValue() failed. - // Returns JSON_NO_ERROR otherwise. - JsonParseError error_code() const; - - // Converts error_code_ to a human-readable string, including line and column - // numbers if appropriate. - std::string GetErrorMessage() const; - - private: - scoped_ptr parser_; -}; - -} // namespace base - -#endif // BASE_JSON_JSON_READER_H_ diff --git a/base/json/json_reader_unittest.cc b/base/json/json_reader_unittest.cc deleted file mode 100644 index 527cb97f2a..0000000000 --- a/base/json/json_reader_unittest.cc +++ /dev/null @@ -1,656 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "base/json/json_reader.h" - -#include "base/base_paths.h" -#include "base/file_util.h" -#include "base/logging.h" -#include "base/memory/scoped_ptr.h" -#include "base/path_service.h" -#include "base/strings/string_piece.h" -#include "base/strings/utf_string_conversions.h" -#include "base/values.h" -#include "build/build_config.h" -#include "testing/gtest/include/gtest/gtest.h" - -namespace base { - -TEST(JSONReaderTest, Reading) { - // some whitespace checking - scoped_ptr root; - root.reset(JSONReader().ReadToValue(" null ")); - ASSERT_TRUE(root.get()); - EXPECT_TRUE(root->IsType(Value::TYPE_NULL)); - - // Invalid JSON string - root.reset(JSONReader().ReadToValue("nu")); - EXPECT_FALSE(root.get()); - - // Simple bool - root.reset(JSONReader().ReadToValue("true ")); - ASSERT_TRUE(root.get()); - EXPECT_TRUE(root->IsType(Value::TYPE_BOOLEAN)); - - // Embedded comment - root.reset(JSONReader().ReadToValue("/* comment */null")); - ASSERT_TRUE(root.get()); - EXPECT_TRUE(root->IsType(Value::TYPE_NULL)); - root.reset(JSONReader().ReadToValue("40 /* comment */")); - ASSERT_TRUE(root.get()); - EXPECT_TRUE(root->IsType(Value::TYPE_INTEGER)); - root.reset(JSONReader().ReadToValue("true // comment")); - ASSERT_TRUE(root.get()); - EXPECT_TRUE(root->IsType(Value::TYPE_BOOLEAN)); - root.reset(JSONReader().ReadToValue("/* comment */\"sample string\"")); - ASSERT_TRUE(root.get()); - EXPECT_TRUE(root->IsType(Value::TYPE_STRING)); - std::string value; - EXPECT_TRUE(root->GetAsString(&value)); - EXPECT_EQ("sample string", value); - root.reset(JSONReader().ReadToValue("[1, /* comment, 2 ] */ \n 3]")); - ASSERT_TRUE(root.get()); - ListValue* list = static_cast(root.get()); - EXPECT_EQ(2u, list->GetSize()); - int int_val = 0; - EXPECT_TRUE(list->GetInteger(0, &int_val)); - EXPECT_EQ(1, int_val); - EXPECT_TRUE(list->GetInteger(1, &int_val)); - EXPECT_EQ(3, int_val); - root.reset(JSONReader().ReadToValue("[1, /*a*/2, 3]")); - ASSERT_TRUE(root.get()); - list = static_cast(root.get()); - EXPECT_EQ(3u, list->GetSize()); - root.reset(JSONReader().ReadToValue("/* comment **/42")); - ASSERT_TRUE(root.get()); - EXPECT_TRUE(root->IsType(Value::TYPE_INTEGER)); - EXPECT_TRUE(root->GetAsInteger(&int_val)); - EXPECT_EQ(42, int_val); - root.reset(JSONReader().ReadToValue( - "/* comment **/\n" - "// */ 43\n" - "44")); - ASSERT_TRUE(root.get()); - EXPECT_TRUE(root->IsType(Value::TYPE_INTEGER)); - EXPECT_TRUE(root->GetAsInteger(&int_val)); - EXPECT_EQ(44, int_val); - - // Test number formats - root.reset(JSONReader().ReadToValue("43")); - ASSERT_TRUE(root.get()); - EXPECT_TRUE(root->IsType(Value::TYPE_INTEGER)); - EXPECT_TRUE(root->GetAsInteger(&int_val)); - EXPECT_EQ(43, int_val); - - // According to RFC4627, oct, hex, and leading zeros are invalid JSON. - root.reset(JSONReader().ReadToValue("043")); - EXPECT_FALSE(root.get()); - root.reset(JSONReader().ReadToValue("0x43")); - EXPECT_FALSE(root.get()); - root.reset(JSONReader().ReadToValue("00")); - EXPECT_FALSE(root.get()); - - // Test 0 (which needs to be special cased because of the leading zero - // clause). - root.reset(JSONReader().ReadToValue("0")); - ASSERT_TRUE(root.get()); - EXPECT_TRUE(root->IsType(Value::TYPE_INTEGER)); - int_val = 1; - EXPECT_TRUE(root->GetAsInteger(&int_val)); - EXPECT_EQ(0, int_val); - - // Numbers that overflow ints should succeed, being internally promoted to - // storage as doubles - root.reset(JSONReader().ReadToValue("2147483648")); - ASSERT_TRUE(root.get()); - double double_val; - EXPECT_TRUE(root->IsType(Value::TYPE_DOUBLE)); - double_val = 0.0; - EXPECT_TRUE(root->GetAsDouble(&double_val)); - EXPECT_DOUBLE_EQ(2147483648.0, double_val); - root.reset(JSONReader().ReadToValue("-2147483649")); - ASSERT_TRUE(root.get()); - EXPECT_TRUE(root->IsType(Value::TYPE_DOUBLE)); - double_val = 0.0; - EXPECT_TRUE(root->GetAsDouble(&double_val)); - EXPECT_DOUBLE_EQ(-2147483649.0, double_val); - - // Parse a double - root.reset(JSONReader().ReadToValue("43.1")); - ASSERT_TRUE(root.get()); - EXPECT_TRUE(root->IsType(Value::TYPE_DOUBLE)); - double_val = 0.0; - EXPECT_TRUE(root->GetAsDouble(&double_val)); - EXPECT_DOUBLE_EQ(43.1, double_val); - - root.reset(JSONReader().ReadToValue("4.3e-1")); - ASSERT_TRUE(root.get()); - EXPECT_TRUE(root->IsType(Value::TYPE_DOUBLE)); - double_val = 0.0; - EXPECT_TRUE(root->GetAsDouble(&double_val)); - EXPECT_DOUBLE_EQ(.43, double_val); - - root.reset(JSONReader().ReadToValue("2.1e0")); - ASSERT_TRUE(root.get()); - EXPECT_TRUE(root->IsType(Value::TYPE_DOUBLE)); - double_val = 0.0; - EXPECT_TRUE(root->GetAsDouble(&double_val)); - EXPECT_DOUBLE_EQ(2.1, double_val); - - root.reset(JSONReader().ReadToValue("2.1e+0001")); - ASSERT_TRUE(root.get()); - EXPECT_TRUE(root->IsType(Value::TYPE_DOUBLE)); - double_val = 0.0; - EXPECT_TRUE(root->GetAsDouble(&double_val)); - EXPECT_DOUBLE_EQ(21.0, double_val); - - root.reset(JSONReader().ReadToValue("0.01")); - ASSERT_TRUE(root.get()); - EXPECT_TRUE(root->IsType(Value::TYPE_DOUBLE)); - double_val = 0.0; - EXPECT_TRUE(root->GetAsDouble(&double_val)); - EXPECT_DOUBLE_EQ(0.01, double_val); - - root.reset(JSONReader().ReadToValue("1.00")); - ASSERT_TRUE(root.get()); - EXPECT_TRUE(root->IsType(Value::TYPE_DOUBLE)); - double_val = 0.0; - EXPECT_TRUE(root->GetAsDouble(&double_val)); - EXPECT_DOUBLE_EQ(1.0, double_val); - - // Fractional parts must have a digit before and after the decimal point. - root.reset(JSONReader().ReadToValue("1.")); - EXPECT_FALSE(root.get()); - root.reset(JSONReader().ReadToValue(".1")); - EXPECT_FALSE(root.get()); - root.reset(JSONReader().ReadToValue("1.e10")); - EXPECT_FALSE(root.get()); - - // Exponent must have a digit following the 'e'. - root.reset(JSONReader().ReadToValue("1e")); - EXPECT_FALSE(root.get()); - root.reset(JSONReader().ReadToValue("1E")); - EXPECT_FALSE(root.get()); - root.reset(JSONReader().ReadToValue("1e1.")); - EXPECT_FALSE(root.get()); - root.reset(JSONReader().ReadToValue("1e1.0")); - EXPECT_FALSE(root.get()); - - // INF/-INF/NaN are not valid - root.reset(JSONReader().ReadToValue("1e1000")); - EXPECT_FALSE(root.get()); - root.reset(JSONReader().ReadToValue("-1e1000")); - EXPECT_FALSE(root.get()); - root.reset(JSONReader().ReadToValue("NaN")); - EXPECT_FALSE(root.get()); - root.reset(JSONReader().ReadToValue("nan")); - EXPECT_FALSE(root.get()); - root.reset(JSONReader().ReadToValue("inf")); - EXPECT_FALSE(root.get()); - - // Invalid number formats - root.reset(JSONReader().ReadToValue("4.3.1")); - EXPECT_FALSE(root.get()); - root.reset(JSONReader().ReadToValue("4e3.1")); - EXPECT_FALSE(root.get()); - - // Test string parser - root.reset(JSONReader().ReadToValue("\"hello world\"")); - ASSERT_TRUE(root.get()); - EXPECT_TRUE(root->IsType(Value::TYPE_STRING)); - std::string str_val; - EXPECT_TRUE(root->GetAsString(&str_val)); - EXPECT_EQ("hello world", str_val); - - // Empty string - root.reset(JSONReader().ReadToValue("\"\"")); - ASSERT_TRUE(root.get()); - EXPECT_TRUE(root->IsType(Value::TYPE_STRING)); - str_val.clear(); - EXPECT_TRUE(root->GetAsString(&str_val)); - EXPECT_EQ("", str_val); - - // Test basic string escapes - root.reset(JSONReader().ReadToValue("\" \\\"\\\\\\/\\b\\f\\n\\r\\t\\v\"")); - ASSERT_TRUE(root.get()); - EXPECT_TRUE(root->IsType(Value::TYPE_STRING)); - str_val.clear(); - EXPECT_TRUE(root->GetAsString(&str_val)); - EXPECT_EQ(" \"\\/\b\f\n\r\t\v", str_val); - - // Test hex and unicode escapes including the null character. - root.reset(JSONReader().ReadToValue("\"\\x41\\x00\\u1234\"")); - ASSERT_TRUE(root.get()); - EXPECT_TRUE(root->IsType(Value::TYPE_STRING)); - str_val.clear(); - EXPECT_TRUE(root->GetAsString(&str_val)); - EXPECT_EQ(std::wstring(L"A\0\x1234", 3), UTF8ToWide(str_val)); - - // Test invalid strings - root.reset(JSONReader().ReadToValue("\"no closing quote")); - EXPECT_FALSE(root.get()); - root.reset(JSONReader().ReadToValue("\"\\z invalid escape char\"")); - EXPECT_FALSE(root.get()); - root.reset(JSONReader().ReadToValue("\"\\xAQ invalid hex code\"")); - EXPECT_FALSE(root.get()); - root.reset(JSONReader().ReadToValue("not enough hex chars\\x1\"")); - EXPECT_FALSE(root.get()); - root.reset(JSONReader().ReadToValue("\"not enough escape chars\\u123\"")); - EXPECT_FALSE(root.get()); - root.reset(JSONReader().ReadToValue("\"extra backslash at end of input\\\"")); - EXPECT_FALSE(root.get()); - - // Basic array - root.reset(JSONReader::Read("[true, false, null]")); - ASSERT_TRUE(root.get()); - EXPECT_TRUE(root->IsType(Value::TYPE_LIST)); - list = static_cast(root.get()); - EXPECT_EQ(3U, list->GetSize()); - - // Test with trailing comma. Should be parsed the same as above. - scoped_ptr root2; - root2.reset(JSONReader::Read("[true, false, null, ]", - JSON_ALLOW_TRAILING_COMMAS)); - EXPECT_TRUE(root->Equals(root2.get())); - - // Empty array - root.reset(JSONReader::Read("[]")); - ASSERT_TRUE(root.get()); - EXPECT_TRUE(root->IsType(Value::TYPE_LIST)); - list = static_cast(root.get()); - EXPECT_EQ(0U, list->GetSize()); - - // Nested arrays - root.reset(JSONReader::Read("[[true], [], [false, [], [null]], null]")); - ASSERT_TRUE(root.get()); - EXPECT_TRUE(root->IsType(Value::TYPE_LIST)); - list = static_cast(root.get()); - EXPECT_EQ(4U, list->GetSize()); - - // Lots of trailing commas. - root2.reset(JSONReader::Read("[[true], [], [false, [], [null, ] , ], null,]", - JSON_ALLOW_TRAILING_COMMAS)); - EXPECT_TRUE(root->Equals(root2.get())); - - // Invalid, missing close brace. - root.reset(JSONReader::Read("[[true], [], [false, [], [null]], null")); - EXPECT_FALSE(root.get()); - - // Invalid, too many commas - root.reset(JSONReader::Read("[true,, null]")); - EXPECT_FALSE(root.get()); - root.reset(JSONReader::Read("[true,, null]", JSON_ALLOW_TRAILING_COMMAS)); - EXPECT_FALSE(root.get()); - - // Invalid, no commas - root.reset(JSONReader::Read("[true null]")); - EXPECT_FALSE(root.get()); - - // Invalid, trailing comma - root.reset(JSONReader::Read("[true,]")); - EXPECT_FALSE(root.get()); - - // Valid if we set |allow_trailing_comma| to true. - root.reset(JSONReader::Read("[true,]", JSON_ALLOW_TRAILING_COMMAS)); - ASSERT_TRUE(root.get()); - EXPECT_TRUE(root->IsType(Value::TYPE_LIST)); - list = static_cast(root.get()); - EXPECT_EQ(1U, list->GetSize()); - Value* tmp_value = NULL; - ASSERT_TRUE(list->Get(0, &tmp_value)); - EXPECT_TRUE(tmp_value->IsType(Value::TYPE_BOOLEAN)); - bool bool_value = false; - EXPECT_TRUE(tmp_value->GetAsBoolean(&bool_value)); - EXPECT_TRUE(bool_value); - - // Don't allow empty elements, even if |allow_trailing_comma| is - // true. - root.reset(JSONReader::Read("[,]", JSON_ALLOW_TRAILING_COMMAS)); - EXPECT_FALSE(root.get()); - root.reset(JSONReader::Read("[true,,]", JSON_ALLOW_TRAILING_COMMAS)); - EXPECT_FALSE(root.get()); - root.reset(JSONReader::Read("[,true,]", JSON_ALLOW_TRAILING_COMMAS)); - EXPECT_FALSE(root.get()); - root.reset(JSONReader::Read("[true,,false]", JSON_ALLOW_TRAILING_COMMAS)); - EXPECT_FALSE(root.get()); - - // Test objects - root.reset(JSONReader::Read("{}")); - ASSERT_TRUE(root.get()); - EXPECT_TRUE(root->IsType(Value::TYPE_DICTIONARY)); - - root.reset(JSONReader::Read( - "{\"number\":9.87654321, \"null\":null , \"\\x53\" : \"str\" }")); - ASSERT_TRUE(root.get()); - EXPECT_TRUE(root->IsType(Value::TYPE_DICTIONARY)); - DictionaryValue* dict_val = static_cast(root.get()); - double_val = 0.0; - EXPECT_TRUE(dict_val->GetDouble("number", &double_val)); - EXPECT_DOUBLE_EQ(9.87654321, double_val); - Value* null_val = NULL; - ASSERT_TRUE(dict_val->Get("null", &null_val)); - EXPECT_TRUE(null_val->IsType(Value::TYPE_NULL)); - str_val.clear(); - EXPECT_TRUE(dict_val->GetString("S", &str_val)); - EXPECT_EQ("str", str_val); - - root2.reset(JSONReader::Read( - "{\"number\":9.87654321, \"null\":null , \"\\x53\" : \"str\", }", - JSON_ALLOW_TRAILING_COMMAS)); - ASSERT_TRUE(root2.get()); - EXPECT_TRUE(root->Equals(root2.get())); - - // Test newline equivalence. - root2.reset(JSONReader::Read( - "{\n" - " \"number\":9.87654321,\n" - " \"null\":null,\n" - " \"\\x53\":\"str\",\n" - "}\n", JSON_ALLOW_TRAILING_COMMAS)); - ASSERT_TRUE(root2.get()); - EXPECT_TRUE(root->Equals(root2.get())); - - root2.reset(JSONReader::Read( - "{\r\n" - " \"number\":9.87654321,\r\n" - " \"null\":null,\r\n" - " \"\\x53\":\"str\",\r\n" - "}\r\n", JSON_ALLOW_TRAILING_COMMAS)); - ASSERT_TRUE(root2.get()); - EXPECT_TRUE(root->Equals(root2.get())); - - // Test nesting - root.reset(JSONReader::Read( - "{\"inner\":{\"array\":[true]},\"false\":false,\"d\":{}}")); - ASSERT_TRUE(root.get()); - EXPECT_TRUE(root->IsType(Value::TYPE_DICTIONARY)); - dict_val = static_cast(root.get()); - DictionaryValue* inner_dict = NULL; - ASSERT_TRUE(dict_val->GetDictionary("inner", &inner_dict)); - ListValue* inner_array = NULL; - ASSERT_TRUE(inner_dict->GetList("array", &inner_array)); - EXPECT_EQ(1U, inner_array->GetSize()); - bool_value = true; - EXPECT_TRUE(dict_val->GetBoolean("false", &bool_value)); - EXPECT_FALSE(bool_value); - inner_dict = NULL; - EXPECT_TRUE(dict_val->GetDictionary("d", &inner_dict)); - - root2.reset(JSONReader::Read( - "{\"inner\": {\"array\":[true] , },\"false\":false,\"d\":{},}", - JSON_ALLOW_TRAILING_COMMAS)); - EXPECT_TRUE(root->Equals(root2.get())); - - // Test keys with periods - root.reset(JSONReader::Read( - "{\"a.b\":3,\"c\":2,\"d.e.f\":{\"g.h.i.j\":1}}")); - ASSERT_TRUE(root.get()); - EXPECT_TRUE(root->IsType(Value::TYPE_DICTIONARY)); - dict_val = static_cast(root.get()); - int integer_value = 0; - EXPECT_TRUE(dict_val->GetIntegerWithoutPathExpansion("a.b", &integer_value)); - EXPECT_EQ(3, integer_value); - EXPECT_TRUE(dict_val->GetIntegerWithoutPathExpansion("c", &integer_value)); - EXPECT_EQ(2, integer_value); - inner_dict = NULL; - ASSERT_TRUE(dict_val->GetDictionaryWithoutPathExpansion("d.e.f", - &inner_dict)); - EXPECT_EQ(1U, inner_dict->size()); - EXPECT_TRUE(inner_dict->GetIntegerWithoutPathExpansion("g.h.i.j", - &integer_value)); - EXPECT_EQ(1, integer_value); - - root.reset(JSONReader::Read("{\"a\":{\"b\":2},\"a.b\":1}")); - ASSERT_TRUE(root.get()); - EXPECT_TRUE(root->IsType(Value::TYPE_DICTIONARY)); - dict_val = static_cast(root.get()); - EXPECT_TRUE(dict_val->GetInteger("a.b", &integer_value)); - EXPECT_EQ(2, integer_value); - EXPECT_TRUE(dict_val->GetIntegerWithoutPathExpansion("a.b", &integer_value)); - EXPECT_EQ(1, integer_value); - - // Invalid, no closing brace - root.reset(JSONReader::Read("{\"a\": true")); - EXPECT_FALSE(root.get()); - - // Invalid, keys must be quoted - root.reset(JSONReader::Read("{foo:true}")); - EXPECT_FALSE(root.get()); - - // Invalid, trailing comma - root.reset(JSONReader::Read("{\"a\":true,}")); - EXPECT_FALSE(root.get()); - - // Invalid, too many commas - root.reset(JSONReader::Read("{\"a\":true,,\"b\":false}")); - EXPECT_FALSE(root.get()); - root.reset(JSONReader::Read("{\"a\":true,,\"b\":false}", - JSON_ALLOW_TRAILING_COMMAS)); - EXPECT_FALSE(root.get()); - - // Invalid, no separator - root.reset(JSONReader::Read("{\"a\" \"b\"}")); - EXPECT_FALSE(root.get()); - - // Invalid, lone comma. - root.reset(JSONReader::Read("{,}")); - EXPECT_FALSE(root.get()); - root.reset(JSONReader::Read("{,}", JSON_ALLOW_TRAILING_COMMAS)); - EXPECT_FALSE(root.get()); - root.reset(JSONReader::Read("{\"a\":true,,}", JSON_ALLOW_TRAILING_COMMAS)); - EXPECT_FALSE(root.get()); - root.reset(JSONReader::Read("{,\"a\":true}", JSON_ALLOW_TRAILING_COMMAS)); - EXPECT_FALSE(root.get()); - root.reset(JSONReader::Read("{\"a\":true,,\"b\":false}", - JSON_ALLOW_TRAILING_COMMAS)); - EXPECT_FALSE(root.get()); - - // Test stack overflow - std::string evil(1000000, '['); - evil.append(std::string(1000000, ']')); - root.reset(JSONReader::Read(evil)); - EXPECT_FALSE(root.get()); - - // A few thousand adjacent lists is fine. - std::string not_evil("["); - not_evil.reserve(15010); - for (int i = 0; i < 5000; ++i) { - not_evil.append("[],"); - } - not_evil.append("[]]"); - root.reset(JSONReader::Read(not_evil)); - ASSERT_TRUE(root.get()); - EXPECT_TRUE(root->IsType(Value::TYPE_LIST)); - list = static_cast(root.get()); - EXPECT_EQ(5001U, list->GetSize()); - - // Test utf8 encoded input - root.reset(JSONReader().ReadToValue("\"\xe7\xbd\x91\xe9\xa1\xb5\"")); - ASSERT_TRUE(root.get()); - EXPECT_TRUE(root->IsType(Value::TYPE_STRING)); - str_val.clear(); - EXPECT_TRUE(root->GetAsString(&str_val)); - EXPECT_EQ(L"\x7f51\x9875", UTF8ToWide(str_val)); - - root.reset(JSONReader().ReadToValue( - "{\"path\": \"/tmp/\xc3\xa0\xc3\xa8\xc3\xb2.png\"}")); - ASSERT_TRUE(root.get()); - EXPECT_TRUE(root->IsType(Value::TYPE_DICTIONARY)); - EXPECT_TRUE(root->GetAsDictionary(&dict_val)); - EXPECT_TRUE(dict_val->GetString("path", &str_val)); - EXPECT_EQ("/tmp/\xC3\xA0\xC3\xA8\xC3\xB2.png", str_val); - - // Test invalid utf8 encoded input - root.reset(JSONReader().ReadToValue("\"345\xb0\xa1\xb0\xa2\"")); - EXPECT_FALSE(root.get()); - root.reset(JSONReader().ReadToValue("\"123\xc0\x81\"")); - EXPECT_FALSE(root.get()); - root.reset(JSONReader().ReadToValue("\"abc\xc0\xae\"")); - EXPECT_FALSE(root.get()); - - // Test utf16 encoded strings. - root.reset(JSONReader().ReadToValue("\"\\u20ac3,14\"")); - ASSERT_TRUE(root.get()); - EXPECT_TRUE(root->IsType(Value::TYPE_STRING)); - str_val.clear(); - EXPECT_TRUE(root->GetAsString(&str_val)); - EXPECT_EQ("\xe2\x82\xac""3,14", str_val); - - root.reset(JSONReader().ReadToValue("\"\\ud83d\\udca9\\ud83d\\udc6c\"")); - ASSERT_TRUE(root.get()); - EXPECT_TRUE(root->IsType(Value::TYPE_STRING)); - str_val.clear(); - EXPECT_TRUE(root->GetAsString(&str_val)); - EXPECT_EQ("\xf0\x9f\x92\xa9\xf0\x9f\x91\xac", str_val); - - // Test invalid utf16 strings. - const char* cases[] = { - "\"\\u123\"", // Invalid scalar. - "\"\\ud83d\"", // Invalid scalar. - "\"\\u$%@!\"", // Invalid scalar. - "\"\\uzz89\"", // Invalid scalar. - "\"\\ud83d\\udca\"", // Invalid lower surrogate. - "\"\\ud83d\\ud83d\"", // Invalid lower surrogate. - "\"\\ud83foo\"", // No lower surrogate. - "\"\\ud83\\foo\"" // No lower surrogate. - }; - for (size_t i = 0; i < arraysize(cases); ++i) { - root.reset(JSONReader().ReadToValue(cases[i])); - EXPECT_FALSE(root.get()) << cases[i]; - } - - // Test literal root objects. - root.reset(JSONReader::Read("null")); - EXPECT_TRUE(root->IsType(Value::TYPE_NULL)); - - root.reset(JSONReader::Read("true")); - ASSERT_TRUE(root.get()); - EXPECT_TRUE(root->GetAsBoolean(&bool_value)); - EXPECT_TRUE(bool_value); - - root.reset(JSONReader::Read("10")); - ASSERT_TRUE(root.get()); - EXPECT_TRUE(root->GetAsInteger(&integer_value)); - EXPECT_EQ(10, integer_value); - - root.reset(JSONReader::Read("\"root\"")); - ASSERT_TRUE(root.get()); - EXPECT_TRUE(root->GetAsString(&str_val)); - EXPECT_EQ("root", str_val); -} - -TEST(JSONReaderTest, ReadFromFile) { - FilePath path; - ASSERT_TRUE(PathService::Get(base::DIR_TEST_DATA, &path)); - path = path.AppendASCII("json"); - ASSERT_TRUE(base::PathExists(path)); - - std::string input; - ASSERT_TRUE(file_util::ReadFileToString( - path.Append(FILE_PATH_LITERAL("bom_feff.json")), &input)); - - JSONReader reader; - scoped_ptr root(reader.ReadToValue(input)); - ASSERT_TRUE(root.get()) << reader.GetErrorMessage(); - EXPECT_TRUE(root->IsType(Value::TYPE_DICTIONARY)); -} - -// Tests that the root of a JSON object can be deleted safely while its -// children outlive it. -TEST(JSONReaderTest, StringOptimizations) { - scoped_ptr dict_literal_0; - scoped_ptr dict_literal_1; - scoped_ptr dict_string_0; - scoped_ptr dict_string_1; - scoped_ptr list_value_0; - scoped_ptr list_value_1; - - { - scoped_ptr root(JSONReader::Read( - "{" - " \"test\": {" - " \"foo\": true," - " \"bar\": 3.14," - " \"baz\": \"bat\"," - " \"moo\": \"cow\"" - " }," - " \"list\": [" - " \"a\"," - " \"b\"" - " ]" - "}", JSON_DETACHABLE_CHILDREN)); - ASSERT_TRUE(root.get()); - - DictionaryValue* root_dict = NULL; - ASSERT_TRUE(root->GetAsDictionary(&root_dict)); - - DictionaryValue* dict = NULL; - ListValue* list = NULL; - - ASSERT_TRUE(root_dict->GetDictionary("test", &dict)); - ASSERT_TRUE(root_dict->GetList("list", &list)); - - EXPECT_TRUE(dict->Remove("foo", &dict_literal_0)); - EXPECT_TRUE(dict->Remove("bar", &dict_literal_1)); - EXPECT_TRUE(dict->Remove("baz", &dict_string_0)); - EXPECT_TRUE(dict->Remove("moo", &dict_string_1)); - - ASSERT_EQ(2u, list->GetSize()); - EXPECT_TRUE(list->Remove(0, &list_value_0)); - EXPECT_TRUE(list->Remove(0, &list_value_1)); - } - - bool b = false; - double d = 0; - std::string s; - - EXPECT_TRUE(dict_literal_0->GetAsBoolean(&b)); - EXPECT_TRUE(b); - - EXPECT_TRUE(dict_literal_1->GetAsDouble(&d)); - EXPECT_EQ(3.14, d); - - EXPECT_TRUE(dict_string_0->GetAsString(&s)); - EXPECT_EQ("bat", s); - - EXPECT_TRUE(dict_string_1->GetAsString(&s)); - EXPECT_EQ("cow", s); - - EXPECT_TRUE(list_value_0->GetAsString(&s)); - EXPECT_EQ("a", s); - EXPECT_TRUE(list_value_1->GetAsString(&s)); - EXPECT_EQ("b", s); -} - -// A smattering of invalid JSON designed to test specific portions of the -// parser implementation against buffer overflow. Best run with DCHECKs so -// that the one in NextChar fires. -TEST(JSONReaderTest, InvalidSanity) { - const char* invalid_json[] = { - "/* test *", - "{\"foo\"", - "{\"foo\":", - " [", - "\"\\u123g\"", - "{\n\"eh:\n}", - }; - - for (size_t i = 0; i < arraysize(invalid_json); ++i) { - JSONReader reader; - LOG(INFO) << "Sanity test " << i << ": <" << invalid_json[i] << ">"; - EXPECT_FALSE(reader.ReadToValue(invalid_json[i])); - EXPECT_NE(JSONReader::JSON_NO_ERROR, reader.error_code()); - EXPECT_NE("", reader.GetErrorMessage()); - } -} - -TEST(JSONReaderTest, IllegalTrailingNull) { - const char json[] = { '"', 'n', 'u', 'l', 'l', '"', '\0' }; - std::string json_string(json, sizeof(json)); - JSONReader reader; - EXPECT_FALSE(reader.ReadToValue(json_string)); - EXPECT_EQ(JSONReader::JSON_UNEXPECTED_DATA_AFTER_ROOT, reader.error_code()); -} - -} // namespace base diff --git a/base/json/json_string_value_serializer.cc b/base/json/json_string_value_serializer.cc deleted file mode 100644 index 7611fbeed6..0000000000 --- a/base/json/json_string_value_serializer.cc +++ /dev/null @@ -1,48 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "base/json/json_string_value_serializer.h" - -#include "base/json/json_reader.h" -#include "base/json/json_writer.h" -#include "base/logging.h" - -using base::Value; - -JSONStringValueSerializer::~JSONStringValueSerializer() {} - -bool JSONStringValueSerializer::Serialize(const Value& root) { - return SerializeInternal(root, false); -} - -bool JSONStringValueSerializer::SerializeAndOmitBinaryValues( - const Value& root) { - return SerializeInternal(root, true); -} - -bool JSONStringValueSerializer::SerializeInternal(const Value& root, - bool omit_binary_values) { - if (!json_string_ || initialized_with_const_string_) - return false; - - int options = 0; - if (omit_binary_values) - options |= base::JSONWriter::OPTIONS_OMIT_BINARY_VALUES; - if (pretty_print_) - options |= base::JSONWriter::OPTIONS_PRETTY_PRINT; - - base::JSONWriter::WriteWithOptions(&root, options, json_string_); - return true; -} - -Value* JSONStringValueSerializer::Deserialize(int* error_code, - std::string* error_str) { - if (!json_string_) - return NULL; - - return base::JSONReader::ReadAndReturnError(*json_string_, - allow_trailing_comma_ ? base::JSON_ALLOW_TRAILING_COMMAS : - base::JSON_PARSE_RFC, - error_code, error_str); -} diff --git a/base/json/json_string_value_serializer.h b/base/json/json_string_value_serializer.h deleted file mode 100644 index 8aa3f95bee..0000000000 --- a/base/json/json_string_value_serializer.h +++ /dev/null @@ -1,77 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef BASE_JSON_JSON_STRING_VALUE_SERIALIZER_H_ -#define BASE_JSON_JSON_STRING_VALUE_SERIALIZER_H_ - -#include - -#include "base/base_export.h" -#include "base/basictypes.h" -#include "base/files/file_path.h" -#include "base/values.h" - -class BASE_EXPORT JSONStringValueSerializer : public base::ValueSerializer { - public: - // json_string is the string that will be source of the deserialization - // or the destination of the serialization. The caller of the constructor - // retains ownership of the string. - explicit JSONStringValueSerializer(std::string* json_string) - : json_string_(json_string), - initialized_with_const_string_(false), - pretty_print_(false), - allow_trailing_comma_(false) { - } - - // This version allows initialization with a const string reference for - // deserialization only. - explicit JSONStringValueSerializer(const std::string& json_string) - : json_string_(&const_cast(json_string)), - initialized_with_const_string_(true), - pretty_print_(false), - allow_trailing_comma_(false) { - } - - virtual ~JSONStringValueSerializer(); - - // Attempt to serialize the data structure represented by Value into - // JSON. If the return value is true, the result will have been written - // into the string passed into the constructor. - virtual bool Serialize(const base::Value& root) OVERRIDE; - - // Equivalent to Serialize(root) except binary values are omitted from the - // output. - bool SerializeAndOmitBinaryValues(const base::Value& root); - - // Attempt to deserialize the data structure encoded in the string passed - // in to the constructor into a structure of Value objects. If the return - // value is NULL, and if |error_code| is non-null, |error_code| will - // contain an integer error code (either JsonFileError or JsonParseError). - // If |error_message| is non-null, it will be filled in with a formatted - // error message including the location of the error if appropriate. - // The caller takes ownership of the returned value. - virtual base::Value* Deserialize(int* error_code, - std::string* error_message) OVERRIDE; - - void set_pretty_print(bool new_value) { pretty_print_ = new_value; } - bool pretty_print() { return pretty_print_; } - - void set_allow_trailing_comma(bool new_value) { - allow_trailing_comma_ = new_value; - } - - private: - bool SerializeInternal(const base::Value& root, bool omit_binary_values); - - std::string* json_string_; - bool initialized_with_const_string_; - bool pretty_print_; // If true, serialization will span multiple lines. - // If true, deserialization will allow trailing commas. - bool allow_trailing_comma_; - - DISALLOW_COPY_AND_ASSIGN(JSONStringValueSerializer); -}; - -#endif // BASE_JSON_JSON_STRING_VALUE_SERIALIZER_H_ - diff --git a/base/json/json_value_converter.h b/base/json/json_value_converter.h deleted file mode 100644 index cf3c74f0c7..0000000000 --- a/base/json/json_value_converter.h +++ /dev/null @@ -1,527 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef BASE_JSON_JSON_VALUE_CONVERTER_H_ -#define BASE_JSON_JSON_VALUE_CONVERTER_H_ - -#include -#include - -#include "base/basictypes.h" -#include "base/logging.h" -#include "base/memory/scoped_ptr.h" -#include "base/memory/scoped_vector.h" -#include "base/stl_util.h" -#include "base/strings/string16.h" -#include "base/strings/string_piece.h" -#include "base/values.h" - -// JSONValueConverter converts a JSON value into a C++ struct in a -// lightweight way. -// -// Usage: -// For real examples, you may want to refer to _unittest.cc file. -// -// Assume that you have a struct like this: -// struct Message { -// int foo; -// std::string bar; -// static void RegisterJSONConverter( -// JSONValueConverter* converter); -// }; -// -// And you want to parse a json data into this struct. First, you -// need to declare RegisterJSONConverter() method in your struct. -// // static -// void Message::RegisterJSONConverter( -// JSONValueConverter* converter) { -// converter->RegisterIntField("foo", &Message::foo); -// converter->RegisterStringField("bar", &Message::bar); -// } -// -// Then, you just instantiate your JSONValueConverter of your type and call -// Convert() method. -// Message message; -// JSONValueConverter converter; -// converter.Convert(json, &message); -// -// Convert() returns false when it fails. Here "fail" means that the value is -// structurally different from expected, such like a string value appears -// for an int field. Do not report failures for missing fields. -// Also note that Convert() will modify the passed |message| even when it -// fails for performance reason. -// -// For nested field, the internal message also has to implement the registration -// method. Then, just use RegisterNestedField() from the containing struct's -// RegisterJSONConverter method. -// struct Nested { -// Message foo; -// static void RegisterJSONConverter(...) { -// ... -// converter->RegisterNestedField("foo", &Nested::foo); -// } -// }; -// -// For repeated field, we just assume ScopedVector for its container -// and you can put RegisterRepeatedInt or some other types. Use -// RegisterRepeatedMessage for nested repeated fields. -// -// Sometimes JSON format uses string representations for other types such -// like enum, timestamp, or URL. You can use RegisterCustomField method -// and specify a function to convert a StringPiece to your type. -// bool ConvertFunc(const StringPiece& s, YourEnum* result) { -// // do something and return true if succeed... -// } -// struct Message { -// YourEnum ye; -// ... -// static void RegisterJSONConverter(...) { -// ... -// converter->RegsiterCustomField( -// "your_enum", &Message::ye, &ConvertFunc); -// } -// }; - -namespace base { - -template -class JSONValueConverter; - -namespace internal { - -template -class FieldConverterBase { - public: - explicit FieldConverterBase(const std::string& path) : field_path_(path) {} - virtual ~FieldConverterBase() {} - virtual bool ConvertField(const base::Value& value, StructType* obj) - const = 0; - const std::string& field_path() const { return field_path_; } - - private: - std::string field_path_; - DISALLOW_COPY_AND_ASSIGN(FieldConverterBase); -}; - -template -class ValueConverter { - public: - virtual ~ValueConverter() {} - virtual bool Convert(const base::Value& value, FieldType* field) const = 0; -}; - -template -class FieldConverter : public FieldConverterBase { - public: - explicit FieldConverter(const std::string& path, - FieldType StructType::* field, - ValueConverter* converter) - : FieldConverterBase(path), - field_pointer_(field), - value_converter_(converter) { - } - - virtual bool ConvertField( - const base::Value& value, StructType* dst) const OVERRIDE { - return value_converter_->Convert(value, &(dst->*field_pointer_)); - } - - private: - FieldType StructType::* field_pointer_; - scoped_ptr > value_converter_; - DISALLOW_COPY_AND_ASSIGN(FieldConverter); -}; - -template -class BasicValueConverter; - -template <> -class BasicValueConverter : public ValueConverter { - public: - BasicValueConverter() {} - - virtual bool Convert(const base::Value& value, int* field) const OVERRIDE { - return value.GetAsInteger(field); - } - - private: - DISALLOW_COPY_AND_ASSIGN(BasicValueConverter); -}; - -template <> -class BasicValueConverter : public ValueConverter { - public: - BasicValueConverter() {} - - virtual bool Convert( - const base::Value& value, std::string* field) const OVERRIDE { - return value.GetAsString(field); - } - - private: - DISALLOW_COPY_AND_ASSIGN(BasicValueConverter); -}; - -template <> -class BasicValueConverter : public ValueConverter { - public: - BasicValueConverter() {} - - virtual bool Convert( - const base::Value& value, string16* field) const OVERRIDE { - return value.GetAsString(field); - } - - private: - DISALLOW_COPY_AND_ASSIGN(BasicValueConverter); -}; - -template <> -class BasicValueConverter : public ValueConverter { - public: - BasicValueConverter() {} - - virtual bool Convert(const base::Value& value, double* field) const OVERRIDE { - return value.GetAsDouble(field); - } - - private: - DISALLOW_COPY_AND_ASSIGN(BasicValueConverter); -}; - -template <> -class BasicValueConverter : public ValueConverter { - public: - BasicValueConverter() {} - - virtual bool Convert(const base::Value& value, bool* field) const OVERRIDE { - return value.GetAsBoolean(field); - } - - private: - DISALLOW_COPY_AND_ASSIGN(BasicValueConverter); -}; - -template -class ValueFieldConverter : public ValueConverter { - public: - typedef bool(*ConvertFunc)(const base::Value* value, FieldType* field); - - ValueFieldConverter(ConvertFunc convert_func) - : convert_func_(convert_func) {} - - virtual bool Convert(const base::Value& value, - FieldType* field) const OVERRIDE { - return convert_func_(&value, field); - } - - private: - ConvertFunc convert_func_; - - DISALLOW_COPY_AND_ASSIGN(ValueFieldConverter); -}; - -template -class CustomFieldConverter : public ValueConverter { - public: - typedef bool(*ConvertFunc)(const StringPiece& value, FieldType* field); - - CustomFieldConverter(ConvertFunc convert_func) - : convert_func_(convert_func) {} - - virtual bool Convert(const base::Value& value, - FieldType* field) const OVERRIDE { - std::string string_value; - return value.GetAsString(&string_value) && - convert_func_(string_value, field); - } - - private: - ConvertFunc convert_func_; - - DISALLOW_COPY_AND_ASSIGN(CustomFieldConverter); -}; - -template -class NestedValueConverter : public ValueConverter { - public: - NestedValueConverter() {} - - virtual bool Convert( - const base::Value& value, NestedType* field) const OVERRIDE { - return converter_.Convert(value, field); - } - - private: - JSONValueConverter converter_; - DISALLOW_COPY_AND_ASSIGN(NestedValueConverter); -}; - -template -class RepeatedValueConverter : public ValueConverter > { - public: - RepeatedValueConverter() {} - - virtual bool Convert( - const base::Value& value, ScopedVector* field) const OVERRIDE { - const base::ListValue* list = NULL; - if (!value.GetAsList(&list)) { - // The field is not a list. - return false; - } - - field->reserve(list->GetSize()); - for (size_t i = 0; i < list->GetSize(); ++i) { - const base::Value* element = NULL; - if (!list->Get(i, &element)) - continue; - - scoped_ptr e(new Element); - if (basic_converter_.Convert(*element, e.get())) { - field->push_back(e.release()); - } else { - DVLOG(1) << "failure at " << i << "-th element"; - return false; - } - } - return true; - } - - private: - BasicValueConverter basic_converter_; - DISALLOW_COPY_AND_ASSIGN(RepeatedValueConverter); -}; - -template -class RepeatedMessageConverter - : public ValueConverter > { - public: - RepeatedMessageConverter() {} - - virtual bool Convert(const base::Value& value, - ScopedVector* field) const OVERRIDE { - const base::ListValue* list = NULL; - if (!value.GetAsList(&list)) - return false; - - field->reserve(list->GetSize()); - for (size_t i = 0; i < list->GetSize(); ++i) { - const base::Value* element = NULL; - if (!list->Get(i, &element)) - continue; - - scoped_ptr nested(new NestedType); - if (converter_.Convert(*element, nested.get())) { - field->push_back(nested.release()); - } else { - DVLOG(1) << "failure at " << i << "-th element"; - return false; - } - } - return true; - } - - private: - JSONValueConverter converter_; - DISALLOW_COPY_AND_ASSIGN(RepeatedMessageConverter); -}; - -template -class RepeatedCustomValueConverter - : public ValueConverter > { - public: - typedef bool(*ConvertFunc)(const base::Value* value, NestedType* field); - - RepeatedCustomValueConverter(ConvertFunc convert_func) - : convert_func_(convert_func) {} - - virtual bool Convert(const base::Value& value, - ScopedVector* field) const OVERRIDE { - const base::ListValue* list = NULL; - if (!value.GetAsList(&list)) - return false; - - field->reserve(list->GetSize()); - for (size_t i = 0; i < list->GetSize(); ++i) { - const base::Value* element = NULL; - if (!list->Get(i, &element)) - continue; - - scoped_ptr nested(new NestedType); - if ((*convert_func_)(element, nested.get())) { - field->push_back(nested.release()); - } else { - DVLOG(1) << "failure at " << i << "-th element"; - return false; - } - } - return true; - } - - private: - ConvertFunc convert_func_; - DISALLOW_COPY_AND_ASSIGN(RepeatedCustomValueConverter); -}; - - -} // namespace internal - -template -class JSONValueConverter { - public: - JSONValueConverter() { - StructType::RegisterJSONConverter(this); - } - - void RegisterIntField(const std::string& field_name, - int StructType::* field) { - fields_.push_back(new internal::FieldConverter( - field_name, field, new internal::BasicValueConverter)); - } - - void RegisterStringField(const std::string& field_name, - std::string StructType::* field) { - fields_.push_back(new internal::FieldConverter( - field_name, field, new internal::BasicValueConverter)); - } - - void RegisterStringField(const std::string& field_name, - string16 StructType::* field) { - fields_.push_back(new internal::FieldConverter( - field_name, field, new internal::BasicValueConverter)); - } - - void RegisterBoolField(const std::string& field_name, - bool StructType::* field) { - fields_.push_back(new internal::FieldConverter( - field_name, field, new internal::BasicValueConverter)); - } - - void RegisterDoubleField(const std::string& field_name, - double StructType::* field) { - fields_.push_back(new internal::FieldConverter( - field_name, field, new internal::BasicValueConverter)); - } - - template - void RegisterNestedField( - const std::string& field_name, NestedType StructType::* field) { - fields_.push_back(new internal::FieldConverter( - field_name, - field, - new internal::NestedValueConverter)); - } - - template - void RegisterCustomField( - const std::string& field_name, - FieldType StructType::* field, - bool (*convert_func)(const StringPiece&, FieldType*)) { - fields_.push_back(new internal::FieldConverter( - field_name, - field, - new internal::CustomFieldConverter(convert_func))); - } - - template - void RegisterCustomValueField( - const std::string& field_name, - FieldType StructType::* field, - bool (*convert_func)(const base::Value*, FieldType*)) { - fields_.push_back(new internal::FieldConverter( - field_name, - field, - new internal::ValueFieldConverter(convert_func))); - } - - void RegisterRepeatedInt(const std::string& field_name, - ScopedVector StructType::* field) { - fields_.push_back( - new internal::FieldConverter >( - field_name, field, new internal::RepeatedValueConverter)); - } - - void RegisterRepeatedString(const std::string& field_name, - ScopedVector StructType::* field) { - fields_.push_back( - new internal::FieldConverter >( - field_name, - field, - new internal::RepeatedValueConverter)); - } - - void RegisterRepeatedString(const std::string& field_name, - ScopedVector StructType::* field) { - fields_.push_back( - new internal::FieldConverter >( - field_name, - field, - new internal::RepeatedValueConverter)); - } - - void RegisterRepeatedDouble(const std::string& field_name, - ScopedVector StructType::* field) { - fields_.push_back( - new internal::FieldConverter >( - field_name, field, new internal::RepeatedValueConverter)); - } - - void RegisterRepeatedBool(const std::string& field_name, - ScopedVector StructType::* field) { - fields_.push_back( - new internal::FieldConverter >( - field_name, field, new internal::RepeatedValueConverter)); - } - - template - void RegisterRepeatedCustomValue( - const std::string& field_name, - ScopedVector StructType::* field, - bool (*convert_func)(const base::Value*, NestedType*)) { - fields_.push_back( - new internal::FieldConverter >( - field_name, - field, - new internal::RepeatedCustomValueConverter( - convert_func))); - } - - template - void RegisterRepeatedMessage(const std::string& field_name, - ScopedVector StructType::* field) { - fields_.push_back( - new internal::FieldConverter >( - field_name, - field, - new internal::RepeatedMessageConverter)); - } - - bool Convert(const base::Value& value, StructType* output) const { - const DictionaryValue* dictionary_value = NULL; - if (!value.GetAsDictionary(&dictionary_value)) - return false; - - for(size_t i = 0; i < fields_.size(); ++i) { - const internal::FieldConverterBase* field_converter = - fields_[i]; - const base::Value* field = NULL; - if (dictionary_value->Get(field_converter->field_path(), &field)) { - if (!field_converter->ConvertField(*field, output)) { - DVLOG(1) << "failure at field " << field_converter->field_path(); - return false; - } - } - } - return true; - } - - private: - ScopedVector > fields_; - - DISALLOW_COPY_AND_ASSIGN(JSONValueConverter); -}; - -} // namespace base - -#endif // BASE_JSON_JSON_VALUE_CONVERTER_H_ diff --git a/base/json/json_value_converter_unittest.cc b/base/json/json_value_converter_unittest.cc deleted file mode 100644 index 7d48f39a30..0000000000 --- a/base/json/json_value_converter_unittest.cc +++ /dev/null @@ -1,256 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "base/json/json_value_converter.h" - -#include -#include - -#include "base/json/json_reader.h" -#include "base/memory/scoped_ptr.h" -#include "base/memory/scoped_vector.h" -#include "base/strings/string_piece.h" -#include "base/values.h" -#include "testing/gtest/include/gtest/gtest.h" - -namespace base { -namespace { - -// Very simple messages. -struct SimpleMessage { - enum SimpleEnum { - FOO, BAR, - }; - int foo; - std::string bar; - bool baz; - bool bstruct; - SimpleEnum simple_enum; - ScopedVector ints; - ScopedVector string_values; - SimpleMessage() : foo(0), baz(false), bstruct(false), simple_enum(FOO) {} - - static bool ParseSimpleEnum(const StringPiece& value, SimpleEnum* field) { - if (value == "foo") { - *field = FOO; - return true; - } else if (value == "bar") { - *field = BAR; - return true; - } - return false; - } - - static bool HasFieldPresent(const base::Value* value, bool* result) { - *result = value != NULL; - return true; - } - - static bool GetValueString(const base::Value* value, std::string* result) { - const base::DictionaryValue* dict = NULL; - if (!value->GetAsDictionary(&dict)) - return false; - - if (!dict->GetString("val", result)) - return false; - - return true; - } - - static void RegisterJSONConverter( - base::JSONValueConverter* converter) { - converter->RegisterIntField("foo", &SimpleMessage::foo); - converter->RegisterStringField("bar", &SimpleMessage::bar); - converter->RegisterBoolField("baz", &SimpleMessage::baz); - converter->RegisterCustomField( - "simple_enum", &SimpleMessage::simple_enum, &ParseSimpleEnum); - converter->RegisterRepeatedInt("ints", &SimpleMessage::ints); - converter->RegisterCustomValueField("bstruct", - &SimpleMessage::bstruct, - &HasFieldPresent); - converter->RegisterRepeatedCustomValue( - "string_values", - &SimpleMessage::string_values, - &GetValueString); - } -}; - -// For nested messages. -struct NestedMessage { - double foo; - SimpleMessage child; - ScopedVector children; - - NestedMessage() : foo(0) {} - - static void RegisterJSONConverter( - base::JSONValueConverter* converter) { - converter->RegisterDoubleField("foo", &NestedMessage::foo); - converter->RegisterNestedField("child", &NestedMessage::child); - converter->RegisterRepeatedMessage("children", &NestedMessage::children); - } -}; - -} // namespace - -TEST(JSONValueConverterTest, ParseSimpleMessage) { - const char normal_data[] = - "{\n" - " \"foo\": 1,\n" - " \"bar\": \"bar\",\n" - " \"baz\": true,\n" - " \"bstruct\": {},\n" - " \"string_values\": [{\"val\": \"value_1\"}, {\"val\": \"value_2\"}]," - " \"simple_enum\": \"foo\"," - " \"ints\": [1, 2]" - "}\n"; - - scoped_ptr value(base::JSONReader::Read(normal_data)); - SimpleMessage message; - base::JSONValueConverter converter; - EXPECT_TRUE(converter.Convert(*value.get(), &message)); - - EXPECT_EQ(1, message.foo); - EXPECT_EQ("bar", message.bar); - EXPECT_TRUE(message.baz); - EXPECT_EQ(SimpleMessage::FOO, message.simple_enum); - EXPECT_EQ(2, static_cast(message.ints.size())); - ASSERT_EQ(2U, message.string_values.size()); - EXPECT_EQ("value_1", *message.string_values[0]); - EXPECT_EQ("value_2", *message.string_values[1]); - EXPECT_EQ(1, *(message.ints[0])); - EXPECT_EQ(2, *(message.ints[1])); -} - -TEST(JSONValueConverterTest, ParseNestedMessage) { - const char normal_data[] = - "{\n" - " \"foo\": 1.0,\n" - " \"child\": {\n" - " \"foo\": 1,\n" - " \"bar\": \"bar\",\n" - " \"bstruct\": {},\n" - " \"string_values\": [{\"val\": \"value_1\"}, {\"val\": \"value_2\"}]," - " \"baz\": true\n" - " },\n" - " \"children\": [{\n" - " \"foo\": 2,\n" - " \"bar\": \"foobar\",\n" - " \"bstruct\": \"\",\n" - " \"string_values\": [{\"val\": \"value_1\"}]," - " \"baz\": true\n" - " },\n" - " {\n" - " \"foo\": 3,\n" - " \"bar\": \"barbaz\",\n" - " \"baz\": false\n" - " }]\n" - "}\n"; - - scoped_ptr value(base::JSONReader::Read(normal_data)); - NestedMessage message; - base::JSONValueConverter converter; - EXPECT_TRUE(converter.Convert(*value.get(), &message)); - - EXPECT_EQ(1.0, message.foo); - EXPECT_EQ(1, message.child.foo); - EXPECT_EQ("bar", message.child.bar); - EXPECT_TRUE(message.child.baz); - EXPECT_TRUE(message.child.bstruct); - ASSERT_EQ(2U, message.child.string_values.size()); - EXPECT_EQ("value_1", *message.child.string_values[0]); - EXPECT_EQ("value_2", *message.child.string_values[1]); - - EXPECT_EQ(2, static_cast(message.children.size())); - const SimpleMessage* first_child = message.children[0]; - ASSERT_TRUE(first_child); - EXPECT_EQ(2, first_child->foo); - EXPECT_EQ("foobar", first_child->bar); - EXPECT_TRUE(first_child->baz); - EXPECT_TRUE(first_child->bstruct); - ASSERT_EQ(1U, first_child->string_values.size()); - EXPECT_EQ("value_1", *first_child->string_values[0]); - - const SimpleMessage* second_child = message.children[1]; - ASSERT_TRUE(second_child); - EXPECT_EQ(3, second_child->foo); - EXPECT_EQ("barbaz", second_child->bar); - EXPECT_FALSE(second_child->baz); - EXPECT_FALSE(second_child->bstruct); - EXPECT_EQ(0U, second_child->string_values.size()); -} - -TEST(JSONValueConverterTest, ParseFailures) { - const char normal_data[] = - "{\n" - " \"foo\": 1,\n" - " \"bar\": 2,\n" // "bar" is an integer here. - " \"baz\": true,\n" - " \"ints\": [1, 2]" - "}\n"; - - scoped_ptr value(base::JSONReader::Read(normal_data)); - SimpleMessage message; - base::JSONValueConverter converter; - EXPECT_FALSE(converter.Convert(*value.get(), &message)); - // Do not check the values below. |message| may be modified during - // Convert() even it fails. -} - -TEST(JSONValueConverterTest, ParseWithMissingFields) { - const char normal_data[] = - "{\n" - " \"foo\": 1,\n" - " \"baz\": true,\n" - " \"ints\": [1, 2]" - "}\n"; - - scoped_ptr value(base::JSONReader::Read(normal_data)); - SimpleMessage message; - base::JSONValueConverter converter; - // Convert() still succeeds even if the input doesn't have "bar" field. - EXPECT_TRUE(converter.Convert(*value.get(), &message)); - - EXPECT_EQ(1, message.foo); - EXPECT_TRUE(message.baz); - EXPECT_EQ(2, static_cast(message.ints.size())); - EXPECT_EQ(1, *(message.ints[0])); - EXPECT_EQ(2, *(message.ints[1])); -} - -TEST(JSONValueConverterTest, EnumParserFails) { - const char normal_data[] = - "{\n" - " \"foo\": 1,\n" - " \"bar\": \"bar\",\n" - " \"baz\": true,\n" - " \"simple_enum\": \"baz\"," - " \"ints\": [1, 2]" - "}\n"; - - scoped_ptr value(base::JSONReader::Read(normal_data)); - SimpleMessage message; - base::JSONValueConverter converter; - EXPECT_FALSE(converter.Convert(*value.get(), &message)); - // No check the values as mentioned above. -} - -TEST(JSONValueConverterTest, RepeatedValueErrorInTheMiddle) { - const char normal_data[] = - "{\n" - " \"foo\": 1,\n" - " \"bar\": \"bar\",\n" - " \"baz\": true,\n" - " \"simple_enum\": \"baz\"," - " \"ints\": [1, false]" - "}\n"; - - scoped_ptr value(base::JSONReader::Read(normal_data)); - SimpleMessage message; - base::JSONValueConverter converter; - EXPECT_FALSE(converter.Convert(*value.get(), &message)); - // No check the values as mentioned above. -} - -} // namespace base diff --git a/base/json/json_value_serializer_unittest.cc b/base/json/json_value_serializer_unittest.cc deleted file mode 100644 index 314cd07a5b..0000000000 --- a/base/json/json_value_serializer_unittest.cc +++ /dev/null @@ -1,471 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include - -#include "base/file_util.h" -#include "base/files/scoped_temp_dir.h" -#include "base/json/json_file_value_serializer.h" -#include "base/json/json_reader.h" -#include "base/json/json_string_value_serializer.h" -#include "base/json/json_writer.h" -#include "base/memory/scoped_ptr.h" -#include "base/path_service.h" -#include "base/strings/string_util.h" -#include "base/strings/utf_string_conversions.h" -#include "base/values.h" -#include "testing/gtest/include/gtest/gtest.h" - -namespace base { - -namespace { - -// Some proper JSON to test with: -const char kProperJSON[] = - "{\n" - " \"compound\": {\n" - " \"a\": 1,\n" - " \"b\": 2\n" - " },\n" - " \"some_String\": \"1337\",\n" - " \"some_int\": 42,\n" - " \"the_list\": [ \"val1\", \"val2\" ]\n" - "}\n"; - -// Some proper JSON with trailing commas: -const char kProperJSONWithCommas[] = - "{\n" - "\t\"some_int\": 42,\n" - "\t\"some_String\": \"1337\",\n" - "\t\"the_list\": [\"val1\", \"val2\", ],\n" - "\t\"compound\": { \"a\": 1, \"b\": 2, },\n" - "}\n"; - -const char kWinLineEnds[] = "\r\n"; -const char kLinuxLineEnds[] = "\n"; - -// Verifies the generated JSON against the expected output. -void CheckJSONIsStillTheSame(Value& value) { - // Serialize back the output. - std::string serialized_json; - JSONStringValueSerializer str_serializer(&serialized_json); - str_serializer.set_pretty_print(true); - ASSERT_TRUE(str_serializer.Serialize(value)); - // Unify line endings between platforms. - ReplaceSubstringsAfterOffset(&serialized_json, 0, - kWinLineEnds, kLinuxLineEnds); - // Now compare the input with the output. - ASSERT_EQ(kProperJSON, serialized_json); -} - -void ValidateJsonList(const std::string& json) { - scoped_ptr root(JSONReader::Read(json)); - ASSERT_TRUE(root.get() && root->IsType(Value::TYPE_LIST)); - ListValue* list = static_cast(root.get()); - ASSERT_EQ(1U, list->GetSize()); - Value* elt = NULL; - ASSERT_TRUE(list->Get(0, &elt)); - int value = 0; - ASSERT_TRUE(elt && elt->GetAsInteger(&value)); - ASSERT_EQ(1, value); -} - -// Test proper JSON [de]serialization from string is working. -TEST(JSONValueSerializerTest, ReadProperJSONFromString) { - // Try to deserialize it through the serializer. - std::string proper_json(kProperJSON); - JSONStringValueSerializer str_deserializer(proper_json); - - int error_code = 0; - std::string error_message; - scoped_ptr value( - str_deserializer.Deserialize(&error_code, &error_message)); - ASSERT_TRUE(value.get()); - ASSERT_EQ(0, error_code); - ASSERT_TRUE(error_message.empty()); - // Verify if the same JSON is still there. - CheckJSONIsStillTheSame(*value); -} - -// Test that trialing commas are only properly deserialized from string when -// the proper flag for that is set. -TEST(JSONValueSerializerTest, ReadJSONWithTrailingCommasFromString) { - // Try to deserialize it through the serializer. - std::string proper_json(kProperJSONWithCommas); - JSONStringValueSerializer str_deserializer(proper_json); - - int error_code = 0; - std::string error_message; - scoped_ptr value( - str_deserializer.Deserialize(&error_code, &error_message)); - ASSERT_FALSE(value.get()); - ASSERT_NE(0, error_code); - ASSERT_FALSE(error_message.empty()); - // Now the flag is set and it must pass. - str_deserializer.set_allow_trailing_comma(true); - value.reset(str_deserializer.Deserialize(&error_code, &error_message)); - ASSERT_TRUE(value.get()); - ASSERT_EQ(JSONReader::JSON_TRAILING_COMMA, error_code); - // Verify if the same JSON is still there. - CheckJSONIsStillTheSame(*value); -} - -// Test proper JSON [de]serialization from file is working. -TEST(JSONValueSerializerTest, ReadProperJSONFromFile) { - ScopedTempDir tempdir; - ASSERT_TRUE(tempdir.CreateUniqueTempDir()); - // Write it down in the file. - FilePath temp_file(tempdir.path().AppendASCII("test.json")); - ASSERT_EQ(static_cast(strlen(kProperJSON)), - file_util::WriteFile(temp_file, kProperJSON, strlen(kProperJSON))); - - // Try to deserialize it through the serializer. - JSONFileValueSerializer file_deserializer(temp_file); - - int error_code = 0; - std::string error_message; - scoped_ptr value( - file_deserializer.Deserialize(&error_code, &error_message)); - ASSERT_TRUE(value.get()); - ASSERT_EQ(0, error_code); - ASSERT_TRUE(error_message.empty()); - // Verify if the same JSON is still there. - CheckJSONIsStillTheSame(*value); -} - -// Test that trialing commas are only properly deserialized from file when -// the proper flag for that is set. -TEST(JSONValueSerializerTest, ReadJSONWithCommasFromFile) { - ScopedTempDir tempdir; - ASSERT_TRUE(tempdir.CreateUniqueTempDir()); - // Write it down in the file. - FilePath temp_file(tempdir.path().AppendASCII("test.json")); - ASSERT_EQ(static_cast(strlen(kProperJSONWithCommas)), - file_util::WriteFile(temp_file, - kProperJSONWithCommas, - strlen(kProperJSONWithCommas))); - - // Try to deserialize it through the serializer. - JSONFileValueSerializer file_deserializer(temp_file); - // This must fail without the proper flag. - int error_code = 0; - std::string error_message; - scoped_ptr value( - file_deserializer.Deserialize(&error_code, &error_message)); - ASSERT_FALSE(value.get()); - ASSERT_NE(0, error_code); - ASSERT_FALSE(error_message.empty()); - // Now the flag is set and it must pass. - file_deserializer.set_allow_trailing_comma(true); - value.reset(file_deserializer.Deserialize(&error_code, &error_message)); - ASSERT_TRUE(value.get()); - ASSERT_EQ(JSONReader::JSON_TRAILING_COMMA, error_code); - // Verify if the same JSON is still there. - CheckJSONIsStillTheSame(*value); -} - -TEST(JSONValueSerializerTest, Roundtrip) { - const std::string original_serialization = - "{\"bool\":true,\"double\":3.14,\"int\":42,\"list\":[1,2],\"null\":null}"; - JSONStringValueSerializer serializer(original_serialization); - scoped_ptr root(serializer.Deserialize(NULL, NULL)); - ASSERT_TRUE(root.get()); - ASSERT_TRUE(root->IsType(Value::TYPE_DICTIONARY)); - - DictionaryValue* root_dict = static_cast(root.get()); - - Value* null_value = NULL; - ASSERT_TRUE(root_dict->Get("null", &null_value)); - ASSERT_TRUE(null_value); - ASSERT_TRUE(null_value->IsType(Value::TYPE_NULL)); - - bool bool_value = false; - ASSERT_TRUE(root_dict->GetBoolean("bool", &bool_value)); - ASSERT_TRUE(bool_value); - - int int_value = 0; - ASSERT_TRUE(root_dict->GetInteger("int", &int_value)); - ASSERT_EQ(42, int_value); - - double double_value = 0.0; - ASSERT_TRUE(root_dict->GetDouble("double", &double_value)); - ASSERT_DOUBLE_EQ(3.14, double_value); - - // We shouldn't be able to write using this serializer, since it was - // initialized with a const string. - ASSERT_FALSE(serializer.Serialize(*root_dict)); - - std::string test_serialization; - JSONStringValueSerializer mutable_serializer(&test_serialization); - ASSERT_TRUE(mutable_serializer.Serialize(*root_dict)); - ASSERT_EQ(original_serialization, test_serialization); - - mutable_serializer.set_pretty_print(true); - ASSERT_TRUE(mutable_serializer.Serialize(*root_dict)); - // JSON output uses a different newline style on Windows than on other - // platforms. -#if defined(OS_WIN) -#define JSON_NEWLINE "\r\n" -#else -#define JSON_NEWLINE "\n" -#endif - const std::string pretty_serialization = - "{" JSON_NEWLINE - " \"bool\": true," JSON_NEWLINE - " \"double\": 3.14," JSON_NEWLINE - " \"int\": 42," JSON_NEWLINE - " \"list\": [ 1, 2 ]," JSON_NEWLINE - " \"null\": null" JSON_NEWLINE - "}" JSON_NEWLINE; -#undef JSON_NEWLINE - ASSERT_EQ(pretty_serialization, test_serialization); -} - -TEST(JSONValueSerializerTest, StringEscape) { - string16 all_chars; - for (int i = 1; i < 256; ++i) { - all_chars += static_cast(i); - } - // Generated in in Firefox using the following js (with an extra backslash for - // double quote): - // var s = ''; - // for (var i = 1; i < 256; ++i) { s += String.fromCharCode(i); } - // uneval(s).replace(/\\/g, "\\\\"); - std::string all_chars_expected = - "\\u0001\\u0002\\u0003\\u0004\\u0005\\u0006\\u0007\\b\\t\\n\\u000B\\f\\r" - "\\u000E\\u000F\\u0010\\u0011\\u0012\\u0013\\u0014\\u0015\\u0016\\u0017" - "\\u0018\\u0019\\u001A\\u001B\\u001C\\u001D\\u001E\\u001F !\\\"" - "#$%&'()*+,-./0123456789:;\\u003C=\\u003E?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\" - "\\]^_`abcdefghijklmnopqrstuvwxyz{|}~\\u007F\\u0080\\u0081\\u0082\\u0083" - "\\u0084\\u0085\\u0086\\u0087\\u0088\\u0089\\u008A\\u008B\\u008C\\u008D" - "\\u008E\\u008F\\u0090\\u0091\\u0092\\u0093\\u0094\\u0095\\u0096\\u0097" - "\\u0098\\u0099\\u009A\\u009B\\u009C\\u009D\\u009E\\u009F\\u00A0\\u00A1" - "\\u00A2\\u00A3\\u00A4\\u00A5\\u00A6\\u00A7\\u00A8\\u00A9\\u00AA\\u00AB" - "\\u00AC\\u00AD\\u00AE\\u00AF\\u00B0\\u00B1\\u00B2\\u00B3\\u00B4\\u00B5" - "\\u00B6\\u00B7\\u00B8\\u00B9\\u00BA\\u00BB\\u00BC\\u00BD\\u00BE\\u00BF" - "\\u00C0\\u00C1\\u00C2\\u00C3\\u00C4\\u00C5\\u00C6\\u00C7\\u00C8\\u00C9" - "\\u00CA\\u00CB\\u00CC\\u00CD\\u00CE\\u00CF\\u00D0\\u00D1\\u00D2\\u00D3" - "\\u00D4\\u00D5\\u00D6\\u00D7\\u00D8\\u00D9\\u00DA\\u00DB\\u00DC\\u00DD" - "\\u00DE\\u00DF\\u00E0\\u00E1\\u00E2\\u00E3\\u00E4\\u00E5\\u00E6\\u00E7" - "\\u00E8\\u00E9\\u00EA\\u00EB\\u00EC\\u00ED\\u00EE\\u00EF\\u00F0\\u00F1" - "\\u00F2\\u00F3\\u00F4\\u00F5\\u00F6\\u00F7\\u00F8\\u00F9\\u00FA\\u00FB" - "\\u00FC\\u00FD\\u00FE\\u00FF"; - - std::string expected_output = "{\"all_chars\":\"" + all_chars_expected + - "\"}"; - // Test JSONWriter interface - std::string output_js; - DictionaryValue valueRoot; - valueRoot.SetString("all_chars", all_chars); - JSONWriter::Write(&valueRoot, &output_js); - ASSERT_EQ(expected_output, output_js); - - // Test JSONValueSerializer interface (uses JSONWriter). - JSONStringValueSerializer serializer(&output_js); - ASSERT_TRUE(serializer.Serialize(valueRoot)); - ASSERT_EQ(expected_output, output_js); -} - -TEST(JSONValueSerializerTest, UnicodeStrings) { - // unicode string json -> escaped ascii text - DictionaryValue root; - string16 test(WideToUTF16(L"\x7F51\x9875")); - root.SetString("web", test); - - std::string expected = "{\"web\":\"\\u7F51\\u9875\"}"; - - std::string actual; - JSONStringValueSerializer serializer(&actual); - ASSERT_TRUE(serializer.Serialize(root)); - ASSERT_EQ(expected, actual); - - // escaped ascii text -> json - JSONStringValueSerializer deserializer(expected); - scoped_ptr deserial_root(deserializer.Deserialize(NULL, NULL)); - ASSERT_TRUE(deserial_root.get()); - DictionaryValue* dict_root = - static_cast(deserial_root.get()); - string16 web_value; - ASSERT_TRUE(dict_root->GetString("web", &web_value)); - ASSERT_EQ(test, web_value); -} - -TEST(JSONValueSerializerTest, HexStrings) { - // hex string json -> escaped ascii text - DictionaryValue root; - string16 test(WideToUTF16(L"\x01\x02")); - root.SetString("test", test); - - std::string expected = "{\"test\":\"\\u0001\\u0002\"}"; - - std::string actual; - JSONStringValueSerializer serializer(&actual); - ASSERT_TRUE(serializer.Serialize(root)); - ASSERT_EQ(expected, actual); - - // escaped ascii text -> json - JSONStringValueSerializer deserializer(expected); - scoped_ptr deserial_root(deserializer.Deserialize(NULL, NULL)); - ASSERT_TRUE(deserial_root.get()); - DictionaryValue* dict_root = - static_cast(deserial_root.get()); - string16 test_value; - ASSERT_TRUE(dict_root->GetString("test", &test_value)); - ASSERT_EQ(test, test_value); - - // Test converting escaped regular chars - std::string escaped_chars = "{\"test\":\"\\u0067\\u006f\"}"; - JSONStringValueSerializer deserializer2(escaped_chars); - deserial_root.reset(deserializer2.Deserialize(NULL, NULL)); - ASSERT_TRUE(deserial_root.get()); - dict_root = static_cast(deserial_root.get()); - ASSERT_TRUE(dict_root->GetString("test", &test_value)); - ASSERT_EQ(ASCIIToUTF16("go"), test_value); -} - -TEST(JSONValueSerializerTest, AllowTrailingComma) { - scoped_ptr root; - scoped_ptr root_expected; - std::string test_with_commas("{\"key\": [true,],}"); - std::string test_no_commas("{\"key\": [true]}"); - - JSONStringValueSerializer serializer(test_with_commas); - serializer.set_allow_trailing_comma(true); - JSONStringValueSerializer serializer_expected(test_no_commas); - root.reset(serializer.Deserialize(NULL, NULL)); - ASSERT_TRUE(root.get()); - root_expected.reset(serializer_expected.Deserialize(NULL, NULL)); - ASSERT_TRUE(root_expected.get()); - ASSERT_TRUE(root->Equals(root_expected.get())); -} - -TEST(JSONValueSerializerTest, JSONReaderComments) { - ValidateJsonList("[ // 2, 3, ignore me ] \n1 ]"); - ValidateJsonList("[ /* 2, \n3, ignore me ]*/ \n1 ]"); - ValidateJsonList("//header\n[ // 2, \n// 3, \n1 ]// footer"); - ValidateJsonList("/*\n[ // 2, \n// 3, \n1 ]*/[1]"); - ValidateJsonList("[ 1 /* one */ ] /* end */"); - ValidateJsonList("[ 1 //// ,2\r\n ]"); - - scoped_ptr root; - - // It's ok to have a comment in a string. - root.reset(JSONReader::Read("[\"// ok\\n /* foo */ \"]")); - ASSERT_TRUE(root.get() && root->IsType(Value::TYPE_LIST)); - ListValue* list = static_cast(root.get()); - ASSERT_EQ(1U, list->GetSize()); - Value* elt = NULL; - ASSERT_TRUE(list->Get(0, &elt)); - std::string value; - ASSERT_TRUE(elt && elt->GetAsString(&value)); - ASSERT_EQ("// ok\n /* foo */ ", value); - - // You can't nest comments. - root.reset(JSONReader::Read("/* /* inner */ outer */ [ 1 ]")); - ASSERT_FALSE(root.get()); - - // Not a open comment token. - root.reset(JSONReader::Read("/ * * / [1]")); - ASSERT_FALSE(root.get()); -} - -class JSONFileValueSerializerTest : public testing::Test { - protected: - virtual void SetUp() OVERRIDE { - ASSERT_TRUE(temp_dir_.CreateUniqueTempDir()); - } - - base::ScopedTempDir temp_dir_; -}; - -TEST_F(JSONFileValueSerializerTest, Roundtrip) { - base::FilePath original_file_path; - ASSERT_TRUE(PathService::Get(DIR_TEST_DATA, &original_file_path)); - original_file_path = - original_file_path.Append(FILE_PATH_LITERAL("serializer_test.json")); - - ASSERT_TRUE(PathExists(original_file_path)); - - JSONFileValueSerializer deserializer(original_file_path); - scoped_ptr root; - root.reset(deserializer.Deserialize(NULL, NULL)); - - ASSERT_TRUE(root.get()); - ASSERT_TRUE(root->IsType(Value::TYPE_DICTIONARY)); - - DictionaryValue* root_dict = static_cast(root.get()); - - Value* null_value = NULL; - ASSERT_TRUE(root_dict->Get("null", &null_value)); - ASSERT_TRUE(null_value); - ASSERT_TRUE(null_value->IsType(Value::TYPE_NULL)); - - bool bool_value = false; - ASSERT_TRUE(root_dict->GetBoolean("bool", &bool_value)); - ASSERT_TRUE(bool_value); - - int int_value = 0; - ASSERT_TRUE(root_dict->GetInteger("int", &int_value)); - ASSERT_EQ(42, int_value); - - std::string string_value; - ASSERT_TRUE(root_dict->GetString("string", &string_value)); - ASSERT_EQ("hello", string_value); - - // Now try writing. - const base::FilePath written_file_path = - temp_dir_.path().Append(FILE_PATH_LITERAL("test_output.js")); - - ASSERT_FALSE(PathExists(written_file_path)); - JSONFileValueSerializer serializer(written_file_path); - ASSERT_TRUE(serializer.Serialize(*root)); - ASSERT_TRUE(PathExists(written_file_path)); - - // Now compare file contents. - EXPECT_TRUE(TextContentsEqual(original_file_path, written_file_path)); - EXPECT_TRUE(base::DeleteFile(written_file_path, false)); -} - -TEST_F(JSONFileValueSerializerTest, RoundtripNested) { - base::FilePath original_file_path; - ASSERT_TRUE(PathService::Get(DIR_TEST_DATA, &original_file_path)); - original_file_path = original_file_path.Append( - FILE_PATH_LITERAL("serializer_nested_test.json")); - - ASSERT_TRUE(PathExists(original_file_path)); - - JSONFileValueSerializer deserializer(original_file_path); - scoped_ptr root; - root.reset(deserializer.Deserialize(NULL, NULL)); - ASSERT_TRUE(root.get()); - - // Now try writing. - base::FilePath written_file_path = temp_dir_.path().Append( - FILE_PATH_LITERAL("test_output.json")); - - ASSERT_FALSE(PathExists(written_file_path)); - JSONFileValueSerializer serializer(written_file_path); - ASSERT_TRUE(serializer.Serialize(*root)); - ASSERT_TRUE(PathExists(written_file_path)); - - // Now compare file contents. - EXPECT_TRUE(TextContentsEqual(original_file_path, written_file_path)); - EXPECT_TRUE(base::DeleteFile(written_file_path, false)); -} - -TEST_F(JSONFileValueSerializerTest, NoWhitespace) { - base::FilePath source_file_path; - ASSERT_TRUE(PathService::Get(DIR_TEST_DATA, &source_file_path)); - source_file_path = source_file_path.Append( - FILE_PATH_LITERAL("serializer_test_nowhitespace.json")); - ASSERT_TRUE(PathExists(source_file_path)); - JSONFileValueSerializer serializer(source_file_path); - scoped_ptr root; - root.reset(serializer.Deserialize(NULL, NULL)); - ASSERT_TRUE(root.get()); -} - -} // namespace - -} // namespace base diff --git a/base/json/json_writer.cc b/base/json/json_writer.cc deleted file mode 100644 index 6a9cc6aa47..0000000000 --- a/base/json/json_writer.cc +++ /dev/null @@ -1,233 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "base/json/json_writer.h" - -#include - -#include "base/json/string_escape.h" -#include "base/logging.h" -#include "base/strings/string_number_conversions.h" -#include "base/strings/stringprintf.h" -#include "base/strings/utf_string_conversions.h" -#include "base/values.h" - -namespace base { - -#if defined(OS_WIN) -static const char kPrettyPrintLineEnding[] = "\r\n"; -#else -static const char kPrettyPrintLineEnding[] = "\n"; -#endif - -/* static */ -const char* JSONWriter::kEmptyArray = "[]"; - -/* static */ -void JSONWriter::Write(const Value* const node, std::string* json) { - WriteWithOptions(node, 0, json); -} - -/* static */ -void JSONWriter::WriteWithOptions(const Value* const node, int options, - std::string* json) { - json->clear(); - // Is there a better way to estimate the size of the output? - json->reserve(1024); - - bool escape = !(options & OPTIONS_DO_NOT_ESCAPE); - bool omit_binary_values = !!(options & OPTIONS_OMIT_BINARY_VALUES); - bool omit_double_type_preservation = - !!(options & OPTIONS_OMIT_DOUBLE_TYPE_PRESERVATION); - bool pretty_print = !!(options & OPTIONS_PRETTY_PRINT); - - JSONWriter writer(escape, omit_binary_values, omit_double_type_preservation, - pretty_print, json); - writer.BuildJSONString(node, 0); - - if (pretty_print) - json->append(kPrettyPrintLineEnding); -} - -JSONWriter::JSONWriter(bool escape, bool omit_binary_values, - bool omit_double_type_preservation, bool pretty_print, - std::string* json) - : escape_(escape), - omit_binary_values_(omit_binary_values), - omit_double_type_preservation_(omit_double_type_preservation), - pretty_print_(pretty_print), - json_string_(json) { - DCHECK(json); -} - -void JSONWriter::BuildJSONString(const Value* const node, int depth) { - switch (node->GetType()) { - case Value::TYPE_NULL: - json_string_->append("null"); - break; - - case Value::TYPE_BOOLEAN: - { - bool value; - bool result = node->GetAsBoolean(&value); - DCHECK(result); - json_string_->append(value ? "true" : "false"); - break; - } - - case Value::TYPE_INTEGER: - { - int value; - bool result = node->GetAsInteger(&value); - DCHECK(result); - base::StringAppendF(json_string_, "%d", value); - break; - } - - case Value::TYPE_DOUBLE: - { - double value; - bool result = node->GetAsDouble(&value); - DCHECK(result); - if (omit_double_type_preservation_ && - value <= kint64max && - value >= kint64min && - std::floor(value) == value) { - json_string_->append(Int64ToString(static_cast(value))); - break; - } - std::string real = DoubleToString(value); - // Ensure that the number has a .0 if there's no decimal or 'e'. This - // makes sure that when we read the JSON back, it's interpreted as a - // real rather than an int. - if (real.find('.') == std::string::npos && - real.find('e') == std::string::npos && - real.find('E') == std::string::npos) { - real.append(".0"); - } - // The JSON spec requires that non-integer values in the range (-1,1) - // have a zero before the decimal point - ".52" is not valid, "0.52" is. - if (real[0] == '.') { - real.insert(0, "0"); - } else if (real.length() > 1 && real[0] == '-' && real[1] == '.') { - // "-.1" bad "-0.1" good - real.insert(1, "0"); - } - json_string_->append(real); - break; - } - - case Value::TYPE_STRING: - { - std::string value; - bool result = node->GetAsString(&value); - DCHECK(result); - if (escape_) { - JsonDoubleQuote(UTF8ToUTF16(value), true, json_string_); - } else { - JsonDoubleQuote(value, true, json_string_); - } - break; - } - - case Value::TYPE_LIST: - { - json_string_->append("["); - if (pretty_print_) - json_string_->append(" "); - - const ListValue* list = static_cast(node); - for (size_t i = 0; i < list->GetSize(); ++i) { - const Value* value = NULL; - bool result = list->Get(i, &value); - DCHECK(result); - - if (omit_binary_values_ && value->GetType() == Value::TYPE_BINARY) { - continue; - } - - if (i != 0) { - json_string_->append(","); - if (pretty_print_) - json_string_->append(" "); - } - - BuildJSONString(value, depth); - } - - if (pretty_print_) - json_string_->append(" "); - json_string_->append("]"); - break; - } - - case Value::TYPE_DICTIONARY: - { - json_string_->append("{"); - if (pretty_print_) - json_string_->append(kPrettyPrintLineEnding); - - const DictionaryValue* dict = - static_cast(node); - bool first_entry = true; - for (DictionaryValue::Iterator itr(*dict); !itr.IsAtEnd(); - itr.Advance(), first_entry = false) { - if (omit_binary_values_ && - itr.value().GetType() == Value::TYPE_BINARY) { - continue; - } - - if (!first_entry) { - json_string_->append(","); - if (pretty_print_) - json_string_->append(kPrettyPrintLineEnding); - } - - if (pretty_print_) - IndentLine(depth + 1); - AppendQuotedString(itr.key()); - if (pretty_print_) { - json_string_->append(": "); - } else { - json_string_->append(":"); - } - BuildJSONString(&itr.value(), depth + 1); - } - - if (pretty_print_) { - json_string_->append(kPrettyPrintLineEnding); - IndentLine(depth); - json_string_->append("}"); - } else { - json_string_->append("}"); - } - break; - } - - case Value::TYPE_BINARY: - { - if (!omit_binary_values_) { - NOTREACHED() << "Cannot serialize binary value."; - } - break; - } - - default: - NOTREACHED() << "unknown json type"; - } -} - -void JSONWriter::AppendQuotedString(const std::string& str) { - // TODO(viettrungluu): |str| is UTF-8, not ASCII, so to properly escape it we - // have to convert it to UTF-16. This round-trip is suboptimal. - JsonDoubleQuote(UTF8ToUTF16(str), true, json_string_); -} - -void JSONWriter::IndentLine(int depth) { - // It may be faster to keep an indent string so we don't have to keep - // reallocating. - json_string_->append(std::string(depth * 3, ' ')); -} - -} // namespace base diff --git a/base/json/json_writer.h b/base/json/json_writer.h deleted file mode 100644 index 94052c8034..0000000000 --- a/base/json/json_writer.h +++ /dev/null @@ -1,83 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef BASE_JSON_JSON_WRITER_H_ -#define BASE_JSON_JSON_WRITER_H_ - -#include - -#include "base/base_export.h" -#include "base/basictypes.h" - -namespace base { - -class Value; - -class BASE_EXPORT JSONWriter { - public: - enum Options { - // Do not escape the string, preserving its UTF8 characters. It is useful - // if you can pass the resulting string to the JSON parser in binary form - // (as UTF8). - OPTIONS_DO_NOT_ESCAPE = 1 << 0, - - // For values of binary type, the value (and key if within a dictionary) - // will be omitted from the output. - OPTIONS_OMIT_BINARY_VALUES = 1 << 1, - - // This option instructs the writer to write doubles that have no fractional - // part as a normal integer (i.e., without using exponential notation - // or appending a '.0') as long as the value is within the range of a - // 64-bit int. - OPTIONS_OMIT_DOUBLE_TYPE_PRESERVATION = 1 << 2, - - // Return a slightly nicer formatted json string (pads with whitespace to - // help with readability). - OPTIONS_PRETTY_PRINT = 1 << 3 - }; - - // Given a root node, generates a JSON string and puts it into |json|. - // TODO(tc): Should we generate json if it would be invalid json (e.g., - // |node| is not a DictionaryValue/ListValue or if there are inf/-inf float - // values)? - static void Write(const Value* const node, std::string* json); - - // Same as above but with |options| which is a bunch of JSONWriter::Options - // bitwise ORed together. - static void WriteWithOptions(const Value* const node, int options, - std::string* json); - - // A static, constant JSON string representing an empty array. Useful - // for empty JSON argument passing. - static const char* kEmptyArray; - - private: - JSONWriter(bool escape, bool omit_binary_values, - bool omit_double_type_preservation, bool pretty_print, - std::string* json); - - // Called recursively to build the JSON string. Whe completed, value is - // json_string_ will contain the JSON. - void BuildJSONString(const Value* const node, int depth); - - // Appends a quoted, escaped, version of (UTF-8) str to json_string_. - void AppendQuotedString(const std::string& str); - - // Adds space to json_string_ for the indent level. - void IndentLine(int depth); - - bool escape_; - bool omit_binary_values_; - bool omit_double_type_preservation_; - bool pretty_print_; - - // Where we write JSON data as we generate it. - std::string* json_string_; - - DISALLOW_COPY_AND_ASSIGN(JSONWriter); -}; - -} // namespace base - -#endif // BASE_JSON_JSON_WRITER_H_ diff --git a/base/json/json_writer_unittest.cc b/base/json/json_writer_unittest.cc deleted file mode 100644 index 7ddd7b462d..0000000000 --- a/base/json/json_writer_unittest.cc +++ /dev/null @@ -1,131 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "base/json/json_writer.h" -#include "base/values.h" -#include "testing/gtest/include/gtest/gtest.h" - -namespace base { - -TEST(JSONWriterTest, Writing) { - // Test null - Value* root = Value::CreateNullValue(); - std::string output_js; - JSONWriter::Write(root, &output_js); - ASSERT_EQ("null", output_js); - delete root; - - // Test empty dict - root = new DictionaryValue; - JSONWriter::Write(root, &output_js); - ASSERT_EQ("{}", output_js); - delete root; - - // Test empty list - root = new ListValue; - JSONWriter::Write(root, &output_js); - ASSERT_EQ("[]", output_js); - delete root; - - // Test Real values should always have a decimal or an 'e'. - root = new FundamentalValue(1.0); - JSONWriter::Write(root, &output_js); - ASSERT_EQ("1.0", output_js); - delete root; - - // Test Real values in the the range (-1, 1) must have leading zeros - root = new FundamentalValue(0.2); - JSONWriter::Write(root, &output_js); - ASSERT_EQ("0.2", output_js); - delete root; - - // Test Real values in the the range (-1, 1) must have leading zeros - root = new FundamentalValue(-0.8); - JSONWriter::Write(root, &output_js); - ASSERT_EQ("-0.8", output_js); - delete root; - - // Writer unittests like empty list/dict nesting, - // list list nesting, etc. - DictionaryValue root_dict; - ListValue* list = new ListValue; - root_dict.Set("list", list); - DictionaryValue* inner_dict = new DictionaryValue; - list->Append(inner_dict); - inner_dict->SetInteger("inner int", 10); - ListValue* inner_list = new ListValue; - list->Append(inner_list); - list->Append(new FundamentalValue(true)); - - // Test the pretty-printer. - JSONWriter::Write(&root_dict, &output_js); - ASSERT_EQ("{\"list\":[{\"inner int\":10},[],true]}", output_js); - JSONWriter::WriteWithOptions(&root_dict, JSONWriter::OPTIONS_PRETTY_PRINT, - &output_js); - // The pretty-printer uses a different newline style on Windows than on - // other platforms. -#if defined(OS_WIN) -#define JSON_NEWLINE "\r\n" -#else -#define JSON_NEWLINE "\n" -#endif - ASSERT_EQ("{" JSON_NEWLINE - " \"list\": [ {" JSON_NEWLINE - " \"inner int\": 10" JSON_NEWLINE - " }, [ ], true ]" JSON_NEWLINE - "}" JSON_NEWLINE, - output_js); -#undef JSON_NEWLINE - - // Test keys with periods - DictionaryValue period_dict; - period_dict.SetWithoutPathExpansion("a.b", new FundamentalValue(3)); - period_dict.SetWithoutPathExpansion("c", new FundamentalValue(2)); - DictionaryValue* period_dict2 = new DictionaryValue; - period_dict2->SetWithoutPathExpansion("g.h.i.j", new FundamentalValue(1)); - period_dict.SetWithoutPathExpansion("d.e.f", period_dict2); - JSONWriter::Write(&period_dict, &output_js); - ASSERT_EQ("{\"a.b\":3,\"c\":2,\"d.e.f\":{\"g.h.i.j\":1}}", output_js); - - DictionaryValue period_dict3; - period_dict3.Set("a.b", new FundamentalValue(2)); - period_dict3.SetWithoutPathExpansion("a.b", new FundamentalValue(1)); - JSONWriter::Write(&period_dict3, &output_js); - ASSERT_EQ("{\"a\":{\"b\":2},\"a.b\":1}", output_js); - - // Test omitting binary values. - root = BinaryValue::CreateWithCopiedBuffer("asdf", 4); - JSONWriter::WriteWithOptions(root, JSONWriter::OPTIONS_OMIT_BINARY_VALUES, - &output_js); - ASSERT_TRUE(output_js.empty()); - delete root; - - ListValue binary_list; - binary_list.Append(new FundamentalValue(5)); - binary_list.Append(BinaryValue::CreateWithCopiedBuffer("asdf", 4)); - binary_list.Append(new FundamentalValue(2)); - JSONWriter::WriteWithOptions(&binary_list, - JSONWriter::OPTIONS_OMIT_BINARY_VALUES, - &output_js); - ASSERT_EQ("[5,2]", output_js); - - DictionaryValue binary_dict; - binary_dict.Set("a", new FundamentalValue(5)); - binary_dict.Set("b", BinaryValue::CreateWithCopiedBuffer("asdf", 4)); - binary_dict.Set("c", new FundamentalValue(2)); - JSONWriter::WriteWithOptions(&binary_dict, - JSONWriter::OPTIONS_OMIT_BINARY_VALUES, - &output_js); - ASSERT_EQ("{\"a\":5,\"c\":2}", output_js); - - // Test allowing a double with no fractional part to be written as an integer. - FundamentalValue double_value(1e10); - JSONWriter::WriteWithOptions( - &double_value, - JSONWriter::OPTIONS_OMIT_DOUBLE_TYPE_PRESERVATION, - &output_js); - ASSERT_EQ("10000000000", output_js); -} - -} // namespace base diff --git a/base/json/string_escape.cc b/base/json/string_escape.cc deleted file mode 100644 index eaa73ce0a0..0000000000 --- a/base/json/string_escape.cc +++ /dev/null @@ -1,105 +0,0 @@ -// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "base/json/string_escape.h" - -#include - -#include "base/strings/string_util.h" -#include "base/strings/stringprintf.h" - -namespace base { - -namespace { - -// Try to escape |c| as a "SingleEscapeCharacter" (\n, etc). If successful, -// returns true and appends the escape sequence to |dst|. This isn't required -// by the spec, but it's more readable by humans than the \uXXXX alternatives. -template -static bool JsonSingleEscapeChar(const CHAR c, std::string* dst) { - // WARNING: if you add a new case here, you need to update the reader as well. - // Note: \v is in the reader, but not here since the JSON spec doesn't - // allow it. - switch (c) { - case '\b': - dst->append("\\b"); - break; - case '\f': - dst->append("\\f"); - break; - case '\n': - dst->append("\\n"); - break; - case '\r': - dst->append("\\r"); - break; - case '\t': - dst->append("\\t"); - break; - case '\\': - dst->append("\\\\"); - break; - case '"': - dst->append("\\\""); - break; - default: - return false; - } - return true; -} - -template -void JsonDoubleQuoteT(const STR& str, - bool put_in_quotes, - std::string* dst) { - if (put_in_quotes) - dst->push_back('"'); - - for (typename STR::const_iterator it = str.begin(); it != str.end(); ++it) { - typename ToUnsigned::Unsigned c = *it; - if (!JsonSingleEscapeChar(c, dst)) { - if (c < 32 || c > 126 || c == '<' || c == '>') { - // 1. Escaping <, > to prevent script execution. - // 2. Technically, we could also pass through c > 126 as UTF8, but this - // is also optional. It would also be a pain to implement here. - unsigned int as_uint = static_cast(c); - base::StringAppendF(dst, "\\u%04X", as_uint); - } else { - unsigned char ascii = static_cast(*it); - dst->push_back(ascii); - } - } - } - - if (put_in_quotes) - dst->push_back('"'); -} - -} // namespace - -void JsonDoubleQuote(const std::string& str, - bool put_in_quotes, - std::string* dst) { - JsonDoubleQuoteT(str, put_in_quotes, dst); -} - -std::string GetDoubleQuotedJson(const std::string& str) { - std::string dst; - JsonDoubleQuote(str, true, &dst); - return dst; -} - -void JsonDoubleQuote(const string16& str, - bool put_in_quotes, - std::string* dst) { - JsonDoubleQuoteT(str, put_in_quotes, dst); -} - -std::string GetDoubleQuotedJson(const string16& str) { - std::string dst; - JsonDoubleQuote(str, true, &dst); - return dst; -} - -} // namespace base diff --git a/base/json/string_escape.h b/base/json/string_escape.h deleted file mode 100644 index 5efc350dea..0000000000 --- a/base/json/string_escape.h +++ /dev/null @@ -1,38 +0,0 @@ -// Copyright (c) 2011 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. -// -// This file defines utility functions for escaping strings. - -#ifndef BASE_JSON_STRING_ESCAPE_H_ -#define BASE_JSON_STRING_ESCAPE_H_ - -#include - -#include "base/base_export.h" -#include "base/strings/string16.h" - -namespace base { - -// Escape |str| appropriately for a JSON string literal, _appending_ the -// result to |dst|. This will create unicode escape sequences (\uXXXX). -// If |put_in_quotes| is true, the result will be surrounded in double quotes. -// The outputted literal, when interpreted by the browser, should result in a -// javascript string that is identical and the same length as the input |str|. -BASE_EXPORT void JsonDoubleQuote(const std::string& str, - bool put_in_quotes, - std::string* dst); - -// Same as above, but always returns the result double quoted. -BASE_EXPORT std::string GetDoubleQuotedJson(const std::string& str); - -BASE_EXPORT void JsonDoubleQuote(const string16& str, - bool put_in_quotes, - std::string* dst); - -// Same as above, but always returns the result double quoted. -BASE_EXPORT std::string GetDoubleQuotedJson(const string16& str); - -} // namespace base - -#endif // BASE_JSON_STRING_ESCAPE_H_ diff --git a/base/json/string_escape_unittest.cc b/base/json/string_escape_unittest.cc deleted file mode 100644 index 8952ee76d2..0000000000 --- a/base/json/string_escape_unittest.cc +++ /dev/null @@ -1,100 +0,0 @@ -// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "base/json/string_escape.h" -#include "base/strings/utf_string_conversions.h" -#include "testing/gtest/include/gtest/gtest.h" - -namespace base { - -namespace { - -const struct json_narrow_test_data { - const char* to_escape; - const char* escaped; -} json_narrow_cases[] = { - {"\b\001aZ\"\\wee", "\\b\\u0001aZ\\\"\\\\wee"}, - {"a\b\f\n\r\t\v\1\\.\"z", - "a\\b\\f\\n\\r\\t\\u000B\\u0001\\\\.\\\"z"}, - {"b\x0f\x7f\xf0\xff!", "b\\u000F\\u007F\\u00F0\\u00FF!"}, - {"c<>d", "c\\u003C\\u003Ed"}, -}; - -} // namespace - -TEST(StringEscapeTest, JsonDoubleQuoteNarrow) { - for (size_t i = 0; i < arraysize(json_narrow_cases); ++i) { - std::string in = json_narrow_cases[i].to_escape; - std::string out; - JsonDoubleQuote(in, false, &out); - EXPECT_EQ(std::string(json_narrow_cases[i].escaped), out); - } - - std::string in = json_narrow_cases[0].to_escape; - std::string out; - JsonDoubleQuote(in, false, &out); - - // test quoting - std::string out_quoted; - JsonDoubleQuote(in, true, &out_quoted); - EXPECT_EQ(out.length() + 2, out_quoted.length()); - EXPECT_EQ(out_quoted.find(out), 1U); - - // now try with a NULL in the string - std::string null_prepend = "test"; - null_prepend.push_back(0); - in = null_prepend + in; - std::string expected = "test\\u0000"; - expected += json_narrow_cases[0].escaped; - out.clear(); - JsonDoubleQuote(in, false, &out); - EXPECT_EQ(expected, out); -} - -namespace { - -const struct json_wide_test_data { - const wchar_t* to_escape; - const char* escaped; -} json_wide_cases[] = { - {L"b\uffb1\u00ff", "b\\uFFB1\\u00FF"}, - {L"\b\001aZ\"\\wee", "\\b\\u0001aZ\\\"\\\\wee"}, - {L"a\b\f\n\r\t\v\1\\.\"z", - "a\\b\\f\\n\\r\\t\\u000B\\u0001\\\\.\\\"z"}, - {L"b\x0f\x7f\xf0\xff!", "b\\u000F\\u007F\\u00F0\\u00FF!"}, - {L"c<>d", "c\\u003C\\u003Ed"}, -}; - -} // namespace - -TEST(StringEscapeTest, JsonDoubleQuoteWide) { - for (size_t i = 0; i < arraysize(json_wide_cases); ++i) { - std::string out; - string16 in = WideToUTF16(json_wide_cases[i].to_escape); - JsonDoubleQuote(in, false, &out); - EXPECT_EQ(std::string(json_wide_cases[i].escaped), out); - } - - string16 in = WideToUTF16(json_wide_cases[0].to_escape); - std::string out; - JsonDoubleQuote(in, false, &out); - - // test quoting - std::string out_quoted; - JsonDoubleQuote(in, true, &out_quoted); - EXPECT_EQ(out.length() + 2, out_quoted.length()); - EXPECT_EQ(out_quoted.find(out), 1U); - - // now try with a NULL in the string - string16 null_prepend = WideToUTF16(L"test"); - null_prepend.push_back(0); - in = null_prepend + in; - std::string expected = "test\\u0000"; - expected += json_wide_cases[0].escaped; - out.clear(); - JsonDoubleQuote(in, false, &out); - EXPECT_EQ(expected, out); -} - -} // namespace base diff --git a/base/lazy_instance.cc b/base/lazy_instance.cc deleted file mode 100644 index a81cb8c2d0..0000000000 --- a/base/lazy_instance.cc +++ /dev/null @@ -1,59 +0,0 @@ -// Copyright (c) 2011 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "base/lazy_instance.h" - -#include "base/at_exit.h" -#include "base/atomicops.h" -#include "base/basictypes.h" -#include "base/threading/platform_thread.h" -#include "base/third_party/dynamic_annotations/dynamic_annotations.h" - -namespace base { -namespace internal { - -// TODO(joth): This function could be shared with Singleton, in place of its -// WaitForInstance() call. -bool NeedsLazyInstance(subtle::AtomicWord* state) { - // Try to create the instance, if we're the first, will go from 0 to - // kLazyInstanceStateCreating, otherwise we've already been beaten here. - // The memory access has no memory ordering as state 0 and - // kLazyInstanceStateCreating have no associated data (memory barriers are - // all about ordering of memory accesses to *associated* data). - if (subtle::NoBarrier_CompareAndSwap(state, 0, - kLazyInstanceStateCreating) == 0) - // Caller must create instance - return true; - - // It's either in the process of being created, or already created. Spin. - // The load has acquire memory ordering as a thread which sees - // state_ == STATE_CREATED needs to acquire visibility over - // the associated data (buf_). Pairing Release_Store is in - // CompleteLazyInstance(). - while (subtle::Acquire_Load(state) == kLazyInstanceStateCreating) { - PlatformThread::YieldCurrentThread(); - } - // Someone else created the instance. - return false; -} - -void CompleteLazyInstance(subtle::AtomicWord* state, - subtle::AtomicWord new_instance, - void* lazy_instance, - void (*dtor)(void*)) { - // See the comment to the corresponding HAPPENS_AFTER in Pointer(). - ANNOTATE_HAPPENS_BEFORE(state); - - // Instance is created, go from CREATING to CREATED. - // Releases visibility over private_buf_ to readers. Pairing Acquire_Load's - // are in NeedsInstance() and Pointer(). - subtle::Release_Store(state, new_instance); - - // Make sure that the lazily instantiated object will get destroyed at exit. - if (dtor) - AtExitManager::RegisterCallback(dtor, lazy_instance); -} - -} // namespace internal -} // namespace base diff --git a/base/lazy_instance.h b/base/lazy_instance.h deleted file mode 100644 index 3935780a55..0000000000 --- a/base/lazy_instance.h +++ /dev/null @@ -1,212 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -// The LazyInstance class manages a single instance of Type, -// which will be lazily created on the first time it's accessed. This class is -// useful for places you would normally use a function-level static, but you -// need to have guaranteed thread-safety. The Type constructor will only ever -// be called once, even if two threads are racing to create the object. Get() -// and Pointer() will always return the same, completely initialized instance. -// When the instance is constructed it is registered with AtExitManager. The -// destructor will be called on program exit. -// -// LazyInstance is completely thread safe, assuming that you create it safely. -// The class was designed to be POD initialized, so it shouldn't require a -// static constructor. It really only makes sense to declare a LazyInstance as -// a global variable using the LAZY_INSTANCE_INITIALIZER initializer. -// -// LazyInstance is similar to Singleton, except it does not have the singleton -// property. You can have multiple LazyInstance's of the same type, and each -// will manage a unique instance. It also preallocates the space for Type, as -// to avoid allocating the Type instance on the heap. This may help with the -// performance of creating the instance, and reducing heap fragmentation. This -// requires that Type be a complete type so we can determine the size. -// -// Example usage: -// static LazyInstance my_instance = LAZY_INSTANCE_INITIALIZER; -// void SomeMethod() { -// my_instance.Get().SomeMethod(); // MyClass::SomeMethod() -// -// MyClass* ptr = my_instance.Pointer(); -// ptr->DoDoDo(); // MyClass::DoDoDo -// } - -#ifndef BASE_LAZY_INSTANCE_H_ -#define BASE_LAZY_INSTANCE_H_ - -#include // For placement new. - -#include "base/atomicops.h" -#include "base/base_export.h" -#include "base/basictypes.h" -#include "base/debug/leak_annotations.h" -#include "base/logging.h" -#include "base/memory/aligned_memory.h" -#include "base/third_party/dynamic_annotations/dynamic_annotations.h" -#include "base/threading/thread_restrictions.h" - -// LazyInstance uses its own struct initializer-list style static -// initialization, as base's LINKER_INITIALIZED requires a constructor and on -// some compilers (notably gcc 4.4) this still ends up needing runtime -// initialization. -#define LAZY_INSTANCE_INITIALIZER {0} - -namespace base { - -template -struct DefaultLazyInstanceTraits { - static const bool kRegisterOnExit = true; - static const bool kAllowedToAccessOnNonjoinableThread = false; - - static Type* New(void* instance) { - DCHECK_EQ(reinterpret_cast(instance) & (ALIGNOF(Type) - 1), 0u) - << ": Bad boy, the buffer passed to placement new is not aligned!\n" - "This may break some stuff like SSE-based optimizations assuming the " - " objects are word aligned."; - // Use placement new to initialize our instance in our preallocated space. - // The parenthesis is very important here to force POD type initialization. - return new (instance) Type(); - } - static void Delete(Type* instance) { - // Explicitly call the destructor. - instance->~Type(); - } -}; - -// We pull out some of the functionality into non-templated functions, so we -// can implement the more complicated pieces out of line in the .cc file. -namespace internal { - -// Use LazyInstance::Leaky for a less-verbose call-site typedef; e.g.: -// base::LazyInstance::Leaky my_leaky_lazy_instance; -// instead of: -// base::LazyInstance > -// my_leaky_lazy_instance; -// (especially when T is MyLongTypeNameImplClientHolderFactory). -// Only use this internal::-qualified verbose form to extend this traits class -// (depending on its implementation details). -template -struct LeakyLazyInstanceTraits { - static const bool kRegisterOnExit = false; - static const bool kAllowedToAccessOnNonjoinableThread = true; - - static Type* New(void* instance) { - ANNOTATE_SCOPED_MEMORY_LEAK; - return DefaultLazyInstanceTraits::New(instance); - } - static void Delete(Type* instance) { - } -}; - -// Our AtomicWord doubles as a spinlock, where a value of -// kBeingCreatedMarker means the spinlock is being held for creation. -static const subtle::AtomicWord kLazyInstanceStateCreating = 1; - -// Check if instance needs to be created. If so return true otherwise -// if another thread has beat us, wait for instance to be created and -// return false. -BASE_EXPORT bool NeedsLazyInstance(subtle::AtomicWord* state); - -// After creating an instance, call this to register the dtor to be called -// at program exit and to update the atomic state to hold the |new_instance| -BASE_EXPORT void CompleteLazyInstance(subtle::AtomicWord* state, - subtle::AtomicWord new_instance, - void* lazy_instance, - void (*dtor)(void*)); - -} // namespace internal - -template > -class LazyInstance { - public: - // Do not define a destructor, as doing so makes LazyInstance a - // non-POD-struct. We don't want that because then a static initializer will - // be created to register the (empty) destructor with atexit() under MSVC, for - // example. We handle destruction of the contained Type class explicitly via - // the OnExit member function, where needed. - // ~LazyInstance() {} - - // Convenience typedef to avoid having to repeat Type for leaky lazy - // instances. - typedef LazyInstance > Leaky; - - Type& Get() { - return *Pointer(); - } - - Type* Pointer() { -#ifndef NDEBUG - // Avoid making TLS lookup on release builds. - if (!Traits::kAllowedToAccessOnNonjoinableThread) - ThreadRestrictions::AssertSingletonAllowed(); -#endif - // If any bit in the created mask is true, the instance has already been - // fully constructed. - static const subtle::AtomicWord kLazyInstanceCreatedMask = - ~internal::kLazyInstanceStateCreating; - - // We will hopefully have fast access when the instance is already created. - // Since a thread sees private_instance_ == 0 or kLazyInstanceStateCreating - // at most once, the load is taken out of NeedsInstance() as a fast-path. - // The load has acquire memory ordering as a thread which sees - // private_instance_ > creating needs to acquire visibility over - // the associated data (private_buf_). Pairing Release_Store is in - // CompleteLazyInstance(). - subtle::AtomicWord value = subtle::Acquire_Load(&private_instance_); - if (!(value & kLazyInstanceCreatedMask) && - internal::NeedsLazyInstance(&private_instance_)) { - // Create the instance in the space provided by |private_buf_|. - value = reinterpret_cast( - Traits::New(private_buf_.void_data())); - internal::CompleteLazyInstance(&private_instance_, value, this, - Traits::kRegisterOnExit ? OnExit : NULL); - } - - // This annotation helps race detectors recognize correct lock-less - // synchronization between different threads calling Pointer(). - // We suggest dynamic race detection tool that "Traits::New" above - // and CompleteLazyInstance(...) happens before "return instance()" below. - // See the corresponding HAPPENS_BEFORE in CompleteLazyInstance(...). - ANNOTATE_HAPPENS_AFTER(&private_instance_); - return instance(); - } - - bool operator==(Type* p) { - switch (subtle::NoBarrier_Load(&private_instance_)) { - case 0: - return p == NULL; - case internal::kLazyInstanceStateCreating: - return static_cast(p) == private_buf_.void_data(); - default: - return p == instance(); - } - } - - // Effectively private: member data is only public to allow the linker to - // statically initialize it and to maintain a POD class. DO NOT USE FROM - // OUTSIDE THIS CLASS. - - subtle::AtomicWord private_instance_; - // Preallocated space for the Type instance. - base::AlignedMemory private_buf_; - - private: - Type* instance() { - return reinterpret_cast(subtle::NoBarrier_Load(&private_instance_)); - } - - // Adapter function for use with AtExit. This should be called single - // threaded, so don't synchronize across threads. - // Calling OnExit while the instance is in use by other threads is a mistake. - static void OnExit(void* lazy_instance) { - LazyInstance* me = - reinterpret_cast*>(lazy_instance); - Traits::Delete(me->instance()); - subtle::NoBarrier_Store(&me->private_instance_, 0); - } -}; - -} // namespace base - -#endif // BASE_LAZY_INSTANCE_H_ diff --git a/base/lazy_instance_unittest.cc b/base/lazy_instance_unittest.cc deleted file mode 100644 index e25366e228..0000000000 --- a/base/lazy_instance_unittest.cc +++ /dev/null @@ -1,172 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "base/at_exit.h" -#include "base/atomic_sequence_num.h" -#include "base/lazy_instance.h" -#include "base/memory/aligned_memory.h" -#include "base/threading/simple_thread.h" -#include "testing/gtest/include/gtest/gtest.h" - -namespace { - -base::StaticAtomicSequenceNumber constructed_seq_; -base::StaticAtomicSequenceNumber destructed_seq_; - -class ConstructAndDestructLogger { - public: - ConstructAndDestructLogger() { - constructed_seq_.GetNext(); - } - ~ConstructAndDestructLogger() { - destructed_seq_.GetNext(); - } -}; - -class SlowConstructor { - public: - SlowConstructor() : some_int_(0) { - // Sleep for 1 second to try to cause a race. - base::PlatformThread::Sleep(base::TimeDelta::FromSeconds(1)); - ++constructed; - some_int_ = 12; - } - int some_int() const { return some_int_; } - - static int constructed; - private: - int some_int_; -}; - -int SlowConstructor::constructed = 0; - -class SlowDelegate : public base::DelegateSimpleThread::Delegate { - public: - explicit SlowDelegate(base::LazyInstance* lazy) - : lazy_(lazy) {} - - virtual void Run() OVERRIDE { - EXPECT_EQ(12, lazy_->Get().some_int()); - EXPECT_EQ(12, lazy_->Pointer()->some_int()); - } - - private: - base::LazyInstance* lazy_; -}; - -} // namespace - -static base::LazyInstance lazy_logger = - LAZY_INSTANCE_INITIALIZER; - -TEST(LazyInstanceTest, Basic) { - { - base::ShadowingAtExitManager shadow; - - EXPECT_EQ(0, constructed_seq_.GetNext()); - EXPECT_EQ(0, destructed_seq_.GetNext()); - - lazy_logger.Get(); - EXPECT_EQ(2, constructed_seq_.GetNext()); - EXPECT_EQ(1, destructed_seq_.GetNext()); - - lazy_logger.Pointer(); - EXPECT_EQ(3, constructed_seq_.GetNext()); - EXPECT_EQ(2, destructed_seq_.GetNext()); - } - EXPECT_EQ(4, constructed_seq_.GetNext()); - EXPECT_EQ(4, destructed_seq_.GetNext()); -} - -static base::LazyInstance lazy_slow = - LAZY_INSTANCE_INITIALIZER; - -TEST(LazyInstanceTest, ConstructorThreadSafety) { - { - base::ShadowingAtExitManager shadow; - - SlowDelegate delegate(&lazy_slow); - EXPECT_EQ(0, SlowConstructor::constructed); - - base::DelegateSimpleThreadPool pool("lazy_instance_cons", 5); - pool.AddWork(&delegate, 20); - EXPECT_EQ(0, SlowConstructor::constructed); - - pool.Start(); - pool.JoinAll(); - EXPECT_EQ(1, SlowConstructor::constructed); - } -} - -namespace { - -// DeleteLogger is an object which sets a flag when it's destroyed. -// It accepts a bool* and sets the bool to true when the dtor runs. -class DeleteLogger { - public: - DeleteLogger() : deleted_(NULL) {} - ~DeleteLogger() { *deleted_ = true; } - - void SetDeletedPtr(bool* deleted) { - deleted_ = deleted; - } - - private: - bool* deleted_; -}; - -} // anonymous namespace - -TEST(LazyInstanceTest, LeakyLazyInstance) { - // Check that using a plain LazyInstance causes the dtor to run - // when the AtExitManager finishes. - bool deleted1 = false; - { - base::ShadowingAtExitManager shadow; - static base::LazyInstance test = LAZY_INSTANCE_INITIALIZER; - test.Get().SetDeletedPtr(&deleted1); - } - EXPECT_TRUE(deleted1); - - // Check that using a *leaky* LazyInstance makes the dtor not run - // when the AtExitManager finishes. - bool deleted2 = false; - { - base::ShadowingAtExitManager shadow; - static base::LazyInstance::Leaky - test = LAZY_INSTANCE_INITIALIZER; - test.Get().SetDeletedPtr(&deleted2); - } - EXPECT_FALSE(deleted2); -} - -namespace { - -template -class AlignedData { - public: - AlignedData() {} - ~AlignedData() {} - base::AlignedMemory data_; -}; - -} // anonymous namespace - -#define EXPECT_ALIGNED(ptr, align) \ - EXPECT_EQ(0u, reinterpret_cast(ptr) & (align - 1)) - -TEST(LazyInstanceTest, Alignment) { - using base::LazyInstance; - - // Create some static instances with increasing sizes and alignment - // requirements. By ordering this way, the linker will need to do some work to - // ensure proper alignment of the static data. - static LazyInstance > align4 = LAZY_INSTANCE_INITIALIZER; - static LazyInstance > align32 = LAZY_INSTANCE_INITIALIZER; - static LazyInstance > align4096 = LAZY_INSTANCE_INITIALIZER; - - EXPECT_ALIGNED(align4.Pointer(), 4); - EXPECT_ALIGNED(align32.Pointer(), 32); - EXPECT_ALIGNED(align4096.Pointer(), 4096); -} diff --git a/base/linux_util.cc b/base/linux_util.cc deleted file mode 100644 index 5f9ecd43ab..0000000000 --- a/base/linux_util.cc +++ /dev/null @@ -1,304 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "base/linux_util.h" - -#include -#include -#include -#include -#include -#include -#include - -#include - -#include "base/command_line.h" -#include "base/file_util.h" -#include "base/memory/scoped_ptr.h" -#include "base/memory/singleton.h" -#include "base/path_service.h" -#include "base/process/launch.h" -#include "base/strings/string_util.h" -#include "base/synchronization/lock.h" - -namespace { - -// Not needed for OS_CHROMEOS. -#if defined(OS_LINUX) -enum LinuxDistroState { - STATE_DID_NOT_CHECK = 0, - STATE_CHECK_STARTED = 1, - STATE_CHECK_FINISHED = 2, -}; - -// Helper class for GetLinuxDistro(). -class LinuxDistroHelper { - public: - // Retrieves the Singleton. - static LinuxDistroHelper* GetInstance() { - return Singleton::get(); - } - - // The simple state machine goes from: - // STATE_DID_NOT_CHECK -> STATE_CHECK_STARTED -> STATE_CHECK_FINISHED. - LinuxDistroHelper() : state_(STATE_DID_NOT_CHECK) {} - ~LinuxDistroHelper() {} - - // Retrieve the current state, if we're in STATE_DID_NOT_CHECK, - // we automatically move to STATE_CHECK_STARTED so nobody else will - // do the check. - LinuxDistroState State() { - base::AutoLock scoped_lock(lock_); - if (STATE_DID_NOT_CHECK == state_) { - state_ = STATE_CHECK_STARTED; - return STATE_DID_NOT_CHECK; - } - return state_; - } - - // Indicate the check finished, move to STATE_CHECK_FINISHED. - void CheckFinished() { - base::AutoLock scoped_lock(lock_); - DCHECK_EQ(STATE_CHECK_STARTED, state_); - state_ = STATE_CHECK_FINISHED; - } - - private: - base::Lock lock_; - LinuxDistroState state_; -}; -#endif // if defined(OS_LINUX) - -// expected prefix of the target of the /proc/self/fd/%d link for a socket -const char kSocketLinkPrefix[] = "socket:["; - -// Parse a symlink in /proc/pid/fd/$x and return the inode number of the -// socket. -// inode_out: (output) set to the inode number on success -// path: e.g. /proc/1234/fd/5 (must be a UNIX domain socket descriptor) -// log: if true, log messages about failure details -bool ProcPathGetInode(ino_t* inode_out, const char* path, bool log = false) { - DCHECK(inode_out); - DCHECK(path); - - char buf[256]; - const ssize_t n = readlink(path, buf, sizeof(buf) - 1); - if (n == -1) { - if (log) { - DLOG(WARNING) << "Failed to read the inode number for a socket from /proc" - "(" << errno << ")"; - } - return false; - } - buf[n] = 0; - - if (memcmp(kSocketLinkPrefix, buf, sizeof(kSocketLinkPrefix) - 1)) { - if (log) { - DLOG(WARNING) << "The descriptor passed from the crashing process wasn't " - " a UNIX domain socket."; - } - return false; - } - - char* endptr; - const unsigned long long int inode_ul = - strtoull(buf + sizeof(kSocketLinkPrefix) - 1, &endptr, 10); - if (*endptr != ']') - return false; - - if (inode_ul == ULLONG_MAX) { - if (log) { - DLOG(WARNING) << "Failed to parse a socket's inode number: the number " - "was too large. Please report this bug: " << buf; - } - return false; - } - - *inode_out = inode_ul; - return true; -} - -} // namespace - -namespace base { - -const char kFindInodeSwitch[] = "--find-inode"; - -// Account for the terminating null character. -static const int kDistroSize = 128 + 1; - -// We use this static string to hold the Linux distro info. If we -// crash, the crash handler code will send this in the crash dump. -char g_linux_distro[kDistroSize] = -#if defined(OS_CHROMEOS) - "CrOS"; -#elif defined(OS_ANDROID) - "Android"; -#else // if defined(OS_LINUX) - "Unknown"; -#endif - -std::string GetLinuxDistro() { -#if defined(OS_CHROMEOS) || defined(OS_ANDROID) - return g_linux_distro; -#elif defined(OS_LINUX) - LinuxDistroHelper* distro_state_singleton = LinuxDistroHelper::GetInstance(); - LinuxDistroState state = distro_state_singleton->State(); - if (STATE_CHECK_FINISHED == state) - return g_linux_distro; - if (STATE_CHECK_STARTED == state) - return "Unknown"; // Don't wait for other thread to finish. - DCHECK_EQ(state, STATE_DID_NOT_CHECK); - // We do this check only once per process. If it fails, there's - // little reason to believe it will work if we attempt to run - // lsb_release again. - std::vector argv; - argv.push_back("lsb_release"); - argv.push_back("-d"); - std::string output; - base::GetAppOutput(CommandLine(argv), &output); - if (output.length() > 0) { - // lsb_release -d should return: Description:Distro Info - const char field[] = "Description:\t"; - if (output.compare(0, strlen(field), field) == 0) { - SetLinuxDistro(output.substr(strlen(field))); - } - } - distro_state_singleton->CheckFinished(); - return g_linux_distro; -#else - NOTIMPLEMENTED(); - return "Unknown"; -#endif -} - -void SetLinuxDistro(const std::string& distro) { - std::string trimmed_distro; - TrimWhitespaceASCII(distro, TRIM_ALL, &trimmed_distro); - base::strlcpy(g_linux_distro, trimmed_distro.c_str(), kDistroSize); -} - -bool FileDescriptorGetInode(ino_t* inode_out, int fd) { - DCHECK(inode_out); - - struct stat buf; - if (fstat(fd, &buf) < 0) - return false; - - if (!S_ISSOCK(buf.st_mode)) - return false; - - *inode_out = buf.st_ino; - return true; -} - -bool FindProcessHoldingSocket(pid_t* pid_out, ino_t socket_inode) { - DCHECK(pid_out); - bool already_found = false; - - DIR* proc = opendir("/proc"); - if (!proc) { - DLOG(WARNING) << "Cannot open /proc"; - return false; - } - - std::vector pids; - - struct dirent* dent; - while ((dent = readdir(proc))) { - char* endptr; - const unsigned long int pid_ul = strtoul(dent->d_name, &endptr, 10); - if (pid_ul == ULONG_MAX || *endptr) - continue; - pids.push_back(pid_ul); - } - closedir(proc); - - for (std::vector::const_iterator - i = pids.begin(); i != pids.end(); ++i) { - const pid_t current_pid = *i; - char buf[256]; - snprintf(buf, sizeof(buf), "/proc/%d/fd", current_pid); - DIR* fd = opendir(buf); - if (!fd) - continue; - - while ((dent = readdir(fd))) { - if (snprintf(buf, sizeof(buf), "/proc/%d/fd/%s", current_pid, - dent->d_name) >= static_cast(sizeof(buf))) { - continue; - } - - ino_t fd_inode = static_cast(-1); - if (ProcPathGetInode(&fd_inode, buf)) { - if (fd_inode == socket_inode) { - if (already_found) { - closedir(fd); - return false; - } - - already_found = true; - *pid_out = current_pid; - break; - } - } - } - - closedir(fd); - } - - return already_found; -} - -pid_t FindThreadIDWithSyscall(pid_t pid, const std::string& expected_data, - bool* syscall_supported) { - char buf[256]; - snprintf(buf, sizeof(buf), "/proc/%d/task", pid); - - if (syscall_supported != NULL) - *syscall_supported = false; - - DIR* task = opendir(buf); - if (!task) { - DLOG(WARNING) << "Cannot open " << buf; - return -1; - } - - std::vector tids; - struct dirent* dent; - while ((dent = readdir(task))) { - char* endptr; - const unsigned long int tid_ul = strtoul(dent->d_name, &endptr, 10); - if (tid_ul == ULONG_MAX || *endptr) - continue; - tids.push_back(tid_ul); - } - closedir(task); - - scoped_ptr syscall_data(new char[expected_data.length()]); - for (std::vector::const_iterator - i = tids.begin(); i != tids.end(); ++i) { - const pid_t current_tid = *i; - snprintf(buf, sizeof(buf), "/proc/%d/task/%d/syscall", pid, current_tid); - int fd = open(buf, O_RDONLY); - if (fd < 0) - continue; - if (syscall_supported != NULL) - *syscall_supported = true; - bool read_ret = - file_util::ReadFromFD(fd, syscall_data.get(), expected_data.length()); - close(fd); - if (!read_ret) - continue; - - if (0 == strncmp(expected_data.c_str(), syscall_data.get(), - expected_data.length())) { - return current_tid; - } - } - return -1; -} - -} // namespace base diff --git a/base/linux_util.h b/base/linux_util.h deleted file mode 100644 index b9ba56dfc9..0000000000 --- a/base/linux_util.h +++ /dev/null @@ -1,47 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef BASE_LINUX_UTIL_H_ -#define BASE_LINUX_UTIL_H_ - -#include -#include - -#include - -#include "base/base_export.h" - -namespace base { - -BASE_EXPORT extern const char kFindInodeSwitch[]; - -// This is declared here so the crash reporter can access the memory directly -// in compromised context without going through the standard library. -BASE_EXPORT extern char g_linux_distro[]; - -// Get the Linux Distro if we can, or return "Unknown". -BASE_EXPORT std::string GetLinuxDistro(); - -// Set the Linux Distro string. -BASE_EXPORT void SetLinuxDistro(const std::string& distro); - -// Return the inode number for the UNIX domain socket |fd|. -BASE_EXPORT bool FileDescriptorGetInode(ino_t* inode_out, int fd); - -// Find the process which holds the given socket, named by inode number. If -// multiple processes hold the socket, this function returns false. -BASE_EXPORT bool FindProcessHoldingSocket(pid_t* pid_out, ino_t socket_inode); - -// For a given process |pid|, look through all its threads and find the first -// thread with /proc/[pid]/task/[thread_id]/syscall whose first N bytes matches -// |expected_data|, where N is the length of |expected_data|. -// Returns the thread id or -1 on error. If |syscall_supported| is -// set to false the kernel does not support syscall in procfs. -BASE_EXPORT pid_t FindThreadIDWithSyscall(pid_t pid, - const std::string& expected_data, - bool* syscall_supported); - -} // namespace base - -#endif // BASE_LINUX_UTIL_H_ diff --git a/base/location.cc b/base/location.cc deleted file mode 100644 index b5da027ee8..0000000000 --- a/base/location.cc +++ /dev/null @@ -1,102 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "build/build_config.h" - -#if defined(COMPILER_MSVC) -// MSDN says to #include , but that breaks the VS2005 build. -extern "C" { - void* _ReturnAddress(); -} -#endif - -#include "base/location.h" -#include "base/strings/string_number_conversions.h" -#include "base/strings/stringprintf.h" - -namespace tracked_objects { - -Location::Location(const char* function_name, - const char* file_name, - int line_number, - const void* program_counter) - : function_name_(function_name), - file_name_(file_name), - line_number_(line_number), - program_counter_(program_counter) { -} - -Location::Location() - : function_name_("Unknown"), - file_name_("Unknown"), - line_number_(-1), - program_counter_(NULL) { -} - -std::string Location::ToString() const { - return std::string(function_name_) + "@" + file_name_ + ":" + - base::IntToString(line_number_); -} - -void Location::Write(bool display_filename, bool display_function_name, - std::string* output) const { - base::StringAppendF(output, "%s[%d] ", - display_filename ? file_name_ : "line", - line_number_); - - if (display_function_name) { - WriteFunctionName(output); - output->push_back(' '); - } -} - -void Location::WriteFunctionName(std::string* output) const { - // Translate "<" to "<" for HTML safety. - // TODO(jar): Support ASCII or html for logging in ASCII. - for (const char *p = function_name_; *p; p++) { - switch (*p) { - case '<': - output->append("<"); - break; - - case '>': - output->append(">"); - break; - - default: - output->push_back(*p); - break; - } - } -} - -//------------------------------------------------------------------------------ -LocationSnapshot::LocationSnapshot() : line_number(-1) { -} - -LocationSnapshot::LocationSnapshot( - const tracked_objects::Location& location) - : file_name(location.file_name()), - function_name(location.function_name()), - line_number(location.line_number()) { -} - -LocationSnapshot::~LocationSnapshot() { -} - -//------------------------------------------------------------------------------ -#if defined(COMPILER_MSVC) -__declspec(noinline) -#endif -BASE_EXPORT const void* GetProgramCounter() { -#if defined(COMPILER_MSVC) - return _ReturnAddress(); -#elif defined(COMPILER_GCC) - return __builtin_extract_return_addr(__builtin_return_address(0)); -#endif // COMPILER_GCC - - return NULL; -} - -} // namespace tracked_objects diff --git a/base/location.h b/base/location.h deleted file mode 100644 index 05a4f66109..0000000000 --- a/base/location.h +++ /dev/null @@ -1,94 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef BASE_LOCATION_H_ -#define BASE_LOCATION_H_ - -#include - -#include "base/base_export.h" -#include "base/basictypes.h" - -namespace tracked_objects { - -// Location provides basic info where of an object was constructed, or was -// significantly brought to life. -class BASE_EXPORT Location { - public: - // Constructor should be called with a long-lived char*, such as __FILE__. - // It assumes the provided value will persist as a global constant, and it - // will not make a copy of it. - Location(const char* function_name, - const char* file_name, - int line_number, - const void* program_counter); - - // Provide a default constructor for easy of debugging. - Location(); - - // Comparison operator for insertion into a std::map<> hash tables. - // All we need is *some* (any) hashing distinction. Strings should already - // be unique, so we don't bother with strcmp or such. - // Use line number as the primary key (because it is fast, and usually gets us - // a difference), and then pointers as secondary keys (just to get some - // distinctions). - bool operator < (const Location& other) const { - if (line_number_ != other.line_number_) - return line_number_ < other.line_number_; - if (file_name_ != other.file_name_) - return file_name_ < other.file_name_; - return function_name_ < other.function_name_; - } - - const char* function_name() const { return function_name_; } - const char* file_name() const { return file_name_; } - int line_number() const { return line_number_; } - const void* program_counter() const { return program_counter_; } - - std::string ToString() const; - - // Translate the some of the state in this instance into a human readable - // string with HTML characters in the function names escaped, and append that - // string to |output|. Inclusion of the file_name_ and function_name_ are - // optional, and controlled by the boolean arguments. - void Write(bool display_filename, bool display_function_name, - std::string* output) const; - - // Write function_name_ in HTML with '<' and '>' properly encoded. - void WriteFunctionName(std::string* output) const; - - private: - const char* function_name_; - const char* file_name_; - int line_number_; - const void* program_counter_; -}; - -// A "snapshotted" representation of the Location class that can safely be -// passed across process boundaries. -struct BASE_EXPORT LocationSnapshot { - // The default constructor is exposed to support the IPC serialization macros. - LocationSnapshot(); - explicit LocationSnapshot(const tracked_objects::Location& location); - ~LocationSnapshot(); - - std::string file_name; - std::string function_name; - int line_number; -}; - -BASE_EXPORT const void* GetProgramCounter(); - -// Define a macro to record the current source location. -#define FROM_HERE FROM_HERE_WITH_EXPLICIT_FUNCTION(__FUNCTION__) - -#define FROM_HERE_WITH_EXPLICIT_FUNCTION(function_name) \ - ::tracked_objects::Location(function_name, \ - __FILE__, \ - __LINE__, \ - ::tracked_objects::GetProgramCounter()) - -} // namespace tracked_objects - -#endif // BASE_LOCATION_H_ diff --git a/base/logging.cc b/base/logging.cc deleted file mode 100644 index e836092e76..0000000000 --- a/base/logging.cc +++ /dev/null @@ -1,866 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "base/logging.h" - -#if defined(OS_WIN) -#include -#include -typedef HANDLE FileHandle; -typedef HANDLE MutexHandle; -// Windows warns on using write(). It prefers _write(). -#define write(fd, buf, count) _write(fd, buf, static_cast(count)) -// Windows doesn't define STDERR_FILENO. Define it here. -#define STDERR_FILENO 2 -#elif defined(OS_MACOSX) -#include -#include -#include -#elif defined(OS_POSIX) -#if defined(OS_NACL) -#include // timespec doesn't seem to be in -#else -#include -#endif -#include -#endif - -#if defined(OS_POSIX) -#include -#include -#include -#include -#include -#include -#define MAX_PATH PATH_MAX -typedef FILE* FileHandle; -typedef pthread_mutex_t* MutexHandle; -#endif - -#include -#include -#include -#include -#include - -#include "base/base_switches.h" -#include "base/command_line.h" -#include "base/debug/alias.h" -#include "base/debug/debugger.h" -#include "base/debug/stack_trace.h" -#include "base/posix/eintr_wrapper.h" -#include "base/strings/string_piece.h" -#include "base/strings/utf_string_conversions.h" -#include "base/synchronization/lock_impl.h" -#include "base/threading/platform_thread.h" -#include "base/vlog.h" -#if defined(OS_POSIX) -#include "base/safe_strerror_posix.h" -#endif - -#if defined(OS_ANDROID) -#include -#endif - -namespace logging { - -DcheckState g_dcheck_state = DISABLE_DCHECK_FOR_NON_OFFICIAL_RELEASE_BUILDS; - -DcheckState get_dcheck_state() { - return g_dcheck_state; -} - -void set_dcheck_state(DcheckState state) { - g_dcheck_state = state; -} - -namespace { - -VlogInfo* g_vlog_info = NULL; -VlogInfo* g_vlog_info_prev = NULL; - -const char* const log_severity_names[LOG_NUM_SEVERITIES] = { - "INFO", "WARNING", "ERROR", "ERROR_REPORT", "FATAL" }; - -int min_log_level = 0; - -LoggingDestination logging_destination = LOG_DEFAULT; - -// For LOG_ERROR and above, always print to stderr. -const int kAlwaysPrintErrorLevel = LOG_ERROR; - -// Which log file to use? This is initialized by InitLogging or -// will be lazily initialized to the default value when it is -// first needed. -#if defined(OS_WIN) -typedef std::wstring PathString; -#else -typedef std::string PathString; -#endif -PathString* log_file_name = NULL; - -// this file is lazily opened and the handle may be NULL -FileHandle log_file = NULL; - -// what should be prepended to each message? -bool log_process_id = false; -bool log_thread_id = false; -bool log_timestamp = true; -bool log_tickcount = false; - -// Should we pop up fatal debug messages in a dialog? -bool show_error_dialogs = false; - -// An assert handler override specified by the client to be called instead of -// the debug message dialog and process termination. -LogAssertHandlerFunction log_assert_handler = NULL; -// An report handler override specified by the client to be called instead of -// the debug message dialog. -LogReportHandlerFunction log_report_handler = NULL; -// A log message handler that gets notified of every log message we process. -LogMessageHandlerFunction log_message_handler = NULL; - -// Helper functions to wrap platform differences. - -int32 CurrentProcessId() { -#if defined(OS_WIN) - return GetCurrentProcessId(); -#elif defined(OS_POSIX) - return getpid(); -#endif -} - -uint64 TickCount() { -#if defined(OS_WIN) - return GetTickCount(); -#elif defined(OS_MACOSX) - return mach_absolute_time(); -#elif defined(OS_NACL) - // NaCl sadly does not have _POSIX_TIMERS enabled in sys/features.h - // So we have to use clock() for now. - return clock(); -#elif defined(OS_POSIX) - struct timespec ts; - clock_gettime(CLOCK_MONOTONIC, &ts); - - uint64 absolute_micro = - static_cast(ts.tv_sec) * 1000000 + - static_cast(ts.tv_nsec) / 1000; - - return absolute_micro; -#endif -} - -void DeleteFilePath(const PathString& log_name) { -#if defined(OS_WIN) - DeleteFile(log_name.c_str()); -#elif defined (OS_NACL) - // Do nothing; unlink() isn't supported on NaCl. -#else - unlink(log_name.c_str()); -#endif -} - -PathString GetDefaultLogFile() { -#if defined(OS_WIN) - // On Windows we use the same path as the exe. - wchar_t module_name[MAX_PATH]; - GetModuleFileName(NULL, module_name, MAX_PATH); - - PathString log_file = module_name; - PathString::size_type last_backslash = - log_file.rfind('\\', log_file.size()); - if (last_backslash != PathString::npos) - log_file.erase(last_backslash + 1); - log_file += L"debug.log"; - return log_file; -#elif defined(OS_POSIX) - // On other platforms we just use the current directory. - return PathString("debug.log"); -#endif -} - -// This class acts as a wrapper for locking the logging files. -// LoggingLock::Init() should be called from the main thread before any logging -// is done. Then whenever logging, be sure to have a local LoggingLock -// instance on the stack. This will ensure that the lock is unlocked upon -// exiting the frame. -// LoggingLocks can not be nested. -class LoggingLock { - public: - LoggingLock() { - LockLogging(); - } - - ~LoggingLock() { - UnlockLogging(); - } - - static void Init(LogLockingState lock_log, const PathChar* new_log_file) { - if (initialized) - return; - lock_log_file = lock_log; - if (lock_log_file == LOCK_LOG_FILE) { -#if defined(OS_WIN) - if (!log_mutex) { - std::wstring safe_name; - if (new_log_file) - safe_name = new_log_file; - else - safe_name = GetDefaultLogFile(); - // \ is not a legal character in mutex names so we replace \ with / - std::replace(safe_name.begin(), safe_name.end(), '\\', '/'); - std::wstring t(L"Global\\"); - t.append(safe_name); - log_mutex = ::CreateMutex(NULL, FALSE, t.c_str()); - - if (log_mutex == NULL) { -#if DEBUG - // Keep the error code for debugging - int error = GetLastError(); // NOLINT - base::debug::BreakDebugger(); -#endif - // Return nicely without putting initialized to true. - return; - } - } -#endif - } else { - log_lock = new base::internal::LockImpl(); - } - initialized = true; - } - - private: - static void LockLogging() { - if (lock_log_file == LOCK_LOG_FILE) { -#if defined(OS_WIN) - ::WaitForSingleObject(log_mutex, INFINITE); - // WaitForSingleObject could have returned WAIT_ABANDONED. We don't - // abort the process here. UI tests might be crashy sometimes, - // and aborting the test binary only makes the problem worse. - // We also don't use LOG macros because that might lead to an infinite - // loop. For more info see http://crbug.com/18028. -#elif defined(OS_POSIX) - pthread_mutex_lock(&log_mutex); -#endif - } else { - // use the lock - log_lock->Lock(); - } - } - - static void UnlockLogging() { - if (lock_log_file == LOCK_LOG_FILE) { -#if defined(OS_WIN) - ReleaseMutex(log_mutex); -#elif defined(OS_POSIX) - pthread_mutex_unlock(&log_mutex); -#endif - } else { - log_lock->Unlock(); - } - } - - // The lock is used if log file locking is false. It helps us avoid problems - // with multiple threads writing to the log file at the same time. Use - // LockImpl directly instead of using Lock, because Lock makes logging calls. - static base::internal::LockImpl* log_lock; - - // When we don't use a lock, we are using a global mutex. We need to do this - // because LockFileEx is not thread safe. -#if defined(OS_WIN) - static MutexHandle log_mutex; -#elif defined(OS_POSIX) - static pthread_mutex_t log_mutex; -#endif - - static bool initialized; - static LogLockingState lock_log_file; -}; - -// static -bool LoggingLock::initialized = false; -// static -base::internal::LockImpl* LoggingLock::log_lock = NULL; -// static -LogLockingState LoggingLock::lock_log_file = LOCK_LOG_FILE; - -#if defined(OS_WIN) -// static -MutexHandle LoggingLock::log_mutex = NULL; -#elif defined(OS_POSIX) -pthread_mutex_t LoggingLock::log_mutex = PTHREAD_MUTEX_INITIALIZER; -#endif - -// Called by logging functions to ensure that debug_file is initialized -// and can be used for writing. Returns false if the file could not be -// initialized. debug_file will be NULL in this case. -bool InitializeLogFileHandle() { - if (log_file) - return true; - - if (!log_file_name) { - // Nobody has called InitLogging to specify a debug log file, so here we - // initialize the log file name to a default. - log_file_name = new PathString(GetDefaultLogFile()); - } - - if ((logging_destination & LOG_TO_FILE) != 0) { -#if defined(OS_WIN) - log_file = CreateFile(log_file_name->c_str(), GENERIC_WRITE, - FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, - OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); - if (log_file == INVALID_HANDLE_VALUE || log_file == NULL) { - // try the current directory - log_file = CreateFile(L".\\debug.log", GENERIC_WRITE, - FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, - OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); - if (log_file == INVALID_HANDLE_VALUE || log_file == NULL) { - log_file = NULL; - return false; - } - } - SetFilePointer(log_file, 0, 0, FILE_END); -#elif defined(OS_POSIX) - log_file = fopen(log_file_name->c_str(), "a"); - if (log_file == NULL) - return false; -#endif - } - - return true; -} - -void CloseFile(FileHandle log) { -#if defined(OS_WIN) - CloseHandle(log); -#else - fclose(log); -#endif -} - -void CloseLogFileUnlocked() { - if (!log_file) - return; - - CloseFile(log_file); - log_file = NULL; -} - -} // namespace - -LoggingSettings::LoggingSettings() - : logging_dest(LOG_DEFAULT), - log_file(NULL), - lock_log(LOCK_LOG_FILE), - delete_old(APPEND_TO_OLD_LOG_FILE), - dcheck_state(DISABLE_DCHECK_FOR_NON_OFFICIAL_RELEASE_BUILDS) {} - -bool BaseInitLoggingImpl(const LoggingSettings& settings) { -#if defined(OS_NACL) - // Can log only to the system debug log. - CHECK_EQ(settings.logging_dest & ~LOG_TO_SYSTEM_DEBUG_LOG, 0); -#endif - g_dcheck_state = settings.dcheck_state; - CommandLine* command_line = CommandLine::ForCurrentProcess(); - // Don't bother initializing g_vlog_info unless we use one of the - // vlog switches. - if (command_line->HasSwitch(switches::kV) || - command_line->HasSwitch(switches::kVModule)) { - // NOTE: If g_vlog_info has already been initialized, it might be in use - // by another thread. Don't delete the old VLogInfo, just create a second - // one. We keep track of both to avoid memory leak warnings. - CHECK(!g_vlog_info_prev); - g_vlog_info_prev = g_vlog_info; - - g_vlog_info = - new VlogInfo(command_line->GetSwitchValueASCII(switches::kV), - command_line->GetSwitchValueASCII(switches::kVModule), - &min_log_level); - } - - logging_destination = settings.logging_dest; - - // ignore file options unless logging to file is set. - if ((logging_destination & LOG_TO_FILE) == 0) - return true; - - LoggingLock::Init(settings.lock_log, settings.log_file); - LoggingLock logging_lock; - - // Calling InitLogging twice or after some log call has already opened the - // default log file will re-initialize to the new options. - CloseLogFileUnlocked(); - - if (!log_file_name) - log_file_name = new PathString(); - *log_file_name = settings.log_file; - if (settings.delete_old == DELETE_OLD_LOG_FILE) - DeleteFilePath(*log_file_name); - - return InitializeLogFileHandle(); -} - -void SetMinLogLevel(int level) { - min_log_level = std::min(LOG_ERROR_REPORT, level); -} - -int GetMinLogLevel() { - return min_log_level; -} - -int GetVlogVerbosity() { - return std::max(-1, LOG_INFO - GetMinLogLevel()); -} - -int GetVlogLevelHelper(const char* file, size_t N) { - DCHECK_GT(N, 0U); - // Note: g_vlog_info may change on a different thread during startup - // (but will always be valid or NULL). - VlogInfo* vlog_info = g_vlog_info; - return vlog_info ? - vlog_info->GetVlogLevel(base::StringPiece(file, N - 1)) : - GetVlogVerbosity(); -} - -void SetLogItems(bool enable_process_id, bool enable_thread_id, - bool enable_timestamp, bool enable_tickcount) { - log_process_id = enable_process_id; - log_thread_id = enable_thread_id; - log_timestamp = enable_timestamp; - log_tickcount = enable_tickcount; -} - -void SetShowErrorDialogs(bool enable_dialogs) { - show_error_dialogs = enable_dialogs; -} - -void SetLogAssertHandler(LogAssertHandlerFunction handler) { - log_assert_handler = handler; -} - -void SetLogReportHandler(LogReportHandlerFunction handler) { - log_report_handler = handler; -} - -void SetLogMessageHandler(LogMessageHandlerFunction handler) { - log_message_handler = handler; -} - -LogMessageHandlerFunction GetLogMessageHandler() { - return log_message_handler; -} - -// MSVC doesn't like complex extern templates and DLLs. -#if !defined(COMPILER_MSVC) -// Explicit instantiations for commonly used comparisons. -template std::string* MakeCheckOpString( - const int&, const int&, const char* names); -template std::string* MakeCheckOpString( - const unsigned long&, const unsigned long&, const char* names); -template std::string* MakeCheckOpString( - const unsigned long&, const unsigned int&, const char* names); -template std::string* MakeCheckOpString( - const unsigned int&, const unsigned long&, const char* names); -template std::string* MakeCheckOpString( - const std::string&, const std::string&, const char* name); -#endif - -// Displays a message box to the user with the error message in it. -// Used for fatal messages, where we close the app simultaneously. -// This is for developers only; we don't use this in circumstances -// (like release builds) where users could see it, since users don't -// understand these messages anyway. -void DisplayDebugMessageInDialog(const std::string& str) { - if (str.empty()) - return; - - if (!show_error_dialogs) - return; - -#if defined(OS_WIN) - // For Windows programs, it's possible that the message loop is - // messed up on a fatal error, and creating a MessageBox will cause - // that message loop to be run. Instead, we try to spawn another - // process that displays its command line. We look for "Debug - // Message.exe" in the same directory as the application. If it - // exists, we use it, otherwise, we use a regular message box. - wchar_t prog_name[MAX_PATH]; - GetModuleFileNameW(NULL, prog_name, MAX_PATH); - wchar_t* backslash = wcsrchr(prog_name, '\\'); - if (backslash) - backslash[1] = 0; - wcscat_s(prog_name, MAX_PATH, L"debug_message.exe"); - - std::wstring cmdline = UTF8ToWide(str); - if (cmdline.empty()) - return; - - STARTUPINFO startup_info; - memset(&startup_info, 0, sizeof(startup_info)); - startup_info.cb = sizeof(startup_info); - - PROCESS_INFORMATION process_info; - if (CreateProcessW(prog_name, &cmdline[0], NULL, NULL, false, 0, NULL, - NULL, &startup_info, &process_info)) { - WaitForSingleObject(process_info.hProcess, INFINITE); - CloseHandle(process_info.hThread); - CloseHandle(process_info.hProcess); - } else { - // debug process broken, let's just do a message box - MessageBoxW(NULL, &cmdline[0], L"Fatal error", - MB_OK | MB_ICONHAND | MB_TOPMOST); - } -#else - // We intentionally don't implement a dialog on other platforms. - // You can just look at stderr. -#endif -} - -#if defined(OS_WIN) -LogMessage::SaveLastError::SaveLastError() : last_error_(::GetLastError()) { -} - -LogMessage::SaveLastError::~SaveLastError() { - ::SetLastError(last_error_); -} -#endif // defined(OS_WIN) - -LogMessage::LogMessage(const char* file, int line, LogSeverity severity, - int ctr) - : severity_(severity), file_(file), line_(line) { - Init(file, line); -} - -LogMessage::LogMessage(const char* file, int line) - : severity_(LOG_INFO), file_(file), line_(line) { - Init(file, line); -} - -LogMessage::LogMessage(const char* file, int line, LogSeverity severity) - : severity_(severity), file_(file), line_(line) { - Init(file, line); -} - -LogMessage::LogMessage(const char* file, int line, std::string* result) - : severity_(LOG_FATAL), file_(file), line_(line) { - Init(file, line); - stream_ << "Check failed: " << *result; - delete result; -} - -LogMessage::LogMessage(const char* file, int line, LogSeverity severity, - std::string* result) - : severity_(severity), file_(file), line_(line) { - Init(file, line); - stream_ << "Check failed: " << *result; - delete result; -} - -LogMessage::~LogMessage() { -#if !defined(NDEBUG) && !defined(OS_NACL) - if (severity_ == LOG_FATAL) { - // Include a stack trace on a fatal. - base::debug::StackTrace trace; - stream_ << std::endl; // Newline to separate from log message. - trace.OutputToStream(&stream_); - } -#endif - stream_ << std::endl; - std::string str_newline(stream_.str()); - - // Give any log message handler first dibs on the message. - if (log_message_handler && - log_message_handler(severity_, file_, line_, - message_start_, str_newline)) { - // The handler took care of it, no further processing. - return; - } - - if ((logging_destination & LOG_TO_SYSTEM_DEBUG_LOG) != 0) { -#if defined(OS_WIN) - OutputDebugStringA(str_newline.c_str()); -#elif defined(OS_ANDROID) - android_LogPriority priority = - (severity_ < 0) ? ANDROID_LOG_VERBOSE : ANDROID_LOG_UNKNOWN; - switch (severity_) { - case LOG_INFO: - priority = ANDROID_LOG_INFO; - break; - case LOG_WARNING: - priority = ANDROID_LOG_WARN; - break; - case LOG_ERROR: - case LOG_ERROR_REPORT: - priority = ANDROID_LOG_ERROR; - break; - case LOG_FATAL: - priority = ANDROID_LOG_FATAL; - break; - } - __android_log_write(priority, "chromium", str_newline.c_str()); -#endif - fprintf(stderr, "%s", str_newline.c_str()); - fflush(stderr); - } else if (severity_ >= kAlwaysPrintErrorLevel) { - // When we're only outputting to a log file, above a certain log level, we - // should still output to stderr so that we can better detect and diagnose - // problems with unit tests, especially on the buildbots. - fprintf(stderr, "%s", str_newline.c_str()); - fflush(stderr); - } - - // write to log file - if ((logging_destination & LOG_TO_FILE) != 0) { - // We can have multiple threads and/or processes, so try to prevent them - // from clobbering each other's writes. - // If the client app did not call InitLogging, and the lock has not - // been created do it now. We do this on demand, but if two threads try - // to do this at the same time, there will be a race condition to create - // the lock. This is why InitLogging should be called from the main - // thread at the beginning of execution. - LoggingLock::Init(LOCK_LOG_FILE, NULL); - LoggingLock logging_lock; - if (InitializeLogFileHandle()) { -#if defined(OS_WIN) - SetFilePointer(log_file, 0, 0, SEEK_END); - DWORD num_written; - WriteFile(log_file, - static_cast(str_newline.c_str()), - static_cast(str_newline.length()), - &num_written, - NULL); -#else - fprintf(log_file, "%s", str_newline.c_str()); - fflush(log_file); -#endif - } - } - - if (severity_ == LOG_FATAL) { - // Ensure the first characters of the string are on the stack so they - // are contained in minidumps for diagnostic purposes. - char str_stack[1024]; - str_newline.copy(str_stack, arraysize(str_stack)); - base::debug::Alias(str_stack); - - // display a message or break into the debugger on a fatal error - if (base::debug::BeingDebugged()) { - base::debug::BreakDebugger(); - } else { - if (log_assert_handler) { - // make a copy of the string for the handler out of paranoia - log_assert_handler(std::string(stream_.str())); - } else { - // Don't use the string with the newline, get a fresh version to send to - // the debug message process. We also don't display assertions to the - // user in release mode. The enduser can't do anything with this - // information, and displaying message boxes when the application is - // hosed can cause additional problems. -#ifndef NDEBUG - DisplayDebugMessageInDialog(stream_.str()); -#endif - // Crash the process to generate a dump. - base::debug::BreakDebugger(); - } - } - } else if (severity_ == LOG_ERROR_REPORT) { - // We are here only if the user runs with --enable-dcheck in release mode. - if (log_report_handler) { - log_report_handler(std::string(stream_.str())); - } else { - DisplayDebugMessageInDialog(stream_.str()); - } - } -} - -// writes the common header info to the stream -void LogMessage::Init(const char* file, int line) { - base::StringPiece filename(file); - size_t last_slash_pos = filename.find_last_of("\\/"); - if (last_slash_pos != base::StringPiece::npos) - filename.remove_prefix(last_slash_pos + 1); - - // TODO(darin): It might be nice if the columns were fixed width. - - stream_ << '['; - if (log_process_id) - stream_ << CurrentProcessId() << ':'; - if (log_thread_id) - stream_ << base::PlatformThread::CurrentId() << ':'; - if (log_timestamp) { - time_t t = time(NULL); - struct tm local_time = {0}; -#if _MSC_VER >= 1400 - localtime_s(&local_time, &t); -#else - localtime_r(&t, &local_time); -#endif - struct tm* tm_time = &local_time; - stream_ << std::setfill('0') - << std::setw(2) << 1 + tm_time->tm_mon - << std::setw(2) << tm_time->tm_mday - << '/' - << std::setw(2) << tm_time->tm_hour - << std::setw(2) << tm_time->tm_min - << std::setw(2) << tm_time->tm_sec - << ':'; - } - if (log_tickcount) - stream_ << TickCount() << ':'; - if (severity_ >= 0) - stream_ << log_severity_names[severity_]; - else - stream_ << "VERBOSE" << -severity_; - - stream_ << ":" << filename << "(" << line << ")] "; - - message_start_ = stream_.tellp(); -} - -#if defined(OS_WIN) -// This has already been defined in the header, but defining it again as DWORD -// ensures that the type used in the header is equivalent to DWORD. If not, -// the redefinition is a compile error. -typedef DWORD SystemErrorCode; -#endif - -SystemErrorCode GetLastSystemErrorCode() { -#if defined(OS_WIN) - return ::GetLastError(); -#elif defined(OS_POSIX) - return errno; -#else -#error Not implemented -#endif -} - -#if defined(OS_WIN) -Win32ErrorLogMessage::Win32ErrorLogMessage(const char* file, - int line, - LogSeverity severity, - SystemErrorCode err, - const char* module) - : err_(err), - module_(module), - log_message_(file, line, severity) { -} - -Win32ErrorLogMessage::Win32ErrorLogMessage(const char* file, - int line, - LogSeverity severity, - SystemErrorCode err) - : err_(err), - module_(NULL), - log_message_(file, line, severity) { -} - -Win32ErrorLogMessage::~Win32ErrorLogMessage() { - const int error_message_buffer_size = 256; - char msgbuf[error_message_buffer_size]; - DWORD flags = FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS; - HMODULE hmod; - if (module_) { - hmod = GetModuleHandleA(module_); - if (hmod) { - flags |= FORMAT_MESSAGE_FROM_HMODULE; - } else { - // This makes a nested Win32ErrorLogMessage. It will have module_ of NULL - // so it will not call GetModuleHandle, so recursive errors are - // impossible. - DPLOG(WARNING) << "Couldn't open module " << module_ - << " for error message query"; - } - } else { - hmod = NULL; - } - DWORD len = FormatMessageA(flags, - hmod, - err_, - 0, - msgbuf, - sizeof(msgbuf) / sizeof(msgbuf[0]), - NULL); - if (len) { - while ((len > 0) && - isspace(static_cast(msgbuf[len - 1]))) { - msgbuf[--len] = 0; - } - stream() << ": " << msgbuf; - } else { - stream() << ": Error " << GetLastError() << " while retrieving error " - << err_; - } - // We're about to crash (CHECK). Put |err_| on the stack (by placing it in a - // field) and use Alias in hopes that it makes it into crash dumps. - DWORD last_error = err_; - base::debug::Alias(&last_error); -} -#elif defined(OS_POSIX) -ErrnoLogMessage::ErrnoLogMessage(const char* file, - int line, - LogSeverity severity, - SystemErrorCode err) - : err_(err), - log_message_(file, line, severity) { -} - -ErrnoLogMessage::~ErrnoLogMessage() { - stream() << ": " << safe_strerror(err_); -} -#endif // OS_WIN - -void CloseLogFile() { - LoggingLock logging_lock; - CloseLogFileUnlocked(); -} - -void RawLog(int level, const char* message) { - if (level >= min_log_level) { - size_t bytes_written = 0; - const size_t message_len = strlen(message); - int rv; - while (bytes_written < message_len) { - rv = HANDLE_EINTR( - write(STDERR_FILENO, message + bytes_written, - message_len - bytes_written)); - if (rv < 0) { - // Give up, nothing we can do now. - break; - } - bytes_written += rv; - } - - if (message_len > 0 && message[message_len - 1] != '\n') { - do { - rv = HANDLE_EINTR(write(STDERR_FILENO, "\n", 1)); - if (rv < 0) { - // Give up, nothing we can do now. - break; - } - } while (rv != 1); - } - } - - if (level == LOG_FATAL) - base::debug::BreakDebugger(); -} - -// This was defined at the beginning of this file. -#undef write - -#if defined(OS_WIN) -std::wstring GetLogFileFullPath() { - if (log_file_name) - return *log_file_name; - return std::wstring(); -} -#endif - -} // namespace logging - -std::ostream& operator<<(std::ostream& out, const wchar_t* wstr) { - return out << WideToUTF8(std::wstring(wstr)); -} diff --git a/base/logging.h b/base/logging.h deleted file mode 100644 index 859f2602fc..0000000000 --- a/base/logging.h +++ /dev/null @@ -1,1022 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef BASE_LOGGING_H_ -#define BASE_LOGGING_H_ - -#include -#include -#include -#include - -#include "base/base_export.h" -#include "base/basictypes.h" -#include "base/debug/debugger.h" -#include "build/build_config.h" - -// -// Optional message capabilities -// ----------------------------- -// Assertion failed messages and fatal errors are displayed in a dialog box -// before the application exits. However, running this UI creates a message -// loop, which causes application messages to be processed and potentially -// dispatched to existing application windows. Since the application is in a -// bad state when this assertion dialog is displayed, these messages may not -// get processed and hang the dialog, or the application might go crazy. -// -// Therefore, it can be beneficial to display the error dialog in a separate -// process from the main application. When the logging system needs to display -// a fatal error dialog box, it will look for a program called -// "DebugMessage.exe" in the same directory as the application executable. It -// will run this application with the message as the command line, and will -// not include the name of the application as is traditional for easier -// parsing. -// -// The code for DebugMessage.exe is only one line. In WinMain, do: -// MessageBox(NULL, GetCommandLineW(), L"Fatal Error", 0); -// -// If DebugMessage.exe is not found, the logging code will use a normal -// MessageBox, potentially causing the problems discussed above. - - -// Instructions -// ------------ -// -// Make a bunch of macros for logging. The way to log things is to stream -// things to LOG(). E.g., -// -// LOG(INFO) << "Found " << num_cookies << " cookies"; -// -// You can also do conditional logging: -// -// LOG_IF(INFO, num_cookies > 10) << "Got lots of cookies"; -// -// The above will cause log messages to be output on the 1st, 11th, 21st, ... -// times it is executed. Note that the special COUNTER value is used to -// identify which repetition is happening. -// -// The CHECK(condition) macro is active in both debug and release builds and -// effectively performs a LOG(FATAL) which terminates the process and -// generates a crashdump unless a debugger is attached. -// -// There are also "debug mode" logging macros like the ones above: -// -// DLOG(INFO) << "Found cookies"; -// -// DLOG_IF(INFO, num_cookies > 10) << "Got lots of cookies"; -// -// All "debug mode" logging is compiled away to nothing for non-debug mode -// compiles. LOG_IF and development flags also work well together -// because the code can be compiled away sometimes. -// -// We also have -// -// LOG_ASSERT(assertion); -// DLOG_ASSERT(assertion); -// -// which is syntactic sugar for {,D}LOG_IF(FATAL, assert fails) << assertion; -// -// There are "verbose level" logging macros. They look like -// -// VLOG(1) << "I'm printed when you run the program with --v=1 or more"; -// VLOG(2) << "I'm printed when you run the program with --v=2 or more"; -// -// These always log at the INFO log level (when they log at all). -// The verbose logging can also be turned on module-by-module. For instance, -// --vmodule=profile=2,icon_loader=1,browser_*=3,*/chromeos/*=4 --v=0 -// will cause: -// a. VLOG(2) and lower messages to be printed from profile.{h,cc} -// b. VLOG(1) and lower messages to be printed from icon_loader.{h,cc} -// c. VLOG(3) and lower messages to be printed from files prefixed with -// "browser" -// d. VLOG(4) and lower messages to be printed from files under a -// "chromeos" directory. -// e. VLOG(0) and lower messages to be printed from elsewhere -// -// The wildcarding functionality shown by (c) supports both '*' (match -// 0 or more characters) and '?' (match any single character) -// wildcards. Any pattern containing a forward or backward slash will -// be tested against the whole pathname and not just the module. -// E.g., "*/foo/bar/*=2" would change the logging level for all code -// in source files under a "foo/bar" directory. -// -// There's also VLOG_IS_ON(n) "verbose level" condition macro. To be used as -// -// if (VLOG_IS_ON(2)) { -// // do some logging preparation and logging -// // that can't be accomplished with just VLOG(2) << ...; -// } -// -// There is also a VLOG_IF "verbose level" condition macro for sample -// cases, when some extra computation and preparation for logs is not -// needed. -// -// VLOG_IF(1, (size > 1024)) -// << "I'm printed when size is more than 1024 and when you run the " -// "program with --v=1 or more"; -// -// We also override the standard 'assert' to use 'DLOG_ASSERT'. -// -// Lastly, there is: -// -// PLOG(ERROR) << "Couldn't do foo"; -// DPLOG(ERROR) << "Couldn't do foo"; -// PLOG_IF(ERROR, cond) << "Couldn't do foo"; -// DPLOG_IF(ERROR, cond) << "Couldn't do foo"; -// PCHECK(condition) << "Couldn't do foo"; -// DPCHECK(condition) << "Couldn't do foo"; -// -// which append the last system error to the message in string form (taken from -// GetLastError() on Windows and errno on POSIX). -// -// The supported severity levels for macros that allow you to specify one -// are (in increasing order of severity) INFO, WARNING, ERROR, ERROR_REPORT, -// and FATAL. -// -// Very important: logging a message at the FATAL severity level causes -// the program to terminate (after the message is logged). -// -// Note the special severity of ERROR_REPORT only available/relevant in normal -// mode, which displays error dialog without terminating the program. There is -// no error dialog for severity ERROR or below in normal mode. -// -// There is also the special severity of DFATAL, which logs FATAL in -// debug mode, ERROR in normal mode. - -namespace logging { - -// TODO(avi): do we want to do a unification of character types here? -#if defined(OS_WIN) -typedef wchar_t PathChar; -#else -typedef char PathChar; -#endif - -// Where to record logging output? A flat file and/or system debug log -// via OutputDebugString. -enum LoggingDestination { - LOG_NONE = 0, - LOG_TO_FILE = 1 << 0, - LOG_TO_SYSTEM_DEBUG_LOG = 1 << 1, - - LOG_TO_ALL = LOG_TO_FILE | LOG_TO_SYSTEM_DEBUG_LOG, - - // On Windows, use a file next to the exe; on POSIX platforms, where - // it may not even be possible to locate the executable on disk, use - // stderr. -#if defined(OS_WIN) - LOG_DEFAULT = LOG_TO_FILE, -#elif defined(OS_POSIX) - LOG_DEFAULT = LOG_TO_SYSTEM_DEBUG_LOG, -#endif -}; - -// Indicates that the log file should be locked when being written to. -// Unless there is only one single-threaded process that is logging to -// the log file, the file should be locked during writes to make each -// log outut atomic. Other writers will block. -// -// All processes writing to the log file must have their locking set for it to -// work properly. Defaults to LOCK_LOG_FILE. -enum LogLockingState { LOCK_LOG_FILE, DONT_LOCK_LOG_FILE }; - -// On startup, should we delete or append to an existing log file (if any)? -// Defaults to APPEND_TO_OLD_LOG_FILE. -enum OldFileDeletionState { DELETE_OLD_LOG_FILE, APPEND_TO_OLD_LOG_FILE }; - -enum DcheckState { - DISABLE_DCHECK_FOR_NON_OFFICIAL_RELEASE_BUILDS, - ENABLE_DCHECK_FOR_NON_OFFICIAL_RELEASE_BUILDS -}; - -struct BASE_EXPORT LoggingSettings { - // The defaults values are: - // - // logging_dest: LOG_DEFAULT - // log_file: NULL - // lock_log: LOCK_LOG_FILE - // delete_old: APPEND_TO_OLD_LOG_FILE - // dcheck_state: DISABLE_DCHECK_FOR_NON_OFFICIAL_RELEASE_BUILDS - LoggingSettings(); - - LoggingDestination logging_dest; - - // The three settings below have an effect only when LOG_TO_FILE is - // set in |logging_dest|. - const PathChar* log_file; - LogLockingState lock_log; - OldFileDeletionState delete_old; - - DcheckState dcheck_state; -}; - -// Define different names for the BaseInitLoggingImpl() function depending on -// whether NDEBUG is defined or not so that we'll fail to link if someone tries -// to compile logging.cc with NDEBUG but includes logging.h without defining it, -// or vice versa. -#if NDEBUG -#define BaseInitLoggingImpl BaseInitLoggingImpl_built_with_NDEBUG -#else -#define BaseInitLoggingImpl BaseInitLoggingImpl_built_without_NDEBUG -#endif - -// Implementation of the InitLogging() method declared below. We use a -// more-specific name so we can #define it above without affecting other code -// that has named stuff "InitLogging". -BASE_EXPORT bool BaseInitLoggingImpl(const LoggingSettings& settings); - -// Sets the log file name and other global logging state. Calling this function -// is recommended, and is normally done at the beginning of application init. -// If you don't call it, all the flags will be initialized to their default -// values, and there is a race condition that may leak a critical section -// object if two threads try to do the first log at the same time. -// See the definition of the enums above for descriptions and default values. -// -// The default log file is initialized to "debug.log" in the application -// directory. You probably don't want this, especially since the program -// directory may not be writable on an enduser's system. -// -// This function may be called a second time to re-direct logging (e.g after -// loging in to a user partition), however it should never be called more than -// twice. -inline bool InitLogging(const LoggingSettings& settings) { - return BaseInitLoggingImpl(settings); -} - -// Sets the log level. Anything at or above this level will be written to the -// log file/displayed to the user (if applicable). Anything below this level -// will be silently ignored. The log level defaults to 0 (everything is logged -// up to level INFO) if this function is not called. -// Note that log messages for VLOG(x) are logged at level -x, so setting -// the min log level to negative values enables verbose logging. -BASE_EXPORT void SetMinLogLevel(int level); - -// Gets the current log level. -BASE_EXPORT int GetMinLogLevel(); - -// Gets the VLOG default verbosity level. -BASE_EXPORT int GetVlogVerbosity(); - -// Gets the current vlog level for the given file (usually taken from -// __FILE__). - -// Note that |N| is the size *with* the null terminator. -BASE_EXPORT int GetVlogLevelHelper(const char* file_start, size_t N); - -template -int GetVlogLevel(const char (&file)[N]) { - return GetVlogLevelHelper(file, N); -} - -// Sets the common items you want to be prepended to each log message. -// process and thread IDs default to off, the timestamp defaults to on. -// If this function is not called, logging defaults to writing the timestamp -// only. -BASE_EXPORT void SetLogItems(bool enable_process_id, bool enable_thread_id, - bool enable_timestamp, bool enable_tickcount); - -// Sets whether or not you'd like to see fatal debug messages popped up in -// a dialog box or not. -// Dialogs are not shown by default. -BASE_EXPORT void SetShowErrorDialogs(bool enable_dialogs); - -// Sets the Log Assert Handler that will be used to notify of check failures. -// The default handler shows a dialog box and then terminate the process, -// however clients can use this function to override with their own handling -// (e.g. a silent one for Unit Tests) -typedef void (*LogAssertHandlerFunction)(const std::string& str); -BASE_EXPORT void SetLogAssertHandler(LogAssertHandlerFunction handler); - -// Sets the Log Report Handler that will be used to notify of check failures -// in non-debug mode. The default handler shows a dialog box and continues -// the execution, however clients can use this function to override with their -// own handling. -typedef void (*LogReportHandlerFunction)(const std::string& str); -BASE_EXPORT void SetLogReportHandler(LogReportHandlerFunction handler); - -// Sets the Log Message Handler that gets passed every log message before -// it's sent to other log destinations (if any). -// Returns true to signal that it handled the message and the message -// should not be sent to other log destinations. -typedef bool (*LogMessageHandlerFunction)(int severity, - const char* file, int line, size_t message_start, const std::string& str); -BASE_EXPORT void SetLogMessageHandler(LogMessageHandlerFunction handler); -BASE_EXPORT LogMessageHandlerFunction GetLogMessageHandler(); - -typedef int LogSeverity; -const LogSeverity LOG_VERBOSE = -1; // This is level 1 verbosity -// Note: the log severities are used to index into the array of names, -// see log_severity_names. -const LogSeverity LOG_INFO = 0; -const LogSeverity LOG_WARNING = 1; -const LogSeverity LOG_ERROR = 2; -const LogSeverity LOG_ERROR_REPORT = 3; -const LogSeverity LOG_FATAL = 4; -const LogSeverity LOG_NUM_SEVERITIES = 5; - -// LOG_DFATAL is LOG_FATAL in debug mode, ERROR in normal mode -#ifdef NDEBUG -const LogSeverity LOG_DFATAL = LOG_ERROR; -#else -const LogSeverity LOG_DFATAL = LOG_FATAL; -#endif - -// A few definitions of macros that don't generate much code. These are used -// by LOG() and LOG_IF, etc. Since these are used all over our code, it's -// better to have compact code for these operations. -#define COMPACT_GOOGLE_LOG_EX_INFO(ClassName, ...) \ - logging::ClassName(__FILE__, __LINE__, logging::LOG_INFO , ##__VA_ARGS__) -#define COMPACT_GOOGLE_LOG_EX_WARNING(ClassName, ...) \ - logging::ClassName(__FILE__, __LINE__, logging::LOG_WARNING , ##__VA_ARGS__) -#define COMPACT_GOOGLE_LOG_EX_ERROR(ClassName, ...) \ - logging::ClassName(__FILE__, __LINE__, logging::LOG_ERROR , ##__VA_ARGS__) -#define COMPACT_GOOGLE_LOG_EX_ERROR_REPORT(ClassName, ...) \ - logging::ClassName(__FILE__, __LINE__, \ - logging::LOG_ERROR_REPORT , ##__VA_ARGS__) -#define COMPACT_GOOGLE_LOG_EX_FATAL(ClassName, ...) \ - logging::ClassName(__FILE__, __LINE__, logging::LOG_FATAL , ##__VA_ARGS__) -#define COMPACT_GOOGLE_LOG_EX_DFATAL(ClassName, ...) \ - logging::ClassName(__FILE__, __LINE__, logging::LOG_DFATAL , ##__VA_ARGS__) - -#define COMPACT_GOOGLE_LOG_INFO \ - COMPACT_GOOGLE_LOG_EX_INFO(LogMessage) -#define COMPACT_GOOGLE_LOG_WARNING \ - COMPACT_GOOGLE_LOG_EX_WARNING(LogMessage) -#define COMPACT_GOOGLE_LOG_ERROR \ - COMPACT_GOOGLE_LOG_EX_ERROR(LogMessage) -#define COMPACT_GOOGLE_LOG_ERROR_REPORT \ - COMPACT_GOOGLE_LOG_EX_ERROR_REPORT(LogMessage) -#define COMPACT_GOOGLE_LOG_FATAL \ - COMPACT_GOOGLE_LOG_EX_FATAL(LogMessage) -#define COMPACT_GOOGLE_LOG_DFATAL \ - COMPACT_GOOGLE_LOG_EX_DFATAL(LogMessage) - -#if defined(OS_WIN) -// wingdi.h defines ERROR to be 0. When we call LOG(ERROR), it gets -// substituted with 0, and it expands to COMPACT_GOOGLE_LOG_0. To allow us -// to keep using this syntax, we define this macro to do the same thing -// as COMPACT_GOOGLE_LOG_ERROR, and also define ERROR the same way that -// the Windows SDK does for consistency. -#define ERROR 0 -#define COMPACT_GOOGLE_LOG_EX_0(ClassName, ...) \ - COMPACT_GOOGLE_LOG_EX_ERROR(ClassName , ##__VA_ARGS__) -#define COMPACT_GOOGLE_LOG_0 COMPACT_GOOGLE_LOG_ERROR -// Needed for LOG_IS_ON(ERROR). -const LogSeverity LOG_0 = LOG_ERROR; -#endif - -// As special cases, we can assume that LOG_IS_ON(ERROR_REPORT) and -// LOG_IS_ON(FATAL) always hold. Also, LOG_IS_ON(DFATAL) always holds -// in debug mode. In particular, CHECK()s will always fire if they -// fail. -#define LOG_IS_ON(severity) \ - ((::logging::LOG_ ## severity) >= ::logging::GetMinLogLevel()) - -// We can't do any caching tricks with VLOG_IS_ON() like the -// google-glog version since it requires GCC extensions. This means -// that using the v-logging functions in conjunction with --vmodule -// may be slow. -#define VLOG_IS_ON(verboselevel) \ - ((verboselevel) <= ::logging::GetVlogLevel(__FILE__)) - -// Helper macro which avoids evaluating the arguments to a stream if -// the condition doesn't hold. -#define LAZY_STREAM(stream, condition) \ - !(condition) ? (void) 0 : ::logging::LogMessageVoidify() & (stream) - -// We use the preprocessor's merging operator, "##", so that, e.g., -// LOG(INFO) becomes the token COMPACT_GOOGLE_LOG_INFO. There's some funny -// subtle difference between ostream member streaming functions (e.g., -// ostream::operator<<(int) and ostream non-member streaming functions -// (e.g., ::operator<<(ostream&, string&): it turns out that it's -// impossible to stream something like a string directly to an unnamed -// ostream. We employ a neat hack by calling the stream() member -// function of LogMessage which seems to avoid the problem. -#define LOG_STREAM(severity) COMPACT_GOOGLE_LOG_ ## severity.stream() - -#define LOG(severity) LAZY_STREAM(LOG_STREAM(severity), LOG_IS_ON(severity)) -#define LOG_IF(severity, condition) \ - LAZY_STREAM(LOG_STREAM(severity), LOG_IS_ON(severity) && (condition)) - -#define SYSLOG(severity) LOG(severity) -#define SYSLOG_IF(severity, condition) LOG_IF(severity, condition) - -// The VLOG macros log with negative verbosities. -#define VLOG_STREAM(verbose_level) \ - logging::LogMessage(__FILE__, __LINE__, -verbose_level).stream() - -#define VLOG(verbose_level) \ - LAZY_STREAM(VLOG_STREAM(verbose_level), VLOG_IS_ON(verbose_level)) - -#define VLOG_IF(verbose_level, condition) \ - LAZY_STREAM(VLOG_STREAM(verbose_level), \ - VLOG_IS_ON(verbose_level) && (condition)) - -#if defined (OS_WIN) -#define VPLOG_STREAM(verbose_level) \ - logging::Win32ErrorLogMessage(__FILE__, __LINE__, -verbose_level, \ - ::logging::GetLastSystemErrorCode()).stream() -#elif defined(OS_POSIX) -#define VPLOG_STREAM(verbose_level) \ - logging::ErrnoLogMessage(__FILE__, __LINE__, -verbose_level, \ - ::logging::GetLastSystemErrorCode()).stream() -#endif - -#define VPLOG(verbose_level) \ - LAZY_STREAM(VPLOG_STREAM(verbose_level), VLOG_IS_ON(verbose_level)) - -#define VPLOG_IF(verbose_level, condition) \ - LAZY_STREAM(VPLOG_STREAM(verbose_level), \ - VLOG_IS_ON(verbose_level) && (condition)) - -// TODO(akalin): Add more VLOG variants, e.g. VPLOG. - -#define LOG_ASSERT(condition) \ - LOG_IF(FATAL, !(condition)) << "Assert failed: " #condition ". " -#define SYSLOG_ASSERT(condition) \ - SYSLOG_IF(FATAL, !(condition)) << "Assert failed: " #condition ". " - -#if defined(OS_WIN) -#define LOG_GETLASTERROR_STREAM(severity) \ - COMPACT_GOOGLE_LOG_EX_ ## severity(Win32ErrorLogMessage, \ - ::logging::GetLastSystemErrorCode()).stream() -#define LOG_GETLASTERROR(severity) \ - LAZY_STREAM(LOG_GETLASTERROR_STREAM(severity), LOG_IS_ON(severity)) -#define LOG_GETLASTERROR_MODULE_STREAM(severity, module) \ - COMPACT_GOOGLE_LOG_EX_ ## severity(Win32ErrorLogMessage, \ - ::logging::GetLastSystemErrorCode(), module).stream() -#define LOG_GETLASTERROR_MODULE(severity, module) \ - LAZY_STREAM(LOG_GETLASTERROR_STREAM(severity, module), \ - LOG_IS_ON(severity)) -// PLOG_STREAM is used by PLOG, which is the usual error logging macro -// for each platform. -#define PLOG_STREAM(severity) LOG_GETLASTERROR_STREAM(severity) -#elif defined(OS_POSIX) -#define LOG_ERRNO_STREAM(severity) \ - COMPACT_GOOGLE_LOG_EX_ ## severity(ErrnoLogMessage, \ - ::logging::GetLastSystemErrorCode()).stream() -#define LOG_ERRNO(severity) \ - LAZY_STREAM(LOG_ERRNO_STREAM(severity), LOG_IS_ON(severity)) -// PLOG_STREAM is used by PLOG, which is the usual error logging macro -// for each platform. -#define PLOG_STREAM(severity) LOG_ERRNO_STREAM(severity) -#endif - -#define PLOG(severity) \ - LAZY_STREAM(PLOG_STREAM(severity), LOG_IS_ON(severity)) - -#define PLOG_IF(severity, condition) \ - LAZY_STREAM(PLOG_STREAM(severity), LOG_IS_ON(severity) && (condition)) - -#if !defined(NDEBUG) -// Debug builds always include DCHECK and DLOG. -#undef LOGGING_IS_OFFICIAL_BUILD -#define LOGGING_IS_OFFICIAL_BUILD 0 -#elif defined(OFFICIAL_BUILD) -// Official release builds always disable and remove DCHECK and DLOG. -#undef LOGGING_IS_OFFICIAL_BUILD -#define LOGGING_IS_OFFICIAL_BUILD 1 -#elif !defined(LOGGING_IS_OFFICIAL_BUILD) -// Unless otherwise specified, unofficial release builds include -// DCHECK and DLOG. -#define LOGGING_IS_OFFICIAL_BUILD 0 -#endif - -// The actual stream used isn't important. -#define EAT_STREAM_PARAMETERS \ - true ? (void) 0 : ::logging::LogMessageVoidify() & LOG_STREAM(FATAL) - -// CHECK dies with a fatal error if condition is not true. It is *not* -// controlled by NDEBUG, so the check will be executed regardless of -// compilation mode. -// -// We make sure CHECK et al. always evaluates their arguments, as -// doing CHECK(FunctionWithSideEffect()) is a common idiom. - -#if LOGGING_IS_OFFICIAL_BUILD - -// Make all CHECK functions discard their log strings to reduce code -// bloat for official builds. - -// TODO(akalin): This would be more valuable if there were some way to -// remove BreakDebugger() from the backtrace, perhaps by turning it -// into a macro (like __debugbreak() on Windows). -#define CHECK(condition) \ - !(condition) ? ::base::debug::BreakDebugger() : EAT_STREAM_PARAMETERS - -#define PCHECK(condition) CHECK(condition) - -#define CHECK_OP(name, op, val1, val2) CHECK((val1) op (val2)) - -#else - -#define CHECK(condition) \ - LAZY_STREAM(LOG_STREAM(FATAL), !(condition)) \ - << "Check failed: " #condition ". " - -#define PCHECK(condition) \ - LAZY_STREAM(PLOG_STREAM(FATAL), !(condition)) \ - << "Check failed: " #condition ". " - -// Helper macro for binary operators. -// Don't use this macro directly in your code, use CHECK_EQ et al below. -// -// TODO(akalin): Rewrite this so that constructs like if (...) -// CHECK_EQ(...) else { ... } work properly. -#define CHECK_OP(name, op, val1, val2) \ - if (std::string* _result = \ - logging::Check##name##Impl((val1), (val2), \ - #val1 " " #op " " #val2)) \ - logging::LogMessage(__FILE__, __LINE__, _result).stream() - -#endif - -// Build the error message string. This is separate from the "Impl" -// function template because it is not performance critical and so can -// be out of line, while the "Impl" code should be inline. Caller -// takes ownership of the returned string. -template -std::string* MakeCheckOpString(const t1& v1, const t2& v2, const char* names) { - std::ostringstream ss; - ss << names << " (" << v1 << " vs. " << v2 << ")"; - std::string* msg = new std::string(ss.str()); - return msg; -} - -// MSVC doesn't like complex extern templates and DLLs. -#if !defined(COMPILER_MSVC) -// Commonly used instantiations of MakeCheckOpString<>. Explicitly instantiated -// in logging.cc. -extern template BASE_EXPORT std::string* MakeCheckOpString( - const int&, const int&, const char* names); -extern template BASE_EXPORT -std::string* MakeCheckOpString( - const unsigned long&, const unsigned long&, const char* names); -extern template BASE_EXPORT -std::string* MakeCheckOpString( - const unsigned long&, const unsigned int&, const char* names); -extern template BASE_EXPORT -std::string* MakeCheckOpString( - const unsigned int&, const unsigned long&, const char* names); -extern template BASE_EXPORT -std::string* MakeCheckOpString( - const std::string&, const std::string&, const char* name); -#endif - -// Helper functions for CHECK_OP macro. -// The (int, int) specialization works around the issue that the compiler -// will not instantiate the template version of the function on values of -// unnamed enum type - see comment below. -#define DEFINE_CHECK_OP_IMPL(name, op) \ - template \ - inline std::string* Check##name##Impl(const t1& v1, const t2& v2, \ - const char* names) { \ - if (v1 op v2) return NULL; \ - else return MakeCheckOpString(v1, v2, names); \ - } \ - inline std::string* Check##name##Impl(int v1, int v2, const char* names) { \ - if (v1 op v2) return NULL; \ - else return MakeCheckOpString(v1, v2, names); \ - } -DEFINE_CHECK_OP_IMPL(EQ, ==) -DEFINE_CHECK_OP_IMPL(NE, !=) -DEFINE_CHECK_OP_IMPL(LE, <=) -DEFINE_CHECK_OP_IMPL(LT, < ) -DEFINE_CHECK_OP_IMPL(GE, >=) -DEFINE_CHECK_OP_IMPL(GT, > ) -#undef DEFINE_CHECK_OP_IMPL - -#define CHECK_EQ(val1, val2) CHECK_OP(EQ, ==, val1, val2) -#define CHECK_NE(val1, val2) CHECK_OP(NE, !=, val1, val2) -#define CHECK_LE(val1, val2) CHECK_OP(LE, <=, val1, val2) -#define CHECK_LT(val1, val2) CHECK_OP(LT, < , val1, val2) -#define CHECK_GE(val1, val2) CHECK_OP(GE, >=, val1, val2) -#define CHECK_GT(val1, val2) CHECK_OP(GT, > , val1, val2) - -#if LOGGING_IS_OFFICIAL_BUILD -// In order to have optimized code for official builds, remove DLOGs and -// DCHECKs. -#define ENABLE_DLOG 0 -#define ENABLE_DCHECK 0 - -#elif defined(NDEBUG) -// Otherwise, if we're a release build, remove DLOGs but not DCHECKs -// (since those can still be turned on via a command-line flag). -#define ENABLE_DLOG 0 -#define ENABLE_DCHECK 1 - -#else -// Otherwise, we're a debug build so enable DLOGs and DCHECKs. -#define ENABLE_DLOG 1 -#define ENABLE_DCHECK 1 -#endif - -// Definitions for DLOG et al. - -#if ENABLE_DLOG - -#define DLOG_IS_ON(severity) LOG_IS_ON(severity) -#define DLOG_IF(severity, condition) LOG_IF(severity, condition) -#define DLOG_ASSERT(condition) LOG_ASSERT(condition) -#define DPLOG_IF(severity, condition) PLOG_IF(severity, condition) -#define DVLOG_IF(verboselevel, condition) VLOG_IF(verboselevel, condition) -#define DVPLOG_IF(verboselevel, condition) VPLOG_IF(verboselevel, condition) - -#else // ENABLE_DLOG - -// If ENABLE_DLOG is off, we want to avoid emitting any references to -// |condition| (which may reference a variable defined only if NDEBUG -// is not defined). Contrast this with DCHECK et al., which has -// different behavior. - -#define DLOG_IS_ON(severity) false -#define DLOG_IF(severity, condition) EAT_STREAM_PARAMETERS -#define DLOG_ASSERT(condition) EAT_STREAM_PARAMETERS -#define DPLOG_IF(severity, condition) EAT_STREAM_PARAMETERS -#define DVLOG_IF(verboselevel, condition) EAT_STREAM_PARAMETERS -#define DVPLOG_IF(verboselevel, condition) EAT_STREAM_PARAMETERS - -#endif // ENABLE_DLOG - -// DEBUG_MODE is for uses like -// if (DEBUG_MODE) foo.CheckThatFoo(); -// instead of -// #ifndef NDEBUG -// foo.CheckThatFoo(); -// #endif -// -// We tie its state to ENABLE_DLOG. -enum { DEBUG_MODE = ENABLE_DLOG }; - -#undef ENABLE_DLOG - -#define DLOG(severity) \ - LAZY_STREAM(LOG_STREAM(severity), DLOG_IS_ON(severity)) - -#if defined(OS_WIN) -#define DLOG_GETLASTERROR(severity) \ - LAZY_STREAM(LOG_GETLASTERROR_STREAM(severity), DLOG_IS_ON(severity)) -#define DLOG_GETLASTERROR_MODULE(severity, module) \ - LAZY_STREAM(LOG_GETLASTERROR_STREAM(severity, module), \ - DLOG_IS_ON(severity)) -#elif defined(OS_POSIX) -#define DLOG_ERRNO(severity) \ - LAZY_STREAM(LOG_ERRNO_STREAM(severity), DLOG_IS_ON(severity)) -#endif - -#define DPLOG(severity) \ - LAZY_STREAM(PLOG_STREAM(severity), DLOG_IS_ON(severity)) - -#define DVLOG(verboselevel) DVLOG_IF(verboselevel, VLOG_IS_ON(verboselevel)) - -#define DVPLOG(verboselevel) DVPLOG_IF(verboselevel, VLOG_IS_ON(verboselevel)) - -// Definitions for DCHECK et al. - -#if ENABLE_DCHECK - -#if defined(NDEBUG) - -BASE_EXPORT DcheckState get_dcheck_state(); -BASE_EXPORT void set_dcheck_state(DcheckState state); - -#if defined(DCHECK_ALWAYS_ON) - -#define DCHECK_IS_ON() true -#define COMPACT_GOOGLE_LOG_EX_DCHECK(ClassName, ...) \ - COMPACT_GOOGLE_LOG_EX_FATAL(ClassName , ##__VA_ARGS__) -#define COMPACT_GOOGLE_LOG_DCHECK COMPACT_GOOGLE_LOG_FATAL -const LogSeverity LOG_DCHECK = LOG_FATAL; - -#else - -#define COMPACT_GOOGLE_LOG_EX_DCHECK(ClassName, ...) \ - COMPACT_GOOGLE_LOG_EX_ERROR_REPORT(ClassName , ##__VA_ARGS__) -#define COMPACT_GOOGLE_LOG_DCHECK COMPACT_GOOGLE_LOG_ERROR_REPORT -const LogSeverity LOG_DCHECK = LOG_ERROR_REPORT; -#define DCHECK_IS_ON() \ - ((::logging::get_dcheck_state() == \ - ::logging::ENABLE_DCHECK_FOR_NON_OFFICIAL_RELEASE_BUILDS) && \ - LOG_IS_ON(DCHECK)) - -#endif // defined(DCHECK_ALWAYS_ON) - -#else // defined(NDEBUG) - -// On a regular debug build, we want to have DCHECKs enabled. -#define COMPACT_GOOGLE_LOG_EX_DCHECK(ClassName, ...) \ - COMPACT_GOOGLE_LOG_EX_FATAL(ClassName , ##__VA_ARGS__) -#define COMPACT_GOOGLE_LOG_DCHECK COMPACT_GOOGLE_LOG_FATAL -const LogSeverity LOG_DCHECK = LOG_FATAL; -#define DCHECK_IS_ON() true - -#endif // defined(NDEBUG) - -#else // ENABLE_DCHECK - -// These are just dummy values since DCHECK_IS_ON() is always false in -// this case. -#define COMPACT_GOOGLE_LOG_EX_DCHECK(ClassName, ...) \ - COMPACT_GOOGLE_LOG_EX_INFO(ClassName , ##__VA_ARGS__) -#define COMPACT_GOOGLE_LOG_DCHECK COMPACT_GOOGLE_LOG_INFO -const LogSeverity LOG_DCHECK = LOG_INFO; -#define DCHECK_IS_ON() false - -#endif // ENABLE_DCHECK -#undef ENABLE_DCHECK - -// DCHECK et al. make sure to reference |condition| regardless of -// whether DCHECKs are enabled; this is so that we don't get unused -// variable warnings if the only use of a variable is in a DCHECK. -// This behavior is different from DLOG_IF et al. - -#define DCHECK(condition) \ - LAZY_STREAM(LOG_STREAM(DCHECK), DCHECK_IS_ON() && !(condition)) \ - << "Check failed: " #condition ". " - -#define DPCHECK(condition) \ - LAZY_STREAM(PLOG_STREAM(DCHECK), DCHECK_IS_ON() && !(condition)) \ - << "Check failed: " #condition ". " - -// Helper macro for binary operators. -// Don't use this macro directly in your code, use DCHECK_EQ et al below. -#define DCHECK_OP(name, op, val1, val2) \ - if (DCHECK_IS_ON()) \ - if (std::string* _result = \ - logging::Check##name##Impl((val1), (val2), \ - #val1 " " #op " " #val2)) \ - logging::LogMessage( \ - __FILE__, __LINE__, ::logging::LOG_DCHECK, \ - _result).stream() - -// Equality/Inequality checks - compare two values, and log a -// LOG_DCHECK message including the two values when the result is not -// as expected. The values must have operator<<(ostream, ...) -// defined. -// -// You may append to the error message like so: -// DCHECK_NE(1, 2) << ": The world must be ending!"; -// -// We are very careful to ensure that each argument is evaluated exactly -// once, and that anything which is legal to pass as a function argument is -// legal here. In particular, the arguments may be temporary expressions -// which will end up being destroyed at the end of the apparent statement, -// for example: -// DCHECK_EQ(string("abc")[1], 'b'); -// -// WARNING: These may not compile correctly if one of the arguments is a pointer -// and the other is NULL. To work around this, simply static_cast NULL to the -// type of the desired pointer. - -#define DCHECK_EQ(val1, val2) DCHECK_OP(EQ, ==, val1, val2) -#define DCHECK_NE(val1, val2) DCHECK_OP(NE, !=, val1, val2) -#define DCHECK_LE(val1, val2) DCHECK_OP(LE, <=, val1, val2) -#define DCHECK_LT(val1, val2) DCHECK_OP(LT, < , val1, val2) -#define DCHECK_GE(val1, val2) DCHECK_OP(GE, >=, val1, val2) -#define DCHECK_GT(val1, val2) DCHECK_OP(GT, > , val1, val2) - -#define NOTREACHED() DCHECK(false) - -// Redefine the standard assert to use our nice log files -#undef assert -#define assert(x) DLOG_ASSERT(x) - -// This class more or less represents a particular log message. You -// create an instance of LogMessage and then stream stuff to it. -// When you finish streaming to it, ~LogMessage is called and the -// full message gets streamed to the appropriate destination. -// -// You shouldn't actually use LogMessage's constructor to log things, -// though. You should use the LOG() macro (and variants thereof) -// above. -class BASE_EXPORT LogMessage { - public: - LogMessage(const char* file, int line, LogSeverity severity, int ctr); - - // Two special constructors that generate reduced amounts of code at - // LOG call sites for common cases. - // - // Used for LOG(INFO): Implied are: - // severity = LOG_INFO, ctr = 0 - // - // Using this constructor instead of the more complex constructor above - // saves a couple of bytes per call site. - LogMessage(const char* file, int line); - - // Used for LOG(severity) where severity != INFO. Implied - // are: ctr = 0 - // - // Using this constructor instead of the more complex constructor above - // saves a couple of bytes per call site. - LogMessage(const char* file, int line, LogSeverity severity); - - // A special constructor used for check failures. Takes ownership - // of the given string. - // Implied severity = LOG_FATAL - LogMessage(const char* file, int line, std::string* result); - - // A special constructor used for check failures, with the option to - // specify severity. Takes ownership of the given string. - LogMessage(const char* file, int line, LogSeverity severity, - std::string* result); - - ~LogMessage(); - - std::ostream& stream() { return stream_; } - - private: - void Init(const char* file, int line); - - LogSeverity severity_; - std::ostringstream stream_; - size_t message_start_; // Offset of the start of the message (past prefix - // info). - // The file and line information passed in to the constructor. - const char* file_; - const int line_; - -#if defined(OS_WIN) - // Stores the current value of GetLastError in the constructor and restores - // it in the destructor by calling SetLastError. - // This is useful since the LogMessage class uses a lot of Win32 calls - // that will lose the value of GLE and the code that called the log function - // will have lost the thread error value when the log call returns. - class SaveLastError { - public: - SaveLastError(); - ~SaveLastError(); - - unsigned long get_error() const { return last_error_; } - - protected: - unsigned long last_error_; - }; - - SaveLastError last_error_; -#endif - - DISALLOW_COPY_AND_ASSIGN(LogMessage); -}; - -// A non-macro interface to the log facility; (useful -// when the logging level is not a compile-time constant). -inline void LogAtLevel(int const log_level, std::string const &msg) { - LogMessage(__FILE__, __LINE__, log_level).stream() << msg; -} - -// This class is used to explicitly ignore values in the conditional -// logging macros. This avoids compiler warnings like "value computed -// is not used" and "statement has no effect". -class LogMessageVoidify { - public: - LogMessageVoidify() { } - // This has to be an operator with a precedence lower than << but - // higher than ?: - void operator&(std::ostream&) { } -}; - -#if defined(OS_WIN) -typedef unsigned long SystemErrorCode; -#elif defined(OS_POSIX) -typedef int SystemErrorCode; -#endif - -// Alias for ::GetLastError() on Windows and errno on POSIX. Avoids having to -// pull in windows.h just for GetLastError() and DWORD. -BASE_EXPORT SystemErrorCode GetLastSystemErrorCode(); - -#if defined(OS_WIN) -// Appends a formatted system message of the GetLastError() type. -class BASE_EXPORT Win32ErrorLogMessage { - public: - Win32ErrorLogMessage(const char* file, - int line, - LogSeverity severity, - SystemErrorCode err, - const char* module); - - Win32ErrorLogMessage(const char* file, - int line, - LogSeverity severity, - SystemErrorCode err); - - // Appends the error message before destructing the encapsulated class. - ~Win32ErrorLogMessage(); - - std::ostream& stream() { return log_message_.stream(); } - - private: - SystemErrorCode err_; - // Optional name of the module defining the error. - const char* module_; - LogMessage log_message_; - - DISALLOW_COPY_AND_ASSIGN(Win32ErrorLogMessage); -}; -#elif defined(OS_POSIX) -// Appends a formatted system message of the errno type -class BASE_EXPORT ErrnoLogMessage { - public: - ErrnoLogMessage(const char* file, - int line, - LogSeverity severity, - SystemErrorCode err); - - // Appends the error message before destructing the encapsulated class. - ~ErrnoLogMessage(); - - std::ostream& stream() { return log_message_.stream(); } - - private: - SystemErrorCode err_; - LogMessage log_message_; - - DISALLOW_COPY_AND_ASSIGN(ErrnoLogMessage); -}; -#endif // OS_WIN - -// Closes the log file explicitly if open. -// NOTE: Since the log file is opened as necessary by the action of logging -// statements, there's no guarantee that it will stay closed -// after this call. -BASE_EXPORT void CloseLogFile(); - -// Async signal safe logging mechanism. -BASE_EXPORT void RawLog(int level, const char* message); - -#define RAW_LOG(level, message) logging::RawLog(logging::LOG_ ## level, message) - -#define RAW_CHECK(condition) \ - do { \ - if (!(condition)) \ - logging::RawLog(logging::LOG_FATAL, "Check failed: " #condition "\n"); \ - } while (0) - -#if defined(OS_WIN) -// Returns the default log file path. -BASE_EXPORT std::wstring GetLogFileFullPath(); -#endif - -} // namespace logging - -// These functions are provided as a convenience for logging, which is where we -// use streams (it is against Google style to use streams in other places). It -// is designed to allow you to emit non-ASCII Unicode strings to the log file, -// which is normally ASCII. It is relatively slow, so try not to use it for -// common cases. Non-ASCII characters will be converted to UTF-8 by these -// operators. -BASE_EXPORT std::ostream& operator<<(std::ostream& out, const wchar_t* wstr); -inline std::ostream& operator<<(std::ostream& out, const std::wstring& wstr) { - return out << wstr.c_str(); -} - -// The NOTIMPLEMENTED() macro annotates codepaths which have -// not been implemented yet. -// -// The implementation of this macro is controlled by NOTIMPLEMENTED_POLICY: -// 0 -- Do nothing (stripped by compiler) -// 1 -- Warn at compile time -// 2 -- Fail at compile time -// 3 -- Fail at runtime (DCHECK) -// 4 -- [default] LOG(ERROR) at runtime -// 5 -- LOG(ERROR) at runtime, only once per call-site - -#ifndef NOTIMPLEMENTED_POLICY -#if defined(OS_ANDROID) && defined(OFFICIAL_BUILD) -#define NOTIMPLEMENTED_POLICY 0 -#else -// Select default policy: LOG(ERROR) -#define NOTIMPLEMENTED_POLICY 4 -#endif -#endif - -#if defined(COMPILER_GCC) -// On Linux, with GCC, we can use __PRETTY_FUNCTION__ to get the demangled name -// of the current function in the NOTIMPLEMENTED message. -#define NOTIMPLEMENTED_MSG "Not implemented reached in " << __PRETTY_FUNCTION__ -#else -#define NOTIMPLEMENTED_MSG "NOT IMPLEMENTED" -#endif - -#if NOTIMPLEMENTED_POLICY == 0 -#define NOTIMPLEMENTED() EAT_STREAM_PARAMETERS -#elif NOTIMPLEMENTED_POLICY == 1 -// TODO, figure out how to generate a warning -#define NOTIMPLEMENTED() COMPILE_ASSERT(false, NOT_IMPLEMENTED) -#elif NOTIMPLEMENTED_POLICY == 2 -#define NOTIMPLEMENTED() COMPILE_ASSERT(false, NOT_IMPLEMENTED) -#elif NOTIMPLEMENTED_POLICY == 3 -#define NOTIMPLEMENTED() NOTREACHED() -#elif NOTIMPLEMENTED_POLICY == 4 -#define NOTIMPLEMENTED() LOG(ERROR) << NOTIMPLEMENTED_MSG -#elif NOTIMPLEMENTED_POLICY == 5 -#define NOTIMPLEMENTED() do {\ - static bool logged_once = false;\ - LOG_IF(ERROR, !logged_once) << NOTIMPLEMENTED_MSG;\ - logged_once = true;\ -} while(0);\ -EAT_STREAM_PARAMETERS -#endif - -#endif // BASE_LOGGING_H_ diff --git a/base/logging_unittest.cc b/base/logging_unittest.cc deleted file mode 100644 index bff10ebdf8..0000000000 --- a/base/logging_unittest.cc +++ /dev/null @@ -1,261 +0,0 @@ -// Copyright (c) 2011 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "base/basictypes.h" -#include "base/logging.h" - -#include "testing/gmock/include/gmock/gmock.h" -#include "testing/gtest/include/gtest/gtest.h" - -namespace logging { - -namespace { - -using ::testing::Return; - -// Needs to be global since log assert handlers can't maintain state. -int log_sink_call_count = 0; - -void LogSink(const std::string& str) { - ++log_sink_call_count; -} - -// Class to make sure any manipulations we do to the min log level are -// contained (i.e., do not affect other unit tests). -class LogStateSaver { - public: - LogStateSaver() : old_min_log_level_(GetMinLogLevel()) {} - - ~LogStateSaver() { - SetMinLogLevel(old_min_log_level_); - SetLogAssertHandler(NULL); - SetLogReportHandler(NULL); - log_sink_call_count = 0; - } - - private: - int old_min_log_level_; - - DISALLOW_COPY_AND_ASSIGN(LogStateSaver); -}; - -class LoggingTest : public testing::Test { - private: - LogStateSaver log_state_saver_; -}; - -class MockLogSource { - public: - MOCK_METHOD0(Log, const char*()); -}; - -TEST_F(LoggingTest, BasicLogging) { - MockLogSource mock_log_source; - const int kExpectedDebugOrReleaseCalls = 6; - const int kExpectedDebugCalls = 6; - const int kExpectedCalls = - kExpectedDebugOrReleaseCalls + (DEBUG_MODE ? kExpectedDebugCalls : 0); - EXPECT_CALL(mock_log_source, Log()).Times(kExpectedCalls). - WillRepeatedly(Return("log message")); - - SetMinLogLevel(LOG_INFO); - - EXPECT_TRUE(LOG_IS_ON(INFO)); - // As of g++-4.5, the first argument to EXPECT_EQ cannot be a - // constant expression. - const bool kIsDebugMode = (DEBUG_MODE != 0); - EXPECT_TRUE(kIsDebugMode == DLOG_IS_ON(INFO)); - EXPECT_TRUE(VLOG_IS_ON(0)); - - LOG(INFO) << mock_log_source.Log(); - LOG_IF(INFO, true) << mock_log_source.Log(); - PLOG(INFO) << mock_log_source.Log(); - PLOG_IF(INFO, true) << mock_log_source.Log(); - VLOG(0) << mock_log_source.Log(); - VLOG_IF(0, true) << mock_log_source.Log(); - - DLOG(INFO) << mock_log_source.Log(); - DLOG_IF(INFO, true) << mock_log_source.Log(); - DPLOG(INFO) << mock_log_source.Log(); - DPLOG_IF(INFO, true) << mock_log_source.Log(); - DVLOG(0) << mock_log_source.Log(); - DVLOG_IF(0, true) << mock_log_source.Log(); -} - -TEST_F(LoggingTest, LogIsOn) { -#if defined(NDEBUG) - const bool kDfatalIsFatal = false; -#else // defined(NDEBUG) - const bool kDfatalIsFatal = true; -#endif // defined(NDEBUG) - - SetMinLogLevel(LOG_INFO); - EXPECT_TRUE(LOG_IS_ON(INFO)); - EXPECT_TRUE(LOG_IS_ON(WARNING)); - EXPECT_TRUE(LOG_IS_ON(ERROR)); - EXPECT_TRUE(LOG_IS_ON(ERROR_REPORT)); - EXPECT_TRUE(LOG_IS_ON(FATAL)); - EXPECT_TRUE(LOG_IS_ON(DFATAL)); - - SetMinLogLevel(LOG_WARNING); - EXPECT_FALSE(LOG_IS_ON(INFO)); - EXPECT_TRUE(LOG_IS_ON(WARNING)); - EXPECT_TRUE(LOG_IS_ON(ERROR)); - EXPECT_TRUE(LOG_IS_ON(ERROR_REPORT)); - EXPECT_TRUE(LOG_IS_ON(FATAL)); - EXPECT_TRUE(LOG_IS_ON(DFATAL)); - - SetMinLogLevel(LOG_ERROR); - EXPECT_FALSE(LOG_IS_ON(INFO)); - EXPECT_FALSE(LOG_IS_ON(WARNING)); - EXPECT_TRUE(LOG_IS_ON(ERROR)); - EXPECT_TRUE(LOG_IS_ON(ERROR_REPORT)); - EXPECT_TRUE(LOG_IS_ON(FATAL)); - EXPECT_TRUE(LOG_IS_ON(DFATAL)); - - SetMinLogLevel(LOG_ERROR_REPORT); - EXPECT_FALSE(LOG_IS_ON(INFO)); - EXPECT_FALSE(LOG_IS_ON(WARNING)); - EXPECT_FALSE(LOG_IS_ON(ERROR)); - EXPECT_TRUE(LOG_IS_ON(ERROR_REPORT)); - EXPECT_TRUE(LOG_IS_ON(FATAL)); - EXPECT_TRUE(kDfatalIsFatal == LOG_IS_ON(DFATAL)); - - // LOG_IS_ON(ERROR_REPORT) should always be true. - SetMinLogLevel(LOG_FATAL); - EXPECT_FALSE(LOG_IS_ON(INFO)); - EXPECT_FALSE(LOG_IS_ON(WARNING)); - EXPECT_FALSE(LOG_IS_ON(ERROR)); - EXPECT_TRUE(LOG_IS_ON(ERROR_REPORT)); - EXPECT_TRUE(LOG_IS_ON(FATAL)); - EXPECT_TRUE(kDfatalIsFatal == LOG_IS_ON(DFATAL)); - - // So should LOG_IS_ON(FATAL). - SetMinLogLevel(LOG_FATAL + 1); - EXPECT_FALSE(LOG_IS_ON(INFO)); - EXPECT_FALSE(LOG_IS_ON(WARNING)); - EXPECT_FALSE(LOG_IS_ON(ERROR)); - EXPECT_TRUE(LOG_IS_ON(ERROR_REPORT)); - EXPECT_TRUE(LOG_IS_ON(FATAL)); - EXPECT_TRUE(kDfatalIsFatal == LOG_IS_ON(DFATAL)); -} - -TEST_F(LoggingTest, LoggingIsLazy) { - MockLogSource mock_log_source; - EXPECT_CALL(mock_log_source, Log()).Times(0); - - SetMinLogLevel(LOG_WARNING); - - EXPECT_FALSE(LOG_IS_ON(INFO)); - EXPECT_FALSE(DLOG_IS_ON(INFO)); - EXPECT_FALSE(VLOG_IS_ON(1)); - - LOG(INFO) << mock_log_source.Log(); - LOG_IF(INFO, false) << mock_log_source.Log(); - PLOG(INFO) << mock_log_source.Log(); - PLOG_IF(INFO, false) << mock_log_source.Log(); - VLOG(1) << mock_log_source.Log(); - VLOG_IF(1, true) << mock_log_source.Log(); - - DLOG(INFO) << mock_log_source.Log(); - DLOG_IF(INFO, true) << mock_log_source.Log(); - DPLOG(INFO) << mock_log_source.Log(); - DPLOG_IF(INFO, true) << mock_log_source.Log(); - DVLOG(1) << mock_log_source.Log(); - DVLOG_IF(1, true) << mock_log_source.Log(); -} - -// Official builds have CHECKs directly call BreakDebugger. -#if !defined(LOGGING_IS_OFFICIAL_BUILD) - -TEST_F(LoggingTest, CheckStreamsAreLazy) { - MockLogSource mock_log_source, uncalled_mock_log_source; - EXPECT_CALL(mock_log_source, Log()).Times(8). - WillRepeatedly(Return("check message")); - EXPECT_CALL(uncalled_mock_log_source, Log()).Times(0); - - SetLogAssertHandler(&LogSink); - - CHECK(mock_log_source.Log()) << uncalled_mock_log_source.Log(); - PCHECK(!mock_log_source.Log()) << mock_log_source.Log(); - CHECK_EQ(mock_log_source.Log(), mock_log_source.Log()) - << uncalled_mock_log_source.Log(); - CHECK_NE(mock_log_source.Log(), mock_log_source.Log()) - << mock_log_source.Log(); -} - -#endif - -TEST_F(LoggingTest, DebugLoggingReleaseBehavior) { -#if !defined(NDEBUG) - int debug_only_variable = 1; -#endif - // These should avoid emitting references to |debug_only_variable| - // in release mode. - DLOG_IF(INFO, debug_only_variable) << "test"; - DLOG_ASSERT(debug_only_variable) << "test"; - DPLOG_IF(INFO, debug_only_variable) << "test"; - DVLOG_IF(1, debug_only_variable) << "test"; -} - -TEST_F(LoggingTest, DcheckStreamsAreLazy) { - MockLogSource mock_log_source; - EXPECT_CALL(mock_log_source, Log()).Times(0); -#if !defined(LOGGING_IS_OFFICIAL_BUILD) && defined(NDEBUG) && \ - !defined(DCHECK_ALWAYS_ON) - // Unofficial release build without dcheck enabled. - set_dcheck_state(DISABLE_DCHECK_FOR_NON_OFFICIAL_RELEASE_BUILDS); - DCHECK(mock_log_source.Log()) << mock_log_source.Log(); - DPCHECK(mock_log_source.Log()) << mock_log_source.Log(); - DCHECK_EQ(0, 0) << mock_log_source.Log(); - DCHECK_EQ(mock_log_source.Log(), static_cast(NULL)) - << mock_log_source.Log(); -#endif -} - -TEST_F(LoggingTest, Dcheck) { -#if LOGGING_IS_OFFICIAL_BUILD - // Official build. - EXPECT_FALSE(DCHECK_IS_ON()); - EXPECT_FALSE(DLOG_IS_ON(DCHECK)); -#elif defined(NDEBUG) && !defined(DCHECK_ALWAYS_ON) - // Unofficial release build. - set_dcheck_state(ENABLE_DCHECK_FOR_NON_OFFICIAL_RELEASE_BUILDS); - SetLogReportHandler(&LogSink); - EXPECT_TRUE(DCHECK_IS_ON()); - EXPECT_FALSE(DLOG_IS_ON(DCHECK)); -#elif defined(NDEBUG) && defined(DCHECK_ALWAYS_ON) - // Unofficial release build with real DCHECKS. - set_dcheck_state(ENABLE_DCHECK_FOR_NON_OFFICIAL_RELEASE_BUILDS); - SetLogAssertHandler(&LogSink); - EXPECT_TRUE(DCHECK_IS_ON()); - EXPECT_FALSE(DLOG_IS_ON(DCHECK)); -#else - // Unofficial debug build. - SetLogAssertHandler(&LogSink); - EXPECT_TRUE(DCHECK_IS_ON()); - EXPECT_TRUE(DLOG_IS_ON(DCHECK)); -#endif // defined(LOGGING_IS_OFFICIAL_BUILD) - - EXPECT_EQ(0, log_sink_call_count); - DCHECK(false); - EXPECT_EQ(DCHECK_IS_ON() ? 1 : 0, log_sink_call_count); - DPCHECK(false); - EXPECT_EQ(DCHECK_IS_ON() ? 2 : 0, log_sink_call_count); - DCHECK_EQ(0, 1); - EXPECT_EQ(DCHECK_IS_ON() ? 3 : 0, log_sink_call_count); -} - -TEST_F(LoggingTest, DcheckReleaseBehavior) { - int some_variable = 1; - // These should still reference |some_variable| so we don't get - // unused variable warnings. - DCHECK(some_variable) << "test"; - DPCHECK(some_variable) << "test"; - DCHECK_EQ(some_variable, 1) << "test"; -} - -} // namespace - -} // namespace logging diff --git a/base/logging_win.cc b/base/logging_win.cc deleted file mode 100644 index a714665788..0000000000 --- a/base/logging_win.cc +++ /dev/null @@ -1,139 +0,0 @@ -// Copyright (c) 2011 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "base/logging_win.h" -#include "base/memory/singleton.h" -#include // NOLINT - -namespace logging { - -using base::win::EtwEventLevel; -using base::win::EtwMofEvent; - -DEFINE_GUID(kLogEventId, - 0x7fe69228, 0x633e, 0x4f06, 0x80, 0xc1, 0x52, 0x7f, 0xea, 0x23, 0xe3, 0xa7); - -LogEventProvider::LogEventProvider() : old_log_level_(LOG_NONE) { -} - -LogEventProvider* LogEventProvider::GetInstance() { - return Singleton >::get(); -} - -bool LogEventProvider::LogMessage(logging::LogSeverity severity, - const char* file, int line, size_t message_start, - const std::string& message) { - EtwEventLevel level = TRACE_LEVEL_NONE; - - // Convert the log severity to the most appropriate ETW trace level. - if (severity >= 0) { - switch (severity) { - case LOG_INFO: - level = TRACE_LEVEL_INFORMATION; - break; - case LOG_WARNING: - level = TRACE_LEVEL_WARNING; - break; - case LOG_ERROR: - case LOG_ERROR_REPORT: - level = TRACE_LEVEL_ERROR; - break; - case LOG_FATAL: - level = TRACE_LEVEL_FATAL; - break; - } - } else { // severity < 0 is VLOG verbosity levels. - level = TRACE_LEVEL_INFORMATION - severity; - } - - // Bail if we're not logging, not at that level, - // or if we're post-atexit handling. - LogEventProvider* provider = LogEventProvider::GetInstance(); - if (provider == NULL || level > provider->enable_level()) - return false; - - // And now log the event. - if (provider->enable_flags() & ENABLE_LOG_MESSAGE_ONLY) { - EtwMofEvent<1> event(kLogEventId, LOG_MESSAGE, level); - event.SetField(0, message.length() + 1 - message_start, - message.c_str() + message_start); - - provider->Log(event.get()); - } else { - const size_t kMaxBacktraceDepth = 32; - void* backtrace[kMaxBacktraceDepth]; - DWORD depth = 0; - - // Capture a stack trace if one is requested. - // requested per our enable flags. - if (provider->enable_flags() & ENABLE_STACK_TRACE_CAPTURE) - depth = CaptureStackBackTrace(2, kMaxBacktraceDepth, backtrace, NULL); - - EtwMofEvent<5> event(kLogEventId, LOG_MESSAGE_FULL, level); - if (file == NULL) - file = ""; - - // Add the stack trace. - event.SetField(0, sizeof(depth), &depth); - event.SetField(1, sizeof(backtrace[0]) * depth, &backtrace); - // The line. - event.SetField(2, sizeof(line), &line); - // The file. - event.SetField(3, strlen(file) + 1, file); - // And finally the message. - event.SetField(4, message.length() + 1 - message_start, - message.c_str() + message_start); - - provider->Log(event.get()); - } - - // Don't increase verbosity in other log destinations. - if (severity < provider->old_log_level_) - return true; - - return false; -} - -void LogEventProvider::Initialize(const GUID& provider_name) { - LogEventProvider* provider = LogEventProvider::GetInstance(); - - provider->set_provider_name(provider_name); - provider->Register(); - - // Register our message handler with logging. - SetLogMessageHandler(LogMessage); -} - -void LogEventProvider::Uninitialize() { - LogEventProvider::GetInstance()->Unregister(); -} - -void LogEventProvider::OnEventsEnabled() { - // Grab the old log level so we can restore it later. - old_log_level_ = GetMinLogLevel(); - - // Convert the new trace level to a logging severity - // and enable logging at that level. - EtwEventLevel level = enable_level(); - if (level == TRACE_LEVEL_NONE || level == TRACE_LEVEL_FATAL) { - SetMinLogLevel(LOG_FATAL); - } else if (level == TRACE_LEVEL_ERROR) { - SetMinLogLevel(LOG_ERROR); - } else if (level == TRACE_LEVEL_WARNING) { - SetMinLogLevel(LOG_WARNING); - } else if (level == TRACE_LEVEL_INFORMATION) { - SetMinLogLevel(LOG_INFO); - } else if (level >= TRACE_LEVEL_VERBOSE) { - // Above INFO, we enable verbose levels with negative severities. - SetMinLogLevel(TRACE_LEVEL_INFORMATION - level); - } -} - -void LogEventProvider::OnEventsDisabled() { - // Restore the old log level. - SetMinLogLevel(old_log_level_); -} - -} // namespace logging diff --git a/base/logging_win.h b/base/logging_win.h deleted file mode 100644 index 38508a3246..0000000000 --- a/base/logging_win.h +++ /dev/null @@ -1,80 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef BASE_LOGGING_WIN_H_ -#define BASE_LOGGING_WIN_H_ - -#include - -#include "base/base_export.h" -#include "base/basictypes.h" -#include "base/win/event_trace_provider.h" -#include "base/logging.h" - -template -struct StaticMemorySingletonTraits; - -namespace logging { - -// Event ID for the log messages we generate. -EXTERN_C BASE_EXPORT const GUID kLogEventId; - -// Feature enable mask for LogEventProvider. -enum LogEnableMask { - // If this bit is set in our provider enable mask, we will include - // a stack trace with every log message. - ENABLE_STACK_TRACE_CAPTURE = 0x0001, - // If this bit is set in our provider enable mask, the provider will log - // a LOG message with only the textual content of the message, and no - // stack trace. - ENABLE_LOG_MESSAGE_ONLY = 0x0002, -}; - -// The message types our log event provider generates. -// ETW likes user message types to start at 10. -enum LogMessageTypes { - // A textual only log message, contains a zero-terminated string. - LOG_MESSAGE = 10, - // A message with a stack trace, followed by the zero-terminated - // message text. - LOG_MESSAGE_WITH_STACKTRACE = 11, - // A message with: - // a stack trace, - // the line number as a four byte integer, - // the file as a zero terminated UTF8 string, - // the zero-terminated UTF8 message text. - LOG_MESSAGE_FULL = 12, -}; - -// Trace provider class to drive log control and transport -// with Event Tracing for Windows. -class BASE_EXPORT LogEventProvider : public base::win::EtwTraceProvider { - public: - static LogEventProvider* GetInstance(); - - static bool LogMessage(logging::LogSeverity severity, const char* file, - int line, size_t message_start, const std::string& str); - - static void Initialize(const GUID& provider_name); - static void Uninitialize(); - - protected: - // Overridden to manipulate the log level on ETW control callbacks. - virtual void OnEventsEnabled(); - virtual void OnEventsDisabled(); - - private: - LogEventProvider(); - - // The log severity prior to OnEventsEnabled, - // restored in OnEventsDisabled. - logging::LogSeverity old_log_level_; - - friend struct StaticMemorySingletonTraits; - DISALLOW_COPY_AND_ASSIGN(LogEventProvider); -}; - -} // namespace logging - -#endif // BASE_LOGGING_WIN_H_ diff --git a/base/mac/OWNERS b/base/mac/OWNERS deleted file mode 100644 index a3fc32fcee..0000000000 --- a/base/mac/OWNERS +++ /dev/null @@ -1,2 +0,0 @@ -mark@chromium.org -thakis@chromium.org diff --git a/base/mac/authorization_util.h b/base/mac/authorization_util.h deleted file mode 100644 index b34348d175..0000000000 --- a/base/mac/authorization_util.h +++ /dev/null @@ -1,73 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef BASE_MAC_AUTHORIZATION_UTIL_H_ -#define BASE_MAC_AUTHORIZATION_UTIL_H_ - -// AuthorizationExecuteWithPrivileges fork()s and exec()s the tool, but it -// does not wait() for it. It also doesn't provide the caller with access to -// the forked pid. If used irresponsibly, zombie processes will accumulate. -// -// Apple's really gotten us between a rock and a hard place, here. -// -// Fortunately, AuthorizationExecuteWithPrivileges does give access to the -// tool's stdout (and stdin) via a FILE* pipe. The tool can output its pid -// to this pipe, and the main program can read it, and then have something -// that it can wait() for. -// -// The contract is that any tool executed by the wrappers declared in this -// file must print its pid to stdout on a line by itself before doing anything -// else. -// -// http://developer.apple.com/library/mac/#samplecode/BetterAuthorizationSample/Listings/BetterAuthorizationSampleLib_c.html -// (Look for "What's This About Zombies?") - -#include -#include -#include -#include - -#include "base/base_export.h" - -namespace base { -namespace mac { - -// Obtains an AuthorizationRef that can be used to run commands as root. If -// necessary, prompts the user for authentication. If the user is prompted, -// |prompt| will be used as the prompt string and an icon appropriate for the -// application will be displayed in a prompt dialog. Note that the system -// appends its own text to the prompt string. Returns NULL on failure. -BASE_EXPORT -AuthorizationRef AuthorizationCreateToRunAsRoot(CFStringRef prompt); - -// Calls straight through to AuthorizationExecuteWithPrivileges. If that -// call succeeds, |pid| will be set to the pid of the executed tool. If the -// pid can't be determined, |pid| will be set to -1. |pid| must not be NULL. -// |pipe| may be NULL, but the tool will always be executed with a pipe in -// order to read the pid from its stdout. -BASE_EXPORT -OSStatus ExecuteWithPrivilegesAndGetPID(AuthorizationRef authorization, - const char* tool_path, - AuthorizationFlags options, - const char** arguments, - FILE** pipe, - pid_t* pid); - -// Calls ExecuteWithPrivilegesAndGetPID, and if that call succeeds, calls -// waitpid() to wait for the process to exit. If waitpid() succeeds, the -// exit status is placed in |exit_status|, otherwise, -1 is stored. -// |exit_status| may be NULL and this function will still wait for the process -// to exit. -BASE_EXPORT -OSStatus ExecuteWithPrivilegesAndWait(AuthorizationRef authorization, - const char* tool_path, - AuthorizationFlags options, - const char** arguments, - FILE** pipe, - int* exit_status); - -} // namespace mac -} // namespace base - -#endif // BASE_MAC_AUTHORIZATION_UTIL_H_ diff --git a/base/mac/authorization_util.mm b/base/mac/authorization_util.mm deleted file mode 100644 index c292589620..0000000000 --- a/base/mac/authorization_util.mm +++ /dev/null @@ -1,187 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "base/mac/authorization_util.h" - -#import -#include - -#include - -#include "base/basictypes.h" -#include "base/logging.h" -#include "base/mac/bundle_locations.h" -#include "base/mac/mac_logging.h" -#import "base/mac/mac_util.h" -#include "base/mac/scoped_authorizationref.h" -#include "base/posix/eintr_wrapper.h" -#include "base/strings/string_number_conversions.h" -#include "base/strings/string_util.h" - -namespace base { -namespace mac { - -AuthorizationRef AuthorizationCreateToRunAsRoot(CFStringRef prompt) { - // Create an empty AuthorizationRef. - ScopedAuthorizationRef authorization; - OSStatus status = AuthorizationCreate(NULL, - kAuthorizationEmptyEnvironment, - kAuthorizationFlagDefaults, - &authorization); - if (status != errAuthorizationSuccess) { - OSSTATUS_LOG(ERROR, status) << "AuthorizationCreate"; - return NULL; - } - - // Specify the "system.privilege.admin" right, which allows - // AuthorizationExecuteWithPrivileges to run commands as root. - AuthorizationItem right_items[] = { - {kAuthorizationRightExecute, 0, NULL, 0} - }; - AuthorizationRights rights = {arraysize(right_items), right_items}; - - // product_logo_32.png is used instead of app.icns because Authorization - // Services can't deal with .icns files. - NSString* icon_path = - [base::mac::FrameworkBundle() pathForResource:@"product_logo_32" - ofType:@"png"]; - const char* icon_path_c = [icon_path fileSystemRepresentation]; - size_t icon_path_length = icon_path_c ? strlen(icon_path_c) : 0; - - // The OS will append " Type an administrator's name and password to allow - // to make changes." - NSString* prompt_ns = base::mac::CFToNSCast(prompt); - const char* prompt_c = [prompt_ns UTF8String]; - size_t prompt_length = prompt_c ? strlen(prompt_c) : 0; - - AuthorizationItem environment_items[] = { - {kAuthorizationEnvironmentIcon, icon_path_length, (void*)icon_path_c, 0}, - {kAuthorizationEnvironmentPrompt, prompt_length, (void*)prompt_c, 0} - }; - - AuthorizationEnvironment environment = {arraysize(environment_items), - environment_items}; - - AuthorizationFlags flags = kAuthorizationFlagDefaults | - kAuthorizationFlagInteractionAllowed | - kAuthorizationFlagExtendRights | - kAuthorizationFlagPreAuthorize; - - status = AuthorizationCopyRights(authorization, - &rights, - &environment, - flags, - NULL); - if (status != errAuthorizationSuccess) { - if (status != errAuthorizationCanceled) { - OSSTATUS_LOG(ERROR, status) << "AuthorizationCopyRights"; - } - return NULL; - } - - return authorization.release(); -} - -OSStatus ExecuteWithPrivilegesAndGetPID(AuthorizationRef authorization, - const char* tool_path, - AuthorizationFlags options, - const char** arguments, - FILE** pipe, - pid_t* pid) { - // pipe may be NULL, but this function needs one. In that case, use a local - // pipe. - FILE* local_pipe; - FILE** pipe_pointer; - if (pipe) { - pipe_pointer = pipe; - } else { - pipe_pointer = &local_pipe; - } - - // AuthorizationExecuteWithPrivileges wants |char* const*| for |arguments|, - // but it doesn't actually modify the arguments, and that type is kind of - // silly and callers probably aren't dealing with that. Put the cast here - // to make things a little easier on callers. - OSStatus status = AuthorizationExecuteWithPrivileges(authorization, - tool_path, - options, - (char* const*)arguments, - pipe_pointer); - if (status != errAuthorizationSuccess) { - return status; - } - - int line_pid = -1; - size_t line_length = 0; - char* line_c = fgetln(*pipe_pointer, &line_length); - if (line_c) { - if (line_length > 0 && line_c[line_length - 1] == '\n') { - // line_c + line_length is the start of the next line if there is one. - // Back up one character. - --line_length; - } - std::string line(line_c, line_length); - if (!base::StringToInt(line, &line_pid)) { - // StringToInt may have set line_pid to something, but if the conversion - // was imperfect, use -1. - LOG(ERROR) << "ExecuteWithPrivilegesAndGetPid: funny line: " << line; - line_pid = -1; - } - } else { - LOG(ERROR) << "ExecuteWithPrivilegesAndGetPid: no line"; - } - - if (!pipe) { - fclose(*pipe_pointer); - } - - if (pid) { - *pid = line_pid; - } - - return status; -} - -OSStatus ExecuteWithPrivilegesAndWait(AuthorizationRef authorization, - const char* tool_path, - AuthorizationFlags options, - const char** arguments, - FILE** pipe, - int* exit_status) { - pid_t pid; - OSStatus status = ExecuteWithPrivilegesAndGetPID(authorization, - tool_path, - options, - arguments, - pipe, - &pid); - if (status != errAuthorizationSuccess) { - return status; - } - - // exit_status may be NULL, but this function needs it. In that case, use a - // local version. - int local_exit_status; - int* exit_status_pointer; - if (exit_status) { - exit_status_pointer = exit_status; - } else { - exit_status_pointer = &local_exit_status; - } - - if (pid != -1) { - pid_t wait_result = HANDLE_EINTR(waitpid(pid, exit_status_pointer, 0)); - if (wait_result != pid) { - PLOG(ERROR) << "waitpid"; - *exit_status_pointer = -1; - } - } else { - *exit_status_pointer = -1; - } - - return status; -} - -} // namespace mac -} // namespace base diff --git a/base/mac/bind_objc_block.h b/base/mac/bind_objc_block.h deleted file mode 100644 index 75da437b5c..0000000000 --- a/base/mac/bind_objc_block.h +++ /dev/null @@ -1,54 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef BASE_MAC_BIND_OBJC_BLOCK_H_ -#define BASE_MAC_BIND_OBJC_BLOCK_H_ - -#include - -#include "base/bind.h" -#include "base/callback_forward.h" -#include "base/mac/scoped_block.h" - -// BindBlock builds a callback from an Objective-C block. Example usages: -// -// Closure closure = BindBlock(^{DoSomething();}); -// Callback callback = BindBlock(^{return 42;}); - -namespace base { - -namespace internal { - -// Helper functions to run the block contained in the parameter. -template -R RunBlock(base::mac::ScopedBlock block) { - R(^extracted_block)() = block.get(); - return extracted_block(); -} - -template -R RunBlock(base::mac::ScopedBlock block, A1 a) { - R(^extracted_block)(A1) = block.get(); - return extracted_block(a); -} - -} // namespace internal - -// Construct a callback with no argument from an objective-C block. -template -base::Callback BindBlock(R(^block)()) { - return base::Bind(&base::internal::RunBlock, - base::mac::ScopedBlock(Block_copy(block))); -} - -// Construct a callback with one argument from an objective-C block. -template -base::Callback BindBlock(R(^block)(A1)) { - return base::Bind(&base::internal::RunBlock, - base::mac::ScopedBlock(Block_copy(block))); -} - -} // namespace base - -#endif // BASE_MAC_BIND_OBJC_BLOCK_H_ diff --git a/base/mac/bind_objc_block_unittest.mm b/base/mac/bind_objc_block_unittest.mm deleted file mode 100644 index 888b3dcff4..0000000000 --- a/base/mac/bind_objc_block_unittest.mm +++ /dev/null @@ -1,54 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#import "base/mac/bind_objc_block.h" - -#include "base/callback.h" -#include "base/bind.h" -#include "base/bind_helpers.h" -#include "testing/gtest/include/gtest/gtest.h" - -namespace { - -TEST(BindObjcBlockTest, TestScopedClosureRunnerExitScope) { - int run_count = 0; - int* ptr = &run_count; - { - base::ScopedClosureRunner runner(base::BindBlock(^{ - (*ptr)++; - })); - EXPECT_EQ(0, run_count); - } - EXPECT_EQ(1, run_count); -} - -TEST(BindObjcBlockTest, TestScopedClosureRunnerRelease) { - int run_count = 0; - int* ptr = &run_count; - base::Closure c; - { - base::ScopedClosureRunner runner(base::BindBlock(^{ - (*ptr)++; - })); - c = runner.Release(); - EXPECT_EQ(0, run_count); - } - EXPECT_EQ(0, run_count); - c.Run(); - EXPECT_EQ(1, run_count); -} - -TEST(BindObjcBlockTest, TestReturnValue) { - const int kReturnValue = 42; - base::Callback c = base::BindBlock(^{return kReturnValue;}); - EXPECT_EQ(kReturnValue, c.Run()); -} - -TEST(BindObjcBlockTest, TestArgument) { - const int kArgument = 42; - base::Callback c = base::BindBlock(^(int a){return a + 1;}); - EXPECT_EQ(kArgument + 1, c.Run(kArgument)); -} - -} // namespace diff --git a/base/mac/bundle_locations.h b/base/mac/bundle_locations.h deleted file mode 100644 index 276290b0e6..0000000000 --- a/base/mac/bundle_locations.h +++ /dev/null @@ -1,67 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef BASE_MAC_BUNDLE_LOCATIONS_H_ -#define BASE_MAC_BUNDLE_LOCATIONS_H_ - -#include "base/base_export.h" -#include "base/files/file_path.h" - -#if defined(__OBJC__) -#import -#else // __OBJC__ -class NSBundle; -class NSString; -#endif // __OBJC__ - -namespace base { - -class FilePath; - -namespace mac { - -// This file provides several functions to explicitly request the various -// component bundles of Chrome. Please use these methods rather than calling -// +[NSBundle mainBundle] or CFBundleGetMainBundle(). -// -// Terminology -// - "Outer Bundle" - This is the main bundle for Chrome; it's what -// +[NSBundle mainBundle] returns when Chrome is launched normally. -// -// - "Main Bundle" - This is the bundle from which Chrome was launched. -// This will be the same as the outer bundle except when Chrome is launched -// via an app shortcut, in which case this will return the app shortcut's -// bundle rather than the main Chrome bundle. -// -// - "Framework Bundle" - This is the bundle corresponding to the Chrome -// framework. -// -// Guidelines for use: -// - To access a resource, the Framework bundle should be used. -// - If the choice is between the Outer or Main bundles then please choose -// carefully. Most often the Outer bundle will be the right choice, but for -// cases such as adding an app to the "launch on startup" list, the Main -// bundle is probably the one to use. - -// Methods for retrieving the various bundles. -BASE_EXPORT NSBundle* MainBundle(); -BASE_EXPORT FilePath MainBundlePath(); -BASE_EXPORT NSBundle* OuterBundle(); -BASE_EXPORT FilePath OuterBundlePath(); -BASE_EXPORT NSBundle* FrameworkBundle(); -BASE_EXPORT FilePath FrameworkBundlePath(); - -// Set the bundle that the preceding functions will return, overriding the -// default values. Restore the default by passing in |nil|. -BASE_EXPORT void SetOverrideOuterBundle(NSBundle* bundle); -BASE_EXPORT void SetOverrideFrameworkBundle(NSBundle* bundle); - -// Same as above but accepting a FilePath argument. -BASE_EXPORT void SetOverrideOuterBundlePath(const FilePath& file_path); -BASE_EXPORT void SetOverrideFrameworkBundlePath(const FilePath& file_path); - -} // namespace mac -} // namespace base - -#endif // BASE_MAC_BUNDLE_LOCATIONS_H_ diff --git a/base/mac/bundle_locations.mm b/base/mac/bundle_locations.mm deleted file mode 100644 index 54021b85ee..0000000000 --- a/base/mac/bundle_locations.mm +++ /dev/null @@ -1,83 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "base/mac/bundle_locations.h" - -#include "base/logging.h" -#include "base/mac/foundation_util.h" -#include "base/strings/sys_string_conversions.h" - -namespace base { -namespace mac { - -// NSBundle isn't threadsafe, all functions in this file must be called on the -// main thread. -static NSBundle* g_override_framework_bundle = nil; -static NSBundle* g_override_outer_bundle = nil; - -NSBundle* MainBundle() { - return [NSBundle mainBundle]; -} - -FilePath MainBundlePath() { - NSBundle* bundle = MainBundle(); - return NSStringToFilePath([bundle bundlePath]); -} - -NSBundle* OuterBundle() { - if (g_override_outer_bundle) - return g_override_outer_bundle; - return [NSBundle mainBundle]; -} - -FilePath OuterBundlePath() { - NSBundle* bundle = OuterBundle(); - return NSStringToFilePath([bundle bundlePath]); -} - -NSBundle* FrameworkBundle() { - if (g_override_framework_bundle) - return g_override_framework_bundle; - return [NSBundle mainBundle]; -} - -FilePath FrameworkBundlePath() { - NSBundle* bundle = FrameworkBundle(); - return NSStringToFilePath([bundle bundlePath]); -} - -static void AssignOverrideBundle(NSBundle* new_bundle, - NSBundle** override_bundle) { - if (new_bundle != *override_bundle) { - [*override_bundle release]; - *override_bundle = [new_bundle retain]; - } -} - -static void AssignOverridePath(const FilePath& file_path, - NSBundle** override_bundle) { - NSString* path = base::SysUTF8ToNSString(file_path.value()); - NSBundle* new_bundle = [NSBundle bundleWithPath:path]; - DCHECK(new_bundle) << "Failed to load the bundle at " << file_path.value(); - AssignOverrideBundle(new_bundle, override_bundle); -} - -void SetOverrideOuterBundle(NSBundle* bundle) { - AssignOverrideBundle(bundle, &g_override_outer_bundle); -} - -void SetOverrideFrameworkBundle(NSBundle* bundle) { - AssignOverrideBundle(bundle, &g_override_framework_bundle); -} - -void SetOverrideOuterBundlePath(const FilePath& file_path) { - AssignOverridePath(file_path, &g_override_outer_bundle); -} - -void SetOverrideFrameworkBundlePath(const FilePath& file_path) { - AssignOverridePath(file_path, &g_override_framework_bundle); -} - -} // namespace mac -} // namespace base diff --git a/base/mac/cocoa_protocols.h b/base/mac/cocoa_protocols.h deleted file mode 100644 index e83fcbb299..0000000000 --- a/base/mac/cocoa_protocols.h +++ /dev/null @@ -1,42 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef BASE_COCOA_PROTOCOLS_MAC_H_ -#define BASE_COCOA_PROTOCOLS_MAC_H_ - -#import - -// GTM also maintinas a list of empty protocols, but only the ones the library -// requires. Augment that below. -#import "third_party/GTM/GTMDefines.h" - -// New Mac OS X SDKs introduce new protocols used for delegates. These -// protocol defintions aren't not present in earlier releases of the Mac OS X -// SDK. In order to support building against the new SDK, which requires -// delegates to conform to these protocols, and earlier SDKs, which do not -// define these protocols at all, this file will provide empty protocol -// definitions when used with earlier SDK versions. - -#define DEFINE_EMPTY_PROTOCOL(p) \ -@protocol p \ -@end - -#if !defined(MAC_OS_X_VERSION_10_7) || \ - MAC_OS_X_VERSION_MAX_ALLOWED < MAC_OS_X_VERSION_10_7 - -DEFINE_EMPTY_PROTOCOL(NSDraggingDestination) -DEFINE_EMPTY_PROTOCOL(ICCameraDeviceDownloadDelegate) - -#endif // MAC_OS_X_VERSION_10_7 - -#if !defined(MAC_OS_X_VERSION_10_8) || \ - MAC_OS_X_VERSION_MAX_ALLOWED < MAC_OS_X_VERSION_10_8 - -DEFINE_EMPTY_PROTOCOL(NSUserNotificationCenterDelegate) - -#endif // MAC_OS_X_VERSION_10_8 - -#undef DEFINE_EMPTY_PROTOCOL - -#endif // BASE_COCOA_PROTOCOLS_MAC_H_ diff --git a/base/mac/foundation_util.h b/base/mac/foundation_util.h deleted file mode 100644 index 447f7bf0d8..0000000000 --- a/base/mac/foundation_util.h +++ /dev/null @@ -1,369 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef BASE_MAC_FOUNDATION_UTIL_H_ -#define BASE_MAC_FOUNDATION_UTIL_H_ - -#include - -#include -#include - -#include "base/base_export.h" -#include "base/logging.h" -#include "base/mac/scoped_cftyperef.h" - -#if defined(__OBJC__) -#import -#else // __OBJC__ -#include -class NSBundle; -class NSString; -#endif // __OBJC__ - -#if defined(OS_IOS) -#include -#else -#include -#endif - -// Adapted from NSObjCRuntime.h NS_ENUM definition (used in Foundation starting -// with the OS X 10.8 SDK and the iOS 6.0 SDK). -#if __has_extension(cxx_strong_enums) && \ - (defined(OS_IOS) || (defined(MAC_OS_X_VERSION_10_8) && \ - MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_8)) -#define CR_FORWARD_ENUM(_type, _name) enum _name : _type _name -#else -#define CR_FORWARD_ENUM(_type, _name) _type _name -#endif - -// Adapted from NSPathUtilities.h and NSObjCRuntime.h. -#if __LP64__ || NS_BUILD_32_LIKE_64 -typedef CR_FORWARD_ENUM(unsigned long, NSSearchPathDirectory); -typedef unsigned long NSSearchPathDomainMask; -#else -typedef CR_FORWARD_ENUM(unsigned int, NSSearchPathDirectory); -typedef unsigned int NSSearchPathDomainMask; -#endif - -typedef struct OpaqueSecTrustRef* SecACLRef; -typedef struct OpaqueSecTrustedApplicationRef* SecTrustedApplicationRef; - -namespace base { - -class FilePath; - -namespace mac { - -// Returns true if the application is running from a bundle -BASE_EXPORT bool AmIBundled(); -BASE_EXPORT void SetOverrideAmIBundled(bool value); - -// Returns true if this process is marked as a "Background only process". -BASE_EXPORT bool IsBackgroundOnlyProcess(); - -// Returns the path to a resource within the framework bundle. -BASE_EXPORT FilePath PathForFrameworkBundleResource(CFStringRef resourceName); - -// Returns the creator code associated with the CFBundleRef at bundle. -OSType CreatorCodeForCFBundleRef(CFBundleRef bundle); - -// Returns the creator code associated with this application, by calling -// CreatorCodeForCFBundleRef for the application's main bundle. If this -// information cannot be determined, returns kUnknownType ('????'). This -// does not respect the override app bundle because it's based on CFBundle -// instead of NSBundle, and because callers probably don't want the override -// app bundle's creator code anyway. -BASE_EXPORT OSType CreatorCodeForApplication(); - -// Searches for directories for the given key in only the given |domain_mask|. -// If found, fills result (which must always be non-NULL) with the -// first found directory and returns true. Otherwise, returns false. -BASE_EXPORT bool GetSearchPathDirectory(NSSearchPathDirectory directory, - NSSearchPathDomainMask domain_mask, - FilePath* result); - -// Searches for directories for the given key in only the local domain. -// If found, fills result (which must always be non-NULL) with the -// first found directory and returns true. Otherwise, returns false. -BASE_EXPORT bool GetLocalDirectory(NSSearchPathDirectory directory, - FilePath* result); - -// Searches for directories for the given key in only the user domain. -// If found, fills result (which must always be non-NULL) with the -// first found directory and returns true. Otherwise, returns false. -BASE_EXPORT bool GetUserDirectory(NSSearchPathDirectory directory, - FilePath* result); - -// Returns the ~/Library directory. -BASE_EXPORT FilePath GetUserLibraryPath(); - -// Takes a path to an (executable) binary and tries to provide the path to an -// application bundle containing it. It takes the outermost bundle that it can -// find (so for "/Foo/Bar.app/.../Baz.app/..." it produces "/Foo/Bar.app"). -// |exec_name| - path to the binary -// returns - path to the application bundle, or empty on error -BASE_EXPORT FilePath GetAppBundlePath(const FilePath& exec_name); - -#define TYPE_NAME_FOR_CF_TYPE_DECL(TypeCF) \ -BASE_EXPORT std::string TypeNameForCFType(TypeCF##Ref); - -TYPE_NAME_FOR_CF_TYPE_DECL(CFArray); -TYPE_NAME_FOR_CF_TYPE_DECL(CFBag); -TYPE_NAME_FOR_CF_TYPE_DECL(CFBoolean); -TYPE_NAME_FOR_CF_TYPE_DECL(CFData); -TYPE_NAME_FOR_CF_TYPE_DECL(CFDate); -TYPE_NAME_FOR_CF_TYPE_DECL(CFDictionary); -TYPE_NAME_FOR_CF_TYPE_DECL(CFNull); -TYPE_NAME_FOR_CF_TYPE_DECL(CFNumber); -TYPE_NAME_FOR_CF_TYPE_DECL(CFSet); -TYPE_NAME_FOR_CF_TYPE_DECL(CFString); -TYPE_NAME_FOR_CF_TYPE_DECL(CFURL); -TYPE_NAME_FOR_CF_TYPE_DECL(CFUUID); - -TYPE_NAME_FOR_CF_TYPE_DECL(CGColor); - -TYPE_NAME_FOR_CF_TYPE_DECL(CTFont); -TYPE_NAME_FOR_CF_TYPE_DECL(CTRun); - -#undef TYPE_NAME_FOR_CF_TYPE_DECL - -// Retain/release calls for memory management in C++. -BASE_EXPORT void NSObjectRetain(void* obj); -BASE_EXPORT void NSObjectRelease(void* obj); - -// CFTypeRefToNSObjectAutorelease transfers ownership of a Core Foundation -// object (one derived from CFTypeRef) to the Foundation memory management -// system. In a traditional managed-memory environment, cf_object is -// autoreleased and returned as an NSObject. In a garbage-collected -// environment, cf_object is marked as eligible for garbage collection. -// -// This function should only be used to convert a concrete CFTypeRef type to -// its equivalent "toll-free bridged" NSObject subclass, for example, -// converting a CFStringRef to NSString. -// -// By calling this function, callers relinquish any ownership claim to -// cf_object. In a managed-memory environment, the object's ownership will be -// managed by the innermost NSAutoreleasePool, so after this function returns, -// callers should not assume that cf_object is valid any longer than the -// returned NSObject. -// -// Returns an id, typed here for C++'s sake as a void*. -BASE_EXPORT void* CFTypeRefToNSObjectAutorelease(CFTypeRef cf_object); - -// Returns the base bundle ID, which can be set by SetBaseBundleID but -// defaults to a reasonable string. This never returns NULL. BaseBundleID -// returns a pointer to static storage that must not be freed. -BASE_EXPORT const char* BaseBundleID(); - -// Sets the base bundle ID to override the default. The implementation will -// make its own copy of new_base_bundle_id. -BASE_EXPORT void SetBaseBundleID(const char* new_base_bundle_id); - -} // namespace mac -} // namespace base - -#if !defined(__OBJC__) -#define OBJC_CPP_CLASS_DECL(x) class x; -#else // __OBJC__ -#define OBJC_CPP_CLASS_DECL(x) -#endif // __OBJC__ - -// Convert toll-free bridged CFTypes to NSTypes and vice-versa. This does not -// autorelease |cf_val|. This is useful for the case where there is a CFType in -// a call that expects an NSType and the compiler is complaining about const -// casting problems. -// The calls are used like this: -// NSString *foo = CFToNSCast(CFSTR("Hello")); -// CFStringRef foo2 = NSToCFCast(@"Hello"); -// The macro magic below is to enforce safe casting. It could possibly have -// been done using template function specialization, but template function -// specialization doesn't always work intuitively, -// (http://www.gotw.ca/publications/mill17.htm) so the trusty combination -// of macros and function overloading is used instead. - -#define CF_TO_NS_CAST_DECL(TypeCF, TypeNS) \ -OBJC_CPP_CLASS_DECL(TypeNS) \ -\ -namespace base { \ -namespace mac { \ -BASE_EXPORT TypeNS* CFToNSCast(TypeCF##Ref cf_val); \ -BASE_EXPORT TypeCF##Ref NSToCFCast(TypeNS* ns_val); \ -} \ -} - -#define CF_TO_NS_MUTABLE_CAST_DECL(name) \ -CF_TO_NS_CAST_DECL(CF##name, NS##name) \ -OBJC_CPP_CLASS_DECL(NSMutable##name) \ -\ -namespace base { \ -namespace mac { \ -BASE_EXPORT NSMutable##name* CFToNSCast(CFMutable##name##Ref cf_val); \ -BASE_EXPORT CFMutable##name##Ref NSToCFCast(NSMutable##name* ns_val); \ -} \ -} - -// List of toll-free bridged types taken from: -// http://www.cocoadev.com/index.pl?TollFreeBridged - -CF_TO_NS_MUTABLE_CAST_DECL(Array); -CF_TO_NS_MUTABLE_CAST_DECL(AttributedString); -CF_TO_NS_CAST_DECL(CFCalendar, NSCalendar); -CF_TO_NS_MUTABLE_CAST_DECL(CharacterSet); -CF_TO_NS_MUTABLE_CAST_DECL(Data); -CF_TO_NS_CAST_DECL(CFDate, NSDate); -CF_TO_NS_MUTABLE_CAST_DECL(Dictionary); -CF_TO_NS_CAST_DECL(CFError, NSError); -CF_TO_NS_CAST_DECL(CFLocale, NSLocale); -CF_TO_NS_CAST_DECL(CFNumber, NSNumber); -CF_TO_NS_CAST_DECL(CFRunLoopTimer, NSTimer); -CF_TO_NS_CAST_DECL(CFTimeZone, NSTimeZone); -CF_TO_NS_MUTABLE_CAST_DECL(Set); -CF_TO_NS_CAST_DECL(CFReadStream, NSInputStream); -CF_TO_NS_CAST_DECL(CFWriteStream, NSOutputStream); -CF_TO_NS_MUTABLE_CAST_DECL(String); -CF_TO_NS_CAST_DECL(CFURL, NSURL); - -#undef CF_TO_NS_CAST_DECL -#undef CF_TO_NS_MUTABLE_CAST_DECL -#undef OBJC_CPP_CLASS_DECL - -namespace base { -namespace mac { - -// CFCast<>() and CFCastStrict<>() cast a basic CFTypeRef to a more -// specific CoreFoundation type. The compatibility of the passed -// object is found by comparing its opaque type against the -// requested type identifier. If the supplied object is not -// compatible with the requested return type, CFCast<>() returns -// NULL and CFCastStrict<>() will DCHECK. Providing a NULL pointer -// to either variant results in NULL being returned without -// triggering any DCHECK. -// -// Example usage: -// CFNumberRef some_number = base::mac::CFCast( -// CFArrayGetValueAtIndex(array, index)); -// -// CFTypeRef hello = CFSTR("hello world"); -// CFStringRef some_string = base::mac::CFCastStrict(hello); - -template -T CFCast(const CFTypeRef& cf_val); - -template -T CFCastStrict(const CFTypeRef& cf_val); - -#define CF_CAST_DECL(TypeCF) \ -template<> BASE_EXPORT TypeCF##Ref \ -CFCast(const CFTypeRef& cf_val);\ -\ -template<> BASE_EXPORT TypeCF##Ref \ -CFCastStrict(const CFTypeRef& cf_val); - -CF_CAST_DECL(CFArray); -CF_CAST_DECL(CFBag); -CF_CAST_DECL(CFBoolean); -CF_CAST_DECL(CFData); -CF_CAST_DECL(CFDate); -CF_CAST_DECL(CFDictionary); -CF_CAST_DECL(CFNull); -CF_CAST_DECL(CFNumber); -CF_CAST_DECL(CFSet); -CF_CAST_DECL(CFString); -CF_CAST_DECL(CFURL); -CF_CAST_DECL(CFUUID); - -CF_CAST_DECL(CGColor); - -CF_CAST_DECL(CTFont); -CF_CAST_DECL(CTRun); - -CF_CAST_DECL(SecACL); -CF_CAST_DECL(SecTrustedApplication); - -#undef CF_CAST_DECL - -#if defined(__OBJC__) - -// ObjCCast<>() and ObjCCastStrict<>() cast a basic id to a more -// specific (NSObject-derived) type. The compatibility of the passed -// object is found by checking if it's a kind of the requested type -// identifier. If the supplied object is not compatible with the -// requested return type, ObjCCast<>() returns nil and -// ObjCCastStrict<>() will DCHECK. Providing a nil pointer to either -// variant results in nil being returned without triggering any DCHECK. -// -// The strict variant is useful when retrieving a value from a -// collection which only has values of a specific type, e.g. an -// NSArray of NSStrings. The non-strict variant is useful when -// retrieving values from data that you can't fully control. For -// example, a plist read from disk may be beyond your exclusive -// control, so you'd only want to check that the values you retrieve -// from it are of the expected types, but not crash if they're not. -// -// Example usage: -// NSString* version = base::mac::ObjCCast( -// [bundle objectForInfoDictionaryKey:@"CFBundleShortVersionString"]); -// -// NSString* str = base::mac::ObjCCastStrict( -// [ns_arr_of_ns_strs objectAtIndex:0]); -template -T* ObjCCast(id objc_val) { - if ([objc_val isKindOfClass:[T class]]) { - return reinterpret_cast(objc_val); - } - return nil; -} - -template -T* ObjCCastStrict(id objc_val) { - T* rv = ObjCCast(objc_val); - DCHECK(objc_val == nil || rv); - return rv; -} - -#endif // defined(__OBJC__) - -// Helper function for GetValueFromDictionary to create the error message -// that appears when a type mismatch is encountered. -BASE_EXPORT std::string GetValueFromDictionaryErrorMessage( - CFStringRef key, const std::string& expected_type, CFTypeRef value); - -// Utility function to pull out a value from a dictionary, check its type, and -// return it. Returns NULL if the key is not present or of the wrong type. -template -T GetValueFromDictionary(CFDictionaryRef dict, CFStringRef key) { - CFTypeRef value = CFDictionaryGetValue(dict, key); - T value_specific = CFCast(value); - - if (value && !value_specific) { - std::string expected_type = TypeNameForCFType(value_specific); - DLOG(WARNING) << GetValueFromDictionaryErrorMessage(key, - expected_type, - value); - } - - return value_specific; -} - -// Converts |path| to an autoreleased NSString. Returns nil if |path| is empty. -BASE_EXPORT NSString* FilePathToNSString(const FilePath& path); - -// Converts |str| to a FilePath. Returns an empty path if |str| is nil. -BASE_EXPORT FilePath NSStringToFilePath(NSString* str); - -} // namespace mac -} // namespace base - -// Stream operations for CFTypes. They can be used with NSTypes as well -// by using the NSToCFCast methods above. -// e.g. LOG(INFO) << base::mac::NSToCFCast(@"foo"); -// Operator << can not be overloaded for ObjectiveC types as the compiler -// can not distinguish between overloads for id with overloads for void*. -BASE_EXPORT extern std::ostream& operator<<(std::ostream& o, - const CFErrorRef err); -BASE_EXPORT extern std::ostream& operator<<(std::ostream& o, - const CFStringRef str); - -#endif // BASE_MAC_FOUNDATION_UTIL_H_ diff --git a/base/mac/foundation_util.mm b/base/mac/foundation_util.mm deleted file mode 100644 index 1897b6f784..0000000000 --- a/base/mac/foundation_util.mm +++ /dev/null @@ -1,400 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "base/mac/foundation_util.h" - -#include -#include - -#include "base/files/file_path.h" -#include "base/logging.h" -#include "base/mac/bundle_locations.h" -#include "base/mac/mac_logging.h" -#include "base/strings/sys_string_conversions.h" - -#if !defined(OS_IOS) -extern "C" { -CFTypeID SecACLGetTypeID(); -CFTypeID SecTrustedApplicationGetTypeID(); -} // extern "C" -#endif - -namespace base { -namespace mac { - -static bool g_override_am_i_bundled = false; -static bool g_override_am_i_bundled_value = false; - -// Adapted from http://developer.apple.com/carbon/tipsandtricks.html#AmIBundled -static bool UncachedAmIBundled() { -#if defined(OS_IOS) - // All apps are bundled on iOS - return true; -#else - if (g_override_am_i_bundled) - return g_override_am_i_bundled_value; - - ProcessSerialNumber psn = {0, kCurrentProcess}; - - FSRef fsref; - OSStatus pbErr; - if ((pbErr = GetProcessBundleLocation(&psn, &fsref)) != noErr) { - OSSTATUS_DLOG(ERROR, pbErr) << "GetProcessBundleLocation failed"; - return false; - } - - FSCatalogInfo info; - OSErr fsErr; - if ((fsErr = FSGetCatalogInfo(&fsref, kFSCatInfoNodeFlags, &info, - NULL, NULL, NULL)) != noErr) { - OSSTATUS_DLOG(ERROR, fsErr) << "FSGetCatalogInfo failed"; - return false; - } - - return info.nodeFlags & kFSNodeIsDirectoryMask; -#endif -} - -bool AmIBundled() { - // If the return value is not cached, this function will return different - // values depending on when it's called. This confuses some client code, see - // http://crbug.com/63183 . - static bool result = UncachedAmIBundled(); - DCHECK_EQ(result, UncachedAmIBundled()) - << "The return value of AmIBundled() changed. This will confuse tests. " - << "Call SetAmIBundled() override manually if your test binary " - << "delay-loads the framework."; - return result; -} - -void SetOverrideAmIBundled(bool value) { -#if defined(OS_IOS) - // It doesn't make sense not to be bundled on iOS. - if (!value) - NOTREACHED(); -#endif - g_override_am_i_bundled = true; - g_override_am_i_bundled_value = value; -} - -bool IsBackgroundOnlyProcess() { - // This function really does want to examine NSBundle's idea of the main - // bundle dictionary. It needs to look at the actual running .app's - // Info.plist to access its LSUIElement property. - NSDictionary* info_dictionary = [base::mac::MainBundle() infoDictionary]; - return [[info_dictionary objectForKey:@"LSUIElement"] boolValue] != NO; -} - -FilePath PathForFrameworkBundleResource(CFStringRef resourceName) { - NSBundle* bundle = base::mac::FrameworkBundle(); - NSString* resourcePath = [bundle pathForResource:(NSString*)resourceName - ofType:nil]; - return NSStringToFilePath(resourcePath); -} - -OSType CreatorCodeForCFBundleRef(CFBundleRef bundle) { - OSType creator = kUnknownType; - CFBundleGetPackageInfo(bundle, NULL, &creator); - return creator; -} - -OSType CreatorCodeForApplication() { - CFBundleRef bundle = CFBundleGetMainBundle(); - if (!bundle) - return kUnknownType; - - return CreatorCodeForCFBundleRef(bundle); -} - -bool GetSearchPathDirectory(NSSearchPathDirectory directory, - NSSearchPathDomainMask domain_mask, - FilePath* result) { - DCHECK(result); - NSArray* dirs = - NSSearchPathForDirectoriesInDomains(directory, domain_mask, YES); - if ([dirs count] < 1) { - return false; - } - *result = NSStringToFilePath([dirs objectAtIndex:0]); - return true; -} - -bool GetLocalDirectory(NSSearchPathDirectory directory, FilePath* result) { - return GetSearchPathDirectory(directory, NSLocalDomainMask, result); -} - -bool GetUserDirectory(NSSearchPathDirectory directory, FilePath* result) { - return GetSearchPathDirectory(directory, NSUserDomainMask, result); -} - -FilePath GetUserLibraryPath() { - FilePath user_library_path; - if (!GetUserDirectory(NSLibraryDirectory, &user_library_path)) { - DLOG(WARNING) << "Could not get user library path"; - } - return user_library_path; -} - -// Takes a path to an (executable) binary and tries to provide the path to an -// application bundle containing it. It takes the outermost bundle that it can -// find (so for "/Foo/Bar.app/.../Baz.app/..." it produces "/Foo/Bar.app"). -// |exec_name| - path to the binary -// returns - path to the application bundle, or empty on error -FilePath GetAppBundlePath(const FilePath& exec_name) { - const char kExt[] = ".app"; - const size_t kExtLength = arraysize(kExt) - 1; - - // Split the path into components. - std::vector components; - exec_name.GetComponents(&components); - - // It's an error if we don't get any components. - if (!components.size()) - return FilePath(); - - // Don't prepend '/' to the first component. - std::vector::const_iterator it = components.begin(); - std::string bundle_name = *it; - DCHECK_GT(it->length(), 0U); - // If the first component ends in ".app", we're already done. - if (it->length() > kExtLength && - !it->compare(it->length() - kExtLength, kExtLength, kExt, kExtLength)) - return FilePath(bundle_name); - - // The first component may be "/" or "//", etc. Only append '/' if it doesn't - // already end in '/'. - if (bundle_name[bundle_name.length() - 1] != '/') - bundle_name += '/'; - - // Go through the remaining components. - for (++it; it != components.end(); ++it) { - DCHECK_GT(it->length(), 0U); - - bundle_name += *it; - - // If the current component ends in ".app", we're done. - if (it->length() > kExtLength && - !it->compare(it->length() - kExtLength, kExtLength, kExt, kExtLength)) - return FilePath(bundle_name); - - // Separate this component from the next one. - bundle_name += '/'; - } - - return FilePath(); -} - -#define TYPE_NAME_FOR_CF_TYPE_DEFN(TypeCF) \ -std::string TypeNameForCFType(TypeCF##Ref) { \ - return #TypeCF; \ -} - -TYPE_NAME_FOR_CF_TYPE_DEFN(CFArray); -TYPE_NAME_FOR_CF_TYPE_DEFN(CFBag); -TYPE_NAME_FOR_CF_TYPE_DEFN(CFBoolean); -TYPE_NAME_FOR_CF_TYPE_DEFN(CFData); -TYPE_NAME_FOR_CF_TYPE_DEFN(CFDate); -TYPE_NAME_FOR_CF_TYPE_DEFN(CFDictionary); -TYPE_NAME_FOR_CF_TYPE_DEFN(CFNull); -TYPE_NAME_FOR_CF_TYPE_DEFN(CFNumber); -TYPE_NAME_FOR_CF_TYPE_DEFN(CFSet); -TYPE_NAME_FOR_CF_TYPE_DEFN(CFString); -TYPE_NAME_FOR_CF_TYPE_DEFN(CFURL); -TYPE_NAME_FOR_CF_TYPE_DEFN(CFUUID); - -TYPE_NAME_FOR_CF_TYPE_DEFN(CGColor); - -TYPE_NAME_FOR_CF_TYPE_DEFN(CTFont); -TYPE_NAME_FOR_CF_TYPE_DEFN(CTRun); - -#undef TYPE_NAME_FOR_CF_TYPE_DEFN - -void NSObjectRetain(void* obj) { - id nsobj = static_cast >(obj); - [nsobj retain]; -} - -void NSObjectRelease(void* obj) { - id nsobj = static_cast >(obj); - [nsobj release]; -} - -void* CFTypeRefToNSObjectAutorelease(CFTypeRef cf_object) { - // When GC is on, NSMakeCollectable marks cf_object for GC and autorelease - // is a no-op. - // - // In the traditional GC-less environment, NSMakeCollectable is a no-op, - // and cf_object is autoreleased, balancing out the caller's ownership claim. - // - // NSMakeCollectable returns nil when used on a NULL object. - return [NSMakeCollectable(cf_object) autorelease]; -} - -static const char* base_bundle_id; - -const char* BaseBundleID() { - if (base_bundle_id) { - return base_bundle_id; - } - -#if defined(GOOGLE_CHROME_BUILD) - return "com.google.Chrome"; -#else - return "org.chromium.Chromium"; -#endif -} - -void SetBaseBundleID(const char* new_base_bundle_id) { - if (new_base_bundle_id != base_bundle_id) { - free((void*)base_bundle_id); - base_bundle_id = new_base_bundle_id ? strdup(new_base_bundle_id) : NULL; - } -} - -// Definitions for the corresponding CF_TO_NS_CAST_DECL macros in -// foundation_util.h. -#define CF_TO_NS_CAST_DEFN(TypeCF, TypeNS) \ -\ -TypeNS* CFToNSCast(TypeCF##Ref cf_val) { \ - DCHECK(!cf_val || TypeCF##GetTypeID() == CFGetTypeID(cf_val)); \ - TypeNS* ns_val = \ - const_cast(reinterpret_cast(cf_val)); \ - return ns_val; \ -} \ -\ -TypeCF##Ref NSToCFCast(TypeNS* ns_val) { \ - TypeCF##Ref cf_val = reinterpret_cast(ns_val); \ - DCHECK(!cf_val || TypeCF##GetTypeID() == CFGetTypeID(cf_val)); \ - return cf_val; \ -} - -#define CF_TO_NS_MUTABLE_CAST_DEFN(name) \ -CF_TO_NS_CAST_DEFN(CF##name, NS##name) \ -\ -NSMutable##name* CFToNSCast(CFMutable##name##Ref cf_val) { \ - DCHECK(!cf_val || CF##name##GetTypeID() == CFGetTypeID(cf_val)); \ - NSMutable##name* ns_val = reinterpret_cast(cf_val); \ - return ns_val; \ -} \ -\ -CFMutable##name##Ref NSToCFCast(NSMutable##name* ns_val) { \ - CFMutable##name##Ref cf_val = \ - reinterpret_cast(ns_val); \ - DCHECK(!cf_val || CF##name##GetTypeID() == CFGetTypeID(cf_val)); \ - return cf_val; \ -} - -CF_TO_NS_MUTABLE_CAST_DEFN(Array); -CF_TO_NS_MUTABLE_CAST_DEFN(AttributedString); -CF_TO_NS_CAST_DEFN(CFCalendar, NSCalendar); -CF_TO_NS_MUTABLE_CAST_DEFN(CharacterSet); -CF_TO_NS_MUTABLE_CAST_DEFN(Data); -CF_TO_NS_CAST_DEFN(CFDate, NSDate); -CF_TO_NS_MUTABLE_CAST_DEFN(Dictionary); -CF_TO_NS_CAST_DEFN(CFError, NSError); -CF_TO_NS_CAST_DEFN(CFLocale, NSLocale); -CF_TO_NS_CAST_DEFN(CFNumber, NSNumber); -CF_TO_NS_CAST_DEFN(CFRunLoopTimer, NSTimer); -CF_TO_NS_CAST_DEFN(CFTimeZone, NSTimeZone); -CF_TO_NS_MUTABLE_CAST_DEFN(Set); -CF_TO_NS_CAST_DEFN(CFReadStream, NSInputStream); -CF_TO_NS_CAST_DEFN(CFWriteStream, NSOutputStream); -CF_TO_NS_MUTABLE_CAST_DEFN(String); -CF_TO_NS_CAST_DEFN(CFURL, NSURL); - -#undef CF_TO_NS_CAST_DEFN -#undef CF_TO_NS_MUTABLE_CAST_DEFN - -#define CF_CAST_DEFN(TypeCF) \ -template<> TypeCF##Ref \ -CFCast(const CFTypeRef& cf_val) { \ - if (cf_val == NULL) { \ - return NULL; \ - } \ - if (CFGetTypeID(cf_val) == TypeCF##GetTypeID()) { \ - return (TypeCF##Ref)(cf_val); \ - } \ - return NULL; \ -} \ -\ -template<> TypeCF##Ref \ -CFCastStrict(const CFTypeRef& cf_val) { \ - TypeCF##Ref rv = CFCast(cf_val); \ - DCHECK(cf_val == NULL || rv); \ - return rv; \ -} - -CF_CAST_DEFN(CFArray); -CF_CAST_DEFN(CFBag); -CF_CAST_DEFN(CFBoolean); -CF_CAST_DEFN(CFData); -CF_CAST_DEFN(CFDate); -CF_CAST_DEFN(CFDictionary); -CF_CAST_DEFN(CFNull); -CF_CAST_DEFN(CFNumber); -CF_CAST_DEFN(CFSet); -CF_CAST_DEFN(CFString); -CF_CAST_DEFN(CFURL); -CF_CAST_DEFN(CFUUID); - -CF_CAST_DEFN(CGColor); - -CF_CAST_DEFN(CTFont); -CF_CAST_DEFN(CTRun); - -#if !defined(OS_IOS) -CF_CAST_DEFN(SecACL); -CF_CAST_DEFN(SecTrustedApplication); -#endif - -#undef CF_CAST_DEFN - -std::string GetValueFromDictionaryErrorMessage( - CFStringRef key, const std::string& expected_type, CFTypeRef value) { - ScopedCFTypeRef actual_type_ref( - CFCopyTypeIDDescription(CFGetTypeID(value))); - return "Expected value for key " + - base::SysCFStringRefToUTF8(key) + - " to be " + - expected_type + - " but it was " + - base::SysCFStringRefToUTF8(actual_type_ref) + - " instead"; -} - -NSString* FilePathToNSString(const FilePath& path) { - if (path.empty()) - return nil; - return [NSString stringWithUTF8String:path.value().c_str()]; -} - -FilePath NSStringToFilePath(NSString* str) { - if (![str length]) - return FilePath(); - return FilePath([str fileSystemRepresentation]); -} - -} // namespace mac -} // namespace base - -std::ostream& operator<<(std::ostream& o, const CFStringRef string) { - return o << base::SysCFStringRefToUTF8(string); -} - -std::ostream& operator<<(std::ostream& o, const CFErrorRef err) { - base::ScopedCFTypeRef desc(CFErrorCopyDescription(err)); - base::ScopedCFTypeRef user_info(CFErrorCopyUserInfo(err)); - CFStringRef errorDesc = NULL; - if (user_info.get()) { - errorDesc = reinterpret_cast( - CFDictionaryGetValue(user_info.get(), kCFErrorDescriptionKey)); - } - o << "Code: " << CFErrorGetCode(err) - << " Domain: " << CFErrorGetDomain(err) - << " Desc: " << desc.get(); - if(errorDesc) { - o << "(" << errorDesc << ")"; - } - return o; -} diff --git a/base/mac/foundation_util_unittest.mm b/base/mac/foundation_util_unittest.mm deleted file mode 100644 index fc7dd099c5..0000000000 --- a/base/mac/foundation_util_unittest.mm +++ /dev/null @@ -1,319 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "base/mac/foundation_util.h" - -#include "base/basictypes.h" -#include "base/files/file_path.h" -#include "base/mac/scoped_cftyperef.h" -#include "base/mac/scoped_nsautorelease_pool.h" -#include "testing/gtest/include/gtest/gtest.h" -#import "testing/gtest_mac.h" - -namespace base { -namespace mac { - -TEST(FoundationUtilTest, CFCast) { - // Build out the CF types to be tested as empty containers. - ScopedCFTypeRef test_array( - CFArrayCreate(NULL, NULL, 0, &kCFTypeArrayCallBacks)); - ScopedCFTypeRef test_array_mutable( - CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks)); - ScopedCFTypeRef test_bag( - CFBagCreate(NULL, NULL, 0, &kCFTypeBagCallBacks)); - ScopedCFTypeRef test_bag_mutable( - CFBagCreateMutable(NULL, 0, &kCFTypeBagCallBacks)); - CFTypeRef test_bool = kCFBooleanTrue; - ScopedCFTypeRef test_data( - CFDataCreate(NULL, NULL, 0)); - ScopedCFTypeRef test_data_mutable( - CFDataCreateMutable(NULL, 0)); - ScopedCFTypeRef test_date( - CFDateCreate(NULL, 0)); - ScopedCFTypeRef test_dict( - CFDictionaryCreate(NULL, NULL, NULL, 0, - &kCFCopyStringDictionaryKeyCallBacks, - &kCFTypeDictionaryValueCallBacks)); - ScopedCFTypeRef test_dict_mutable( - CFDictionaryCreateMutable(NULL, 0, - &kCFCopyStringDictionaryKeyCallBacks, - &kCFTypeDictionaryValueCallBacks)); - int int_val = 256; - ScopedCFTypeRef test_number( - CFNumberCreate(NULL, kCFNumberIntType, &int_val)); - CFTypeRef test_null = kCFNull; - ScopedCFTypeRef test_set( - CFSetCreate(NULL, NULL, 0, &kCFTypeSetCallBacks)); - ScopedCFTypeRef test_set_mutable( - CFSetCreateMutable(NULL, 0, &kCFTypeSetCallBacks)); - ScopedCFTypeRef test_str( - CFStringCreateWithBytes(NULL, NULL, 0, kCFStringEncodingASCII, false)); - CFTypeRef test_str_const = CFSTR("hello"); - ScopedCFTypeRef test_str_mutable(CFStringCreateMutable(NULL, 0)); - - // Make sure the allocations of CF types are good. - EXPECT_TRUE(test_array); - EXPECT_TRUE(test_array_mutable); - EXPECT_TRUE(test_bag); - EXPECT_TRUE(test_bag_mutable); - EXPECT_TRUE(test_bool); - EXPECT_TRUE(test_data); - EXPECT_TRUE(test_data_mutable); - EXPECT_TRUE(test_date); - EXPECT_TRUE(test_dict); - EXPECT_TRUE(test_dict_mutable); - EXPECT_TRUE(test_number); - EXPECT_TRUE(test_null); - EXPECT_TRUE(test_set); - EXPECT_TRUE(test_set_mutable); - EXPECT_TRUE(test_str); - EXPECT_TRUE(test_str_const); - EXPECT_TRUE(test_str_mutable); - - // Casting the CFTypeRef objects correctly provides the same pointer. - EXPECT_EQ(test_array, CFCast(test_array)); - EXPECT_EQ(test_array_mutable, CFCast(test_array_mutable)); - EXPECT_EQ(test_bag, CFCast(test_bag)); - EXPECT_EQ(test_bag_mutable, CFCast(test_bag_mutable)); - EXPECT_EQ(test_bool, CFCast(test_bool)); - EXPECT_EQ(test_data, CFCast(test_data)); - EXPECT_EQ(test_data_mutable, CFCast(test_data_mutable)); - EXPECT_EQ(test_date, CFCast(test_date)); - EXPECT_EQ(test_dict, CFCast(test_dict)); - EXPECT_EQ(test_dict_mutable, CFCast(test_dict_mutable)); - EXPECT_EQ(test_number, CFCast(test_number)); - EXPECT_EQ(test_null, CFCast(test_null)); - EXPECT_EQ(test_set, CFCast(test_set)); - EXPECT_EQ(test_set_mutable, CFCast(test_set_mutable)); - EXPECT_EQ(test_str, CFCast(test_str)); - EXPECT_EQ(test_str_const, CFCast(test_str_const)); - EXPECT_EQ(test_str_mutable, CFCast(test_str_mutable)); - - // When given an incorrect CF cast, provide NULL. - EXPECT_FALSE(CFCast(test_array)); - EXPECT_FALSE(CFCast(test_array_mutable)); - EXPECT_FALSE(CFCast(test_bag)); - EXPECT_FALSE(CFCast(test_bag_mutable)); - EXPECT_FALSE(CFCast(test_bool)); - EXPECT_FALSE(CFCast(test_data)); - EXPECT_FALSE(CFCast(test_data_mutable)); - EXPECT_FALSE(CFCast(test_date)); - EXPECT_FALSE(CFCast(test_dict)); - EXPECT_FALSE(CFCast(test_dict_mutable)); - EXPECT_FALSE(CFCast(test_number)); - EXPECT_FALSE(CFCast(test_null)); - EXPECT_FALSE(CFCast(test_set)); - EXPECT_FALSE(CFCast(test_set_mutable)); - EXPECT_FALSE(CFCast(test_str)); - EXPECT_FALSE(CFCast(test_str_const)); - EXPECT_FALSE(CFCast(test_str_mutable)); - - // Giving a NULL provides a NULL. - EXPECT_FALSE(CFCast(NULL)); - EXPECT_FALSE(CFCast(NULL)); - EXPECT_FALSE(CFCast(NULL)); - EXPECT_FALSE(CFCast(NULL)); - EXPECT_FALSE(CFCast(NULL)); - EXPECT_FALSE(CFCast(NULL)); - EXPECT_FALSE(CFCast(NULL)); - EXPECT_FALSE(CFCast(NULL)); - EXPECT_FALSE(CFCast(NULL)); - EXPECT_FALSE(CFCast(NULL)); - - // CFCastStrict: correct cast results in correct pointer being returned. - EXPECT_EQ(test_array, CFCastStrict(test_array)); - EXPECT_EQ(test_array_mutable, CFCastStrict(test_array_mutable)); - EXPECT_EQ(test_bag, CFCastStrict(test_bag)); - EXPECT_EQ(test_bag_mutable, CFCastStrict(test_bag_mutable)); - EXPECT_EQ(test_bool, CFCastStrict(test_bool)); - EXPECT_EQ(test_data, CFCastStrict(test_data)); - EXPECT_EQ(test_data_mutable, CFCastStrict(test_data_mutable)); - EXPECT_EQ(test_date, CFCastStrict(test_date)); - EXPECT_EQ(test_dict, CFCastStrict(test_dict)); - EXPECT_EQ(test_dict_mutable, - CFCastStrict(test_dict_mutable)); - EXPECT_EQ(test_number, CFCastStrict(test_number)); - EXPECT_EQ(test_null, CFCastStrict(test_null)); - EXPECT_EQ(test_set, CFCastStrict(test_set)); - EXPECT_EQ(test_set_mutable, CFCastStrict(test_set_mutable)); - EXPECT_EQ(test_str, CFCastStrict(test_str)); - EXPECT_EQ(test_str_const, CFCastStrict(test_str_const)); - EXPECT_EQ(test_str_mutable, CFCastStrict(test_str_mutable)); - - // CFCastStrict: Giving a NULL provides a NULL. - EXPECT_FALSE(CFCastStrict(NULL)); - EXPECT_FALSE(CFCastStrict(NULL)); - EXPECT_FALSE(CFCastStrict(NULL)); - EXPECT_FALSE(CFCastStrict(NULL)); - EXPECT_FALSE(CFCastStrict(NULL)); - EXPECT_FALSE(CFCastStrict(NULL)); - EXPECT_FALSE(CFCastStrict(NULL)); - EXPECT_FALSE(CFCastStrict(NULL)); - EXPECT_FALSE(CFCastStrict(NULL)); - EXPECT_FALSE(CFCastStrict(NULL)); -} - -TEST(FoundationUtilTest, ObjCCast) { - ScopedNSAutoreleasePool pool; - - id test_array = [NSArray array]; - id test_array_mutable = [NSMutableArray array]; - id test_data = [NSData data]; - id test_data_mutable = [NSMutableData dataWithCapacity:10]; - id test_date = [NSDate date]; - id test_dict = - [NSDictionary dictionaryWithObject:[NSNumber numberWithInt:42] - forKey:@"meaning"]; - id test_dict_mutable = [NSMutableDictionary dictionaryWithCapacity:10]; - id test_number = [NSNumber numberWithInt:42]; - id test_null = [NSNull null]; - id test_set = [NSSet setWithObject:@"string object"]; - id test_set_mutable = [NSMutableSet setWithCapacity:10]; - id test_str = [NSString string]; - id test_str_const = @"bonjour"; - id test_str_mutable = [NSMutableString stringWithCapacity:10]; - - // Make sure the allocations of NS types are good. - EXPECT_TRUE(test_array); - EXPECT_TRUE(test_array_mutable); - EXPECT_TRUE(test_data); - EXPECT_TRUE(test_data_mutable); - EXPECT_TRUE(test_date); - EXPECT_TRUE(test_dict); - EXPECT_TRUE(test_dict_mutable); - EXPECT_TRUE(test_number); - EXPECT_TRUE(test_null); - EXPECT_TRUE(test_set); - EXPECT_TRUE(test_set_mutable); - EXPECT_TRUE(test_str); - EXPECT_TRUE(test_str_const); - EXPECT_TRUE(test_str_mutable); - - // Casting the id correctly provides the same pointer. - EXPECT_EQ(test_array, ObjCCast(test_array)); - EXPECT_EQ(test_array_mutable, ObjCCast(test_array_mutable)); - EXPECT_EQ(test_data, ObjCCast(test_data)); - EXPECT_EQ(test_data_mutable, ObjCCast(test_data_mutable)); - EXPECT_EQ(test_date, ObjCCast(test_date)); - EXPECT_EQ(test_dict, ObjCCast(test_dict)); - EXPECT_EQ(test_dict_mutable, ObjCCast(test_dict_mutable)); - EXPECT_EQ(test_number, ObjCCast(test_number)); - EXPECT_EQ(test_null, ObjCCast(test_null)); - EXPECT_EQ(test_set, ObjCCast(test_set)); - EXPECT_EQ(test_set_mutable, ObjCCast(test_set_mutable)); - EXPECT_EQ(test_str, ObjCCast(test_str)); - EXPECT_EQ(test_str_const, ObjCCast(test_str_const)); - EXPECT_EQ(test_str_mutable, ObjCCast(test_str_mutable)); - - // When given an incorrect ObjC cast, provide nil. - EXPECT_FALSE(ObjCCast(test_array)); - EXPECT_FALSE(ObjCCast(test_array_mutable)); - EXPECT_FALSE(ObjCCast(test_data)); - EXPECT_FALSE(ObjCCast(test_data_mutable)); - EXPECT_FALSE(ObjCCast(test_date)); - EXPECT_FALSE(ObjCCast(test_dict)); - EXPECT_FALSE(ObjCCast(test_dict_mutable)); - EXPECT_FALSE(ObjCCast(test_number)); - EXPECT_FALSE(ObjCCast(test_null)); - EXPECT_FALSE(ObjCCast(test_set)); - EXPECT_FALSE(ObjCCast(test_set_mutable)); - EXPECT_FALSE(ObjCCast(test_str)); - EXPECT_FALSE(ObjCCast(test_str_const)); - EXPECT_FALSE(ObjCCast(test_str_mutable)); - - // Giving a nil provides a nil. - EXPECT_FALSE(ObjCCast(nil)); - EXPECT_FALSE(ObjCCast(nil)); - EXPECT_FALSE(ObjCCast(nil)); - EXPECT_FALSE(ObjCCast(nil)); - EXPECT_FALSE(ObjCCast(nil)); - EXPECT_FALSE(ObjCCast(nil)); - EXPECT_FALSE(ObjCCast(nil)); - EXPECT_FALSE(ObjCCast(nil)); - - // ObjCCastStrict: correct cast results in correct pointer being returned. - EXPECT_EQ(test_array, ObjCCastStrict(test_array)); - EXPECT_EQ(test_array_mutable, - ObjCCastStrict(test_array_mutable)); - EXPECT_EQ(test_data, ObjCCastStrict(test_data)); - EXPECT_EQ(test_data_mutable, - ObjCCastStrict(test_data_mutable)); - EXPECT_EQ(test_date, ObjCCastStrict(test_date)); - EXPECT_EQ(test_dict, ObjCCastStrict(test_dict)); - EXPECT_EQ(test_dict_mutable, - ObjCCastStrict(test_dict_mutable)); - EXPECT_EQ(test_number, ObjCCastStrict(test_number)); - EXPECT_EQ(test_null, ObjCCastStrict(test_null)); - EXPECT_EQ(test_set, ObjCCastStrict(test_set)); - EXPECT_EQ(test_set_mutable, - ObjCCastStrict(test_set_mutable)); - EXPECT_EQ(test_str, ObjCCastStrict(test_str)); - EXPECT_EQ(test_str_const, - ObjCCastStrict(test_str_const)); - EXPECT_EQ(test_str_mutable, - ObjCCastStrict(test_str_mutable)); - - // ObjCCastStrict: Giving a nil provides a nil. - EXPECT_FALSE(ObjCCastStrict(nil)); - EXPECT_FALSE(ObjCCastStrict(nil)); - EXPECT_FALSE(ObjCCastStrict(nil)); - EXPECT_FALSE(ObjCCastStrict(nil)); - EXPECT_FALSE(ObjCCastStrict(nil)); - EXPECT_FALSE(ObjCCastStrict(nil)); - EXPECT_FALSE(ObjCCastStrict(nil)); - EXPECT_FALSE(ObjCCastStrict(nil)); -} - -TEST(FoundationUtilTest, GetValueFromDictionary) { - int one = 1, two = 2, three = 3; - - ScopedCFTypeRef cf_one( - CFNumberCreate(kCFAllocatorDefault, kCFNumberIntType, &one)); - ScopedCFTypeRef cf_two( - CFNumberCreate(kCFAllocatorDefault, kCFNumberIntType, &two)); - ScopedCFTypeRef cf_three( - CFNumberCreate(kCFAllocatorDefault, kCFNumberIntType, &three)); - - CFStringRef keys[] = { CFSTR("one"), CFSTR("two"), CFSTR("three") }; - CFNumberRef values[] = { cf_one, cf_two, cf_three }; - - COMPILE_ASSERT(arraysize(keys) == arraysize(values), - keys_and_values_arraysizes_are_different); - - ScopedCFTypeRef test_dict( - CFDictionaryCreate(kCFAllocatorDefault, - reinterpret_cast(keys), - reinterpret_cast(values), - arraysize(values), - &kCFCopyStringDictionaryKeyCallBacks, - &kCFTypeDictionaryValueCallBacks)); - - // GetValueFromDictionary<>(_, _) should produce the correct - // expected output. - EXPECT_EQ(values[0], - GetValueFromDictionary(test_dict, CFSTR("one"))); - EXPECT_EQ(values[1], - GetValueFromDictionary(test_dict, CFSTR("two"))); - EXPECT_EQ(values[2], - GetValueFromDictionary(test_dict, CFSTR("three"))); - - // Bad input should produce bad output. - EXPECT_FALSE(GetValueFromDictionary(test_dict, CFSTR("four"))); - EXPECT_FALSE(GetValueFromDictionary(test_dict, CFSTR("one"))); -} - -TEST(FoundationUtilTest, FilePathToNSString) { - EXPECT_NSEQ(nil, FilePathToNSString(FilePath())); - EXPECT_NSEQ(@"/a/b", FilePathToNSString(FilePath("/a/b"))); -} - -// http://crbug.com/173983 Fails consistently under Mac ASAN. -TEST(FoundationUtilTest, DISABLED_NSStringToFilePath) { - EXPECT_EQ(FilePath(), NSStringToFilePath(nil)); - EXPECT_EQ(FilePath(), NSStringToFilePath(@"")); - EXPECT_EQ(FilePath("/a/b"), NSStringToFilePath(@"/a/b")); -} - -} // namespace mac -} // namespace base diff --git a/base/mac/launch_services_util.cc b/base/mac/launch_services_util.cc deleted file mode 100644 index 6121081404..0000000000 --- a/base/mac/launch_services_util.cc +++ /dev/null @@ -1,65 +0,0 @@ -// Copyright 2013 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "base/mac/launch_services_util.h" - -#include "base/logging.h" -#include "base/mac/mac_logging.h" -#include "base/mac/mac_util.h" -#include "base/strings/sys_string_conversions.h" - -namespace base { -namespace mac { - -bool OpenApplicationWithPath(const base::FilePath& bundle_path, - const CommandLine& command_line, - LSLaunchFlags launch_flags, - ProcessSerialNumber* out_psn) { - FSRef app_fsref; - if (!base::mac::FSRefFromPath(bundle_path.value(), &app_fsref)) { - LOG(ERROR) << "base::mac::FSRefFromPath failed for " << bundle_path.value(); - return false; - } - - std::vector argv = command_line.argv(); - int argc = argv.size(); - base::ScopedCFTypeRef launch_args( - CFArrayCreateMutable(NULL, argc - 1, &kCFTypeArrayCallBacks)); - if (!launch_args) { - LOG(ERROR) << "CFArrayCreateMutable failed, size was " << argc; - return false; - } - - for (int i = 1; i < argc; ++i) { - const std::string& arg(argv[i]); - - base::ScopedCFTypeRef arg_cf(base::SysUTF8ToCFStringRef(arg)); - if (!arg_cf) { - LOG(ERROR) << "base::SysUTF8ToCFStringRef failed for " << arg; - return false; - } - CFArrayAppendValue(launch_args, arg_cf); - } - - LSApplicationParameters ls_parameters = { - 0, // version - launch_flags, - &app_fsref, - NULL, // asyncLaunchRefCon - NULL, // environment - launch_args, - NULL // initialEvent - }; - // TODO(jeremya): this opens a new browser window if Chrome is already - // running without any windows open. - OSStatus status = LSOpenApplication(&ls_parameters, out_psn); - if (status != noErr) { - OSSTATUS_LOG(ERROR, status) << "LSOpenApplication"; - return false; - } - return true; -} - -} // namespace mac -} // namespace base diff --git a/base/mac/launch_services_util.h b/base/mac/launch_services_util.h deleted file mode 100644 index d4aa9ffcbe..0000000000 --- a/base/mac/launch_services_util.h +++ /dev/null @@ -1,33 +0,0 @@ -// Copyright (c) 2013 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef BASE_MAC_LAUNCH_SERVICES_UTIL_H_ -#define BASE_MAC_LAUNCH_SERVICES_UTIL_H_ - -#include - -#include "base/base_export.h" -#include "base/command_line.h" -#include "base/files/file_path.h" - -struct ProcessSerialNumber; - -namespace base { -namespace mac { - -// Launches the application bundle at |bundle_path|, passing argv[1..] from -// |command_line| as command line arguments if the app isn't already running. -// |launch_flags| are passed directly to LSApplicationParameters. -// |out_psn|, if not NULL, will be set to the process serial number of the -// application's main process if the app was successfully launched. -// Returns true if the app was successfully launched. -BASE_EXPORT bool OpenApplicationWithPath(const base::FilePath& bundle_path, - const CommandLine& command_line, - LSLaunchFlags launch_flags, - ProcessSerialNumber* out_psn); - -} // namespace mac -} // namespace base - -#endif // BASE_MAC_LAUNCH_SERVICES_UTIL_H_ diff --git a/base/mac/launchd.cc b/base/mac/launchd.cc deleted file mode 100644 index 1d384c93a2..0000000000 --- a/base/mac/launchd.cc +++ /dev/null @@ -1,75 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "base/mac/launchd.h" - -#include "base/logging.h" -#include "base/mac/scoped_launch_data.h" - -namespace base { -namespace mac { - -// MessageForJob sends a single message to launchd with a simple dictionary -// mapping |operation| to |job_label|, and returns the result of calling -// launch_msg to send that message. On failure, returns NULL. The caller -// assumes ownership of the returned launch_data_t object. -launch_data_t MessageForJob(const std::string& job_label, - const char* operation) { - // launch_data_alloc returns something that needs to be freed. - ScopedLaunchData message(launch_data_alloc(LAUNCH_DATA_DICTIONARY)); - if (!message) { - LOG(ERROR) << "launch_data_alloc"; - return NULL; - } - - // launch_data_new_string returns something that needs to be freed, but - // the dictionary will assume ownership when launch_data_dict_insert is - // called, so put it in a scoper and .release() it when given to the - // dictionary. - ScopedLaunchData job_label_launchd(launch_data_new_string(job_label.c_str())); - if (!job_label_launchd) { - LOG(ERROR) << "launch_data_new_string"; - return NULL; - } - - if (!launch_data_dict_insert(message, - job_label_launchd.release(), - operation)) { - return NULL; - } - - return launch_msg(message); -} - -pid_t PIDForJob(const std::string& job_label) { - ScopedLaunchData response(MessageForJob(job_label, LAUNCH_KEY_GETJOB)); - if (!response) { - return -1; - } - - launch_data_type_t response_type = launch_data_get_type(response); - if (response_type != LAUNCH_DATA_DICTIONARY) { - if (response_type == LAUNCH_DATA_ERRNO) { - LOG(ERROR) << "PIDForJob: error " << launch_data_get_errno(response); - } else { - LOG(ERROR) << "PIDForJob: expected dictionary, got " << response_type; - } - return -1; - } - - launch_data_t pid_data = launch_data_dict_lookup(response, - LAUNCH_JOBKEY_PID); - if (!pid_data) - return 0; - - if (launch_data_get_type(pid_data) != LAUNCH_DATA_INTEGER) { - LOG(ERROR) << "PIDForJob: expected integer"; - return -1; - } - - return launch_data_get_integer(pid_data); -} - -} // namespace mac -} // namespace base diff --git a/base/mac/launchd.h b/base/mac/launchd.h deleted file mode 100644 index 9e4514e839..0000000000 --- a/base/mac/launchd.h +++ /dev/null @@ -1,34 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef BASE_MAC_LAUNCHD_H_ -#define BASE_MAC_LAUNCHD_H_ - -#include -#include - -#include - -#include "base/base_export.h" - -namespace base { -namespace mac { - -// MessageForJob sends a single message to launchd with a simple dictionary -// mapping |operation| to |job_label|, and returns the result of calling -// launch_msg to send that message. On failure, returns NULL. The caller -// assumes ownership of the returned launch_data_t object. -BASE_EXPORT -launch_data_t MessageForJob(const std::string& job_label, - const char* operation); - -// Returns the process ID for |job_label| if the job is running, 0 if the job -// is loaded but not running, or -1 on error. -BASE_EXPORT -pid_t PIDForJob(const std::string& job_label); - -} // namespace mac -} // namespace base - -#endif // BASE_MAC_LAUNCHD_H_ diff --git a/base/mac/libdispatch_task_runner.cc b/base/mac/libdispatch_task_runner.cc deleted file mode 100644 index 4b5abaf30c..0000000000 --- a/base/mac/libdispatch_task_runner.cc +++ /dev/null @@ -1,80 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "base/mac/libdispatch_task_runner.h" - -#include "base/callback.h" - -namespace base { -namespace mac { - -LibDispatchTaskRunner::LibDispatchTaskRunner(const char* name) - : queue_(dispatch_queue_create(name, NULL)), - queue_finalized_(false, false) { - dispatch_set_context(queue_, this); - dispatch_set_finalizer_f(queue_, &LibDispatchTaskRunner::Finalizer); -} - -bool LibDispatchTaskRunner::PostDelayedTask( - const tracked_objects::Location& from_here, - const Closure& task, - base::TimeDelta delay) { - if (!queue_) - return false; - - // The block runtime would implicitly copy the reference, not the object - // it's referencing. Copy the closure into block storage so it's available - // to run. - __block const Closure task_copy = task; - void(^run_task)(void) = ^{ - task_copy.Run(); - }; - - int64 delay_nano = - delay.InMicroseconds() * base::Time::kNanosecondsPerMicrosecond; - if (delay_nano > 0) { - dispatch_time_t time = dispatch_time(DISPATCH_TIME_NOW, delay_nano); - dispatch_after(time, queue_, run_task); - } else { - dispatch_async(queue_, run_task); - } - return true; -} - -bool LibDispatchTaskRunner::RunsTasksOnCurrentThread() const { - return queue_ == dispatch_get_current_queue(); -} - -bool LibDispatchTaskRunner::PostNonNestableDelayedTask( - const tracked_objects::Location& from_here, - const Closure& task, - base::TimeDelta delay) { - return PostDelayedTask(from_here, task, delay); -} - -void LibDispatchTaskRunner::Shutdown() { - dispatch_release(queue_); - queue_ = NULL; - queue_finalized_.Wait(); -} - -dispatch_queue_t LibDispatchTaskRunner::GetDispatchQueue() const { - return queue_; -} - -LibDispatchTaskRunner::~LibDispatchTaskRunner() { - if (queue_) { - dispatch_set_context(queue_, NULL); - dispatch_set_finalizer_f(queue_, NULL); - dispatch_release(queue_); - } -} - -void LibDispatchTaskRunner::Finalizer(void* context) { - LibDispatchTaskRunner* self = static_cast(context); - self->queue_finalized_.Signal(); -} - -} // namespace mac -} // namespace base diff --git a/base/mac/libdispatch_task_runner.h b/base/mac/libdispatch_task_runner.h deleted file mode 100644 index b1d90e29ac..0000000000 --- a/base/mac/libdispatch_task_runner.h +++ /dev/null @@ -1,81 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef BASE_MAC_LIBDISPATCH_SEQUENCED_TASK_RUNNER_H_ -#define BASE_MAC_LIBDISPATCH_SEQUENCED_TASK_RUNNER_H_ - -#include - -#include "base/single_thread_task_runner.h" -#include "base/synchronization/waitable_event.h" - -namespace base { -namespace mac { - -// This is an implementation of the TaskRunner interface that runs closures on -// a thread managed by Apple's libdispatch. This has the benefit of being able -// to PostTask() and friends to a dispatch queue, while being reusable as a -// dispatch_queue_t. -// -// One would use this class if an object lives exclusively on one thread but -// needs a dispatch_queue_t for use in a system API. This ensures all dispatch -// callbacks happen on the same thread as Closure tasks. -// -// A LibDispatchTaskRunner will continue to run until all references to the -// underlying dispatch queue are released. -// -// Important Notes: -// - There is no MessageLoop running on this thread, and ::current() returns -// NULL. -// - No nested loops can be run, and all tasks are run non-nested. -// - Work scheduled via libdispatch runs at the same priority as and is -// interleaved with posted tasks, though FIFO order is guaranteed. -// -class BASE_EXPORT LibDispatchTaskRunner : public base::SingleThreadTaskRunner { - public: - // Starts a new serial dispatch queue with a given name. - explicit LibDispatchTaskRunner(const char* name); - - // base::TaskRunner: - virtual bool PostDelayedTask(const tracked_objects::Location& from_here, - const Closure& task, - base::TimeDelta delay) OVERRIDE; - virtual bool RunsTasksOnCurrentThread() const OVERRIDE; - - // base::SequencedTaskRunner: - virtual bool PostNonNestableDelayedTask( - const tracked_objects::Location& from_here, - const Closure& task, - base::TimeDelta delay) OVERRIDE; - - // This blocks the calling thread until all work on the dispatch queue has - // been run and the queue has been destroyed. Destroying a queue requires - // ALL retained references to it to be released. Any new tasks posted to - // this thread after shutdown are dropped. - void Shutdown(); - - // Returns the dispatch queue associated with this task runner, for use with - // system APIs that take dispatch queues. The caller is responsible for - // retaining the result. - // - // All properties (context, finalizer, etc.) are managed by this class, and - // clients should only use the result of this for dispatch_async(). - dispatch_queue_t GetDispatchQueue() const; - - protected: - virtual ~LibDispatchTaskRunner(); - - private: - static void Finalizer(void* context); - - dispatch_queue_t queue_; - - // The event on which Shutdown waits until Finalizer runs. - base::WaitableEvent queue_finalized_; -}; - -} // namespace mac -} // namespace base - -#endif // BASE_MAC_LIBDISPATCH_SEQUENCED_TASK_RUNNER_H_ diff --git a/base/mac/libdispatch_task_runner_unittest.cc b/base/mac/libdispatch_task_runner_unittest.cc deleted file mode 100644 index a4f3202ac5..0000000000 --- a/base/mac/libdispatch_task_runner_unittest.cc +++ /dev/null @@ -1,224 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "base/mac/libdispatch_task_runner.h" - -#include "base/bind.h" -#include "base/mac/bind_objc_block.h" -#include "base/message_loop/message_loop.h" -#include "base/strings/stringprintf.h" -#include "testing/gtest/include/gtest/gtest.h" - -class LibDispatchTaskRunnerTest : public testing::Test { - public: - virtual void SetUp() OVERRIDE { - task_runner_ = new base::mac::LibDispatchTaskRunner( - "org.chromium.LibDispatchTaskRunnerTest"); - } - - // DispatchLastTask is used to run the main test thread's MessageLoop until - // all non-delayed tasks are run on the LibDispatchTaskRunner. - void DispatchLastTask() { - dispatch_async(task_runner_->GetDispatchQueue(), ^{ - message_loop_.PostTask(FROM_HERE, - base::MessageLoop::QuitWhenIdleClosure()); - }); - message_loop_.Run(); - task_runner_->Shutdown(); - } - - // VerifyTaskOrder takes the expectations from TaskOrderMarkers and compares - // them against the recorded values. - void VerifyTaskOrder(const char* const expectations[], - size_t num_expectations) { - size_t actual_size = task_order_.size(); - - for (size_t i = 0; i < num_expectations; ++i) { - if (i >= actual_size) { - EXPECT_LE(i, actual_size) << "Expected " << expectations[i]; - continue; - } - - EXPECT_EQ(expectations[i], task_order_[i]); - } - - if (actual_size > num_expectations) { - EXPECT_LE(actual_size, num_expectations) << "Extra tasks were run:"; - for (size_t i = num_expectations; i < actual_size; ++i) { - EXPECT_EQ("", task_order_[i]) << " (i=" << i << ")"; - } - } - } - - // The message loop for the test main thread. - base::MessageLoop message_loop_; - - // The task runner under test. - scoped_refptr task_runner_; - - // Vector that records data from TaskOrderMarker. - std::vector task_order_; -}; - -// Scoper that records the beginning and end of a running task. -class TaskOrderMarker { - public: - TaskOrderMarker(LibDispatchTaskRunnerTest* test, const std::string& name) - : test_(test), - name_(name) { - test->task_order_.push_back(std::string("BEGIN ") + name); - } - ~TaskOrderMarker() { - test_->task_order_.push_back(std::string("END ") + name_); - } - - private: - LibDispatchTaskRunnerTest* test_; - std::string name_; -}; - -void RecordTaskOrder(LibDispatchTaskRunnerTest* test, const std::string& name) { - TaskOrderMarker marker(test, name); -} - -// Returns a closure that records the task order. -base::Closure BoundRecordTaskOrder(LibDispatchTaskRunnerTest* test, - const std::string& name) { - return base::Bind(&RecordTaskOrder, base::Unretained(test), name); -} - -TEST_F(LibDispatchTaskRunnerTest, PostTask) { - task_runner_->PostTask(FROM_HERE, BoundRecordTaskOrder(this, "Basic Task")); - DispatchLastTask(); - const char* const expectations[] = { - "BEGIN Basic Task", - "END Basic Task" - }; - VerifyTaskOrder(expectations, arraysize(expectations)); -} - -TEST_F(LibDispatchTaskRunnerTest, PostTaskWithinTask) { - task_runner_->PostTask(FROM_HERE, base::BindBlock(^{ - TaskOrderMarker marker(this, "Outer"); - task_runner_->PostTask(FROM_HERE, BoundRecordTaskOrder(this, "Inner")); - })); - DispatchLastTask(); - - const char* const expectations[] = { - "BEGIN Outer", - "END Outer", - "BEGIN Inner", - "END Inner" - }; - VerifyTaskOrder(expectations, arraysize(expectations)); -} - -TEST_F(LibDispatchTaskRunnerTest, NoMessageLoop) { - task_runner_->PostTask(FROM_HERE, base::BindBlock(^{ - TaskOrderMarker marker(this, - base::StringPrintf("MessageLoop = %p", base::MessageLoop::current())); - })); - DispatchLastTask(); - - const char* const expectations[] = { - "BEGIN MessageLoop = 0x0", - "END MessageLoop = 0x0" - }; - VerifyTaskOrder(expectations, arraysize(expectations)); -} - -TEST_F(LibDispatchTaskRunnerTest, DispatchAndPostTasks) { - dispatch_async(task_runner_->GetDispatchQueue(), ^{ - TaskOrderMarker marker(this, "First Block"); - }); - task_runner_->PostTask(FROM_HERE, BoundRecordTaskOrder(this, "First Task")); - dispatch_async(task_runner_->GetDispatchQueue(), ^{ - TaskOrderMarker marker(this, "Second Block"); - }); - task_runner_->PostTask(FROM_HERE, BoundRecordTaskOrder(this, "Second Task")); - DispatchLastTask(); - - const char* const expectations[] = { - "BEGIN First Block", - "END First Block", - "BEGIN First Task", - "END First Task", - "BEGIN Second Block", - "END Second Block", - "BEGIN Second Task", - "END Second Task", - }; - VerifyTaskOrder(expectations, arraysize(expectations)); -} - -TEST_F(LibDispatchTaskRunnerTest, NonNestable) { - task_runner_->PostTask(FROM_HERE, base::BindBlock(^{ - TaskOrderMarker marker(this, "First"); - task_runner_->PostNonNestableTask(FROM_HERE, base::BindBlock(^{ - TaskOrderMarker marker(this, "Second NonNestable"); - message_loop_.PostTask(FROM_HERE, - base::MessageLoop::QuitWhenIdleClosure()); - })); - })); - message_loop_.Run(); - task_runner_->Shutdown(); - - const char* const expectations[] = { - "BEGIN First", - "END First", - "BEGIN Second NonNestable", - "END Second NonNestable" - }; - VerifyTaskOrder(expectations, arraysize(expectations)); -} - -TEST_F(LibDispatchTaskRunnerTest, PostDelayed) { - base::TimeTicks post_time; - __block base::TimeTicks run_time; - const base::TimeDelta delta = base::TimeDelta::FromMilliseconds(50); - - task_runner_->PostTask(FROM_HERE, BoundRecordTaskOrder(this, "First")); - post_time = base::TimeTicks::Now(); - task_runner_->PostDelayedTask(FROM_HERE, base::BindBlock(^{ - TaskOrderMarker marker(this, "Timed"); - run_time = base::TimeTicks::Now(); - message_loop_.PostTask(FROM_HERE, - base::MessageLoop::QuitWhenIdleClosure()); - }), delta); - task_runner_->PostTask(FROM_HERE, BoundRecordTaskOrder(this, "Second")); - message_loop_.Run(); - task_runner_->Shutdown(); - - const char* const expectations[] = { - "BEGIN First", - "END First", - "BEGIN Second", - "END Second", - "BEGIN Timed", - "END Timed", - }; - VerifyTaskOrder(expectations, arraysize(expectations)); - - EXPECT_GE(run_time, post_time + delta); -} - -TEST_F(LibDispatchTaskRunnerTest, PostAfterShutdown) { - EXPECT_TRUE(task_runner_->PostTask(FROM_HERE, - BoundRecordTaskOrder(this, "First"))); - EXPECT_TRUE(task_runner_->PostTask(FROM_HERE, - BoundRecordTaskOrder(this, "Second"))); - task_runner_->Shutdown(); - EXPECT_FALSE(task_runner_->PostTask(FROM_HERE, base::BindBlock(^{ - TaskOrderMarker marker(this, "Not Run"); - ADD_FAILURE() << "Should not run a task after Shutdown"; - }))); - - const char* const expectations[] = { - "BEGIN First", - "END First", - "BEGIN Second", - "END Second" - }; - VerifyTaskOrder(expectations, arraysize(expectations)); -} diff --git a/base/mac/mac_logging.cc b/base/mac/mac_logging.cc deleted file mode 100644 index d58220fe89..0000000000 --- a/base/mac/mac_logging.cc +++ /dev/null @@ -1,37 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "base/mac/mac_logging.h" - -#include - -#if !defined(OS_IOS) -#include -#endif - -namespace logging { - -OSStatusLogMessage::OSStatusLogMessage(const char* file_path, - int line, - LogSeverity severity, - OSStatus status) - : LogMessage(file_path, line, severity), - status_(status) { -} - -OSStatusLogMessage::~OSStatusLogMessage() { -#if defined(OS_IOS) - // TODO(ios): Consider using NSError with NSOSStatusErrorDomain to try to - // get a description of the failure. - stream() << ": " << status_; -#else - stream() << ": " - << GetMacOSStatusErrorString(status_) - << " (" - << status_ - << ")"; -#endif -} - -} // namespace logging diff --git a/base/mac/mac_logging.h b/base/mac/mac_logging.h deleted file mode 100644 index 9a0003e9ad..0000000000 --- a/base/mac/mac_logging.h +++ /dev/null @@ -1,87 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef BASE_MAC_MAC_LOGGING_H_ -#define BASE_MAC_MAC_LOGGING_H_ - -#include "base/logging.h" -#include "build/build_config.h" - -#if defined(OS_IOS) -#include -#else -#include -#endif - -// Use the OSSTATUS_LOG family to log messages related to errors in Mac OS X -// system routines that report status via an OSStatus or OSErr value. It is -// similar to the PLOG family which operates on errno, but because there is no -// global (or thread-local) OSStatus or OSErr value, the specific error must -// be supplied as an argument to the OSSTATUS_LOG macro. The message logged -// will contain the symbolic constant name corresponding to the status value, -// along with the value itself. -// -// OSErr is just an older 16-bit form of the newer 32-bit OSStatus. Despite -// the name, OSSTATUS_LOG can be used equally well for OSStatus and OSErr. - -namespace logging { - -class BASE_EXPORT OSStatusLogMessage : public logging::LogMessage { - public: - OSStatusLogMessage(const char* file_path, - int line, - LogSeverity severity, - OSStatus status); - ~OSStatusLogMessage(); - - private: - OSStatus status_; - - DISALLOW_COPY_AND_ASSIGN(OSStatusLogMessage); -}; - -} // namespace logging - -#define OSSTATUS_LOG_STREAM(severity, status) \ - COMPACT_GOOGLE_LOG_EX_ ## severity(OSStatusLogMessage, status).stream() -#define OSSTATUS_VLOG_STREAM(verbose_level, status) \ - logging::OSStatusLogMessage(__FILE__, __LINE__, \ - -verbose_level, status).stream() - -#define OSSTATUS_LOG(severity, status) \ - LAZY_STREAM(OSSTATUS_LOG_STREAM(severity, status), LOG_IS_ON(severity)) -#define OSSTATUS_LOG_IF(severity, condition, status) \ - LAZY_STREAM(OSSTATUS_LOG_STREAM(severity, status), \ - LOG_IS_ON(severity) && (condition)) - -#define OSSTATUS_VLOG(verbose_level, status) \ - LAZY_STREAM(OSSTATUS_VLOG_STREAM(verbose_level, status), \ - VLOG_IS_ON(verbose_level)) -#define OSSTATUS_VLOG_IF(verbose_level, condition, status) \ - LAZY_STREAM(OSSTATUS_VLOG_STREAM(verbose_level, status), \ - VLOG_IS_ON(verbose_level) && (condition)) - -#define OSSTATUS_CHECK(condition, status) \ - LAZY_STREAM(OSSTATUS_LOG_STREAM(FATAL, status), !(condition)) \ - << "Check failed: " # condition << ". " - -#define OSSTATUS_DLOG(severity, status) \ - LAZY_STREAM(OSSTATUS_LOG_STREAM(severity, status), DLOG_IS_ON(severity)) -#define OSSTATUS_DLOG_IF(severity, condition, status) \ - LAZY_STREAM(OSSTATUS_LOG_STREAM(severity, status), \ - DLOG_IS_ON(severity) && (condition)) - -#define OSSTATUS_DVLOG(verbose_level, status) \ - LAZY_STREAM(OSSTATUS_VPLOG_STREAM(verbose_level, status), \ - DVLOG_IS_ON(verbose_level)) -#define OSSTATUS_DVLOG_IF(verbose_level, condition, status) \ - LAZY_STREAM(OSSTATUS_VPLOG_STREAM(verbose_level, status) \ - DVLOG_IS_ON(verbose_level) && (condition)) - -#define OSSTATUS_DCHECK(condition, status) \ - LAZY_STREAM(OSSTATUS_LOG_STREAM(FATAL, status), \ - DCHECK_IS_ON() && !(condition)) \ - << "Check failed: " # condition << ". " - -#endif // BASE_MAC_MAC_LOGGING_H_ diff --git a/base/mac/mac_util.h b/base/mac/mac_util.h deleted file mode 100644 index 23b57edaee..0000000000 --- a/base/mac/mac_util.h +++ /dev/null @@ -1,204 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef BASE_MAC_MAC_UTIL_H_ -#define BASE_MAC_MAC_UTIL_H_ - -#include -#include -#include - -#include "base/base_export.h" -#include "base/logging.h" - -// TODO(rohitrao): Clean up sites that include mac_util.h and remove this line. -#include "base/mac/foundation_util.h" - -#if defined(__OBJC__) -#import -#else // __OBJC__ -class NSImage; -#endif // __OBJC__ - -namespace base { - -class FilePath; - -namespace mac { - -// Full screen modes, in increasing order of priority. More permissive modes -// take predecence. -enum FullScreenMode { - kFullScreenModeHideAll = 0, - kFullScreenModeHideDock = 1, - kFullScreenModeAutoHideAll = 2, - kNumFullScreenModes = 3, - - // kFullScreenModeNormal is not a valid FullScreenMode, but it is useful to - // other classes, so we include it here. - kFullScreenModeNormal = 10, -}; - -BASE_EXPORT std::string PathFromFSRef(const FSRef& ref); -BASE_EXPORT bool FSRefFromPath(const std::string& path, FSRef* ref); - -// Returns an sRGB color space. The return value is a static value; do not -// release it! -BASE_EXPORT CGColorSpaceRef GetSRGBColorSpace(); - -// Returns the generic RGB color space. The return value is a static value; do -// not release it! -BASE_EXPORT CGColorSpaceRef GetGenericRGBColorSpace(); - -// Returns the color space being used by the main display. The return value -// is a static value; do not release it! -BASE_EXPORT CGColorSpaceRef GetSystemColorSpace(); - -// Add a full screen request for the given |mode|. Must be paired with a -// ReleaseFullScreen() call for the same |mode|. This does not by itself create -// a fullscreen window; rather, it manages per-application state related to -// hiding the dock and menubar. Must be called on the main thread. -BASE_EXPORT void RequestFullScreen(FullScreenMode mode); - -// Release a request for full screen mode. Must be matched with a -// RequestFullScreen() call for the same |mode|. As with RequestFullScreen(), -// this does not affect windows directly, but rather manages per-application -// state. For example, if there are no other outstanding -// |kFullScreenModeAutoHideAll| requests, this will reshow the menu bar. Must -// be called on main thread. -BASE_EXPORT void ReleaseFullScreen(FullScreenMode mode); - -// Convenience method to switch the current fullscreen mode. This has the same -// net effect as a ReleaseFullScreen(from_mode) call followed immediately by a -// RequestFullScreen(to_mode). Must be called on the main thread. -BASE_EXPORT void SwitchFullScreenModes(FullScreenMode from_mode, - FullScreenMode to_mode); - -// Set the visibility of the cursor. -BASE_EXPORT void SetCursorVisibility(bool visible); - -// Should windows miniaturize on a double-click (on the title bar)? -BASE_EXPORT bool ShouldWindowsMiniaturizeOnDoubleClick(); - -// Activates the process with the given PID. -BASE_EXPORT void ActivateProcess(pid_t pid); - -// Returns true if this process is in the foreground, meaning that it's the -// frontmost process, the one whose menu bar is shown at the top of the main -// display. -BASE_EXPORT bool AmIForeground(); - -// Excludes the file given by |file_path| from being backed up by Time Machine. -BASE_EXPORT bool SetFileBackupExclusion(const FilePath& file_path); - -// Sets the process name as displayed in Activity Monitor to process_name. -BASE_EXPORT void SetProcessName(CFStringRef process_name); - -// Converts a NSImage to a CGImageRef. Normally, the system frameworks can do -// this fine, especially on 10.6. On 10.5, however, CGImage cannot handle -// converting a PDF-backed NSImage into a CGImageRef. This function will -// rasterize the PDF into a bitmap CGImage. The caller is responsible for -// releasing the return value. -BASE_EXPORT CGImageRef CopyNSImageToCGImage(NSImage* image); - -// Checks if the current application is set as a Login Item, so it will launch -// on Login. If a non-NULL pointer to is_hidden is passed, the Login Item also -// is queried for the 'hide on launch' flag. -BASE_EXPORT bool CheckLoginItemStatus(bool* is_hidden); - -// Adds current application to the set of Login Items with specified "hide" -// flag. This has the same effect as adding/removing the application in -// SystemPreferences->Accounts->LoginItems or marking Application in the Dock -// as "Options->Open on Login". -// Does nothing if the application is already set up as Login Item with -// specified hide flag. -BASE_EXPORT void AddToLoginItems(bool hide_on_startup); - -// Removes the current application from the list Of Login Items. -BASE_EXPORT void RemoveFromLoginItems(); - -// Returns true if the current process was automatically launched as a -// 'Login Item' or via Lion's Resume. Used to suppress opening windows. -BASE_EXPORT bool WasLaunchedAsLoginOrResumeItem(); - -// Returns true if the current process was automatically launched as a -// 'Login Item' with 'hide on startup' flag. Used to suppress opening windows. -BASE_EXPORT bool WasLaunchedAsHiddenLoginItem(); - -// Remove the quarantine xattr from the given file. Returns false if there was -// an error, or true otherwise. -BASE_EXPORT bool RemoveQuarantineAttribute(const FilePath& file_path); - -// Run-time OS version checks. Use these instead of -// base::SysInfo::OperatingSystemVersionNumbers. Prefer the "OrEarlier" and -// "OrLater" variants to those that check for a specific version, unless you -// know for sure that you need to check for a specific version. - -// Snow Leopard is Mac OS X 10.6, Darwin 10. -BASE_EXPORT bool IsOSSnowLeopard(); - -// Lion is Mac OS X 10.7, Darwin 11. -BASE_EXPORT bool IsOSLion(); -BASE_EXPORT bool IsOSLionOrEarlier(); -BASE_EXPORT bool IsOSLionOrLater(); - -// Mountain Lion is Mac OS X 10.8, Darwin 12. -BASE_EXPORT bool IsOSMountainLion(); -BASE_EXPORT bool IsOSMountainLionOrLater(); - -// This should be infrequently used. It only makes sense to use this to avoid -// codepaths that are very likely to break on future (unreleased, untested, -// unborn) OS releases, or to log when the OS is newer than any known version. -BASE_EXPORT bool IsOSLaterThanMountainLion_DontCallThis(); - -// When the deployment target is set, the code produced cannot run on earlier -// OS releases. That enables some of the IsOS* family to be implemented as -// constant-value inline functions. The MAC_OS_X_VERSION_MIN_REQUIRED macro -// contains the value of the deployment target. - -#if defined(MAC_OS_X_VERSION_10_7) && \ - MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_7 -#define BASE_MAC_MAC_UTIL_H_INLINED_GE_10_7 -inline bool IsOSSnowLeopard() { return false; } -inline bool IsOSLionOrLater() { return true; } -#endif - -#if defined(MAC_OS_X_VERSION_10_7) && \ - MAC_OS_X_VERSION_MIN_REQUIRED > MAC_OS_X_VERSION_10_7 -#define BASE_MAC_MAC_UTIL_H_INLINED_GT_10_7 -inline bool IsOSLion() { return false; } -inline bool IsOSLionOrEarlier() { return false; } -#endif - -#if defined(MAC_OS_X_VERSION_10_8) && \ - MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_8 -#define BASE_MAC_MAC_UTIL_H_INLINED_GE_10_8 -inline bool IsOSMountainLionOrLater() { return true; } -#endif - -#if defined(MAC_OS_X_VERSION_10_8) && \ - MAC_OS_X_VERSION_MIN_REQUIRED > MAC_OS_X_VERSION_10_8 -#define BASE_MAC_MAC_UTIL_H_INLINED_GT_10_8 -inline bool IsOSMountainLion() { return false; } -inline bool IsOSLaterThanMountainLion_DontCallThis() { - return true; -} -#endif - -// Retrieve the system's model identifier string from the IOKit registry: -// for example, "MacPro4,1", "MacBookPro6,1". Returns empty string upon -// failure. -BASE_EXPORT std::string GetModelIdentifier(); - -// Parse a model identifier string; for example, into ("MacBookPro", 6, 1). -// If any error occurs, none of the input pointers are touched. -BASE_EXPORT bool ParseModelIdentifier(const std::string& ident, - std::string* type, - int32* major, - int32* minor); - -} // namespace mac -} // namespace base - -#endif // BASE_MAC_MAC_UTIL_H_ diff --git a/base/mac/mac_util.mm b/base/mac/mac_util.mm deleted file mode 100644 index 04311ecf11..0000000000 --- a/base/mac/mac_util.mm +++ /dev/null @@ -1,703 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "base/mac/mac_util.h" - -#import -#import - -#include -#include -#include -#include - -#include "base/files/file_path.h" -#include "base/logging.h" -#include "base/mac/bundle_locations.h" -#include "base/mac/foundation_util.h" -#include "base/mac/mac_logging.h" -#include "base/mac/scoped_cftyperef.h" -#include "base/mac/scoped_ioobject.h" -#include "base/mac/scoped_nsobject.h" -#include "base/strings/string_number_conversions.h" -#include "base/strings/string_piece.h" -#include "base/strings/sys_string_conversions.h" - -namespace base { -namespace mac { - -// Replicate specific 10.7 SDK declarations for building with prior SDKs. -#if !defined(MAC_OS_X_VERSION_10_7) || \ - MAC_OS_X_VERSION_MAX_ALLOWED < MAC_OS_X_VERSION_10_7 - -enum { - NSApplicationPresentationFullScreen = 1 << 10 -}; - -#endif // MAC_OS_X_VERSION_10_7 - -namespace { - -// The current count of outstanding requests for full screen mode from browser -// windows, plugins, etc. -int g_full_screen_requests[kNumFullScreenModes] = { 0 }; - -// Sets the appropriate application presentation option based on the current -// full screen requests. Since only one presentation option can be active at a -// given time, full screen requests are ordered by priority. If there are no -// outstanding full screen requests, reverts to normal mode. If the correct -// presentation option is already set, does nothing. -void SetUIMode() { - NSApplicationPresentationOptions current_options = - [NSApp presentationOptions]; - - // Determine which mode should be active, based on which requests are - // currently outstanding. More permissive requests take precedence. For - // example, plugins request |kFullScreenModeAutoHideAll|, while browser - // windows request |kFullScreenModeHideDock| when the fullscreen overlay is - // down. Precedence goes to plugins in this case, so AutoHideAll wins over - // HideDock. - NSApplicationPresentationOptions desired_options = - NSApplicationPresentationDefault; - if (g_full_screen_requests[kFullScreenModeAutoHideAll] > 0) { - desired_options = NSApplicationPresentationHideDock | - NSApplicationPresentationAutoHideMenuBar; - } else if (g_full_screen_requests[kFullScreenModeHideDock] > 0) { - desired_options = NSApplicationPresentationHideDock; - } else if (g_full_screen_requests[kFullScreenModeHideAll] > 0) { - desired_options = NSApplicationPresentationHideDock | - NSApplicationPresentationHideMenuBar; - } - - // Mac OS X bug: if the window is fullscreened (Lion-style) and - // NSApplicationPresentationDefault is requested, the result is that the menu - // bar doesn't auto-hide. rdar://13576498 http://www.openradar.me/13576498 - // - // As a workaround, in that case, explicitly set the presentation options to - // the ones that are set by the system as it fullscreens a window. - if (desired_options == NSApplicationPresentationDefault && - current_options & NSApplicationPresentationFullScreen) { - desired_options |= NSApplicationPresentationFullScreen | - NSApplicationPresentationAutoHideMenuBar | - NSApplicationPresentationAutoHideDock; - } - - if (current_options != desired_options) - [NSApp setPresentationOptions:desired_options]; -} - -// Looks into Shared File Lists corresponding to Login Items for the item -// representing the current application. If such an item is found, returns a -// retained reference to it. Caller is responsible for releasing the reference. -LSSharedFileListItemRef GetLoginItemForApp() { - ScopedCFTypeRef login_items(LSSharedFileListCreate( - NULL, kLSSharedFileListSessionLoginItems, NULL)); - - if (!login_items.get()) { - DLOG(ERROR) << "Couldn't get a Login Items list."; - return NULL; - } - - base::scoped_nsobject login_items_array( - CFToNSCast(LSSharedFileListCopySnapshot(login_items, NULL))); - - NSURL* url = [NSURL fileURLWithPath:[base::mac::MainBundle() bundlePath]]; - - for(NSUInteger i = 0; i < [login_items_array count]; ++i) { - LSSharedFileListItemRef item = reinterpret_cast( - [login_items_array objectAtIndex:i]); - CFURLRef item_url_ref = NULL; - - if (LSSharedFileListItemResolve(item, 0, &item_url_ref, NULL) == noErr) { - ScopedCFTypeRef item_url(item_url_ref); - if (CFEqual(item_url, url)) { - CFRetain(item); - return item; - } - } - } - - return NULL; -} - -bool IsHiddenLoginItem(LSSharedFileListItemRef item) { - ScopedCFTypeRef hidden(reinterpret_cast( - LSSharedFileListItemCopyProperty(item, - reinterpret_cast(kLSSharedFileListLoginItemHidden)))); - - return hidden && hidden == kCFBooleanTrue; -} - -} // namespace - -std::string PathFromFSRef(const FSRef& ref) { - ScopedCFTypeRef url( - CFURLCreateFromFSRef(kCFAllocatorDefault, &ref)); - NSString *path_string = [(NSURL *)url.get() path]; - return [path_string fileSystemRepresentation]; -} - -bool FSRefFromPath(const std::string& path, FSRef* ref) { - OSStatus status = FSPathMakeRef((const UInt8*)path.c_str(), - ref, nil); - return status == noErr; -} - -CGColorSpaceRef GetGenericRGBColorSpace() { - // Leaked. That's OK, it's scoped to the lifetime of the application. - static CGColorSpaceRef g_color_space_generic_rgb( - CGColorSpaceCreateWithName(kCGColorSpaceGenericRGB)); - DLOG_IF(ERROR, !g_color_space_generic_rgb) << - "Couldn't get the generic RGB color space"; - return g_color_space_generic_rgb; -} - -CGColorSpaceRef GetSRGBColorSpace() { - // Leaked. That's OK, it's scoped to the lifetime of the application. - static CGColorSpaceRef g_color_space_sRGB = - CGColorSpaceCreateWithName(kCGColorSpaceSRGB); - DLOG_IF(ERROR, !g_color_space_sRGB) << "Couldn't get the sRGB color space"; - return g_color_space_sRGB; -} - -CGColorSpaceRef GetSystemColorSpace() { - // Leaked. That's OK, it's scoped to the lifetime of the application. - // Try to get the main display's color space. - static CGColorSpaceRef g_system_color_space = - CGDisplayCopyColorSpace(CGMainDisplayID()); - - if (!g_system_color_space) { - // Use a generic RGB color space. This is better than nothing. - g_system_color_space = CGColorSpaceCreateDeviceRGB(); - - if (g_system_color_space) { - DLOG(WARNING) << - "Couldn't get the main display's color space, using generic"; - } else { - DLOG(ERROR) << "Couldn't get any color space"; - } - } - - return g_system_color_space; -} - -// Add a request for full screen mode. Must be called on the main thread. -void RequestFullScreen(FullScreenMode mode) { - DCHECK_LT(mode, kNumFullScreenModes); - if (mode >= kNumFullScreenModes) - return; - - DCHECK_GE(g_full_screen_requests[mode], 0); - if (mode < 0) - return; - - g_full_screen_requests[mode] = std::max(g_full_screen_requests[mode] + 1, 1); - SetUIMode(); -} - -// Release a request for full screen mode. Must be called on the main thread. -void ReleaseFullScreen(FullScreenMode mode) { - DCHECK_LT(mode, kNumFullScreenModes); - if (mode >= kNumFullScreenModes) - return; - - DCHECK_GE(g_full_screen_requests[mode], 0); - if (mode < 0) - return; - - g_full_screen_requests[mode] = std::max(g_full_screen_requests[mode] - 1, 0); - SetUIMode(); -} - -// Switches full screen modes. Releases a request for |from_mode| and adds a -// new request for |to_mode|. Must be called on the main thread. -void SwitchFullScreenModes(FullScreenMode from_mode, FullScreenMode to_mode) { - DCHECK_LT(from_mode, kNumFullScreenModes); - DCHECK_LT(to_mode, kNumFullScreenModes); - if (from_mode >= kNumFullScreenModes || to_mode >= kNumFullScreenModes) - return; - - DCHECK_GT(g_full_screen_requests[from_mode], 0); - DCHECK_GE(g_full_screen_requests[to_mode], 0); - g_full_screen_requests[from_mode] = - std::max(g_full_screen_requests[from_mode] - 1, 0); - g_full_screen_requests[to_mode] = - std::max(g_full_screen_requests[to_mode] + 1, 1); - SetUIMode(); -} - -void SetCursorVisibility(bool visible) { - if (visible) - [NSCursor unhide]; - else - [NSCursor hide]; -} - -bool ShouldWindowsMiniaturizeOnDoubleClick() { - // We use an undocumented method in Cocoa; if it doesn't exist, default to - // |true|. If it ever goes away, we can do (using an undocumented pref key): - // NSUserDefaults* defaults = [NSUserDefaults standardUserDefaults]; - // return ![defaults objectForKey:@"AppleMiniaturizeOnDoubleClick"] || - // [defaults boolForKey:@"AppleMiniaturizeOnDoubleClick"]; - BOOL methodImplemented = - [NSWindow respondsToSelector:@selector(_shouldMiniaturizeOnDoubleClick)]; - DCHECK(methodImplemented); - return !methodImplemented || - [NSWindow performSelector:@selector(_shouldMiniaturizeOnDoubleClick)]; -} - -void ActivateProcess(pid_t pid) { - ProcessSerialNumber process; - OSStatus status = GetProcessForPID(pid, &process); - if (status == noErr) { - SetFrontProcess(&process); - } else { - OSSTATUS_DLOG(WARNING, status) << "Unable to get process for pid " << pid; - } -} - -bool AmIForeground() { - ProcessSerialNumber foreground_psn = { 0 }; - OSErr err = GetFrontProcess(&foreground_psn); - if (err != noErr) { - OSSTATUS_DLOG(WARNING, err) << "GetFrontProcess"; - return false; - } - - ProcessSerialNumber my_psn = { 0, kCurrentProcess }; - - Boolean result = FALSE; - err = SameProcess(&foreground_psn, &my_psn, &result); - if (err != noErr) { - OSSTATUS_DLOG(WARNING, err) << "SameProcess"; - return false; - } - - return result; -} - -bool SetFileBackupExclusion(const FilePath& file_path) { - NSString* file_path_ns = - [NSString stringWithUTF8String:file_path.value().c_str()]; - NSURL* file_url = [NSURL fileURLWithPath:file_path_ns]; - - // When excludeByPath is true the application must be running with root - // privileges (admin for 10.6 and earlier) but the URL does not have to - // already exist. When excludeByPath is false the URL must already exist but - // can be used in non-root (or admin as above) mode. We use false so that - // non-root (or admin) users don't get their TimeMachine drive filled up with - // unnecessary backups. - OSStatus os_err = - CSBackupSetItemExcluded(base::mac::NSToCFCast(file_url), TRUE, FALSE); - if (os_err != noErr) { - OSSTATUS_DLOG(WARNING, os_err) - << "Failed to set backup exclusion for file '" - << file_path.value().c_str() << "'"; - } - return os_err == noErr; -} - -void SetProcessName(CFStringRef process_name) { - if (!process_name || CFStringGetLength(process_name) == 0) { - NOTREACHED() << "SetProcessName given bad name."; - return; - } - - if (![NSThread isMainThread]) { - NOTREACHED() << "Should only set process name from main thread."; - return; - } - - // Warning: here be dragons! This is SPI reverse-engineered from WebKit's - // plugin host, and could break at any time (although realistically it's only - // likely to break in a new major release). - // When 10.7 is available, check that this still works, and update this - // comment for 10.8. - - // Private CFType used in these LaunchServices calls. - typedef CFTypeRef PrivateLSASN; - typedef PrivateLSASN (*LSGetCurrentApplicationASNType)(); - typedef OSStatus (*LSSetApplicationInformationItemType)(int, PrivateLSASN, - CFStringRef, - CFStringRef, - CFDictionaryRef*); - - static LSGetCurrentApplicationASNType ls_get_current_application_asn_func = - NULL; - static LSSetApplicationInformationItemType - ls_set_application_information_item_func = NULL; - static CFStringRef ls_display_name_key = NULL; - - static bool did_symbol_lookup = false; - if (!did_symbol_lookup) { - did_symbol_lookup = true; - CFBundleRef launch_services_bundle = - CFBundleGetBundleWithIdentifier(CFSTR("com.apple.LaunchServices")); - if (!launch_services_bundle) { - DLOG(ERROR) << "Failed to look up LaunchServices bundle"; - return; - } - - ls_get_current_application_asn_func = - reinterpret_cast( - CFBundleGetFunctionPointerForName( - launch_services_bundle, CFSTR("_LSGetCurrentApplicationASN"))); - if (!ls_get_current_application_asn_func) - DLOG(ERROR) << "Could not find _LSGetCurrentApplicationASN"; - - ls_set_application_information_item_func = - reinterpret_cast( - CFBundleGetFunctionPointerForName( - launch_services_bundle, - CFSTR("_LSSetApplicationInformationItem"))); - if (!ls_set_application_information_item_func) - DLOG(ERROR) << "Could not find _LSSetApplicationInformationItem"; - - CFStringRef* key_pointer = reinterpret_cast( - CFBundleGetDataPointerForName(launch_services_bundle, - CFSTR("_kLSDisplayNameKey"))); - ls_display_name_key = key_pointer ? *key_pointer : NULL; - if (!ls_display_name_key) - DLOG(ERROR) << "Could not find _kLSDisplayNameKey"; - - // Internally, this call relies on the Mach ports that are started up by the - // Carbon Process Manager. In debug builds this usually happens due to how - // the logging layers are started up; but in release, it isn't started in as - // much of a defined order. So if the symbols had to be loaded, go ahead - // and force a call to make sure the manager has been initialized and hence - // the ports are opened. - ProcessSerialNumber psn; - GetCurrentProcess(&psn); - } - if (!ls_get_current_application_asn_func || - !ls_set_application_information_item_func || - !ls_display_name_key) { - return; - } - - PrivateLSASN asn = ls_get_current_application_asn_func(); - // Constant used by WebKit; what exactly it means is unknown. - const int magic_session_constant = -2; - OSErr err = - ls_set_application_information_item_func(magic_session_constant, asn, - ls_display_name_key, - process_name, - NULL /* optional out param */); - OSSTATUS_DLOG_IF(ERROR, err != noErr, err) - << "Call to set process name failed"; -} - -// Converts a NSImage to a CGImageRef. Normally, the system frameworks can do -// this fine, especially on 10.6. On 10.5, however, CGImage cannot handle -// converting a PDF-backed NSImage into a CGImageRef. This function will -// rasterize the PDF into a bitmap CGImage. The caller is responsible for -// releasing the return value. -CGImageRef CopyNSImageToCGImage(NSImage* image) { - // This is based loosely on http://www.cocoadev.com/index.pl?CGImageRef . - NSSize size = [image size]; - ScopedCFTypeRef context( - CGBitmapContextCreate(NULL, // Allow CG to allocate memory. - size.width, - size.height, - 8, // bitsPerComponent - 0, // bytesPerRow - CG will calculate by default. - [[NSColorSpace genericRGBColorSpace] CGColorSpace], - kCGBitmapByteOrder32Host | - kCGImageAlphaPremultipliedFirst)); - if (!context.get()) - return NULL; - - [NSGraphicsContext saveGraphicsState]; - [NSGraphicsContext setCurrentContext: - [NSGraphicsContext graphicsContextWithGraphicsPort:context.get() - flipped:NO]]; - [image drawInRect:NSMakeRect(0,0, size.width, size.height) - fromRect:NSZeroRect - operation:NSCompositeCopy - fraction:1.0]; - [NSGraphicsContext restoreGraphicsState]; - - return CGBitmapContextCreateImage(context); -} - -bool CheckLoginItemStatus(bool* is_hidden) { - ScopedCFTypeRef item(GetLoginItemForApp()); - if (!item.get()) - return false; - - if (is_hidden) - *is_hidden = IsHiddenLoginItem(item); - - return true; -} - -void AddToLoginItems(bool hide_on_startup) { - ScopedCFTypeRef item(GetLoginItemForApp()); - if (item.get() && (IsHiddenLoginItem(item) == hide_on_startup)) { - return; // Already is a login item with required hide flag. - } - - ScopedCFTypeRef login_items(LSSharedFileListCreate( - NULL, kLSSharedFileListSessionLoginItems, NULL)); - - if (!login_items.get()) { - DLOG(ERROR) << "Couldn't get a Login Items list."; - return; - } - - // Remove the old item, it has wrong hide flag, we'll create a new one. - if (item.get()) { - LSSharedFileListItemRemove(login_items, item); - } - - NSURL* url = [NSURL fileURLWithPath:[base::mac::MainBundle() bundlePath]]; - - BOOL hide = hide_on_startup ? YES : NO; - NSDictionary* properties = - [NSDictionary - dictionaryWithObject:[NSNumber numberWithBool:hide] - forKey:(NSString*)kLSSharedFileListLoginItemHidden]; - - ScopedCFTypeRef new_item; - new_item.reset(LSSharedFileListInsertItemURL( - login_items, kLSSharedFileListItemLast, NULL, NULL, - reinterpret_cast(url), - reinterpret_cast(properties), NULL)); - - if (!new_item.get()) { - DLOG(ERROR) << "Couldn't insert current app into Login Items list."; - } -} - -void RemoveFromLoginItems() { - ScopedCFTypeRef item(GetLoginItemForApp()); - if (!item.get()) - return; - - ScopedCFTypeRef login_items(LSSharedFileListCreate( - NULL, kLSSharedFileListSessionLoginItems, NULL)); - - if (!login_items.get()) { - DLOG(ERROR) << "Couldn't get a Login Items list."; - return; - } - - LSSharedFileListItemRemove(login_items, item); -} - -bool WasLaunchedAsLoginOrResumeItem() { - ProcessSerialNumber psn = { 0, kCurrentProcess }; - - base::scoped_nsobject process_info( - CFToNSCast(ProcessInformationCopyDictionary( - &psn, kProcessDictionaryIncludeAllInformationMask))); - - long long temp = [[process_info objectForKey:@"ParentPSN"] longLongValue]; - ProcessSerialNumber parent_psn = - { (temp >> 32) & 0x00000000FFFFFFFFLL, temp & 0x00000000FFFFFFFFLL }; - - base::scoped_nsobject parent_info( - CFToNSCast(ProcessInformationCopyDictionary( - &parent_psn, kProcessDictionaryIncludeAllInformationMask))); - - // Check that creator process code is that of loginwindow. - BOOL result = - [[parent_info objectForKey:@"FileCreator"] isEqualToString:@"lgnw"]; - - return result == YES; -} - -bool WasLaunchedAsHiddenLoginItem() { - if (!WasLaunchedAsLoginOrResumeItem()) - return false; - - ScopedCFTypeRef item(GetLoginItemForApp()); - if (!item.get()) { - // Lion can launch items for the resume feature. So log an error only for - // Snow Leopard or earlier. - if (IsOSSnowLeopard()) - DLOG(ERROR) << - "Process launched at Login but can't access Login Item List."; - - return false; - } - return IsHiddenLoginItem(item); -} - -bool RemoveQuarantineAttribute(const FilePath& file_path) { - const char kQuarantineAttrName[] = "com.apple.quarantine"; - int status = removexattr(file_path.value().c_str(), kQuarantineAttrName, 0); - return status == 0 || errno == ENOATTR; -} - -namespace { - -// Returns the running system's Darwin major version. Don't call this, it's -// an implementation detail and its result is meant to be cached by -// MacOSXMinorVersion. -int DarwinMajorVersionInternal() { - // base::OperatingSystemVersionNumbers calls Gestalt, which is a - // higher-level operation than is needed. It might perform unnecessary - // operations. On 10.6, it was observed to be able to spawn threads (see - // http://crbug.com/53200). It might also read files or perform other - // blocking operations. Actually, nobody really knows for sure just what - // Gestalt might do, or what it might be taught to do in the future. - // - // uname, on the other hand, is implemented as a simple series of sysctl - // system calls to obtain the relevant data from the kernel. The data is - // compiled right into the kernel, so no threads or blocking or other - // funny business is necessary. - - struct utsname uname_info; - if (uname(&uname_info) != 0) { - DPLOG(ERROR) << "uname"; - return 0; - } - - if (strcmp(uname_info.sysname, "Darwin") != 0) { - DLOG(ERROR) << "unexpected uname sysname " << uname_info.sysname; - return 0; - } - - int darwin_major_version = 0; - char* dot = strchr(uname_info.release, '.'); - if (dot) { - if (!base::StringToInt(base::StringPiece(uname_info.release, - dot - uname_info.release), - &darwin_major_version)) { - dot = NULL; - } - } - - if (!dot) { - DLOG(ERROR) << "could not parse uname release " << uname_info.release; - return 0; - } - - return darwin_major_version; -} - -// Returns the running system's Mac OS X minor version. This is the |y| value -// in 10.y or 10.y.z. Don't call this, it's an implementation detail and the -// result is meant to be cached by MacOSXMinorVersion. -int MacOSXMinorVersionInternal() { - int darwin_major_version = DarwinMajorVersionInternal(); - - // The Darwin major version is always 4 greater than the Mac OS X minor - // version for Darwin versions beginning with 6, corresponding to Mac OS X - // 10.2. Since this correspondence may change in the future, warn when - // encountering a version higher than anything seen before. Older Darwin - // versions, or versions that can't be determined, result in - // immediate death. - CHECK(darwin_major_version >= 6); - int mac_os_x_minor_version = darwin_major_version - 4; - DLOG_IF(WARNING, darwin_major_version > 12) << "Assuming Darwin " - << base::IntToString(darwin_major_version) << " is Mac OS X 10." - << base::IntToString(mac_os_x_minor_version); - - return mac_os_x_minor_version; -} - -// Returns the running system's Mac OS X minor version. This is the |y| value -// in 10.y or 10.y.z. -int MacOSXMinorVersion() { - static int mac_os_x_minor_version = MacOSXMinorVersionInternal(); - return mac_os_x_minor_version; -} - -enum { - SNOW_LEOPARD_MINOR_VERSION = 6, - LION_MINOR_VERSION = 7, - MOUNTAIN_LION_MINOR_VERSION = 8, -}; - -} // namespace - -#if !defined(BASE_MAC_MAC_UTIL_H_INLINED_GE_10_7) -bool IsOSSnowLeopard() { - return MacOSXMinorVersion() == SNOW_LEOPARD_MINOR_VERSION; -} -#endif - -#if !defined(BASE_MAC_MAC_UTIL_H_INLINED_GT_10_7) -bool IsOSLion() { - return MacOSXMinorVersion() == LION_MINOR_VERSION; -} -#endif - -#if !defined(BASE_MAC_MAC_UTIL_H_INLINED_GT_10_7) -bool IsOSLionOrEarlier() { - return MacOSXMinorVersion() <= LION_MINOR_VERSION; -} -#endif - -#if !defined(BASE_MAC_MAC_UTIL_H_INLINED_GE_10_7) -bool IsOSLionOrLater() { - return MacOSXMinorVersion() >= LION_MINOR_VERSION; -} -#endif - -#if !defined(BASE_MAC_MAC_UTIL_H_INLINED_GT_10_8) -bool IsOSMountainLion() { - return MacOSXMinorVersion() == MOUNTAIN_LION_MINOR_VERSION; -} -#endif - -#if !defined(BASE_MAC_MAC_UTIL_H_INLINED_GE_10_8) -bool IsOSMountainLionOrLater() { - return MacOSXMinorVersion() >= MOUNTAIN_LION_MINOR_VERSION; -} -#endif - -#if !defined(BASE_MAC_MAC_UTIL_H_INLINED_GT_10_8) -bool IsOSLaterThanMountainLion_DontCallThis() { - return MacOSXMinorVersion() > MOUNTAIN_LION_MINOR_VERSION; -} -#endif - -std::string GetModelIdentifier() { - std::string return_string; - ScopedIOObject platform_expert( - IOServiceGetMatchingService(kIOMasterPortDefault, - IOServiceMatching("IOPlatformExpertDevice"))); - if (platform_expert) { - ScopedCFTypeRef model_data( - static_cast(IORegistryEntryCreateCFProperty( - platform_expert, - CFSTR("model"), - kCFAllocatorDefault, - 0))); - if (model_data) { - return_string = - reinterpret_cast(CFDataGetBytePtr(model_data)); - } - } - return return_string; -} - -bool ParseModelIdentifier(const std::string& ident, - std::string* type, - int32* major, - int32* minor) { - size_t number_loc = ident.find_first_of("0123456789"); - if (number_loc == std::string::npos) - return false; - size_t comma_loc = ident.find(',', number_loc); - if (comma_loc == std::string::npos) - return false; - int32 major_tmp, minor_tmp; - std::string::const_iterator begin = ident.begin(); - if (!StringToInt( - StringPiece(begin + number_loc, begin + comma_loc), &major_tmp) || - !StringToInt( - StringPiece(begin + comma_loc + 1, ident.end()), &minor_tmp)) - return false; - *type = ident.substr(0, number_loc); - *major = major_tmp; - *minor = minor_tmp; - return true; -} - -} // namespace mac -} // namespace base diff --git a/base/mac/mac_util_unittest.mm b/base/mac/mac_util_unittest.mm deleted file mode 100644 index d246757870..0000000000 --- a/base/mac/mac_util_unittest.mm +++ /dev/null @@ -1,256 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#import - -#include "base/mac/mac_util.h" - -#include "base/file_util.h" -#include "base/files/file_path.h" -#include "base/files/scoped_temp_dir.h" -#include "base/mac/foundation_util.h" -#include "base/mac/scoped_cftyperef.h" -#include "base/mac/scoped_nsobject.h" -#include "base/sys_info.h" -#include "testing/gtest/include/gtest/gtest.h" -#include "testing/platform_test.h" - -#include -#include - -namespace base { -namespace mac { - -namespace { - -typedef PlatformTest MacUtilTest; - -TEST_F(MacUtilTest, TestFSRef) { - FSRef ref; - std::string path("/System/Library"); - - ASSERT_TRUE(FSRefFromPath(path, &ref)); - EXPECT_EQ(path, PathFromFSRef(ref)); -} - -TEST_F(MacUtilTest, GetUserDirectoryTest) { - // Try a few keys, make sure they come back with non-empty paths. - FilePath caches_dir; - EXPECT_TRUE(GetUserDirectory(NSCachesDirectory, &caches_dir)); - EXPECT_FALSE(caches_dir.empty()); - - FilePath application_support_dir; - EXPECT_TRUE(GetUserDirectory(NSApplicationSupportDirectory, - &application_support_dir)); - EXPECT_FALSE(application_support_dir.empty()); - - FilePath library_dir; - EXPECT_TRUE(GetUserDirectory(NSLibraryDirectory, &library_dir)); - EXPECT_FALSE(library_dir.empty()); -} - -TEST_F(MacUtilTest, TestLibraryPath) { - FilePath library_dir = GetUserLibraryPath(); - // Make sure the string isn't empty. - EXPECT_FALSE(library_dir.value().empty()); -} - -TEST_F(MacUtilTest, TestGetAppBundlePath) { - FilePath out; - - // Make sure it doesn't crash. - out = GetAppBundlePath(FilePath()); - EXPECT_TRUE(out.empty()); - - // Some more invalid inputs. - const char* invalid_inputs[] = { - "/", "/foo", "foo", "/foo/bar.", "foo/bar.", "/foo/bar./bazquux", - "foo/bar./bazquux", "foo/.app", "//foo", - }; - for (size_t i = 0; i < arraysize(invalid_inputs); i++) { - out = GetAppBundlePath(FilePath(invalid_inputs[i])); - EXPECT_TRUE(out.empty()) << "loop: " << i; - } - - // Some valid inputs; this and |expected_outputs| should be in sync. - struct { - const char *in; - const char *expected_out; - } valid_inputs[] = { - { "FooBar.app/", "FooBar.app" }, - { "/FooBar.app", "/FooBar.app" }, - { "/FooBar.app/", "/FooBar.app" }, - { "//FooBar.app", "//FooBar.app" }, - { "/Foo/Bar.app", "/Foo/Bar.app" }, - { "/Foo/Bar.app/", "/Foo/Bar.app" }, - { "/F/B.app", "/F/B.app" }, - { "/F/B.app/", "/F/B.app" }, - { "/Foo/Bar.app/baz", "/Foo/Bar.app" }, - { "/Foo/Bar.app/baz/", "/Foo/Bar.app" }, - { "/Foo/Bar.app/baz/quux.app/quuux", "/Foo/Bar.app" }, - { "/Applications/Google Foo.app/bar/Foo Helper.app/quux/Foo Helper", - "/Applications/Google Foo.app" }, - }; - for (size_t i = 0; i < ARRAYSIZE_UNSAFE(valid_inputs); i++) { - out = GetAppBundlePath(FilePath(valid_inputs[i].in)); - EXPECT_FALSE(out.empty()) << "loop: " << i; - EXPECT_STREQ(valid_inputs[i].expected_out, - out.value().c_str()) << "loop: " << i; - } -} - -TEST_F(MacUtilTest, TestExcludeFileFromBackups) { - // The file must already exist in order to set its exclusion property. - ScopedTempDir temp_dir_; - ASSERT_TRUE(temp_dir_.CreateUniqueTempDir()); - FilePath dummy_file_path = temp_dir_.path().Append("DummyFile"); - const char dummy_data[] = "All your base are belong to us!"; - // Dump something real into the file. - ASSERT_EQ(static_cast(arraysize(dummy_data)), - file_util::WriteFile(dummy_file_path, dummy_data, arraysize(dummy_data))); - NSString* fileURLString = - [NSString stringWithUTF8String:dummy_file_path.value().c_str()]; - NSURL* fileURL = [NSURL URLWithString:fileURLString]; - // Initial state should be non-excluded. - EXPECT_FALSE(CSBackupIsItemExcluded(base::mac::NSToCFCast(fileURL), NULL)); - // Exclude the file. - EXPECT_TRUE(SetFileBackupExclusion(dummy_file_path)); - // SetFileBackupExclusion never excludes by path. - Boolean excluded_by_path = FALSE; - Boolean excluded = - CSBackupIsItemExcluded(base::mac::NSToCFCast(fileURL), &excluded_by_path); - EXPECT_TRUE(excluded); - EXPECT_FALSE(excluded_by_path); -} - -TEST_F(MacUtilTest, CopyNSImageToCGImage) { - base::scoped_nsobject nsImage( - [[NSImage alloc] initWithSize:NSMakeSize(20, 20)]); - [nsImage lockFocus]; - [[NSColor redColor] set]; - NSRect rect = NSZeroRect; - rect.size = [nsImage size]; - NSRectFill(rect); - [nsImage unlockFocus]; - - ScopedCFTypeRef cgImage(CopyNSImageToCGImage(nsImage.get())); - EXPECT_TRUE(cgImage.get()); -} - -TEST_F(MacUtilTest, NSObjectRetainRelease) { - base::scoped_nsobject array( - [[NSArray alloc] initWithObjects:@"foo", nil]); - EXPECT_EQ(1U, [array retainCount]); - - NSObjectRetain(array); - EXPECT_EQ(2U, [array retainCount]); - - NSObjectRelease(array); - EXPECT_EQ(1U, [array retainCount]); -} - -TEST_F(MacUtilTest, IsOSEllipsis) { - int32 major, minor, bugfix; - base::SysInfo::OperatingSystemVersionNumbers(&major, &minor, &bugfix); - - if (major == 10) { - if (minor == 6) { - EXPECT_TRUE(IsOSSnowLeopard()); - EXPECT_FALSE(IsOSLion()); - EXPECT_TRUE(IsOSLionOrEarlier()); - EXPECT_FALSE(IsOSLionOrLater()); - EXPECT_FALSE(IsOSMountainLion()); - EXPECT_FALSE(IsOSMountainLionOrLater()); - EXPECT_FALSE(IsOSLaterThanMountainLion_DontCallThis()); - } else if (minor == 7) { - EXPECT_FALSE(IsOSSnowLeopard()); - EXPECT_TRUE(IsOSLion()); - EXPECT_TRUE(IsOSLionOrEarlier()); - EXPECT_TRUE(IsOSLionOrLater()); - EXPECT_FALSE(IsOSMountainLion()); - EXPECT_FALSE(IsOSMountainLionOrLater()); - EXPECT_FALSE(IsOSLaterThanMountainLion_DontCallThis()); - } else if (minor == 8) { - EXPECT_FALSE(IsOSSnowLeopard()); - EXPECT_FALSE(IsOSLion()); - EXPECT_FALSE(IsOSLionOrEarlier()); - EXPECT_TRUE(IsOSLionOrLater()); - EXPECT_TRUE(IsOSMountainLion()); - EXPECT_TRUE(IsOSMountainLionOrLater()); - EXPECT_FALSE(IsOSLaterThanMountainLion_DontCallThis()); - } else { - // Not five, six, seven, or eight. Ah, ah, ah. - EXPECT_TRUE(false); - } - } else { - // Not ten. What you gonna do? - EXPECT_FALSE(true); - } -} - -TEST_F(MacUtilTest, ParseModelIdentifier) { - std::string model; - int32 major = 1, minor = 2; - - EXPECT_FALSE(ParseModelIdentifier("", &model, &major, &minor)); - EXPECT_EQ(0U, model.length()); - EXPECT_EQ(1, major); - EXPECT_EQ(2, minor); - EXPECT_FALSE(ParseModelIdentifier("FooBar", &model, &major, &minor)); - - EXPECT_TRUE(ParseModelIdentifier("MacPro4,1", &model, &major, &minor)); - EXPECT_EQ(model, "MacPro"); - EXPECT_EQ(4, major); - EXPECT_EQ(1, minor); - - EXPECT_TRUE(ParseModelIdentifier("MacBookPro6,2", &model, &major, &minor)); - EXPECT_EQ(model, "MacBookPro"); - EXPECT_EQ(6, major); - EXPECT_EQ(2, minor); -} - -TEST_F(MacUtilTest, TestRemoveQuarantineAttribute) { - ScopedTempDir temp_dir_; - ASSERT_TRUE(temp_dir_.CreateUniqueTempDir()); - FilePath dummy_folder_path = temp_dir_.path().Append("DummyFolder"); - ASSERT_TRUE(file_util::CreateDirectory(dummy_folder_path)); - const char* quarantine_str = "0000;4b392bb2;Chromium;|org.chromium.Chromium"; - const char* file_path_str = dummy_folder_path.value().c_str(); - EXPECT_EQ(0, setxattr(file_path_str, "com.apple.quarantine", - quarantine_str, strlen(quarantine_str), 0, 0)); - EXPECT_EQ(static_cast(strlen(quarantine_str)), - getxattr(file_path_str, "com.apple.quarantine", - NULL, 0, 0, 0)); - EXPECT_TRUE(RemoveQuarantineAttribute(dummy_folder_path)); - EXPECT_EQ(-1, getxattr(file_path_str, "com.apple.quarantine", NULL, 0, 0, 0)); - EXPECT_EQ(ENOATTR, errno); -} - -TEST_F(MacUtilTest, TestRemoveQuarantineAttributeTwice) { - ScopedTempDir temp_dir_; - ASSERT_TRUE(temp_dir_.CreateUniqueTempDir()); - FilePath dummy_folder_path = temp_dir_.path().Append("DummyFolder"); - const char* file_path_str = dummy_folder_path.value().c_str(); - ASSERT_TRUE(file_util::CreateDirectory(dummy_folder_path)); - EXPECT_EQ(-1, getxattr(file_path_str, "com.apple.quarantine", NULL, 0, 0, 0)); - // No quarantine attribute to begin with, but RemoveQuarantineAttribute still - // succeeds because in the end the folder still doesn't have the quarantine - // attribute set. - EXPECT_TRUE(RemoveQuarantineAttribute(dummy_folder_path)); - EXPECT_TRUE(RemoveQuarantineAttribute(dummy_folder_path)); - EXPECT_EQ(ENOATTR, errno); -} - -TEST_F(MacUtilTest, TestRemoveQuarantineAttributeNonExistentPath) { - ScopedTempDir temp_dir_; - ASSERT_TRUE(temp_dir_.CreateUniqueTempDir()); - FilePath non_existent_path = temp_dir_.path().Append("DummyPath"); - ASSERT_FALSE(PathExists(non_existent_path)); - EXPECT_FALSE(RemoveQuarantineAttribute(non_existent_path)); -} - -} // namespace - -} // namespace mac -} // namespace base diff --git a/base/mac/objc_property_releaser.h b/base/mac/objc_property_releaser.h deleted file mode 100644 index 973d793218..0000000000 --- a/base/mac/objc_property_releaser.h +++ /dev/null @@ -1,127 +0,0 @@ -// Copyright (c) 2011 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef BASE_MAC_OBJC_PROPERTY_RELEASER_H_ -#define BASE_MAC_OBJC_PROPERTY_RELEASER_H_ - -#import - -#include "base/base_export.h" - -namespace base { -namespace mac { - -// ObjCPropertyReleaser is a C++ class that can automatically release -// synthesized Objective-C properties marked "retain" or "copy". The expected -// use is to place an ObjCPropertyReleaser object within an Objective-C class -// definition. When built with the -fobjc-call-cxx-cdtors compiler option, -// the ObjCPropertyReleaser's destructor will be called when the Objective-C -// object that owns it is deallocated, and it will send a -release message to -// the instance variables backing the appropriate properties. If -// -fobjc-call-cxx-cdtors is not in use, ObjCPropertyReleaser's -// ReleaseProperties method can be called from -dealloc to achieve the same -// effect. -// -// Example usage: -// -// @interface AllaysIBF : NSObject { -// @private -// NSString* string_; -// NSMutableDictionary* dictionary_; -// NSString* notAProperty_; -// IBFDelegate* delegate_; // weak -// -// // It's recommended to put the class name into the property releaser's -// // instance variable name to gracefully handle subclassing, where -// // multiple classes in a hierarchy might want their own property -// // releasers. -// base::mac::ObjCPropertyReleaser propertyReleaser_AllaysIBF_; -// } -// -// @property(retain, nonatomic) NSString* string; -// @property(copy, nonatomic) NSMutableDictionary* dictionary; -// @property(assign, nonatomic) IBFDelegate* delegate; -// @property(retain, nonatomic) NSString* autoProp; -// -// @end // @interface AllaysIBF -// -// @implementation AllaysIBF -// -// @synthesize string = string_; -// @synthesize dictionary = dictionary_; -// @synthesize delegate = delegate_; -// @synthesize autoProp; -// -// - (id)init { -// if ((self = [super init])) { -// // Initialize with [AllaysIBF class]. Never use [self class] because -// // in the case of subclassing, it will return the most specific class -// // for |self|, which may not be the same as [AllaysIBF class]. This -// // would cause AllaysIBF's -.cxx_destruct or -dealloc to release -// // instance variables that only exist in subclasses, likely causing -// // mass disaster. -// propertyReleaser_AllaysIBF_.Init(self, [AllaysIBF class]); -// } -// return self; -// } -// -// @end // @implementation AllaysIBF -// -// When an instance of AllaysIBF is deallocated, the ObjCPropertyReleaser will -// send a -release message to string_, dictionary_, and the compiler-created -// autoProp instance variables. No -release will be sent to delegate_ as it -// is marked "assign" and not "retain" or "copy". No -release will be sent to -// notAProperty_ because it doesn't correspond to any declared @property. -// -// Another way of doing this would be to provide a base class that others can -// inherit from, and to have the base class' -dealloc walk the property lists -// of all subclasses in an object to send the -release messages. Since this -// involves a base reaching into its subclasses, it's deemed scary, so don't -// do it. ObjCPropertyReleaser's design ensures that the property releaser -// will only operate on instance variables in the immediate object in which -// the property releaser is placed. - -class BASE_EXPORT ObjCPropertyReleaser { - public: - // ObjCPropertyReleaser can only be owned by an Objective-C object, so its - // memory is always guaranteed to be 0-initialized. Not defining the default - // constructor can prevent an otherwise no-op -.cxx_construct method from - // showing up in Objective-C classes that contain a ObjCPropertyReleaser. - - // Upon destruction (expected to occur from an Objective-C object's - // -.cxx_destruct method), release all properties. - ~ObjCPropertyReleaser() { - ReleaseProperties(); - } - - // Initialize this object so that it's armed to release the properties of - // object |object|, which must be of type |classy|. The class argument must - // be supplied separately and cannot be gleaned from the object's own type - // because an object will allays identify itself as the most-specific type - // that describes it, but the ObjCPropertyReleaser needs to know which class - // type in the class hierarchy it's responsible for releasing properties - // for. For the same reason, Init must be called with a |classy| argument - // initialized using a +class (class) method such as [MyClass class], and - // never a -class (instance) method such as [self class]. - // - // -.cxx_construct can only call the default constructor, but - // ObjCPropertyReleaser needs to know about the Objective-C object that owns - // it, so this can't be handled in a constructor, it needs to be a distinct - // Init method. - void Init(id object, Class classy); - - // Release all of the properties in object_ defined in class_ as either - // "retain" or "copy" and with an identifiable backing instance variable. - // Properties must be synthesized to have identifiable instance variables. - void ReleaseProperties(); - - private: - id object_; - Class class_; -}; - -} // namespace mac -} // namespace base - -#endif // BASE_MAC_OBJC_PROPERTY_RELEASER_H_ diff --git a/base/mac/objc_property_releaser.mm b/base/mac/objc_property_releaser.mm deleted file mode 100644 index f7ee88fbcc..0000000000 --- a/base/mac/objc_property_releaser.mm +++ /dev/null @@ -1,131 +0,0 @@ -// Copyright (c) 2011 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#import "base/mac/objc_property_releaser.h" - -#import -#include - -#include - -#include "base/logging.h" - -namespace base { -namespace mac { - -namespace { - -// Returns the name of the instance variable backing the property, if known, -// if the property is marked "retain" or "copy". If the instance variable name -// is not known (perhaps because it was not automatically associated with the -// property by @synthesize) or if the property is not "retain" or "copy", -// returns an empty string. -std::string ReleasableInstanceName(objc_property_t property) { - // TODO(mark): Starting in newer system releases, the Objective-C runtime - // provides a function to break the property attribute string into - // individual attributes (property_copyAttributeList), as well as a function - // to look up the value of a specific attribute - // (property_copyAttributeValue). When the SDK defining that interface is - // final, this function should be adapted to walk the attribute list as - // returned by property_copyAttributeList when that function is available in - // preference to scanning through the attribute list manually. - - // The format of the string returned by property_getAttributes is documented - // at - // http://developer.apple.com/library/mac/#documentation/Cocoa/Conceptual/ObjCRuntimeGuide/Articles/ocrtPropertyIntrospection.html#//apple_ref/doc/uid/TP40008048-CH101-SW6 - const char* property_attributes = property_getAttributes(property); - - std::string instance_name; - bool releasable = false; - while (*property_attributes) { - char name = *property_attributes; - - const char* value = ++property_attributes; - while (*property_attributes && *property_attributes != ',') { - ++property_attributes; - } - - switch (name) { - // It might seem intelligent to check the type ('T') attribute to verify - // that it identifies an NSObject-derived type (the attribute value - // begins with '@'.) This is a bad idea beacuse it fails to identify - // CFTypeRef-based properties declared as __attribute__((NSObject)), - // which just show up as pointers to their underlying CFType structs. - // - // Quoting - // http://developer.apple.com/library/mac/#documentation/Cocoa/Conceptual/ObjectiveC/Chapters/ocProperties.html#//apple_ref/doc/uid/TP30001163-CH17-SW27 - // - // > In Mac OS X v10.6 and later, you can use the __attribute__ keyword - // > to specify that a Core Foundation property should be treated like - // > an Objective-C object for memory management: - // > @property(retain) __attribute__((NSObject)) CFDictionaryRef - // > myDictionary; - case 'C': // copy - case '&': // retain - releasable = true; - break; - case 'V': // instance variable name - // 'V' is specified as the last attribute to occur in the - // documentation, but empirically, it's not always the last. In - // GC-supported or GC-required code, the 'P' (GC-eligible) attribute - // occurs after 'V'. - instance_name.assign(value, property_attributes - value); - break; - } - - if (*property_attributes) { - ++property_attributes; - } - } - - if (releasable) { - return instance_name; - } - - return std::string(); -} - -} // namespace - -void ObjCPropertyReleaser::Init(id object, Class classy) { - DCHECK(!object_); - DCHECK(!class_); - CHECK([object isKindOfClass:classy]); - - object_ = object; - class_ = classy; -} - -void ObjCPropertyReleaser::ReleaseProperties() { - DCHECK(object_); - DCHECK(class_); - - unsigned int property_count = 0; - objc_property_t* properties = class_copyPropertyList(class_, &property_count); - - for (unsigned int property_index = 0; - property_index < property_count; - ++property_index) { - objc_property_t property = properties[property_index]; - std::string instance_name = ReleasableInstanceName(property); - if (!instance_name.empty()) { - id instance_value = nil; - Ivar instance_variable = - object_getInstanceVariable(object_, instance_name.c_str(), - (void**)&instance_value); - DCHECK(instance_variable); - [instance_value release]; - } - } - - free(properties); - - // Clear object_ and class_ in case this ObjCPropertyReleaser will live on. - // It's only expected to release the properties it supervises once per Init. - object_ = nil; - class_ = nil; -} - -} // namespace mac -} // namespace base diff --git a/base/mac/objc_property_releaser_unittest.mm b/base/mac/objc_property_releaser_unittest.mm deleted file mode 100644 index 50f81a8762..0000000000 --- a/base/mac/objc_property_releaser_unittest.mm +++ /dev/null @@ -1,350 +0,0 @@ -// Copyright (c) 2011 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#import - -#import "base/mac/objc_property_releaser.h" -#import "base/mac/scoped_nsautorelease_pool.h" -#include "testing/gtest/include/gtest/gtest.h" - -// "When I'm alone, I count myself." -// --Count von Count, http://www.youtube.com/watch?v=FKzszqa9WA4 - -namespace { - -// The number of CountVonCounts outstanding. -int ah_ah_ah; - -// NumberHolder exists to exercise the property attribute string parser by -// providing a named struct and an anonymous union. -struct NumberHolder { - union { - long long sixty_four; - int thirty_two; - short sixteen; - char eight; - } what; - enum { - SIXTY_FOUR, - THIRTY_TWO, - SIXTEEN, - EIGHT - } how; -}; - -} // namespace - -@interface CountVonCount : NSObject - -+ (CountVonCount*)countVonCount; - -@end // @interface CountVonCount - -@implementation CountVonCount - -+ (CountVonCount*)countVonCount { - return [[[CountVonCount alloc] init] autorelease]; -} - -- (id)init { - ++ah_ah_ah; - return [super init]; -} - -- (void)dealloc { - --ah_ah_ah; - [super dealloc]; -} - -- (id)copyWithZone:(NSZone*)zone { - return [[CountVonCount allocWithZone:zone] init]; -} - -@end // @implementation CountVonCount - -@interface ObjCPropertyTestBase : NSObject { - @private - CountVonCount* baseCvcRetain_; - CountVonCount* baseCvcCopy_; - CountVonCount* baseCvcAssign_; - CountVonCount* baseCvcNotProperty_; - CountVonCount* baseCvcNil_; - CountVonCount* baseCvcCustom_; - int baseInt_; - double baseDouble_; - void* basePointer_; - NumberHolder baseStruct_; - - base::mac::ObjCPropertyReleaser propertyReleaser_ObjCPropertyTestBase_; -} - -@property(retain, nonatomic) CountVonCount* baseCvcRetain; -@property(copy, nonatomic) CountVonCount* baseCvcCopy; -@property(assign, nonatomic) CountVonCount* baseCvcAssign; -@property(retain, nonatomic) CountVonCount* baseCvcNil; -@property(retain, nonatomic, getter=baseCustom, setter=setBaseCustom:) - CountVonCount* baseCvcCustom; -@property(retain, nonatomic) CountVonCount* baseCvcDynamic; -@property(assign, nonatomic) int baseInt; -@property(assign, nonatomic) double baseDouble; -@property(assign, nonatomic) void* basePointer; -@property(assign, nonatomic) NumberHolder baseStruct; - -- (void)setBaseCvcNotProperty:(CountVonCount*)cvc; - -@end // @interface ObjCPropertyTestBase - -@implementation ObjCPropertyTestBase - -@synthesize baseCvcRetain = baseCvcRetain_; -@synthesize baseCvcCopy = baseCvcCopy_; -@synthesize baseCvcAssign = baseCvcAssign_; -@synthesize baseCvcNil = baseCvcNil_; -@synthesize baseCvcCustom = baseCvcCustom_; -@dynamic baseCvcDynamic; -@synthesize baseInt = baseInt_; -@synthesize baseDouble = baseDouble_; -@synthesize basePointer = basePointer_; -@synthesize baseStruct = baseStruct_; - -- (id)init { - if ((self = [super init])) { - propertyReleaser_ObjCPropertyTestBase_.Init( - self, [ObjCPropertyTestBase class]); - } - return self; -} - -- (void)dealloc { - [baseCvcNotProperty_ release]; - [super dealloc]; -} - -- (void)setBaseCvcNotProperty:(CountVonCount*)cvc { - if (cvc != baseCvcNotProperty_) { - [baseCvcNotProperty_ release]; - baseCvcNotProperty_ = [cvc retain]; - } -} - -@end // @implementation ObjCPropertyTestBase - -@protocol ObjCPropertyTestProtocol - -@property(retain, nonatomic) CountVonCount* protoCvcRetain; -@property(copy, nonatomic) CountVonCount* protoCvcCopy; -@property(assign, nonatomic) CountVonCount* protoCvcAssign; -@property(retain, nonatomic) CountVonCount* protoCvcNil; -@property(retain, nonatomic, getter=protoCustom, setter=setProtoCustom:) - CountVonCount* protoCvcCustom; -@property(retain, nonatomic) CountVonCount* protoCvcDynamic; -@property(assign, nonatomic) int protoInt; -@property(assign, nonatomic) double protoDouble; -@property(assign, nonatomic) void* protoPointer; -@property(assign, nonatomic) NumberHolder protoStruct; - -@end // @protocol ObjCPropertyTestProtocol - -@interface ObjCPropertyTestDerived - : ObjCPropertyTestBase { - @private - CountVonCount* derivedCvcRetain_; - CountVonCount* derivedCvcCopy_; - CountVonCount* derivedCvcAssign_; - CountVonCount* derivedCvcNotProperty_; - CountVonCount* derivedCvcNil_; - CountVonCount* derivedCvcCustom_; - int derivedInt_; - double derivedDouble_; - void* derivedPointer_; - NumberHolder derivedStruct_; - - CountVonCount* protoCvcRetain_; - CountVonCount* protoCvcCopy_; - CountVonCount* protoCvcAssign_; - CountVonCount* protoCvcNil_; - CountVonCount* protoCvcCustom_; - int protoInt_; - double protoDouble_; - void* protoPointer_; - NumberHolder protoStruct_; - - base::mac::ObjCPropertyReleaser propertyReleaser_ObjCPropertyTestDerived_; -} - -@property(retain, nonatomic) CountVonCount* derivedCvcRetain; -@property(copy, nonatomic) CountVonCount* derivedCvcCopy; -@property(assign, nonatomic) CountVonCount* derivedCvcAssign; -@property(retain, nonatomic) CountVonCount* derivedCvcNil; -@property(retain, nonatomic, getter=derivedCustom, setter=setDerivedCustom:) - CountVonCount* derivedCvcCustom; -@property(retain, nonatomic) CountVonCount* derivedCvcDynamic; -@property(assign, nonatomic) int derivedInt; -@property(assign, nonatomic) double derivedDouble; -@property(assign, nonatomic) void* derivedPointer; -@property(assign, nonatomic) NumberHolder derivedStruct; - -- (void)setDerivedCvcNotProperty:(CountVonCount*)cvc; - -@end // @interface ObjCPropertyTestDerived - -@implementation ObjCPropertyTestDerived - -@synthesize derivedCvcRetain = derivedCvcRetain_; -@synthesize derivedCvcCopy = derivedCvcCopy_; -@synthesize derivedCvcAssign = derivedCvcAssign_; -@synthesize derivedCvcNil = derivedCvcNil_; -@synthesize derivedCvcCustom = derivedCvcCustom_; -@dynamic derivedCvcDynamic; -@synthesize derivedInt = derivedInt_; -@synthesize derivedDouble = derivedDouble_; -@synthesize derivedPointer = derivedPointer_; -@synthesize derivedStruct = derivedStruct_; - -@synthesize protoCvcRetain = protoCvcRetain_; -@synthesize protoCvcCopy = protoCvcCopy_; -@synthesize protoCvcAssign = protoCvcAssign_; -@synthesize protoCvcNil = protoCvcNil_; -@synthesize protoCvcCustom = protoCvcCustom_; -@dynamic protoCvcDynamic; -@synthesize protoInt = protoInt_; -@synthesize protoDouble = protoDouble_; -@synthesize protoPointer = protoPointer_; -@synthesize protoStruct = protoStruct_; - -- (id)init { - if ((self = [super init])) { - propertyReleaser_ObjCPropertyTestDerived_.Init( - self, [ObjCPropertyTestDerived class]); - } - return self; -} - -- (void)dealloc { - [derivedCvcNotProperty_ release]; - [super dealloc]; -} - -- (void)setDerivedCvcNotProperty:(CountVonCount*)cvc { - if (cvc != derivedCvcNotProperty_) { - [derivedCvcNotProperty_ release]; - derivedCvcNotProperty_ = [cvc retain]; - } -} - -@end // @implementation ObjCPropertyTestDerived - -namespace { - -TEST(ObjCPropertyReleaserTest, SesameStreet) { - ObjCPropertyTestDerived* test_object = [[ObjCPropertyTestDerived alloc] init]; - - // Assure a clean slate. - EXPECT_EQ(0, ah_ah_ah); - EXPECT_EQ(1U, [test_object retainCount]); - - CountVonCount* baseAssign = [[CountVonCount alloc] init]; - CountVonCount* derivedAssign = [[CountVonCount alloc] init]; - CountVonCount* protoAssign = [[CountVonCount alloc] init]; - - // Make sure that worked before things get more involved. - EXPECT_EQ(3, ah_ah_ah); - - { - base::mac::ScopedNSAutoreleasePool pool; - - test_object.baseCvcRetain = [CountVonCount countVonCount]; - test_object.baseCvcCopy = [CountVonCount countVonCount]; - test_object.baseCvcAssign = baseAssign; - test_object.baseCvcCustom = [CountVonCount countVonCount]; - [test_object setBaseCvcNotProperty:[CountVonCount countVonCount]]; - - // That added 4 objects, plus 1 more that was copied. - EXPECT_EQ(8, ah_ah_ah); - - test_object.derivedCvcRetain = [CountVonCount countVonCount]; - test_object.derivedCvcCopy = [CountVonCount countVonCount]; - test_object.derivedCvcAssign = derivedAssign; - test_object.derivedCvcCustom = [CountVonCount countVonCount]; - [test_object setDerivedCvcNotProperty:[CountVonCount countVonCount]]; - - // That added 4 objects, plus 1 more that was copied. - EXPECT_EQ(13, ah_ah_ah); - - test_object.protoCvcRetain = [CountVonCount countVonCount]; - test_object.protoCvcCopy = [CountVonCount countVonCount]; - test_object.protoCvcAssign = protoAssign; - test_object.protoCvcCustom = [CountVonCount countVonCount]; - - // That added 3 objects, plus 1 more that was copied. - EXPECT_EQ(17, ah_ah_ah); - } - - // Now that the autorelease pool has been popped, the 3 objects that were - // copied when placed into the test object will have been deallocated. - EXPECT_EQ(14, ah_ah_ah); - - // Make sure that the setters work and have the expected semantics. - test_object.baseCvcRetain = nil; - test_object.baseCvcCopy = nil; - test_object.baseCvcAssign = nil; - test_object.baseCvcCustom = nil; - test_object.derivedCvcRetain = nil; - test_object.derivedCvcCopy = nil; - test_object.derivedCvcAssign = nil; - test_object.derivedCvcCustom = nil; - test_object.protoCvcRetain = nil; - test_object.protoCvcCopy = nil; - test_object.protoCvcAssign = nil; - test_object.protoCvcCustom = nil; - - // The CountVonCounts marked "retain" and "copy" should have been - // deallocated. Those marked assign should not have been. The only ones that - // should exist now are the ones marked "assign" and the ones held in - // non-property instance variables. - EXPECT_EQ(5, ah_ah_ah); - - { - base::mac::ScopedNSAutoreleasePool pool; - - // Put things back to how they were. - test_object.baseCvcRetain = [CountVonCount countVonCount]; - test_object.baseCvcCopy = [CountVonCount countVonCount]; - test_object.baseCvcAssign = baseAssign; - test_object.baseCvcCustom = [CountVonCount countVonCount]; - test_object.derivedCvcRetain = [CountVonCount countVonCount]; - test_object.derivedCvcCopy = [CountVonCount countVonCount]; - test_object.derivedCvcAssign = derivedAssign; - test_object.derivedCvcCustom = [CountVonCount countVonCount]; - test_object.protoCvcRetain = [CountVonCount countVonCount]; - test_object.protoCvcCopy = [CountVonCount countVonCount]; - test_object.protoCvcAssign = protoAssign; - test_object.protoCvcCustom = [CountVonCount countVonCount]; - - // 9 more CountVonCounts, 3 of which were copied. - EXPECT_EQ(17, ah_ah_ah); - } - - // Now that the autorelease pool has been popped, the 3 copies are gone. - EXPECT_EQ(14, ah_ah_ah); - - // Releasing the test object should get rid of everything that it owns. - [test_object release]; - - // The property releaser should have released all of the CountVonCounts - // associated with properties marked "retain" or "copy". The -dealloc - // methods in each should have released the single non-property objects in - // each. Only the CountVonCounts assigned to the properties marked "assign" - // should remain. - EXPECT_EQ(3, ah_ah_ah); - - [baseAssign release]; - [derivedAssign release]; - [protoAssign release]; - - // Zero! Zero counts! Ah, ah, ah. - EXPECT_EQ(0, ah_ah_ah); -} - -} // namespace diff --git a/base/mac/os_crash_dumps.cc b/base/mac/os_crash_dumps.cc deleted file mode 100644 index e6b0996ac6..0000000000 --- a/base/mac/os_crash_dumps.cc +++ /dev/null @@ -1,57 +0,0 @@ -// Copyright (c) 2010 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "base/mac/os_crash_dumps.h" - -#include -#include - -#include "base/basictypes.h" -#include "base/logging.h" - -namespace base { -namespace mac { - -namespace { - -void ExitSignalHandler(int sig) { - // A call to exit() can call atexit() handlers. If we SIGSEGV due - // to a corrupt heap, and if we have an atexit handler that - // allocates or frees memory, we are in trouble if we do not _exit. - _exit(128 + sig); -} - -} // namespace - -void DisableOSCrashDumps() { - // These are the POSIX signals corresponding to the Mach exceptions that - // Apple Crash Reporter handles. See ux_exception() in xnu's - // bsd/uxkern/ux_exception.c and machine_exception() in xnu's - // bsd/dev/*/unix_signal.c. - const int signals_to_intercept[] = { - SIGILL, // EXC_BAD_INSTRUCTION - SIGTRAP, // EXC_BREAKPOINT - SIGFPE, // EXC_ARITHMETIC - SIGBUS, // EXC_BAD_ACCESS - SIGSEGV // EXC_BAD_ACCESS - }; - - // For all these signals, just wire things up so we exit immediately. - for (size_t i = 0; i < arraysize(signals_to_intercept); ++i) { - struct sigaction act = {}; - act.sa_handler = ExitSignalHandler; - - // It is better to allow the signal handler to run on the stack - // registered with sigaltstack(), if one is present. - act.sa_flags = SA_ONSTACK; - - if (sigemptyset(&act.sa_mask) != 0) - DLOG_ERRNO(FATAL) << "sigemptyset() failed"; - if (sigaction(signals_to_intercept[i], &act, NULL) != 0) - DLOG_ERRNO(FATAL) << "sigaction() failed"; - } -} - -} // namespace mac -} // namespace base diff --git a/base/mac/os_crash_dumps.h b/base/mac/os_crash_dumps.h deleted file mode 100644 index 31d90fb24f..0000000000 --- a/base/mac/os_crash_dumps.h +++ /dev/null @@ -1,22 +0,0 @@ -// Copyright (c) 2011 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef BASE_MAC_OS_CRASH_DUMPS_H_ -#define BASE_MAC_OS_CRASH_DUMPS_H_ - -#include "base/base_export.h" - -namespace base { -namespace mac { - -// On Mac OS X, it can take a really long time for the OS crash handler to -// process a Chrome crash when debugging symbols are available. This -// translates into a long wait until the process actually dies. This call -// disables Apple Crash Reporter entirely. -BASE_EXPORT void DisableOSCrashDumps(); - -} // namespace mac -} // namespace base - -#endif // BASE_MAC_OS_CRASH_DUMPS_H_ diff --git a/base/mac/scoped_aedesc.h b/base/mac/scoped_aedesc.h deleted file mode 100644 index a1323c0cb7..0000000000 --- a/base/mac/scoped_aedesc.h +++ /dev/null @@ -1,52 +0,0 @@ -// Copyright (c) 2010 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef BASE_MAC_SCOPED_AEDESC_H_ -#define BASE_MAC_SCOPED_AEDESC_H_ - -#import - -#include "base/basictypes.h" - -namespace base { -namespace mac { - -// The ScopedAEDesc is used to scope AppleEvent descriptors. On creation, -// it will store a NULL descriptor. On destruction, it will dispose of the -// descriptor. -// -// This class is parameterized for additional type safety checks. You can use -// the generic AEDesc type by not providing a template parameter: -// ScopedAEDesc<> desc; -template -class ScopedAEDesc { - public: - ScopedAEDesc() { - AECreateDesc(typeNull, NULL, 0, &desc_); - } - - ~ScopedAEDesc() { - AEDisposeDesc(&desc_); - } - - // Used for in parameters. - operator const AEDescType*() { - return &desc_; - } - - // Used for out parameters. - AEDescType* OutPointer() { - return &desc_; - } - - private: - AEDescType desc_; - - DISALLOW_COPY_AND_ASSIGN(ScopedAEDesc); -}; - -} // namespace mac -} // namespace base - -#endif // BASE_MAC_SCOPED_AEDESC_H_ diff --git a/base/mac/scoped_authorizationref.h b/base/mac/scoped_authorizationref.h deleted file mode 100644 index 6413f2e416..0000000000 --- a/base/mac/scoped_authorizationref.h +++ /dev/null @@ -1,85 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef BASE_MAC_SCOPED_AUTHORIZATIONREF_H_ -#define BASE_MAC_SCOPED_AUTHORIZATIONREF_H_ - -#include - -#include "base/basictypes.h" -#include "base/compiler_specific.h" - -// ScopedAuthorizationRef maintains ownership of an AuthorizationRef. It is -// patterned after the scoped_ptr interface. - -namespace base { -namespace mac { - -class ScopedAuthorizationRef { - public: - explicit ScopedAuthorizationRef(AuthorizationRef authorization = NULL) - : authorization_(authorization) { - } - - ~ScopedAuthorizationRef() { - if (authorization_) { - AuthorizationFree(authorization_, kAuthorizationFlagDestroyRights); - } - } - - void reset(AuthorizationRef authorization = NULL) { - if (authorization_ != authorization) { - if (authorization_) { - AuthorizationFree(authorization_, kAuthorizationFlagDestroyRights); - } - authorization_ = authorization; - } - } - - bool operator==(AuthorizationRef that) const { - return authorization_ == that; - } - - bool operator!=(AuthorizationRef that) const { - return authorization_ != that; - } - - operator AuthorizationRef() const { - return authorization_; - } - - AuthorizationRef* operator&() { - return &authorization_; - } - - AuthorizationRef get() const { - return authorization_; - } - - void swap(ScopedAuthorizationRef& that) { - AuthorizationRef temp = that.authorization_; - that.authorization_ = authorization_; - authorization_ = temp; - } - - // ScopedAuthorizationRef::release() is like scoped_ptr<>::release. It is - // NOT a wrapper for AuthorizationFree(). To force a - // ScopedAuthorizationRef object to call AuthorizationFree(), use - // ScopedAuthorizationRef::reset(). - AuthorizationRef release() WARN_UNUSED_RESULT { - AuthorizationRef temp = authorization_; - authorization_ = NULL; - return temp; - } - - private: - AuthorizationRef authorization_; - - DISALLOW_COPY_AND_ASSIGN(ScopedAuthorizationRef); -}; - -} // namespace mac -} // namespace base - -#endif // BASE_MAC_SCOPED_AUTHORIZATIONREF_H_ diff --git a/base/mac/scoped_block.h b/base/mac/scoped_block.h deleted file mode 100644 index 509a1c2c19..0000000000 --- a/base/mac/scoped_block.h +++ /dev/null @@ -1,92 +0,0 @@ -// Copyright (c) 2013 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef BASE_MAC_SCOPED_BLOCK_H_ -#define BASE_MAC_SCOPED_BLOCK_H_ - -#include - -#include "base/basictypes.h" -#include "base/compiler_specific.h" -#include "base/memory/scoped_policy.h" - -namespace base { -namespace mac { - -// ScopedBlock<> is patterned after ScopedCFTypeRef<>, but uses Block_copy() and -// Block_release() instead of CFRetain() and CFRelease(). - -template -class ScopedBlock { - public: - explicit ScopedBlock( - B block = NULL, - base::scoped_policy::OwnershipPolicy policy = base::scoped_policy::ASSUME) - : block_(block) { - if (block_ && policy == base::scoped_policy::RETAIN) - block_ = Block_copy(block); - } - - ScopedBlock(const ScopedBlock& that) - : block_(that.block_) { - if (block_) - block_ = Block_copy(block_); - } - - ~ScopedBlock() { - if (block_) - Block_release(block_); - } - - ScopedBlock& operator=(const ScopedBlock& that) { - reset(that.get(), base::scoped_policy::RETAIN); - return *this; - } - - void reset(B block = NULL, - base::scoped_policy::OwnershipPolicy policy = - base::scoped_policy::ASSUME) { - if (block && policy == base::scoped_policy::RETAIN) - block = Block_copy(block); - if (block_) - Block_release(block_); - block_ = block; - } - - bool operator==(B that) const { - return block_ == that; - } - - bool operator!=(B that) const { - return block_ != that; - } - - operator B() const { - return block_; - } - - B get() const { - return block_; - } - - void swap(ScopedBlock& that) { - B temp = that.block_; - that.block_ = block_; - block_ = temp; - } - - B release() WARN_UNUSED_RESULT { - B temp = block_; - block_ = NULL; - return temp; - } - - private: - B block_; -}; - -} // namespace mac -} // namespace base - -#endif // BASE_MAC_SCOPED_BLOCK_H_ diff --git a/base/mac/scoped_cffiledescriptorref.h b/base/mac/scoped_cffiledescriptorref.h deleted file mode 100644 index 07196aa921..0000000000 --- a/base/mac/scoped_cffiledescriptorref.h +++ /dev/null @@ -1,75 +0,0 @@ -// Copyright 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef BASE_MAC_SCOPED_CFFILEDESCRIPTORREF_H_ -#define BASE_MAC_SCOPED_CFFILEDESCRIPTORREF_H_ - -#include - -#include "base/basictypes.h" -#include "base/compiler_specific.h" - -namespace base { -namespace mac { - -// ScopedCFFileDescriptorRef is designed after ScopedCFTypeRef<>. On -// destruction, it will invalidate the file descriptor. -// ScopedCFFileDescriptorRef (unlike ScopedCFTypeRef<>) does not support RETAIN -// semantics, copying, or assignment, as doing so would increase the chances -// that a file descriptor is invalidated while still in use. -class ScopedCFFileDescriptorRef { - public: - explicit ScopedCFFileDescriptorRef(CFFileDescriptorRef fdref = NULL) - : fdref_(fdref) { - } - - ~ScopedCFFileDescriptorRef() { - if (fdref_) { - CFFileDescriptorInvalidate(fdref_); - CFRelease(fdref_); - } - } - - void reset(CFFileDescriptorRef fdref = NULL) { - if (fdref_ == fdref) - return; - if (fdref_) { - CFFileDescriptorInvalidate(fdref_); - CFRelease(fdref_); - } - fdref_ = fdref; - } - - bool operator==(CFFileDescriptorRef that) const { - return fdref_ == that; - } - - bool operator!=(CFFileDescriptorRef that) const { - return fdref_ != that; - } - - operator CFFileDescriptorRef() const { - return fdref_; - } - - CFFileDescriptorRef get() const { - return fdref_; - } - - CFFileDescriptorRef release() WARN_UNUSED_RESULT { - CFFileDescriptorRef temp = fdref_; - fdref_ = NULL; - return temp; - } - - private: - CFFileDescriptorRef fdref_; - - DISALLOW_COPY_AND_ASSIGN(ScopedCFFileDescriptorRef); -}; - -} // namespace mac -} // namespace base - -#endif // BASE_MAC_SCOPED_CFFILEDESCRIPTORREF_H_ diff --git a/base/mac/scoped_cftyperef.h b/base/mac/scoped_cftyperef.h deleted file mode 100644 index c41de80d80..0000000000 --- a/base/mac/scoped_cftyperef.h +++ /dev/null @@ -1,106 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef BASE_MAC_SCOPED_CFTYPEREF_H_ -#define BASE_MAC_SCOPED_CFTYPEREF_H_ - -#include - -#include "base/basictypes.h" -#include "base/compiler_specific.h" -#include "base/memory/scoped_policy.h" - -namespace base { - -// ScopedCFTypeRef<> is patterned after scoped_ptr<>, but maintains ownership -// of a CoreFoundation object: any object that can be represented as a -// CFTypeRef. Style deviations here are solely for compatibility with -// scoped_ptr<>'s interface, with which everyone is already familiar. -// -// By default, ScopedCFTypeRef<> takes ownership of an object (in the -// constructor or in reset()) by taking over the caller's existing ownership -// claim. The caller must own the object it gives to ScopedCFTypeRef<>, and -// relinquishes an ownership claim to that object. ScopedCFTypeRef<> does not -// call CFRetain(). This behavior is parameterized by the |OwnershipPolicy| -// enum. If the value |RETAIN| is passed (in the constructor or in reset()), -// then ScopedCFTypeRef<> will call CFRetain() on the object, and the initial -// ownership is not changed. - -template -class ScopedCFTypeRef { - public: - typedef CFT element_type; - - explicit ScopedCFTypeRef( - CFT object = NULL, - base::scoped_policy::OwnershipPolicy policy = base::scoped_policy::ASSUME) - : object_(object) { - if (object_ && policy == base::scoped_policy::RETAIN) - CFRetain(object_); - } - - ScopedCFTypeRef(const ScopedCFTypeRef& that) - : object_(that.object_) { - if (object_) - CFRetain(object_); - } - - ~ScopedCFTypeRef() { - if (object_) - CFRelease(object_); - } - - ScopedCFTypeRef& operator=(const ScopedCFTypeRef& that) { - reset(that.get(), base::scoped_policy::RETAIN); - return *this; - } - - void reset(CFT object = NULL, - base::scoped_policy::OwnershipPolicy policy = - base::scoped_policy::ASSUME) { - if (object && policy == base::scoped_policy::RETAIN) - CFRetain(object); - if (object_) - CFRelease(object_); - object_ = object; - } - - bool operator==(CFT that) const { - return object_ == that; - } - - bool operator!=(CFT that) const { - return object_ != that; - } - - operator CFT() const { - return object_; - } - - CFT get() const { - return object_; - } - - void swap(ScopedCFTypeRef& that) { - CFT temp = that.object_; - that.object_ = object_; - object_ = temp; - } - - // ScopedCFTypeRef<>::release() is like scoped_ptr<>::release. It is NOT - // a wrapper for CFRelease(). To force a ScopedCFTypeRef<> object to call - // CFRelease(), use ScopedCFTypeRef<>::reset(). - CFT release() WARN_UNUSED_RESULT { - CFT temp = object_; - object_ = NULL; - return temp; - } - - private: - CFT object_; -}; - -} // namespace base - -#endif // BASE_MAC_SCOPED_CFTYPEREF_H_ diff --git a/base/mac/scoped_ioobject.h b/base/mac/scoped_ioobject.h deleted file mode 100644 index 854039b553..0000000000 --- a/base/mac/scoped_ioobject.h +++ /dev/null @@ -1,74 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef BASE_MAC_SCOPED_IOOBJECT_H_ -#define BASE_MAC_SCOPED_IOOBJECT_H_ - -#include - -#include "base/basictypes.h" -#include "base/compiler_specific.h" - -namespace base { -namespace mac { - -// Just like ScopedCFTypeRef but for io_object_t and subclasses. -template -class ScopedIOObject { - public: - typedef IOT element_type; - - explicit ScopedIOObject(IOT object = IO_OBJECT_NULL) - : object_(object) { - } - - ~ScopedIOObject() { - if (object_) - IOObjectRelease(object_); - } - - void reset(IOT object = IO_OBJECT_NULL) { - if (object_) - IOObjectRelease(object_); - object_ = object; - } - - bool operator==(IOT that) const { - return object_ == that; - } - - bool operator!=(IOT that) const { - return object_ != that; - } - - operator IOT() const { - return object_; - } - - IOT get() const { - return object_; - } - - void swap(ScopedIOObject& that) { - IOT temp = that.object_; - that.object_ = object_; - object_ = temp; - } - - IOT release() WARN_UNUSED_RESULT { - IOT temp = object_; - object_ = IO_OBJECT_NULL; - return temp; - } - - private: - IOT object_; - - DISALLOW_COPY_AND_ASSIGN(ScopedIOObject); -}; - -} // namespace mac -} // namespace base - -#endif // BASE_MAC_SCOPED_IOOBJECT_H_ diff --git a/base/mac/scoped_ioplugininterface.h b/base/mac/scoped_ioplugininterface.h deleted file mode 100644 index 503980c3ef..0000000000 --- a/base/mac/scoped_ioplugininterface.h +++ /dev/null @@ -1,76 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef BASE_MAC_SCOPED_IOPLUGININTERFACE_H_ -#define BASE_MAC_SCOPED_IOPLUGININTERFACE_H_ - -#include - -#include "base/basictypes.h" -#include "base/compiler_specific.h" - -namespace base { -namespace mac { - -// Just like ScopedCFTypeRef but for IOCFPlugInInterface and friends -// (IOUSBInterfaceStruct and IOUSBDeviceStruct320 in particular). -template -class ScopedIOPluginInterface { - public: - typedef T** InterfaceT; - typedef InterfaceT element_type; - - explicit ScopedIOPluginInterface(InterfaceT object = NULL) - : object_(object) { - } - - ~ScopedIOPluginInterface() { - if (object_) - (*object_)->Release(object_); - } - - void reset(InterfaceT object = NULL) { - if (object_) - (*object_)->Release(object_); - object_ = object; - } - - bool operator==(InterfaceT that) const { - return object_ == that; - } - - bool operator!=(InterfaceT that) const { - return object_ != that; - } - - operator InterfaceT() const { - return object_; - } - - InterfaceT get() const { - return object_; - } - - void swap(ScopedIOPluginInterface& that) { - InterfaceT temp = that.object_; - that.object_ = object_; - object_ = temp; - } - - InterfaceT release() WARN_UNUSED_RESULT { - InterfaceT temp = object_; - object_ = NULL; - return temp; - } - - private: - InterfaceT object_; - - DISALLOW_COPY_AND_ASSIGN(ScopedIOPluginInterface); -}; - -} // namespace mac -} // namespace base - -#endif // BASE_MAC_SCOPED_IOPLUGININTERFACE_H_ diff --git a/base/mac/scoped_launch_data.h b/base/mac/scoped_launch_data.h deleted file mode 100644 index e4343b8939..0000000000 --- a/base/mac/scoped_launch_data.h +++ /dev/null @@ -1,75 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef BASE_MAC_SCOPED_LAUNCH_DATA_H_ -#define BASE_MAC_SCOPED_LAUNCH_DATA_H_ - -#include - -#include - -#include "base/basictypes.h" -#include "base/compiler_specific.h" - -namespace base { -namespace mac { - -// Just like scoped_ptr<> but for launch_data_t. -class ScopedLaunchData { - public: - typedef launch_data_t element_type; - - explicit ScopedLaunchData(launch_data_t object = NULL) - : object_(object) { - } - - ~ScopedLaunchData() { - if (object_) - launch_data_free(object_); - } - - void reset(launch_data_t object = NULL) { - if (object != object_) { - if (object_) - launch_data_free(object_); - object_ = object; - } - } - - bool operator==(launch_data_t that) const { - return object_ == that; - } - - bool operator!=(launch_data_t that) const { - return object_ != that; - } - - operator launch_data_t() const { - return object_; - } - - launch_data_t get() const { - return object_; - } - - void swap(ScopedLaunchData& that) { - std::swap(object_, that.object_); - } - - launch_data_t release() WARN_UNUSED_RESULT { - launch_data_t temp = object_; - object_ = NULL; - return temp; - } - - private: - launch_data_t object_; - - DISALLOW_COPY_AND_ASSIGN(ScopedLaunchData); -}; - -} // namespace mac -} // namespace base - -#endif // BASE_MAC_SCOPED_LAUNCH_DATA_H_ diff --git a/base/mac/scoped_mach_port.cc b/base/mac/scoped_mach_port.cc deleted file mode 100644 index 9e45a856a8..0000000000 --- a/base/mac/scoped_mach_port.cc +++ /dev/null @@ -1,25 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "base/mac/scoped_mach_port.h" - -namespace base { -namespace mac { - -ScopedMachPort::ScopedMachPort(mach_port_t port) : port_(port) { -} - -ScopedMachPort::~ScopedMachPort() { - reset(); -} - -void ScopedMachPort::reset(mach_port_t port) { - if (port_ != MACH_PORT_NULL) { - mach_port_deallocate(mach_task_self(), port_); - } - port_ = port; -} - -} // namespace mac -} // namespace base diff --git a/base/mac/scoped_mach_port.h b/base/mac/scoped_mach_port.h deleted file mode 100644 index cc2ef20fe7..0000000000 --- a/base/mac/scoped_mach_port.h +++ /dev/null @@ -1,44 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef BASE_MAC_SCOPED_MACH_PORT_H_ -#define BASE_MAC_SCOPED_MACH_PORT_H_ - -#include - -#include "base/basictypes.h" -#include "base/base_export.h" - -namespace base { -namespace mac { - -// A class for managing the life of a Mach port, releasing via -// mach_port_deallocate either its send and/or receive rights. -class BASE_EXPORT ScopedMachPort { - public: - // Creates a scoper by taking ownership of the port. - explicit ScopedMachPort(mach_port_t port); - - ~ScopedMachPort(); - - void reset(mach_port_t port = MACH_PORT_NULL); - - operator mach_port_t() const { - return port_; - } - - mach_port_t get() const { - return port_; - } - - private: - mach_port_t port_; - - DISALLOW_COPY_AND_ASSIGN(ScopedMachPort); -}; - -} // namespace mac -} // namespace base - -#endif // BASE_MAC_SCOPED_MACH_PORT_H_ diff --git a/base/mac/scoped_nsautorelease_pool.h b/base/mac/scoped_nsautorelease_pool.h deleted file mode 100644 index 60af71ae05..0000000000 --- a/base/mac/scoped_nsautorelease_pool.h +++ /dev/null @@ -1,45 +0,0 @@ -// Copyright (c) 2011 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef BASE_MAC_SCOPED_NSAUTORELEASE_POOL_H_ -#define BASE_MAC_SCOPED_NSAUTORELEASE_POOL_H_ - -#include "base/base_export.h" -#include "base/basictypes.h" - -#if defined(__OBJC__) -@class NSAutoreleasePool; -#else // __OBJC__ -class NSAutoreleasePool; -#endif // __OBJC__ - -namespace base { -namespace mac { - -// ScopedNSAutoreleasePool allocates an NSAutoreleasePool when instantiated and -// sends it a -drain message when destroyed. This allows an autorelease pool to -// be maintained in ordinary C++ code without bringing in any direct Objective-C -// dependency. - -class BASE_EXPORT ScopedNSAutoreleasePool { - public: - ScopedNSAutoreleasePool(); - ~ScopedNSAutoreleasePool(); - - // Clear out the pool in case its position on the stack causes it to be - // alive for long periods of time (such as the entire length of the app). - // Only use then when you're certain the items currently in the pool are - // no longer needed. - void Recycle(); - private: - NSAutoreleasePool* autorelease_pool_; - - private: - DISALLOW_COPY_AND_ASSIGN(ScopedNSAutoreleasePool); -}; - -} // namespace mac -} // namespace base - -#endif // BASE_MAC_SCOPED_NSAUTORELEASE_POOL_H_ diff --git a/base/mac/scoped_nsautorelease_pool.mm b/base/mac/scoped_nsautorelease_pool.mm deleted file mode 100644 index e542ca86b2..0000000000 --- a/base/mac/scoped_nsautorelease_pool.mm +++ /dev/null @@ -1,32 +0,0 @@ -// Copyright (c) 2010 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "base/mac/scoped_nsautorelease_pool.h" - -#import - -#include "base/logging.h" - -namespace base { -namespace mac { - -ScopedNSAutoreleasePool::ScopedNSAutoreleasePool() - : autorelease_pool_([[NSAutoreleasePool alloc] init]) { - DCHECK(autorelease_pool_); -} - -ScopedNSAutoreleasePool::~ScopedNSAutoreleasePool() { - [autorelease_pool_ drain]; -} - -// Cycle the internal pool, allowing everything there to get cleaned up and -// start anew. -void ScopedNSAutoreleasePool::Recycle() { - [autorelease_pool_ drain]; - autorelease_pool_ = [[NSAutoreleasePool alloc] init]; - DCHECK(autorelease_pool_); -} - -} // namespace mac -} // namespace base diff --git a/base/mac/scoped_nsexception_enabler.h b/base/mac/scoped_nsexception_enabler.h deleted file mode 100644 index 484dd53449..0000000000 --- a/base/mac/scoped_nsexception_enabler.h +++ /dev/null @@ -1,54 +0,0 @@ -// Copyright (c) 2011 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef BASE_MAC_SCOPED_NSEXCEPTION_ENABLER_H_ -#define BASE_MAC_SCOPED_NSEXCEPTION_ENABLER_H_ - -#import - -#include "base/base_export.h" -#include "base/basictypes.h" - -namespace base { -namespace mac { - -// BrowserCrApplication attempts to restrict throwing of NSExceptions -// because they interact badly with C++ scoping rules. Unfortunately, -// there are some cases where exceptions must be supported, such as -// when third-party printer drivers are used. These helpers can be -// used to enable exceptions for narrow windows. - -// Make it easy to safely allow NSException to be thrown in a limited -// scope. Note that if an exception is thrown, then this object will -// not be appropriately destructed! If the exception ends up in the -// top-level event loop, things are cleared in -reportException:. If -// the exception is caught at a lower level, a higher level scoper -// should eventually reset things. -class BASE_EXPORT ScopedNSExceptionEnabler { - public: - ScopedNSExceptionEnabler(); - ~ScopedNSExceptionEnabler(); - - private: - bool was_enabled_; - - DISALLOW_COPY_AND_ASSIGN(ScopedNSExceptionEnabler); -}; - -// Access the exception setting for the current thread. This is for -// the support code in BrowserCrApplication, other code should use -// the scoper. -BASE_EXPORT bool GetNSExceptionsAllowed(); -BASE_EXPORT void SetNSExceptionsAllowed(bool allowed); - -// Executes |block| with fatal-exceptions turned off, and returns the -// result. If an exception is thrown during the perform, nil is -// returned. -typedef id (^BlockReturningId)(); -BASE_EXPORT id RunBlockIgnoringExceptions(BlockReturningId block); - -} // namespace mac -} // namespace base - -#endif // BASE_MAC_SCOPED_NSEXCEPTION_ENABLER_H_ diff --git a/base/mac/scoped_nsexception_enabler.mm b/base/mac/scoped_nsexception_enabler.mm deleted file mode 100644 index 7b8ad9266b..0000000000 --- a/base/mac/scoped_nsexception_enabler.mm +++ /dev/null @@ -1,63 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#import "base/mac/scoped_nsexception_enabler.h" - -#import "base/lazy_instance.h" -#import "base/threading/thread_local.h" - -// To make the |g_exceptionsAllowed| declaration readable. -using base::LazyInstance; -using base::ThreadLocalBoolean; - -// When C++ exceptions are disabled, the C++ library defines |try| and -// |catch| so as to allow exception-expecting C++ code to build properly when -// language support for exceptions is not present. These macros interfere -// with the use of |@try| and |@catch| in Objective-C files such as this one. -// Undefine these macros here, after everything has been #included, since -// there will be no C++ uses and only Objective-C uses from this point on. -#undef try -#undef catch - -namespace { - -// Whether to allow NSExceptions to be raised on the current thread. -LazyInstance::Leaky - g_exceptionsAllowed = LAZY_INSTANCE_INITIALIZER; - -} // namespace - -namespace base { -namespace mac { - -bool GetNSExceptionsAllowed() { - return g_exceptionsAllowed.Get().Get(); -} - -void SetNSExceptionsAllowed(bool allowed) { - return g_exceptionsAllowed.Get().Set(allowed); -} - -id RunBlockIgnoringExceptions(BlockReturningId block) { - id ret = nil; - @try { - base::mac::ScopedNSExceptionEnabler enable; - ret = block(); - } - @catch(id exception) { - } - return ret; -} - -ScopedNSExceptionEnabler::ScopedNSExceptionEnabler() { - was_enabled_ = GetNSExceptionsAllowed(); - SetNSExceptionsAllowed(true); -} - -ScopedNSExceptionEnabler::~ScopedNSExceptionEnabler() { - SetNSExceptionsAllowed(was_enabled_); -} - -} // namespace mac -} // namespace base diff --git a/base/mac/scoped_nsobject.h b/base/mac/scoped_nsobject.h deleted file mode 100644 index 8d7bd4a27b..0000000000 --- a/base/mac/scoped_nsobject.h +++ /dev/null @@ -1,156 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef BASE_MAC_SCOPED_NSOBJECT_H_ -#define BASE_MAC_SCOPED_NSOBJECT_H_ - -#import -#include "base/basictypes.h" -#include "base/compiler_specific.h" - -namespace base { - -// scoped_nsobject<> is patterned after scoped_ptr<>, but maintains ownership -// of an NSObject subclass object. Style deviations here are solely for -// compatibility with scoped_ptr<>'s interface, with which everyone is already -// familiar. -// -// scoped_nsobject<> takes ownership of an object (in the constructor or in -// reset()) by taking over the caller's existing ownership claim. The caller -// must own the object it gives to scoped_nsobject<>, and relinquishes an -// ownership claim to that object. scoped_nsobject<> does not call -retain, -// callers have to call this manually if appropriate. -// -// scoped_nsprotocol<> has the same behavior as scoped_nsobject, but can be used -// with protocols. -// -// scoped_nsobject<> is not to be used for NSAutoreleasePools. For -// NSAutoreleasePools use ScopedNSAutoreleasePool from -// scoped_nsautorelease_pool.h instead. -// We check for bad uses of scoped_nsobject and NSAutoreleasePool at compile -// time with a template specialization (see below). - -template -class scoped_nsprotocol { - public: - explicit scoped_nsprotocol(NST object = nil) : object_(object) {} - - scoped_nsprotocol(const scoped_nsprotocol& that) - : object_([that.object_ retain]) { - } - - ~scoped_nsprotocol() { - [object_ release]; - } - - scoped_nsprotocol& operator=(const scoped_nsprotocol& that) { - reset([that.get() retain]); - return *this; - } - - void reset(NST object = nil) { - // We intentionally do not check that object != object_ as the caller must - // either already have an ownership claim over whatever it passes to this - // method, or call it with the |RETAIN| policy which will have ensured that - // the object is retained once more when reaching this point. - [object_ release]; - object_ = object; - } - - bool operator==(NST that) const { return object_ == that; } - bool operator!=(NST that) const { return object_ != that; } - - operator NST() const { - return object_; - } - - NST get() const { - return object_; - } - - void swap(scoped_nsprotocol& that) { - NST temp = that.object_; - that.object_ = object_; - object_ = temp; - } - - // scoped_nsprotocol<>::release() is like scoped_ptr<>::release. It is NOT a - // wrapper for [object_ release]. To force a scoped_nsprotocol<> to call - // [object_ release], use scoped_nsprotocol<>::reset(). - NST release() WARN_UNUSED_RESULT { - NST temp = object_; - object_ = nil; - return temp; - } - - // Shift reference to the autorelease pool to be released later. - NST autorelease() { - return [release() autorelease]; - } - - private: - NST object_; -}; - -// Free functions -template -void swap(scoped_nsprotocol& p1, scoped_nsprotocol& p2) { - p1.swap(p2); -} - -template -bool operator==(C p1, const scoped_nsprotocol& p2) { - return p1 == p2.get(); -} - -template -bool operator!=(C p1, const scoped_nsprotocol& p2) { - return p1 != p2.get(); -} - -template -class scoped_nsobject : public scoped_nsprotocol { - public: - explicit scoped_nsobject(NST* object = nil) - : scoped_nsprotocol(object) {} - - scoped_nsobject(const scoped_nsobject& that) - : scoped_nsprotocol(that) { - } - - scoped_nsobject& operator=(const scoped_nsobject& that) { - scoped_nsprotocol::operator=(that); - return *this; - } -}; - -// Specialization to make scoped_nsobject work. -template<> -class scoped_nsobject : public scoped_nsprotocol { - public: - explicit scoped_nsobject(id object = nil) : scoped_nsprotocol(object) {} - - scoped_nsobject(const scoped_nsobject& that) - : scoped_nsprotocol(that) { - } - - scoped_nsobject& operator=(const scoped_nsobject& that) { - scoped_nsprotocol::operator=(that); - return *this; - } -}; - -// Do not use scoped_nsobject for NSAutoreleasePools, use -// ScopedNSAutoreleasePool instead. This is a compile time check. See details -// at top of header. -template<> -class scoped_nsobject { - private: - explicit scoped_nsobject(NSAutoreleasePool* object = nil); - DISALLOW_COPY_AND_ASSIGN(scoped_nsobject); -}; - -} // namespace base - -#endif // BASE_MAC_SCOPED_NSOBJECT_H_ diff --git a/base/mac/scoped_nsobject_unittest.mm b/base/mac/scoped_nsobject_unittest.mm deleted file mode 100644 index f290c3aef0..0000000000 --- a/base/mac/scoped_nsobject_unittest.mm +++ /dev/null @@ -1,86 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include - -#include "base/basictypes.h" -#include "base/mac/scoped_nsautorelease_pool.h" -#include "base/mac/scoped_nsobject.h" -#include "testing/gtest/include/gtest/gtest.h" - -namespace { - -TEST(ScopedNSObjectTest, ScopedNSObject) { - base::scoped_nsobject p1([[NSObject alloc] init]); - ASSERT_TRUE(p1.get()); - ASSERT_EQ(1u, [p1 retainCount]); - base::scoped_nsobject p2(p1); - ASSERT_EQ(p1.get(), p2.get()); - ASSERT_EQ(2u, [p1 retainCount]); - p2.reset(); - ASSERT_EQ(nil, p2.get()); - ASSERT_EQ(1u, [p1 retainCount]); - { - base::scoped_nsobject p3 = p1; - ASSERT_EQ(p1.get(), p3.get()); - ASSERT_EQ(2u, [p1 retainCount]); - p3 = p1; - ASSERT_EQ(p1.get(), p3.get()); - ASSERT_EQ(2u, [p1 retainCount]); - } - ASSERT_EQ(1u, [p1 retainCount]); - base::scoped_nsobject p4([p1.get() retain]); - ASSERT_EQ(2u, [p1 retainCount]); - ASSERT_TRUE(p1 == p1.get()); - ASSERT_TRUE(p1 == p1); - ASSERT_FALSE(p1 != p1); - ASSERT_FALSE(p1 != p1.get()); - base::scoped_nsobject p5([[NSObject alloc] init]); - ASSERT_TRUE(p1 != p5); - ASSERT_TRUE(p1 != p5.get()); - ASSERT_FALSE(p1 == p5); - ASSERT_FALSE(p1 == p5.get()); - - base::scoped_nsobject p6 = p1; - ASSERT_EQ(3u, [p6 retainCount]); - { - base::mac::ScopedNSAutoreleasePool pool; - p6.autorelease(); - ASSERT_EQ(nil, p6.get()); - ASSERT_EQ(3u, [p1 retainCount]); - } - ASSERT_EQ(2u, [p1 retainCount]); -} - -TEST(ScopedNSObjectTest, ScopedNSObjectInContainer) { - base::scoped_nsobject p([[NSObject alloc] init]); - ASSERT_TRUE(p.get()); - ASSERT_EQ(1u, [p retainCount]); - { - std::vector> objects; - objects.push_back(p); - ASSERT_EQ(2u, [p retainCount]); - ASSERT_EQ(p.get(), objects[0].get()); - objects.push_back(base::scoped_nsobject([[NSObject alloc] init])); - ASSERT_TRUE(objects[1].get()); - ASSERT_EQ(1u, [objects[1] retainCount]); - } - ASSERT_EQ(1u, [p retainCount]); -} - -TEST(ScopedNSObjectTest, ScopedNSObjectFreeFunctions) { - base::scoped_nsobject p1([[NSObject alloc] init]); - id o1 = p1.get(); - ASSERT_TRUE(o1 == p1); - ASSERT_FALSE(o1 != p1); - base::scoped_nsobject p2([[NSObject alloc] init]); - ASSERT_TRUE(o1 != p2); - ASSERT_FALSE(o1 == p2); - id o2 = p2.get(); - swap(p1, p2); - ASSERT_EQ(o2, p1.get()); - ASSERT_EQ(o1, p2.get()); -} - -} // namespace diff --git a/base/mac/scoped_sending_event.h b/base/mac/scoped_sending_event.h deleted file mode 100644 index 92c2155e15..0000000000 --- a/base/mac/scoped_sending_event.h +++ /dev/null @@ -1,48 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef BASE_MAC_SCOPED_SENDING_EVENT_H_ -#define BASE_MAC_SCOPED_SENDING_EVENT_H_ - -#include "base/base_export.h" -#include "base/basictypes.h" -#include "base/message_loop/message_pump_mac.h" - -// Nested event loops can pump IPC messages, including -// script-initiated tab closes, which could release objects that the -// nested event loop might message. CrAppProtocol defines how to ask -// the embedding NSApplication subclass if an event is currently being -// handled, in which case such closes are deferred to the top-level -// event loop. -// -// ScopedSendingEvent allows script-initiated event loops to work like -// a nested event loop, as such events do not arrive via -sendEvent:. -// CrAppControlProtocol lets ScopedSendingEvent tell the embedding -// NSApplication what to return from -handlingSendEvent. - -@protocol CrAppControlProtocol -- (void)setHandlingSendEvent:(BOOL)handlingSendEvent; -@end - -namespace base { -namespace mac { - -class BASE_EXPORT ScopedSendingEvent { - public: - ScopedSendingEvent(); - ~ScopedSendingEvent(); - - private: - // The NSApp in control at the time the constructor was run, to be - // sure the |handling_| setting is restored appropriately. - NSObject* app_; - BOOL handling_; // Value of -[app_ handlingSendEvent] at construction. - - DISALLOW_COPY_AND_ASSIGN(ScopedSendingEvent); -}; - -} // namespace mac -} // namespace base - -#endif // BASE_MAC_SCOPED_SENDING_EVENT_H_ diff --git a/base/mac/scoped_sending_event.mm b/base/mac/scoped_sending_event.mm deleted file mode 100644 index c3813d8ae6..0000000000 --- a/base/mac/scoped_sending_event.mm +++ /dev/null @@ -1,24 +0,0 @@ -// Copyright (c) 2011 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#import "base/mac/scoped_sending_event.h" - -#include "base/logging.h" - -namespace base { -namespace mac { - -ScopedSendingEvent::ScopedSendingEvent() - : app_(static_cast*>(NSApp)) { - DCHECK([app_ conformsToProtocol:@protocol(CrAppControlProtocol)]); - handling_ = [app_ isHandlingSendEvent]; - [app_ setHandlingSendEvent:YES]; -} - -ScopedSendingEvent::~ScopedSendingEvent() { - [app_ setHandlingSendEvent:handling_]; -} - -} // namespace mac -} // namespace base diff --git a/base/mac/scoped_sending_event_unittest.mm b/base/mac/scoped_sending_event_unittest.mm deleted file mode 100644 index 9ae99856c9..0000000000 --- a/base/mac/scoped_sending_event_unittest.mm +++ /dev/null @@ -1,38 +0,0 @@ -// Copyright (c) 2011 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#import "base/mac/scoped_sending_event.h" - -#include "testing/gtest/include/gtest/gtest.h" - -namespace { - -// Sets the flag within scope, resets when leaving scope. -TEST(ScopedSendingEventTest, SetHandlingSendEvent) { - id app = NSApp; - EXPECT_FALSE([app isHandlingSendEvent]); - { - base::mac::ScopedSendingEvent is_handling_send_event; - EXPECT_TRUE([app isHandlingSendEvent]); - } - EXPECT_FALSE([app isHandlingSendEvent]); -} - -// Nested call restores previous value rather than resetting flag. -TEST(ScopedSendingEventTest, NestedSetHandlingSendEvent) { - id app = NSApp; - EXPECT_FALSE([app isHandlingSendEvent]); - { - base::mac::ScopedSendingEvent is_handling_send_event; - EXPECT_TRUE([app isHandlingSendEvent]); - { - base::mac::ScopedSendingEvent nested_is_handling_send_event; - EXPECT_TRUE([app isHandlingSendEvent]); - } - EXPECT_TRUE([app isHandlingSendEvent]); - } - EXPECT_FALSE([app isHandlingSendEvent]); -} - -} // namespace diff --git a/base/mac/sdk_forward_declarations.h b/base/mac/sdk_forward_declarations.h deleted file mode 100644 index a2d4013723..0000000000 --- a/base/mac/sdk_forward_declarations.h +++ /dev/null @@ -1,67 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -// This file contains forward declarations for items in later SDKs than the -// default one with which Chromium is built (currently 10.6). -// If you call any function from this header, be sure to check at runtime for -// respondsToSelector: before calling these functions (else your code will crash -// on older OS X versions that chrome still supports). - -#ifndef BASE_MAC_SDK_FORWARD_DECLARATIONS_H_ -#define BASE_MAC_SDK_FORWARD_DECLARATIONS_H_ - -#import - -#if !defined(MAC_OS_X_VERSION_10_7) || \ - MAC_OS_X_VERSION_MAX_ALLOWED < MAC_OS_X_VERSION_10_7 -enum { - NSEventPhaseNone = 0, // event not associated with a phase. - NSEventPhaseBegan = 0x1 << 0, - NSEventPhaseStationary = 0x1 << 1, - NSEventPhaseChanged = 0x1 << 2, - NSEventPhaseEnded = 0x1 << 3, - NSEventPhaseCancelled = 0x1 << 4, -}; -typedef NSUInteger NSEventPhase; - -enum { - NSEventSwipeTrackingLockDirection = 0x1 << 0, - NSEventSwipeTrackingClampGestureAmount = 0x1 << 1, -}; -typedef NSUInteger NSEventSwipeTrackingOptions; - -@interface NSEvent (LionSDK) -+ (BOOL)isSwipeTrackingFromScrollEventsEnabled; - -- (NSEventPhase)phase; -- (CGFloat)scrollingDeltaX; -- (CGFloat)scrollingDeltaY; -- (void)trackSwipeEventWithOptions:(NSEventSwipeTrackingOptions)options - dampenAmountThresholdMin:(CGFloat)minDampenThreshold - max:(CGFloat)maxDampenThreshold - usingHandler:(void (^)(CGFloat gestureAmount, - NSEventPhase phase, - BOOL isComplete, - BOOL *stop))trackingHandler; - -- (BOOL)isDirectionInvertedFromDevice; - -@end - -@interface CALayer (LionAPI) -- (CGFloat)contentsScale; -- (void)setContentsScale:(CGFloat)contentsScale; -@end - -@interface NSScreen (LionSDK) -- (CGFloat)backingScaleFactor; -- (NSRect)convertRectToBacking:(NSRect)aRect; -@end - -@interface NSWindow (LionSDK) -- (CGFloat)backingScaleFactor; -@end -#endif // MAC_OS_X_VERSION_10_7 - -#endif // BASE_MAC_SDK_FORWARD_DECLARATIONS_H_ diff --git a/base/md5.cc b/base/md5.cc deleted file mode 100644 index 754994c0e5..0000000000 --- a/base/md5.cc +++ /dev/null @@ -1,292 +0,0 @@ -// Copyright (c) 2011 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -// The original file was copied from sqlite, and was in the public domain. - -/* - * This code implements the MD5 message-digest algorithm. - * The algorithm is due to Ron Rivest. This code was - * written by Colin Plumb in 1993, no copyright is claimed. - * This code is in the public domain; do with it what you wish. - * - * Equivalent code is available from RSA Data Security, Inc. - * This code has been tested against that, and is equivalent, - * except that you don't need to include two pages of legalese - * with every copy. - * - * To compute the message digest of a chunk of bytes, declare an - * MD5Context structure, pass it to MD5Init, call MD5Update as - * needed on buffers full of bytes, and then call MD5Final, which - * will fill a supplied 16-byte array with the digest. - */ - -#include "base/md5.h" - -#include "base/basictypes.h" - -namespace { - -struct Context { - uint32 buf[4]; - uint32 bits[2]; - unsigned char in[64]; -}; - -/* - * Note: this code is harmless on little-endian machines. - */ -void byteReverse(unsigned char *buf, unsigned longs) { - uint32 t; - do { - t = (uint32)((unsigned)buf[3]<<8 | buf[2]) << 16 | - ((unsigned)buf[1]<<8 | buf[0]); - *(uint32 *)buf = t; - buf += 4; - } while (--longs); -} - -/* The four core functions - F1 is optimized somewhat */ - -/* #define F1(x, y, z) (x & y | ~x & z) */ -#define F1(x, y, z) (z ^ (x & (y ^ z))) -#define F2(x, y, z) F1(z, x, y) -#define F3(x, y, z) (x ^ y ^ z) -#define F4(x, y, z) (y ^ (x | ~z)) - -/* This is the central step in the MD5 algorithm. */ -#define MD5STEP(f, w, x, y, z, data, s) \ - ( w += f(x, y, z) + data, w = w<>(32-s), w += x ) - -/* - * The core of the MD5 algorithm, this alters an existing MD5 hash to - * reflect the addition of 16 longwords of new data. MD5Update blocks - * the data and converts bytes into longwords for this routine. - */ -void MD5Transform(uint32 buf[4], const uint32 in[16]) { - register uint32 a, b, c, d; - - a = buf[0]; - b = buf[1]; - c = buf[2]; - d = buf[3]; - - MD5STEP(F1, a, b, c, d, in[ 0]+0xd76aa478, 7); - MD5STEP(F1, d, a, b, c, in[ 1]+0xe8c7b756, 12); - MD5STEP(F1, c, d, a, b, in[ 2]+0x242070db, 17); - MD5STEP(F1, b, c, d, a, in[ 3]+0xc1bdceee, 22); - MD5STEP(F1, a, b, c, d, in[ 4]+0xf57c0faf, 7); - MD5STEP(F1, d, a, b, c, in[ 5]+0x4787c62a, 12); - MD5STEP(F1, c, d, a, b, in[ 6]+0xa8304613, 17); - MD5STEP(F1, b, c, d, a, in[ 7]+0xfd469501, 22); - MD5STEP(F1, a, b, c, d, in[ 8]+0x698098d8, 7); - MD5STEP(F1, d, a, b, c, in[ 9]+0x8b44f7af, 12); - MD5STEP(F1, c, d, a, b, in[10]+0xffff5bb1, 17); - MD5STEP(F1, b, c, d, a, in[11]+0x895cd7be, 22); - MD5STEP(F1, a, b, c, d, in[12]+0x6b901122, 7); - MD5STEP(F1, d, a, b, c, in[13]+0xfd987193, 12); - MD5STEP(F1, c, d, a, b, in[14]+0xa679438e, 17); - MD5STEP(F1, b, c, d, a, in[15]+0x49b40821, 22); - - MD5STEP(F2, a, b, c, d, in[ 1]+0xf61e2562, 5); - MD5STEP(F2, d, a, b, c, in[ 6]+0xc040b340, 9); - MD5STEP(F2, c, d, a, b, in[11]+0x265e5a51, 14); - MD5STEP(F2, b, c, d, a, in[ 0]+0xe9b6c7aa, 20); - MD5STEP(F2, a, b, c, d, in[ 5]+0xd62f105d, 5); - MD5STEP(F2, d, a, b, c, in[10]+0x02441453, 9); - MD5STEP(F2, c, d, a, b, in[15]+0xd8a1e681, 14); - MD5STEP(F2, b, c, d, a, in[ 4]+0xe7d3fbc8, 20); - MD5STEP(F2, a, b, c, d, in[ 9]+0x21e1cde6, 5); - MD5STEP(F2, d, a, b, c, in[14]+0xc33707d6, 9); - MD5STEP(F2, c, d, a, b, in[ 3]+0xf4d50d87, 14); - MD5STEP(F2, b, c, d, a, in[ 8]+0x455a14ed, 20); - MD5STEP(F2, a, b, c, d, in[13]+0xa9e3e905, 5); - MD5STEP(F2, d, a, b, c, in[ 2]+0xfcefa3f8, 9); - MD5STEP(F2, c, d, a, b, in[ 7]+0x676f02d9, 14); - MD5STEP(F2, b, c, d, a, in[12]+0x8d2a4c8a, 20); - - MD5STEP(F3, a, b, c, d, in[ 5]+0xfffa3942, 4); - MD5STEP(F3, d, a, b, c, in[ 8]+0x8771f681, 11); - MD5STEP(F3, c, d, a, b, in[11]+0x6d9d6122, 16); - MD5STEP(F3, b, c, d, a, in[14]+0xfde5380c, 23); - MD5STEP(F3, a, b, c, d, in[ 1]+0xa4beea44, 4); - MD5STEP(F3, d, a, b, c, in[ 4]+0x4bdecfa9, 11); - MD5STEP(F3, c, d, a, b, in[ 7]+0xf6bb4b60, 16); - MD5STEP(F3, b, c, d, a, in[10]+0xbebfbc70, 23); - MD5STEP(F3, a, b, c, d, in[13]+0x289b7ec6, 4); - MD5STEP(F3, d, a, b, c, in[ 0]+0xeaa127fa, 11); - MD5STEP(F3, c, d, a, b, in[ 3]+0xd4ef3085, 16); - MD5STEP(F3, b, c, d, a, in[ 6]+0x04881d05, 23); - MD5STEP(F3, a, b, c, d, in[ 9]+0xd9d4d039, 4); - MD5STEP(F3, d, a, b, c, in[12]+0xe6db99e5, 11); - MD5STEP(F3, c, d, a, b, in[15]+0x1fa27cf8, 16); - MD5STEP(F3, b, c, d, a, in[ 2]+0xc4ac5665, 23); - - MD5STEP(F4, a, b, c, d, in[ 0]+0xf4292244, 6); - MD5STEP(F4, d, a, b, c, in[ 7]+0x432aff97, 10); - MD5STEP(F4, c, d, a, b, in[14]+0xab9423a7, 15); - MD5STEP(F4, b, c, d, a, in[ 5]+0xfc93a039, 21); - MD5STEP(F4, a, b, c, d, in[12]+0x655b59c3, 6); - MD5STEP(F4, d, a, b, c, in[ 3]+0x8f0ccc92, 10); - MD5STEP(F4, c, d, a, b, in[10]+0xffeff47d, 15); - MD5STEP(F4, b, c, d, a, in[ 1]+0x85845dd1, 21); - MD5STEP(F4, a, b, c, d, in[ 8]+0x6fa87e4f, 6); - MD5STEP(F4, d, a, b, c, in[15]+0xfe2ce6e0, 10); - MD5STEP(F4, c, d, a, b, in[ 6]+0xa3014314, 15); - MD5STEP(F4, b, c, d, a, in[13]+0x4e0811a1, 21); - MD5STEP(F4, a, b, c, d, in[ 4]+0xf7537e82, 6); - MD5STEP(F4, d, a, b, c, in[11]+0xbd3af235, 10); - MD5STEP(F4, c, d, a, b, in[ 2]+0x2ad7d2bb, 15); - MD5STEP(F4, b, c, d, a, in[ 9]+0xeb86d391, 21); - - buf[0] += a; - buf[1] += b; - buf[2] += c; - buf[3] += d; -} - -} // namespace - -namespace base { - -/* - * Start MD5 accumulation. Set bit count to 0 and buffer to mysterious - * initialization constants. - */ -void MD5Init(MD5Context* context) { - struct Context *ctx = (struct Context *)context; - ctx->buf[0] = 0x67452301; - ctx->buf[1] = 0xefcdab89; - ctx->buf[2] = 0x98badcfe; - ctx->buf[3] = 0x10325476; - ctx->bits[0] = 0; - ctx->bits[1] = 0; -} - -/* - * Update context to reflect the concatenation of another buffer full - * of bytes. - */ -void MD5Update(MD5Context* context, const StringPiece& data) { - const unsigned char* inbuf = (const unsigned char*)data.data(); - size_t len = data.size(); - struct Context *ctx = (struct Context *)context; - const unsigned char* buf = (const unsigned char*)inbuf; - uint32 t; - - /* Update bitcount */ - - t = ctx->bits[0]; - if ((ctx->bits[0] = t + ((uint32)len << 3)) < t) - ctx->bits[1]++; /* Carry from low to high */ - ctx->bits[1] += static_cast(len >> 29); - - t = (t >> 3) & 0x3f; /* Bytes already in shsInfo->data */ - - /* Handle any leading odd-sized chunks */ - - if (t) { - unsigned char *p = (unsigned char *)ctx->in + t; - - t = 64-t; - if (len < t) { - memcpy(p, buf, len); - return; - } - memcpy(p, buf, t); - byteReverse(ctx->in, 16); - MD5Transform(ctx->buf, (uint32 *)ctx->in); - buf += t; - len -= t; - } - - /* Process data in 64-byte chunks */ - - while (len >= 64) { - memcpy(ctx->in, buf, 64); - byteReverse(ctx->in, 16); - MD5Transform(ctx->buf, (uint32 *)ctx->in); - buf += 64; - len -= 64; - } - - /* Handle any remaining bytes of data. */ - - memcpy(ctx->in, buf, len); -} - -/* - * Final wrapup - pad to 64-byte boundary with the bit pattern - * 1 0* (64-bit count of bits processed, MSB-first) - */ -void MD5Final(MD5Digest* digest, MD5Context* context) { - struct Context *ctx = (struct Context *)context; - unsigned count; - unsigned char *p; - - /* Compute number of bytes mod 64 */ - count = (ctx->bits[0] >> 3) & 0x3F; - - /* Set the first char of padding to 0x80. This is safe since there is - always at least one byte free */ - p = ctx->in + count; - *p++ = 0x80; - - /* Bytes of padding needed to make 64 bytes */ - count = 64 - 1 - count; - - /* Pad out to 56 mod 64 */ - if (count < 8) { - /* Two lots of padding: Pad the first block to 64 bytes */ - memset(p, 0, count); - byteReverse(ctx->in, 16); - MD5Transform(ctx->buf, (uint32 *)ctx->in); - - /* Now fill the next block with 56 bytes */ - memset(ctx->in, 0, 56); - } else { - /* Pad block to 56 bytes */ - memset(p, 0, count-8); - } - byteReverse(ctx->in, 14); - - /* Append length in bits and transform */ - ((uint32 *)ctx->in)[ 14 ] = ctx->bits[0]; - ((uint32 *)ctx->in)[ 15 ] = ctx->bits[1]; - - MD5Transform(ctx->buf, (uint32 *)ctx->in); - byteReverse((unsigned char *)ctx->buf, 4); - memcpy(digest->a, ctx->buf, 16); - memset(ctx, 0, sizeof(*ctx)); /* In case it's sensitive */ -} - -std::string MD5DigestToBase16(const MD5Digest& digest) { - static char const zEncode[] = "0123456789abcdef"; - - std::string ret; - ret.resize(32); - - int j = 0; - for (int i = 0; i < 16; i ++) { - int a = digest.a[i]; - ret[j++] = zEncode[(a>>4)&0xf]; - ret[j++] = zEncode[a & 0xf]; - } - return ret; -} - -void MD5Sum(const void* data, size_t length, MD5Digest* digest) { - MD5Context ctx; - MD5Init(&ctx); - MD5Update(&ctx, - StringPiece(reinterpret_cast(data), length)); - MD5Final(digest, &ctx); -} - -std::string MD5String(const StringPiece& str) { - MD5Digest digest; - MD5Sum(str.data(), str.length(), &digest); - return MD5DigestToBase16(digest); -} - -} // namespace base diff --git a/base/md5.h b/base/md5.h deleted file mode 100644 index fba02bd116..0000000000 --- a/base/md5.h +++ /dev/null @@ -1,69 +0,0 @@ -// Copyright (c) 2011 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef BASE_MD5_H_ -#define BASE_MD5_H_ - -#include "base/base_export.h" -#include "base/strings/string_piece.h" - -namespace base { - -// MD5 stands for Message Digest algorithm 5. -// MD5 is a robust hash function, designed for cyptography, but often used -// for file checksums. The code is complex and slow, but has few -// collisions. -// See Also: -// http://en.wikipedia.org/wiki/MD5 - -// These functions perform MD5 operations. The simplest call is MD5Sum() to -// generate the MD5 sum of the given data. -// -// You can also compute the MD5 sum of data incrementally by making multiple -// calls to MD5Update(): -// MD5Context ctx; // intermediate MD5 data: do not use -// MD5Init(&ctx); -// MD5Update(&ctx, data1, length1); -// MD5Update(&ctx, data2, length2); -// ... -// -// MD5Digest digest; // the result of the computation -// MD5Final(&digest, &ctx); -// -// You can call MD5DigestToBase16() to generate a string of the digest. - -// The output of an MD5 operation. -struct MD5Digest { - unsigned char a[16]; -}; - -// Used for storing intermediate data during an MD5 computation. Callers -// should not access the data. -typedef char MD5Context[88]; - -// Computes the MD5 sum of the given data buffer with the given length. -// The given 'digest' structure will be filled with the result data. -BASE_EXPORT void MD5Sum(const void* data, size_t length, MD5Digest* digest); - -// Initializes the given MD5 context structure for subsequent calls to -// MD5Update(). -BASE_EXPORT void MD5Init(MD5Context* context); - -// For the given buffer of |data| as a StringPiece, updates the given MD5 -// context with the sum of the data. You can call this any number of times -// during the computation, except that MD5Init() must have been called first. -BASE_EXPORT void MD5Update(MD5Context* context, const StringPiece& data); - -// Finalizes the MD5 operation and fills the buffer with the digest. -BASE_EXPORT void MD5Final(MD5Digest* digest, MD5Context* context); - -// Converts a digest into human-readable hexadecimal. -BASE_EXPORT std::string MD5DigestToBase16(const MD5Digest& digest); - -// Returns the MD5 (in hexadecimal) of a string. -BASE_EXPORT std::string MD5String(const StringPiece& str); - -} // namespace base - -#endif // BASE_MD5_H_ diff --git a/base/md5_unittest.cc b/base/md5_unittest.cc deleted file mode 100644 index 1112c4b425..0000000000 --- a/base/md5_unittest.cc +++ /dev/null @@ -1,207 +0,0 @@ -// Copyright (c) 2011 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include -#include - -#include "base/basictypes.h" -#include "base/memory/scoped_ptr.h" -#include "base/md5.h" -#include "testing/gtest/include/gtest/gtest.h" - -namespace base { - -TEST(MD5, DigestToBase16) { - MD5Digest digest; - - int data[] = { - 0xd4, 0x1d, 0x8c, 0xd9, - 0x8f, 0x00, 0xb2, 0x04, - 0xe9, 0x80, 0x09, 0x98, - 0xec, 0xf8, 0x42, 0x7e - }; - - for (int i = 0; i < 16; ++i) - digest.a[i] = data[i] & 0xff; - - std::string actual = MD5DigestToBase16(digest); - std::string expected = "d41d8cd98f00b204e9800998ecf8427e"; - - EXPECT_EQ(expected, actual); -} - -TEST(MD5, MD5SumEmtpyData) { - MD5Digest digest; - const char* data = ""; - - MD5Sum(data, strlen(data), &digest); - - int expected[] = { - 0xd4, 0x1d, 0x8c, 0xd9, - 0x8f, 0x00, 0xb2, 0x04, - 0xe9, 0x80, 0x09, 0x98, - 0xec, 0xf8, 0x42, 0x7e - }; - - for (int i = 0; i < 16; ++i) - EXPECT_EQ(expected[i], digest.a[i] & 0xFF); -} - -TEST(MD5, MD5SumOneByteData) { - MD5Digest digest; - const char* data = "a"; - - MD5Sum(data, strlen(data), &digest); - - int expected[] = { - 0x0c, 0xc1, 0x75, 0xb9, - 0xc0, 0xf1, 0xb6, 0xa8, - 0x31, 0xc3, 0x99, 0xe2, - 0x69, 0x77, 0x26, 0x61 - }; - - for (int i = 0; i < 16; ++i) - EXPECT_EQ(expected[i], digest.a[i] & 0xFF); -} - -TEST(MD5, MD5SumLongData) { - const int length = 10 * 1024 * 1024 + 1; - scoped_ptr data(new char[length]); - - for (int i = 0; i < length; ++i) - data[i] = i & 0xFF; - - MD5Digest digest; - MD5Sum(data.get(), length, &digest); - - int expected[] = { - 0x90, 0xbd, 0x6a, 0xd9, - 0x0a, 0xce, 0xf5, 0xad, - 0xaa, 0x92, 0x20, 0x3e, - 0x21, 0xc7, 0xa1, 0x3e - }; - - for (int i = 0; i < 16; ++i) - EXPECT_EQ(expected[i], digest.a[i] & 0xFF); -} - -TEST(MD5, ContextWithEmptyData) { - MD5Context ctx; - MD5Init(&ctx); - - MD5Digest digest; - MD5Final(&digest, &ctx); - - int expected[] = { - 0xd4, 0x1d, 0x8c, 0xd9, - 0x8f, 0x00, 0xb2, 0x04, - 0xe9, 0x80, 0x09, 0x98, - 0xec, 0xf8, 0x42, 0x7e - }; - - for (int i = 0; i < 16; ++i) - EXPECT_EQ(expected[i], digest.a[i] & 0xFF); -} - -TEST(MD5, ContextWithLongData) { - MD5Context ctx; - MD5Init(&ctx); - - const int length = 10 * 1024 * 1024 + 1; - scoped_ptr data(new char[length]); - - for (int i = 0; i < length; ++i) - data[i] = i & 0xFF; - - int total = 0; - while (total < length) { - int len = 4097; // intentionally not 2^k. - if (len > length - total) - len = length - total; - - MD5Update(&ctx, - StringPiece(reinterpret_cast(data.get() + total), len)); - total += len; - } - - EXPECT_EQ(length, total); - - MD5Digest digest; - MD5Final(&digest, &ctx); - - int expected[] = { - 0x90, 0xbd, 0x6a, 0xd9, - 0x0a, 0xce, 0xf5, 0xad, - 0xaa, 0x92, 0x20, 0x3e, - 0x21, 0xc7, 0xa1, 0x3e - }; - - for (int i = 0; i < 16; ++i) - EXPECT_EQ(expected[i], digest.a[i] & 0xFF); -} - -// Example data from http://www.ietf.org/rfc/rfc1321.txt A.5 Test Suite -TEST(MD5, MD5StringTestSuite1) { - std::string actual = MD5String(""); - std::string expected = "d41d8cd98f00b204e9800998ecf8427e"; - EXPECT_EQ(expected, actual); -} - -TEST(MD5, MD5StringTestSuite2) { - std::string actual = MD5String("a"); - std::string expected = "0cc175b9c0f1b6a831c399e269772661"; - EXPECT_EQ(expected, actual); -} - -TEST(MD5, MD5StringTestSuite3) { - std::string actual = MD5String("abc"); - std::string expected = "900150983cd24fb0d6963f7d28e17f72"; - EXPECT_EQ(expected, actual); -} - -TEST(MD5, MD5StringTestSuite4) { - std::string actual = MD5String("message digest"); - std::string expected = "f96b697d7cb7938d525a2f31aaf161d0"; - EXPECT_EQ(expected, actual); -} - -TEST(MD5, MD5StringTestSuite5) { - std::string actual = MD5String("abcdefghijklmnopqrstuvwxyz"); - std::string expected = "c3fcd3d76192e4007dfb496cca67e13b"; - EXPECT_EQ(expected, actual); -} - -TEST(MD5, MD5StringTestSuite6) { - std::string actual = MD5String("ABCDEFGHIJKLMNOPQRSTUVWXYZ" - "abcdefghijklmnopqrstuvwxyz" - "0123456789"); - std::string expected = "d174ab98d277d9f5a5611c2c9f419d9f"; - EXPECT_EQ(expected, actual); -} - -TEST(MD5, MD5StringTestSuite7) { - std::string actual = MD5String("12345678901234567890" - "12345678901234567890" - "12345678901234567890" - "12345678901234567890"); - std::string expected = "57edf4a22be3c955ac49da2e2107b67a"; - EXPECT_EQ(expected, actual); -} - -TEST(MD5, ContextWithStringData) { - MD5Context ctx; - MD5Init(&ctx); - - MD5Update(&ctx, "abc"); - - MD5Digest digest; - MD5Final(&digest, &ctx); - - std::string actual = MD5DigestToBase16(digest); - std::string expected = "900150983cd24fb0d6963f7d28e17f72"; - - EXPECT_EQ(expected, actual); -} - -} // namespace base diff --git a/base/memory/aligned_memory.cc b/base/memory/aligned_memory.cc deleted file mode 100644 index b6278aba2c..0000000000 --- a/base/memory/aligned_memory.cc +++ /dev/null @@ -1,47 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "base/memory/aligned_memory.h" - -#include "base/logging.h" - -#if defined(OS_ANDROID) || defined(OS_NACL) -#include -#endif - -namespace base { - -void* AlignedAlloc(size_t size, size_t alignment) { - DCHECK_GT(size, 0U); - DCHECK_EQ(alignment & (alignment - 1), 0U); - DCHECK_EQ(alignment % sizeof(void*), 0U); - void* ptr = NULL; -#if defined(COMPILER_MSVC) - ptr = _aligned_malloc(size, alignment); -// Both Android and NaCl technically support posix_memalign(), but do not expose -// it in the current version of the library headers used by Chrome. Luckily, -// memalign() on both platforms returns pointers which can safely be used with -// free(), so we can use it instead. Issues filed with each project for docs: -// http://code.google.com/p/android/issues/detail?id=35391 -// http://code.google.com/p/chromium/issues/detail?id=138579 -#elif defined(OS_ANDROID) || defined(OS_NACL) - ptr = memalign(alignment, size); -#else - if (posix_memalign(&ptr, alignment, size)) - ptr = NULL; -#endif - // Since aligned allocations may fail for non-memory related reasons, force a - // crash if we encounter a failed allocation; maintaining consistent behavior - // with a normal allocation failure in Chrome. - if (!ptr) { - DLOG(ERROR) << "If you crashed here, your aligned allocation is incorrect: " - << "size=" << size << ", alignment=" << alignment; - CHECK(false); - } - // Sanity check alignment just to be safe. - DCHECK_EQ(reinterpret_cast(ptr) & (alignment - 1), 0U); - return ptr; -} - -} // namespace base diff --git a/base/memory/aligned_memory.h b/base/memory/aligned_memory.h deleted file mode 100644 index 6719599dc5..0000000000 --- a/base/memory/aligned_memory.h +++ /dev/null @@ -1,114 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -// AlignedMemory is a POD type that gives you a portable way to specify static -// or local stack data of a given alignment and size. For example, if you need -// static storage for a class, but you want manual control over when the object -// is constructed and destructed (you don't want static initialization and -// destruction), use AlignedMemory: -// -// static AlignedMemory my_class; -// -// // ... at runtime: -// new(my_class.void_data()) MyClass(); -// -// // ... use it: -// MyClass* mc = my_class.data_as(); -// -// // ... later, to destruct my_class: -// my_class.data_as()->MyClass::~MyClass(); -// -// Alternatively, a runtime sized aligned allocation can be created: -// -// float* my_array = static_cast(AlignedAlloc(size, alignment)); -// -// // ... later, to release the memory: -// AlignedFree(my_array); -// -// Or using scoped_ptr_malloc: -// -// scoped_ptr_malloc my_array( -// static_cast(AlignedAlloc(size, alignment))); - -#ifndef BASE_MEMORY_ALIGNED_MEMORY_H_ -#define BASE_MEMORY_ALIGNED_MEMORY_H_ - -#include "base/base_export.h" -#include "base/basictypes.h" -#include "base/compiler_specific.h" - -#if defined(COMPILER_MSVC) -#include -#else -#include -#endif - -namespace base { - -// AlignedMemory is specialized for all supported alignments. -// Make sure we get a compiler error if someone uses an unsupported alignment. -template -struct AlignedMemory {}; - -#define BASE_DECL_ALIGNED_MEMORY(byte_alignment) \ - template \ - class AlignedMemory { \ - public: \ - ALIGNAS(byte_alignment) uint8 data_[Size]; \ - void* void_data() { return static_cast(data_); } \ - const void* void_data() const { \ - return static_cast(data_); \ - } \ - template \ - Type* data_as() { return static_cast(void_data()); } \ - template \ - const Type* data_as() const { \ - return static_cast(void_data()); \ - } \ - private: \ - void* operator new(size_t); \ - void operator delete(void*); \ - } - -// Specialization for all alignments is required because MSVC (as of VS 2008) -// does not understand ALIGNAS(ALIGNOF(Type)) or ALIGNAS(template_param). -// Greater than 4096 alignment is not supported by some compilers, so 4096 is -// the maximum specified here. -BASE_DECL_ALIGNED_MEMORY(1); -BASE_DECL_ALIGNED_MEMORY(2); -BASE_DECL_ALIGNED_MEMORY(4); -BASE_DECL_ALIGNED_MEMORY(8); -BASE_DECL_ALIGNED_MEMORY(16); -BASE_DECL_ALIGNED_MEMORY(32); -BASE_DECL_ALIGNED_MEMORY(64); -BASE_DECL_ALIGNED_MEMORY(128); -BASE_DECL_ALIGNED_MEMORY(256); -BASE_DECL_ALIGNED_MEMORY(512); -BASE_DECL_ALIGNED_MEMORY(1024); -BASE_DECL_ALIGNED_MEMORY(2048); -BASE_DECL_ALIGNED_MEMORY(4096); - -#undef BASE_DECL_ALIGNED_MEMORY - -BASE_EXPORT void* AlignedAlloc(size_t size, size_t alignment); - -inline void AlignedFree(void* ptr) { -#if defined(COMPILER_MSVC) - _aligned_free(ptr); -#else - free(ptr); -#endif -} - -// Helper class for use with scoped_ptr_malloc. -class BASE_EXPORT ScopedPtrAlignedFree { - public: - inline void operator()(void* ptr) const { - AlignedFree(ptr); - } -}; - -} // namespace base - -#endif // BASE_MEMORY_ALIGNED_MEMORY_H_ diff --git a/base/memory/aligned_memory_unittest.cc b/base/memory/aligned_memory_unittest.cc deleted file mode 100644 index 6942249f5a..0000000000 --- a/base/memory/aligned_memory_unittest.cc +++ /dev/null @@ -1,95 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "base/memory/aligned_memory.h" -#include "base/memory/scoped_ptr.h" -#include "testing/gtest/include/gtest/gtest.h" - -#define EXPECT_ALIGNED(ptr, align) \ - EXPECT_EQ(0u, reinterpret_cast(ptr) & (align - 1)) - -namespace { - -using base::AlignedMemory; - -TEST(AlignedMemoryTest, StaticAlignment) { - static AlignedMemory<8, 8> raw8; - static AlignedMemory<8, 16> raw16; - static AlignedMemory<8, 256> raw256; - static AlignedMemory<8, 4096> raw4096; - - EXPECT_EQ(8u, ALIGNOF(raw8)); - EXPECT_EQ(16u, ALIGNOF(raw16)); - EXPECT_EQ(256u, ALIGNOF(raw256)); - EXPECT_EQ(4096u, ALIGNOF(raw4096)); - - EXPECT_ALIGNED(raw8.void_data(), 8); - EXPECT_ALIGNED(raw16.void_data(), 16); - EXPECT_ALIGNED(raw256.void_data(), 256); - EXPECT_ALIGNED(raw4096.void_data(), 4096); -} - -TEST(AlignedMemoryTest, StackAlignment) { - AlignedMemory<8, 8> raw8; - AlignedMemory<8, 16> raw16; - AlignedMemory<8, 128> raw128; - - EXPECT_EQ(8u, ALIGNOF(raw8)); - EXPECT_EQ(16u, ALIGNOF(raw16)); - EXPECT_EQ(128u, ALIGNOF(raw128)); - - EXPECT_ALIGNED(raw8.void_data(), 8); - EXPECT_ALIGNED(raw16.void_data(), 16); - EXPECT_ALIGNED(raw128.void_data(), 128); - - // NaCl x86-64 compiler emits non-validating instructions for >128 - // bytes alignment. - // http://www.chromium.org/nativeclient/design-documents/nacl-sfi-model-on-x86-64-systems - // TODO(hamaji): Ideally, NaCl compiler for x86-64 should workaround - // this limitation and this #if should be removed. - // https://code.google.com/p/nativeclient/issues/detail?id=3463 -#if !(defined(OS_NACL) && defined(ARCH_CPU_X86_64)) - AlignedMemory<8, 256> raw256; - EXPECT_EQ(256u, ALIGNOF(raw256)); - EXPECT_ALIGNED(raw256.void_data(), 256); - - // TODO(ios): This test hits an armv7 bug in clang. crbug.com/138066 -#if !(defined(OS_IOS) && defined(ARCH_CPU_ARM_FAMILY)) - AlignedMemory<8, 4096> raw4096; - EXPECT_EQ(4096u, ALIGNOF(raw4096)); - EXPECT_ALIGNED(raw4096.void_data(), 4096); -#endif // !(defined(OS_IOS) && defined(ARCH_CPU_ARM_FAMILY)) -#endif -} - -TEST(AlignedMemoryTest, DynamicAllocation) { - void* p = base::AlignedAlloc(8, 8); - EXPECT_TRUE(p); - EXPECT_ALIGNED(p, 8); - base::AlignedFree(p); - - p = base::AlignedAlloc(8, 16); - EXPECT_TRUE(p); - EXPECT_ALIGNED(p, 16); - base::AlignedFree(p); - - p = base::AlignedAlloc(8, 256); - EXPECT_TRUE(p); - EXPECT_ALIGNED(p, 256); - base::AlignedFree(p); - - p = base::AlignedAlloc(8, 4096); - EXPECT_TRUE(p); - EXPECT_ALIGNED(p, 4096); - base::AlignedFree(p); -} - -TEST(AlignedMemoryTest, ScopedDynamicAllocation) { - scoped_ptr_malloc p( - static_cast(base::AlignedAlloc(8, 8))); - EXPECT_TRUE(p.get()); - EXPECT_ALIGNED(p.get(), 8); -} - -} // namespace diff --git a/base/memory/discardable_memory.cc b/base/memory/discardable_memory.cc deleted file mode 100644 index 33f9e19cde..0000000000 --- a/base/memory/discardable_memory.cc +++ /dev/null @@ -1,66 +0,0 @@ -// Copyright (c) 2013 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "base/memory/discardable_memory.h" - -#include "base/logging.h" - -namespace base { - -DiscardableMemory::DiscardableMemory() - : memory_(NULL), - size_(0), - is_locked_(false) -#if defined(OS_ANDROID) - , fd_(-1) -#endif // OS_ANDROID - { - DCHECK(Supported()); -} - -void* DiscardableMemory::Memory() const { - DCHECK(is_locked_); - return memory_; -} - -// Stub implementations for platforms that don't support discardable memory. - -#if !defined(OS_ANDROID) && !defined(OS_MACOSX) - -DiscardableMemory::~DiscardableMemory() { - NOTIMPLEMENTED(); -} - -// static -bool DiscardableMemory::Supported() { - return false; -} - -bool DiscardableMemory::InitializeAndLock(size_t size) { - NOTIMPLEMENTED(); - return false; -} - -LockDiscardableMemoryStatus DiscardableMemory::Lock() { - NOTIMPLEMENTED(); - return DISCARDABLE_MEMORY_FAILED; -} - -void DiscardableMemory::Unlock() { - NOTIMPLEMENTED(); -} - -// static -bool DiscardableMemory::PurgeForTestingSupported() { - return false; -} - -// static -void DiscardableMemory::PurgeForTesting() { - NOTIMPLEMENTED(); -} - -#endif // OS_* - -} // namespace base diff --git a/base/memory/discardable_memory.h b/base/memory/discardable_memory.h deleted file mode 100644 index d6e91b979d..0000000000 --- a/base/memory/discardable_memory.h +++ /dev/null @@ -1,118 +0,0 @@ -// Copyright (c) 2013 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef BASE_MEMORY_DISCARDABLE_MEMORY_H_ -#define BASE_MEMORY_DISCARDABLE_MEMORY_H_ - -#include "base/base_export.h" -#include "base/basictypes.h" -#include "base/compiler_specific.h" - -namespace base { - -enum LockDiscardableMemoryStatus { - DISCARDABLE_MEMORY_FAILED = -1, - DISCARDABLE_MEMORY_PURGED = 0, - DISCARDABLE_MEMORY_SUCCESS = 1 -}; - -// Platform abstraction for discardable memory. DiscardableMemory is used to -// cache large objects without worrying about blowing out memory, both on mobile -// devices where there is no swap, and desktop devices where unused free memory -// should be used to help the user experience. This is preferable to releasing -// memory in response to an OOM signal because it is simpler, though it has less -// flexibility as to which objects get discarded. -// -// Discardable memory has two states: locked and unlocked. While the memory is -// locked, it will not be discarded. Unlocking the memory allows the OS to -// reclaim it if needed. Locks do not nest. -// -// Notes: -// - The paging behavior of memory while it is locked is not specified. While -// mobile platforms will not swap it out, it may qualify for swapping -// on desktop platforms. It is not expected that this will matter, as the -// preferred pattern of usage for DiscardableMemory is to lock down the -// memory, use it as quickly as possible, and then unlock it. -// - Because of memory alignment, the amount of memory allocated can be -// larger than the requested memory size. It is not very efficient for -// small allocations. -// -// References: -// - Linux: http://lwn.net/Articles/452035/ -// - Mac: http://trac.webkit.org/browser/trunk/Source/WebCore/platform/mac/PurgeableBufferMac.cpp -// the comment starting with "vm_object_purgable_control" at -// http://www.opensource.apple.com/source/xnu/xnu-792.13.8/osfmk/vm/vm_object.c -class BASE_EXPORT DiscardableMemory { - public: - DiscardableMemory(); - - // If the discardable memory is locked, the destructor will unlock it. - // The opened file will also be closed after this. - ~DiscardableMemory(); - - // Check whether the system supports discardable memory. - static bool Supported(); - - // Initialize the DiscardableMemory object. On success, this function returns - // true and the memory is locked. This should only be called once. - // This call could fail because of platform-specific limitations and the user - // should stop using the DiscardableMemory afterwards. - bool InitializeAndLock(size_t size); - - // Lock the memory so that it will not be purged by the system. Returns - // DISCARDABLE_MEMORY_SUCCESS on success. If the return value is - // DISCARDABLE_MEMORY_FAILED then this object should be discarded and - // a new one should be created. If the return value is - // DISCARDABLE_MEMORY_PURGED then the memory is present but any data that - // was in it is gone. - LockDiscardableMemoryStatus Lock() WARN_UNUSED_RESULT; - - // Unlock the memory so that it can be purged by the system. Must be called - // after every successful lock call. - void Unlock(); - - // Return the memory address held by this object. The object must be locked - // before calling this. Otherwise, this will cause a DCHECK error. - void* Memory() const; - - // Testing utility calls. - - // Check whether a purge of all discardable memory in the system is supported. - // Use only for testing! - static bool PurgeForTestingSupported(); - - // Purge all discardable memory in the system. This call has global effects - // across all running processes, so it should only be used for testing! - static void PurgeForTesting(); - - private: -#if defined(OS_ANDROID) - // Maps the discardable memory into the caller's address space. - // Returns true on success, false otherwise. - bool Map(); - - // Unmaps the discardable memory from the caller's address space. - void Unmap(); - - // Reserve a file descriptor. When reaching the fd limit, this call returns - // false and initialization should fail. - bool ReserveFileDescriptor(); - - // Release a file descriptor so that others can reserve it. - void ReleaseFileDescriptor(); -#endif // OS_ANDROID - - void* memory_; - size_t size_; - bool is_locked_; -#if defined(OS_ANDROID) - int fd_; -#endif // OS_ANDROID - - DISALLOW_COPY_AND_ASSIGN(DiscardableMemory); -}; - -} // namespace base - -#endif // BASE_MEMORY_DISCARDABLE_MEMORY_H_ diff --git a/base/memory/discardable_memory_android.cc b/base/memory/discardable_memory_android.cc deleted file mode 100644 index 73a25ae419..0000000000 --- a/base/memory/discardable_memory_android.cc +++ /dev/null @@ -1,164 +0,0 @@ -// Copyright (c) 2013 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "base/memory/discardable_memory.h" - -#include -#include - -#include "base/lazy_instance.h" -#include "base/logging.h" -#include "base/posix/eintr_wrapper.h" -#include "base/synchronization/lock.h" -#include "third_party/ashmem/ashmem.h" - -namespace { - -base::LazyInstance::Leaky g_discardable_memory_lock = - LAZY_INSTANCE_INITIALIZER; - -// Total number of discardable memory in the process. -int g_num_discardable_memory = 0; - -// Upper limit on the number of discardable memory to avoid hitting file -// descriptor limit. -const int kDiscardableMemoryNumLimit = 128; - -} - -namespace base { - -// static -bool DiscardableMemory::Supported() { - return true; -} - -DiscardableMemory::~DiscardableMemory() { - if (is_locked_) - Unlock(); - // If fd_ is smaller than 0, initialization must have failed and - // g_num_discardable_memory is not incremented by the caller. - if (fd_ < 0) - return; - HANDLE_EINTR(close(fd_)); - fd_ = -1; - ReleaseFileDescriptor(); -} - -bool DiscardableMemory::ReserveFileDescriptor() { - base::AutoLock lock(g_discardable_memory_lock.Get()); - if (g_num_discardable_memory < kDiscardableMemoryNumLimit) { - ++g_num_discardable_memory; - return true; - } - return false; -} - -void DiscardableMemory::ReleaseFileDescriptor() { - base::AutoLock lock(g_discardable_memory_lock.Get()); - --g_num_discardable_memory; - DCHECK_LE(0, g_num_discardable_memory); -} - -bool DiscardableMemory::InitializeAndLock(size_t size) { - // When this function returns true, fd_ should be larger or equal than 0 - // and g_num_discardable_memory is incremented by 1. Otherwise, fd_ - // is less than 0 and g_num_discardable_memory is not incremented by - // the caller. - DCHECK_EQ(fd_, -1); - DCHECK(!memory_); - if (!ReserveFileDescriptor()) - return false; - - size_ = size; - fd_ = ashmem_create_region("", size); - - if (fd_ < 0) { - DLOG(ERROR) << "ashmem_create_region() failed"; - ReleaseFileDescriptor(); - return false; - } - - int err = ashmem_set_prot_region(fd_, PROT_READ | PROT_WRITE); - if (err < 0) { - DLOG(ERROR) << "Error " << err << " when setting protection of ashmem"; - HANDLE_EINTR(close(fd_)); - fd_ = -1; - ReleaseFileDescriptor(); - return false; - } - - if (!Map()) { - // Close the file descriptor in case of any initialization errors. - HANDLE_EINTR(close(fd_)); - fd_ = -1; - ReleaseFileDescriptor(); - return false; - } - - is_locked_ = true; - return true; -} - -LockDiscardableMemoryStatus DiscardableMemory::Lock() { - DCHECK_NE(fd_, -1); - DCHECK(!is_locked_); - - bool purged = false; - if (ashmem_pin_region(fd_, 0, 0) == ASHMEM_WAS_PURGED) - purged = true; - - if (!Map()) - return DISCARDABLE_MEMORY_FAILED; - - is_locked_ = true; - return purged ? DISCARDABLE_MEMORY_PURGED : DISCARDABLE_MEMORY_SUCCESS; -} - -void DiscardableMemory::Unlock() { - DCHECK_GE(fd_, 0); - DCHECK(is_locked_); - - Unmap(); - if (ashmem_unpin_region(fd_, 0, 0)) - DLOG(ERROR) << "Failed to unpin memory."; - is_locked_ = false; -} - -bool DiscardableMemory::Map() { - DCHECK(!memory_); - // There is a problem using MAP_PRIVATE here. As we are constantly calling - // Lock() and Unlock(), data could get lost if they are not written to the - // underlying file when Unlock() gets called. - memory_ = mmap(NULL, size_, PROT_READ | PROT_WRITE, MAP_SHARED, fd_, 0); - if (memory_ == (void*)-1) { - DPLOG(ERROR) << "Failed to map memory."; - memory_ = NULL; - if (ashmem_unpin_region(fd_, 0, 0)) - DLOG(ERROR) << "Failed to unpin memory."; - return false; - } - return true; -} - -void DiscardableMemory::Unmap() { - DCHECK(memory_); - - if (-1 == munmap(memory_, size_)) - DPLOG(ERROR) << "Failed to unmap memory."; - - memory_ = NULL; -} - -// static -bool DiscardableMemory::PurgeForTestingSupported() { - return false; -} - -// static -void DiscardableMemory::PurgeForTesting() { - NOTIMPLEMENTED(); -} - -} // namespace base diff --git a/base/memory/discardable_memory_mac.cc b/base/memory/discardable_memory_mac.cc deleted file mode 100644 index 1dbb6ad1fd..0000000000 --- a/base/memory/discardable_memory_mac.cc +++ /dev/null @@ -1,102 +0,0 @@ -// Copyright (c) 2013 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "base/memory/discardable_memory.h" - -#include - -#include "base/logging.h" - -namespace base { - -namespace { - -// The VM subsystem allows tagging of memory and 240-255 is reserved for -// application use (see mach/vm_statistics.h). Pick 252 (after chromium's atomic -// weight of ~52). -const int kDiscardableMemoryTag = VM_MAKE_TAG(252); - -} // namespace - -// static -bool DiscardableMemory::Supported() { - return true; -} - -DiscardableMemory::~DiscardableMemory() { - if (memory_) { - vm_deallocate(mach_task_self(), - reinterpret_cast(memory_), - size_); - } -} - -bool DiscardableMemory::InitializeAndLock(size_t size) { - DCHECK(!memory_); - size_ = size; - - vm_address_t buffer = 0; - kern_return_t ret = vm_allocate(mach_task_self(), - &buffer, - size, - VM_FLAGS_PURGABLE | - VM_FLAGS_ANYWHERE | - kDiscardableMemoryTag); - - if (ret != KERN_SUCCESS) { - DLOG(ERROR) << "vm_allocate() failed"; - return false; - } - - is_locked_ = true; - memory_ = reinterpret_cast(buffer); - return true; -} - -LockDiscardableMemoryStatus DiscardableMemory::Lock() { - DCHECK(!is_locked_); - - int state = VM_PURGABLE_NONVOLATILE; - kern_return_t ret = vm_purgable_control( - mach_task_self(), - reinterpret_cast(memory_), - VM_PURGABLE_SET_STATE, - &state); - - if (ret != KERN_SUCCESS) - return DISCARDABLE_MEMORY_FAILED; - - is_locked_ = true; - return state & VM_PURGABLE_EMPTY ? DISCARDABLE_MEMORY_PURGED - : DISCARDABLE_MEMORY_SUCCESS; -} - -void DiscardableMemory::Unlock() { - DCHECK(is_locked_); - - int state = VM_PURGABLE_VOLATILE | VM_VOLATILE_GROUP_DEFAULT; - kern_return_t ret = vm_purgable_control( - mach_task_self(), - reinterpret_cast(memory_), - VM_PURGABLE_SET_STATE, - &state); - - if (ret != KERN_SUCCESS) - DLOG(ERROR) << "Failed to unlock memory."; - - is_locked_ = false; -} - -// static -bool DiscardableMemory::PurgeForTestingSupported() { - return true; -} - -// static -void DiscardableMemory::PurgeForTesting() { - int state = 0; - vm_purgable_control(mach_task_self(), 0, VM_PURGABLE_PURGE_ALL, &state); -} - -} // namespace base diff --git a/base/memory/discardable_memory_unittest.cc b/base/memory/discardable_memory_unittest.cc deleted file mode 100644 index 60d35820fb..0000000000 --- a/base/memory/discardable_memory_unittest.cc +++ /dev/null @@ -1,61 +0,0 @@ -// Copyright (c) 2013 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "base/memory/discardable_memory.h" -#include "testing/gtest/include/gtest/gtest.h" - -namespace base { - -#if defined(OS_ANDROID) || defined(OS_MACOSX) -// Test Lock() and Unlock() functionalities. -TEST(DiscardableMemoryTest, LockAndUnLock) { - ASSERT_TRUE(DiscardableMemory::Supported()); - - const size_t size = 1024; - - DiscardableMemory memory; - ASSERT_TRUE(memory.InitializeAndLock(size)); - void* addr = memory.Memory(); - ASSERT_NE(static_cast(NULL), addr); - - memory.Unlock(); - // The system should have no reason to purge discardable blocks in this brief - // interval, though technically speaking this might flake. - EXPECT_EQ(DISCARDABLE_MEMORY_SUCCESS, memory.Lock()); - addr = memory.Memory(); - ASSERT_NE(static_cast(NULL), addr); - - memory.Unlock(); -} - -// Test delete a discardable memory while it is locked. -TEST(DiscardableMemoryTest, DeleteWhileLocked) { - ASSERT_TRUE(DiscardableMemory::Supported()); - - const size_t size = 1024; - - DiscardableMemory memory; - ASSERT_TRUE(memory.InitializeAndLock(size)); -} - -#if defined(OS_MACOSX) -// Test forced purging. -TEST(DiscardableMemoryTest, Purge) { - ASSERT_TRUE(DiscardableMemory::Supported()); - ASSERT_TRUE(DiscardableMemory::PurgeForTestingSupported()); - - const size_t size = 1024; - - DiscardableMemory memory; - ASSERT_TRUE(memory.InitializeAndLock(size)); - memory.Unlock(); - - DiscardableMemory::PurgeForTesting(); - EXPECT_EQ(DISCARDABLE_MEMORY_PURGED, memory.Lock()); -} -#endif // OS_MACOSX - -#endif // OS_* - -} diff --git a/base/memory/linked_ptr.h b/base/memory/linked_ptr.h deleted file mode 100644 index 80044add81..0000000000 --- a/base/memory/linked_ptr.h +++ /dev/null @@ -1,181 +0,0 @@ -// Copyright (c) 2011 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. -// -// A "smart" pointer type with reference tracking. Every pointer to a -// particular object is kept on a circular linked list. When the last pointer -// to an object is destroyed or reassigned, the object is deleted. -// -// Used properly, this deletes the object when the last reference goes away. -// There are several caveats: -// - Like all reference counting schemes, cycles lead to leaks. -// - Each smart pointer is actually two pointers (8 bytes instead of 4). -// - Every time a pointer is released, the entire list of pointers to that -// object is traversed. This class is therefore NOT SUITABLE when there -// will often be more than two or three pointers to a particular object. -// - References are only tracked as long as linked_ptr<> objects are copied. -// If a linked_ptr<> is converted to a raw pointer and back, BAD THINGS -// will happen (double deletion). -// -// A good use of this class is storing object references in STL containers. -// You can safely put linked_ptr<> in a vector<>. -// Other uses may not be as good. -// -// Note: If you use an incomplete type with linked_ptr<>, the class -// *containing* linked_ptr<> must have a constructor and destructor (even -// if they do nothing!). -// -// Thread Safety: -// A linked_ptr is NOT thread safe. Copying a linked_ptr object is -// effectively a read-write operation. -// -// Alternative: to linked_ptr is shared_ptr, which -// - is also two pointers in size (8 bytes for 32 bit addresses) -// - is thread safe for copying and deletion -// - supports weak_ptrs - -#ifndef BASE_MEMORY_LINKED_PTR_H_ -#define BASE_MEMORY_LINKED_PTR_H_ - -#include "base/logging.h" // for CHECK macros - -// This is used internally by all instances of linked_ptr<>. It needs to be -// a non-template class because different types of linked_ptr<> can refer to -// the same object (linked_ptr(obj) vs linked_ptr(obj)). -// So, it needs to be possible for different types of linked_ptr to participate -// in the same circular linked list, so we need a single class type here. -// -// DO NOT USE THIS CLASS DIRECTLY YOURSELF. Use linked_ptr. -class linked_ptr_internal { - public: - // Create a new circle that includes only this instance. - void join_new() { - next_ = this; - } - - // Join an existing circle. - void join(linked_ptr_internal const* ptr) { - next_ = ptr->next_; - ptr->next_ = this; - } - - // Leave whatever circle we're part of. Returns true iff we were the - // last member of the circle. Once this is done, you can join() another. - bool depart() { - if (next_ == this) return true; - linked_ptr_internal const* p = next_; - while (p->next_ != this) p = p->next_; - p->next_ = next_; - return false; - } - - private: - mutable linked_ptr_internal const* next_; -}; - -template -class linked_ptr { - public: - typedef T element_type; - - // Take over ownership of a raw pointer. This should happen as soon as - // possible after the object is created. - explicit linked_ptr(T* ptr = NULL) { capture(ptr); } - ~linked_ptr() { depart(); } - - // Copy an existing linked_ptr<>, adding ourselves to the list of references. - template linked_ptr(linked_ptr const& ptr) { copy(&ptr); } - - linked_ptr(linked_ptr const& ptr) { - DCHECK_NE(&ptr, this); - copy(&ptr); - } - - // Assignment releases the old value and acquires the new. - template linked_ptr& operator=(linked_ptr const& ptr) { - depart(); - copy(&ptr); - return *this; - } - - linked_ptr& operator=(linked_ptr const& ptr) { - if (&ptr != this) { - depart(); - copy(&ptr); - } - return *this; - } - - // Smart pointer members. - void reset(T* ptr = NULL) { - depart(); - capture(ptr); - } - T* get() const { return value_; } - T* operator->() const { return value_; } - T& operator*() const { return *value_; } - // Release ownership of the pointed object and returns it. - // Sole ownership by this linked_ptr object is required. - T* release() { - bool last = link_.depart(); - CHECK(last); - T* v = value_; - value_ = NULL; - return v; - } - - bool operator==(const T* p) const { return value_ == p; } - bool operator!=(const T* p) const { return value_ != p; } - template - bool operator==(linked_ptr const& ptr) const { - return value_ == ptr.get(); - } - template - bool operator!=(linked_ptr const& ptr) const { - return value_ != ptr.get(); - } - - private: - template - friend class linked_ptr; - - T* value_; - linked_ptr_internal link_; - - void depart() { - if (link_.depart()) delete value_; - } - - void capture(T* ptr) { - value_ = ptr; - link_.join_new(); - } - - template void copy(linked_ptr const* ptr) { - value_ = ptr->get(); - if (value_) - link_.join(&ptr->link_); - else - link_.join_new(); - } -}; - -template inline -bool operator==(T* ptr, const linked_ptr& x) { - return ptr == x.get(); -} - -template inline -bool operator!=(T* ptr, const linked_ptr& x) { - return ptr != x.get(); -} - -// A function to convert T* into linked_ptr -// Doing e.g. make_linked_ptr(new FooBarBaz(arg)) is a shorter notation -// for linked_ptr >(new FooBarBaz(arg)) -template -linked_ptr make_linked_ptr(T* ptr) { - return linked_ptr(ptr); -} - -#endif // BASE_MEMORY_LINKED_PTR_H_ diff --git a/base/memory/linked_ptr_unittest.cc b/base/memory/linked_ptr_unittest.cc deleted file mode 100644 index 8b938f2d6c..0000000000 --- a/base/memory/linked_ptr_unittest.cc +++ /dev/null @@ -1,110 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include - -#include "base/memory/linked_ptr.h" -#include "base/strings/stringprintf.h" -#include "testing/gtest/include/gtest/gtest.h" - -namespace { - -int num = 0; - -std::string history; - -// Class which tracks allocation/deallocation -struct A { - A(): mynum(num++) { history += base::StringPrintf("A%d ctor\n", mynum); } - virtual ~A() { history += base::StringPrintf("A%d dtor\n", mynum); } - virtual void Use() { history += base::StringPrintf("A%d use\n", mynum); } - int mynum; -}; - -// Subclass -struct B: public A { - B() { history += base::StringPrintf("B%d ctor\n", mynum); } - virtual ~B() { history += base::StringPrintf("B%d dtor\n", mynum); } - virtual void Use() OVERRIDE { - history += base::StringPrintf("B%d use\n", mynum); - } -}; - -} // namespace - -TEST(LinkedPtrTest, Test) { - { - linked_ptr a0, a1, a2; - a0 = a0; - a1 = a2; - ASSERT_EQ(a0.get(), static_cast(NULL)); - ASSERT_EQ(a1.get(), static_cast(NULL)); - ASSERT_EQ(a2.get(), static_cast(NULL)); - ASSERT_TRUE(a0 == NULL); - ASSERT_TRUE(a1 == NULL); - ASSERT_TRUE(a2 == NULL); - - { - linked_ptr a3(new A); - a0 = a3; - ASSERT_TRUE(a0 == a3); - ASSERT_TRUE(a0 != NULL); - ASSERT_TRUE(a0.get() == a3); - ASSERT_TRUE(a0 == a3.get()); - linked_ptr a4(a0); - a1 = a4; - linked_ptr a5(new A); - ASSERT_TRUE(a5.get() != a3); - ASSERT_TRUE(a5 != a3.get()); - a2 = a5; - linked_ptr b0(new B); - linked_ptr a6(b0); - ASSERT_TRUE(b0 == a6); - ASSERT_TRUE(a6 == b0); - ASSERT_TRUE(b0 != NULL); - a5 = b0; - a5 = b0; - a3->Use(); - a4->Use(); - a5->Use(); - a6->Use(); - b0->Use(); - (*b0).Use(); - b0.get()->Use(); - } - - a0->Use(); - a1->Use(); - a2->Use(); - - a1 = a2; - a2.reset(new A); - a0.reset(); - - linked_ptr a7; - } - - ASSERT_EQ(history, - "A0 ctor\n" - "A1 ctor\n" - "A2 ctor\n" - "B2 ctor\n" - "A0 use\n" - "A0 use\n" - "B2 use\n" - "B2 use\n" - "B2 use\n" - "B2 use\n" - "B2 use\n" - "B2 dtor\n" - "A2 dtor\n" - "A0 use\n" - "A0 use\n" - "A1 use\n" - "A3 ctor\n" - "A0 dtor\n" - "A3 dtor\n" - "A1 dtor\n" - ); -} diff --git a/base/memory/manual_constructor.h b/base/memory/manual_constructor.h deleted file mode 100644 index 9275f73b83..0000000000 --- a/base/memory/manual_constructor.h +++ /dev/null @@ -1,125 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -// ManualConstructor statically-allocates space in which to store some -// object, but does not initialize it. You can then call the constructor -// and destructor for the object yourself as you see fit. This is useful -// for memory management optimizations, where you want to initialize and -// destroy an object multiple times but only allocate it once. -// -// (When I say ManualConstructor statically allocates space, I mean that -// the ManualConstructor object itself is forced to be the right size.) -// -// For example usage, check out base/containers/small_map.h. - -#ifndef BASE_MEMORY_MANUAL_CONSTRUCTOR_H_ -#define BASE_MEMORY_MANUAL_CONSTRUCTOR_H_ - -#include - -#include "base/memory/aligned_memory.h" - -namespace base { - -template -class ManualConstructor { - public: - // No constructor or destructor because one of the most useful uses of - // this class is as part of a union, and members of a union cannot have - // constructors or destructors. And, anyway, the whole point of this - // class is to bypass these. - - // Support users creating arrays of ManualConstructor<>s. This ensures that - // the array itself has the correct alignment. - static void* operator new[](size_t size) { -#if defined(COMPILER_MSVC) - return AlignedAlloc(size, __alignof(Type)); -#else - return AlignedAlloc(size, __alignof__(Type)); -#endif - } - static void operator delete[](void* mem) { - AlignedFree(mem); - } - - inline Type* get() { - return space_.template data_as(); - } - inline const Type* get() const { - return space_.template data_as(); - } - - inline Type* operator->() { return get(); } - inline const Type* operator->() const { return get(); } - - inline Type& operator*() { return *get(); } - inline const Type& operator*() const { return *get(); } - - // You can pass up to eight constructor arguments as arguments of Init(). - inline void Init() { - new(space_.void_data()) Type; - } - - template - inline void Init(const T1& p1) { - new(space_.void_data()) Type(p1); - } - - template - inline void Init(const T1& p1, const T2& p2) { - new(space_.void_data()) Type(p1, p2); - } - - template - inline void Init(const T1& p1, const T2& p2, const T3& p3) { - new(space_.void_data()) Type(p1, p2, p3); - } - - template - inline void Init(const T1& p1, const T2& p2, const T3& p3, const T4& p4) { - new(space_.void_data()) Type(p1, p2, p3, p4); - } - - template - inline void Init(const T1& p1, const T2& p2, const T3& p3, const T4& p4, - const T5& p5) { - new(space_.void_data()) Type(p1, p2, p3, p4, p5); - } - - template - inline void Init(const T1& p1, const T2& p2, const T3& p3, const T4& p4, - const T5& p5, const T6& p6) { - new(space_.void_data()) Type(p1, p2, p3, p4, p5, p6); - } - - template - inline void Init(const T1& p1, const T2& p2, const T3& p3, const T4& p4, - const T5& p5, const T6& p6, const T7& p7) { - new(space_.void_data()) Type(p1, p2, p3, p4, p5, p6, p7); - } - - template - inline void Init(const T1& p1, const T2& p2, const T3& p3, const T4& p4, - const T5& p5, const T6& p6, const T7& p7, const T8& p8) { - new(space_.void_data()) Type(p1, p2, p3, p4, p5, p6, p7, p8); - } - - inline void Destroy() { - get()->~Type(); - } - - private: -#if defined(COMPILER_MSVC) - AlignedMemory space_; -#else - AlignedMemory space_; -#endif -}; - -} // namespace base - -#endif // BASE_MEMORY_MANUAL_CONSTRUCTOR_H_ diff --git a/base/memory/memory_pressure_level_list.h b/base/memory/memory_pressure_level_list.h deleted file mode 100644 index bf3ce60503..0000000000 --- a/base/memory/memory_pressure_level_list.h +++ /dev/null @@ -1,19 +0,0 @@ -// Copyright 2013 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -// This file intentionally does not have header guards, it's included -// inside a macro to generate enum and a java class for the values. - -#ifndef DEFINE_MEMORY_PRESSURE_LEVEL -#error "DEFINE_MEMORY_PRESSURE_LEVEL should be defined." -#endif - -// Modules are advised to free buffers that are cheap to re-allocate and not -// immediately needed. -DEFINE_MEMORY_PRESSURE_LEVEL(MEMORY_PRESSURE_MODERATE, 0) - -// At this level, modules are advised to free all possible memory. -// The alternative is to be killed by the system, which means all memory will -// have to be re-created, plus the cost of a cold start. -DEFINE_MEMORY_PRESSURE_LEVEL(MEMORY_PRESSURE_CRITICAL, 2) diff --git a/base/memory/memory_pressure_listener.cc b/base/memory/memory_pressure_listener.cc deleted file mode 100644 index e2ea106eaa..0000000000 --- a/base/memory/memory_pressure_listener.cc +++ /dev/null @@ -1,57 +0,0 @@ -// Copyright 2013 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "base/memory/memory_pressure_listener.h" - -#include "base/lazy_instance.h" -#include "base/observer_list_threadsafe.h" - -namespace { - -// ObserverListThreadSafe is RefCountedThreadSafe, this traits is needed -// to ensure the LazyInstance will hold a reference to it. -struct LeakyLazyObserverListTraits : - base::internal::LeakyLazyInstanceTraits< - ObserverListThreadSafe > { - static ObserverListThreadSafe* - New(void* instance) { - ObserverListThreadSafe* ret = - base::internal::LeakyLazyInstanceTraits< - ObserverListThreadSafe >::New( - instance); - // Leaky. - ret->AddRef(); - return ret; - } -}; - -base::LazyInstance< - ObserverListThreadSafe, - LeakyLazyObserverListTraits> g_observers = LAZY_INSTANCE_INITIALIZER; -} // namespace - -namespace base { - -MemoryPressureListener::MemoryPressureListener( - const MemoryPressureListener::MemoryPressureCallback& callback) - : callback_(callback) { - g_observers.Get().AddObserver(this); -} - -MemoryPressureListener::~MemoryPressureListener() { - g_observers.Get().RemoveObserver(this); -} - -void MemoryPressureListener::Notify(MemoryPressureLevel memory_pressure_level) { - callback_.Run(memory_pressure_level); -} - -// static -void MemoryPressureListener::NotifyMemoryPressure( - MemoryPressureLevel memory_pressure_level) { - g_observers.Get().Notify(&MemoryPressureListener::Notify, - memory_pressure_level); -} - -} // namespace base diff --git a/base/memory/memory_pressure_listener.h b/base/memory/memory_pressure_listener.h deleted file mode 100644 index 7b8029dd71..0000000000 --- a/base/memory/memory_pressure_listener.h +++ /dev/null @@ -1,80 +0,0 @@ -// Copyright 2013 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -// MemoryPressure provides static APIs for handling memory pressure on -// platforms that have such signals, such as Android. -// The app will try to discard buffers that aren't deemed essential (individual -// modules will implement their own policy). -// -// Refer to memory_pressure_level_list.h for information about what sorts of -// signals can be sent under what conditions. - -#ifndef BASE_MEMORY_PRESSURE_LISTENER_H_ -#define BASE_MEMORY_PRESSURE_LISTENER_H_ - -#include "base/base_export.h" -#include "base/basictypes.h" -#include "base/callback.h" - -namespace base { - -// To start listening, create a new instance, passing a callback to a -// function that takes a MemoryPressureLevel parameter. To stop listening, -// simply delete the listener object. The implementation guarantees -// that the callback will always be called on the thread that created -// the listener. -// If this is the same thread as the system is broadcasting the memory pressure -// event on, then it is guaranteed you're called synchronously within that -// broadcast and hence you should not do long-running garbage collection work. -// But conversely, if there's something that needs to be released before -// control is returned to system code, this is the place to do it. -// Please see notes on memory_pressure_level_list.h: some levels are absolutely -// critical, and if not enough memory is returned to the system, it'll -// potentially kill the app, and then later the app will have to be -// cold-started. -// -// -// Example: -// -// void OnMemoryPressure(MemoryPressureLevel memory_pressure_level) { -// ... -// } -// -// // Start listening. -// MemoryPressureListener* my_listener = -// new MemoryPressureListener(base::Bind(&OnMemoryPressure)); -// -// ... -// -// // Stop listening. -// delete my_listener; -// -class BASE_EXPORT MemoryPressureListener { - public: - enum MemoryPressureLevel { -#define DEFINE_MEMORY_PRESSURE_LEVEL(name, value) name = value, -#include "base/memory/memory_pressure_level_list.h" -#undef DEFINE_MEMORY_PRESSURE_LEVEL - }; - - typedef base::Callback MemoryPressureCallback; - - explicit MemoryPressureListener( - const MemoryPressureCallback& memory_pressure_callback); - ~MemoryPressureListener(); - - // Intended for use by the platform specific implementation. - static void NotifyMemoryPressure(MemoryPressureLevel memory_pressure_level); - - private: - void Notify(MemoryPressureLevel memory_pressure_level); - - MemoryPressureCallback callback_; - - DISALLOW_COPY_AND_ASSIGN(MemoryPressureListener); -}; - -} // namespace base - -#endif // BASE_MEMORY_PRESSURE_LISTENER_H_ diff --git a/base/memory/raw_scoped_refptr_mismatch_checker.h b/base/memory/raw_scoped_refptr_mismatch_checker.h deleted file mode 100644 index 7974f3047b..0000000000 --- a/base/memory/raw_scoped_refptr_mismatch_checker.h +++ /dev/null @@ -1,129 +0,0 @@ -// Copyright (c) 2011 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef BASE_MEMORY_RAW_SCOPED_REFPTR_MISMATCH_CHECKER_H_ -#define BASE_MEMORY_RAW_SCOPED_REFPTR_MISMATCH_CHECKER_H_ - -#include "base/memory/ref_counted.h" -#include "base/template_util.h" -#include "base/tuple.h" -#include "build/build_config.h" - -// It is dangerous to post a task with a T* argument where T is a subtype of -// RefCounted(Base|ThreadSafeBase), since by the time the parameter is used, the -// object may already have been deleted since it was not held with a -// scoped_refptr. Example: http://crbug.com/27191 -// The following set of traits are designed to generate a compile error -// whenever this antipattern is attempted. - -namespace base { - -// This is a base internal implementation file used by task.h and callback.h. -// Not for public consumption, so we wrap it in namespace internal. -namespace internal { - -template -struct NeedsScopedRefptrButGetsRawPtr { -#if defined(OS_WIN) - enum { - value = base::false_type::value - }; -#else - enum { - // Human readable translation: you needed to be a scoped_refptr if you are a - // raw pointer type and are convertible to a RefCounted(Base|ThreadSafeBase) - // type. - value = (is_pointer::value && - (is_convertible::value || - is_convertible::value)) - }; -#endif -}; - -template -struct ParamsUseScopedRefptrCorrectly { - enum { value = 0 }; -}; - -template <> -struct ParamsUseScopedRefptrCorrectly { - enum { value = 1 }; -}; - -template -struct ParamsUseScopedRefptrCorrectly > { - enum { value = !NeedsScopedRefptrButGetsRawPtr::value }; -}; - -template -struct ParamsUseScopedRefptrCorrectly > { - enum { value = !(NeedsScopedRefptrButGetsRawPtr::value || - NeedsScopedRefptrButGetsRawPtr::value) }; -}; - -template -struct ParamsUseScopedRefptrCorrectly > { - enum { value = !(NeedsScopedRefptrButGetsRawPtr::value || - NeedsScopedRefptrButGetsRawPtr::value || - NeedsScopedRefptrButGetsRawPtr::value) }; -}; - -template -struct ParamsUseScopedRefptrCorrectly > { - enum { value = !(NeedsScopedRefptrButGetsRawPtr::value || - NeedsScopedRefptrButGetsRawPtr::value || - NeedsScopedRefptrButGetsRawPtr::value || - NeedsScopedRefptrButGetsRawPtr::value) }; -}; - -template -struct ParamsUseScopedRefptrCorrectly > { - enum { value = !(NeedsScopedRefptrButGetsRawPtr::value || - NeedsScopedRefptrButGetsRawPtr::value || - NeedsScopedRefptrButGetsRawPtr::value || - NeedsScopedRefptrButGetsRawPtr::value || - NeedsScopedRefptrButGetsRawPtr::value) }; -}; - -template -struct ParamsUseScopedRefptrCorrectly > { - enum { value = !(NeedsScopedRefptrButGetsRawPtr::value || - NeedsScopedRefptrButGetsRawPtr::value || - NeedsScopedRefptrButGetsRawPtr::value || - NeedsScopedRefptrButGetsRawPtr::value || - NeedsScopedRefptrButGetsRawPtr::value || - NeedsScopedRefptrButGetsRawPtr::value) }; -}; - -template -struct ParamsUseScopedRefptrCorrectly > { - enum { value = !(NeedsScopedRefptrButGetsRawPtr::value || - NeedsScopedRefptrButGetsRawPtr::value || - NeedsScopedRefptrButGetsRawPtr::value || - NeedsScopedRefptrButGetsRawPtr::value || - NeedsScopedRefptrButGetsRawPtr::value || - NeedsScopedRefptrButGetsRawPtr::value || - NeedsScopedRefptrButGetsRawPtr::value) }; -}; - -template -struct ParamsUseScopedRefptrCorrectly > { - enum { value = !(NeedsScopedRefptrButGetsRawPtr::value || - NeedsScopedRefptrButGetsRawPtr::value || - NeedsScopedRefptrButGetsRawPtr::value || - NeedsScopedRefptrButGetsRawPtr::value || - NeedsScopedRefptrButGetsRawPtr::value || - NeedsScopedRefptrButGetsRawPtr::value || - NeedsScopedRefptrButGetsRawPtr::value || - NeedsScopedRefptrButGetsRawPtr::value) }; -}; - -} // namespace internal - -} // namespace base - -#endif // BASE_MEMORY_RAW_SCOPED_REFPTR_MISMATCH_CHECKER_H_ diff --git a/base/memory/ref_counted.cc b/base/memory/ref_counted.cc deleted file mode 100644 index 31ad5098cd..0000000000 --- a/base/memory/ref_counted.cc +++ /dev/null @@ -1,95 +0,0 @@ -// Copyright (c) 2011 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "base/memory/ref_counted.h" - -#include "base/logging.h" -#include "base/threading/thread_collision_warner.h" - -namespace base { - -namespace subtle { - -RefCountedBase::RefCountedBase() - : ref_count_(0) -#ifndef NDEBUG - , in_dtor_(false) -#endif - { -} - -RefCountedBase::~RefCountedBase() { -#ifndef NDEBUG - DCHECK(in_dtor_) << "RefCounted object deleted without calling Release()"; -#endif -} - -void RefCountedBase::AddRef() const { - // TODO(maruel): Add back once it doesn't assert 500 times/sec. - // Current thread books the critical section "AddRelease" without release it. - // DFAKE_SCOPED_LOCK_THREAD_LOCKED(add_release_); -#ifndef NDEBUG - DCHECK(!in_dtor_); -#endif - ++ref_count_; -} - -bool RefCountedBase::Release() const { - // TODO(maruel): Add back once it doesn't assert 500 times/sec. - // Current thread books the critical section "AddRelease" without release it. - // DFAKE_SCOPED_LOCK_THREAD_LOCKED(add_release_); -#ifndef NDEBUG - DCHECK(!in_dtor_); -#endif - if (--ref_count_ == 0) { -#ifndef NDEBUG - in_dtor_ = true; -#endif - return true; - } - return false; -} - -bool RefCountedThreadSafeBase::HasOneRef() const { - return AtomicRefCountIsOne( - &const_cast(this)->ref_count_); -} - -RefCountedThreadSafeBase::RefCountedThreadSafeBase() : ref_count_(0) { -#ifndef NDEBUG - in_dtor_ = false; -#endif -} - -RefCountedThreadSafeBase::~RefCountedThreadSafeBase() { -#ifndef NDEBUG - DCHECK(in_dtor_) << "RefCountedThreadSafe object deleted without " - "calling Release()"; -#endif -} - -void RefCountedThreadSafeBase::AddRef() const { -#ifndef NDEBUG - DCHECK(!in_dtor_); -#endif - AtomicRefCountInc(&ref_count_); -} - -bool RefCountedThreadSafeBase::Release() const { -#ifndef NDEBUG - DCHECK(!in_dtor_); - DCHECK(!AtomicRefCountIsZero(&ref_count_)); -#endif - if (!AtomicRefCountDec(&ref_count_)) { -#ifndef NDEBUG - in_dtor_ = true; -#endif - return true; - } - return false; -} - -} // namespace subtle - -} // namespace base diff --git a/base/memory/ref_counted.h b/base/memory/ref_counted.h deleted file mode 100644 index 0c6a71fdb3..0000000000 --- a/base/memory/ref_counted.h +++ /dev/null @@ -1,301 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef BASE_MEMORY_REF_COUNTED_H_ -#define BASE_MEMORY_REF_COUNTED_H_ - -#include - -#include "base/atomic_ref_count.h" -#include "base/base_export.h" -#include "base/compiler_specific.h" -#include "base/threading/thread_collision_warner.h" - -namespace base { - -namespace subtle { - -class BASE_EXPORT RefCountedBase { - public: - bool HasOneRef() const { return ref_count_ == 1; } - - protected: - RefCountedBase(); - ~RefCountedBase(); - - void AddRef() const; - - // Returns true if the object should self-delete. - bool Release() const; - - private: - mutable int ref_count_; -#ifndef NDEBUG - mutable bool in_dtor_; -#endif - - DFAKE_MUTEX(add_release_); - - DISALLOW_COPY_AND_ASSIGN(RefCountedBase); -}; - -class BASE_EXPORT RefCountedThreadSafeBase { - public: - bool HasOneRef() const; - - protected: - RefCountedThreadSafeBase(); - ~RefCountedThreadSafeBase(); - - void AddRef() const; - - // Returns true if the object should self-delete. - bool Release() const; - - private: - mutable AtomicRefCount ref_count_; -#ifndef NDEBUG - mutable bool in_dtor_; -#endif - - DISALLOW_COPY_AND_ASSIGN(RefCountedThreadSafeBase); -}; - -} // namespace subtle - -// -// A base class for reference counted classes. Otherwise, known as a cheap -// knock-off of WebKit's RefCounted class. To use this guy just extend your -// class from it like so: -// -// class MyFoo : public base::RefCounted { -// ... -// private: -// friend class base::RefCounted; -// ~MyFoo(); -// }; -// -// You should always make your destructor private, to avoid any code deleting -// the object accidently while there are references to it. -template -class RefCounted : public subtle::RefCountedBase { - public: - RefCounted() {} - - void AddRef() const { - subtle::RefCountedBase::AddRef(); - } - - void Release() const { - if (subtle::RefCountedBase::Release()) { - delete static_cast(this); - } - } - - protected: - ~RefCounted() {} - - private: - DISALLOW_COPY_AND_ASSIGN(RefCounted); -}; - -// Forward declaration. -template class RefCountedThreadSafe; - -// Default traits for RefCountedThreadSafe. Deletes the object when its ref -// count reaches 0. Overload to delete it on a different thread etc. -template -struct DefaultRefCountedThreadSafeTraits { - static void Destruct(const T* x) { - // Delete through RefCountedThreadSafe to make child classes only need to be - // friend with RefCountedThreadSafe instead of this struct, which is an - // implementation detail. - RefCountedThreadSafe::DeleteInternal(x); - } -}; - -// -// A thread-safe variant of RefCounted -// -// class MyFoo : public base::RefCountedThreadSafe { -// ... -// }; -// -// If you're using the default trait, then you should add compile time -// asserts that no one else is deleting your object. i.e. -// private: -// friend class base::RefCountedThreadSafe; -// ~MyFoo(); -template > -class RefCountedThreadSafe : public subtle::RefCountedThreadSafeBase { - public: - RefCountedThreadSafe() {} - - void AddRef() const { - subtle::RefCountedThreadSafeBase::AddRef(); - } - - void Release() const { - if (subtle::RefCountedThreadSafeBase::Release()) { - Traits::Destruct(static_cast(this)); - } - } - - protected: - ~RefCountedThreadSafe() {} - - private: - friend struct DefaultRefCountedThreadSafeTraits; - static void DeleteInternal(const T* x) { delete x; } - - DISALLOW_COPY_AND_ASSIGN(RefCountedThreadSafe); -}; - -// -// A thread-safe wrapper for some piece of data so we can place other -// things in scoped_refptrs<>. -// -template -class RefCountedData - : public base::RefCountedThreadSafe< base::RefCountedData > { - public: - RefCountedData() : data() {} - RefCountedData(const T& in_value) : data(in_value) {} - - T data; - - private: - friend class base::RefCountedThreadSafe >; - ~RefCountedData() {} -}; - -} // namespace base - -// -// A smart pointer class for reference counted objects. Use this class instead -// of calling AddRef and Release manually on a reference counted object to -// avoid common memory leaks caused by forgetting to Release an object -// reference. Sample usage: -// -// class MyFoo : public RefCounted { -// ... -// }; -// -// void some_function() { -// scoped_refptr foo = new MyFoo(); -// foo->Method(param); -// // |foo| is released when this function returns -// } -// -// void some_other_function() { -// scoped_refptr foo = new MyFoo(); -// ... -// foo = NULL; // explicitly releases |foo| -// ... -// if (foo) -// foo->Method(param); -// } -// -// The above examples show how scoped_refptr acts like a pointer to T. -// Given two scoped_refptr classes, it is also possible to exchange -// references between the two objects, like so: -// -// { -// scoped_refptr a = new MyFoo(); -// scoped_refptr b; -// -// b.swap(a); -// // now, |b| references the MyFoo object, and |a| references NULL. -// } -// -// To make both |a| and |b| in the above example reference the same MyFoo -// object, simply use the assignment operator: -// -// { -// scoped_refptr a = new MyFoo(); -// scoped_refptr b; -// -// b = a; -// // now, |a| and |b| each own a reference to the same MyFoo object. -// } -// -template -class scoped_refptr { - public: - typedef T element_type; - - scoped_refptr() : ptr_(NULL) { - } - - scoped_refptr(T* p) : ptr_(p) { - if (ptr_) - ptr_->AddRef(); - } - - scoped_refptr(const scoped_refptr& r) : ptr_(r.ptr_) { - if (ptr_) - ptr_->AddRef(); - } - - template - scoped_refptr(const scoped_refptr& r) : ptr_(r.get()) { - if (ptr_) - ptr_->AddRef(); - } - - ~scoped_refptr() { - if (ptr_) - ptr_->Release(); - } - - T* get() const { return ptr_; } - operator T*() const { return ptr_; } - T* operator->() const { - assert(ptr_ != NULL); - return ptr_; - } - - scoped_refptr& operator=(T* p) { - // AddRef first so that self assignment should work - if (p) - p->AddRef(); - T* old_ptr = ptr_; - ptr_ = p; - if (old_ptr) - old_ptr->Release(); - return *this; - } - - scoped_refptr& operator=(const scoped_refptr& r) { - return *this = r.ptr_; - } - - template - scoped_refptr& operator=(const scoped_refptr& r) { - return *this = r.get(); - } - - void swap(T** pp) { - T* p = ptr_; - ptr_ = *pp; - *pp = p; - } - - void swap(scoped_refptr& r) { - swap(&r.ptr_); - } - - protected: - T* ptr_; -}; - -// Handy utility for creating a scoped_refptr out of a T* explicitly without -// having to retype all the template arguments -template -scoped_refptr make_scoped_refptr(T* t) { - return scoped_refptr(t); -} - -#endif // BASE_MEMORY_REF_COUNTED_H_ diff --git a/base/memory/ref_counted_delete_on_message_loop.h b/base/memory/ref_counted_delete_on_message_loop.h deleted file mode 100644 index 7b898ac00d..0000000000 --- a/base/memory/ref_counted_delete_on_message_loop.h +++ /dev/null @@ -1,70 +0,0 @@ -// Copyright 2013 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef BASE_MEMORY_REF_COUNTED_DELETE_ON_MESSAGE_LOOP_H_ -#define BASE_MEMORY_REF_COUNTED_DELETE_ON_MESSAGE_LOOP_H_ - -#include "base/location.h" -#include "base/logging.h" -#include "base/memory/ref_counted.h" -#include "base/message_loop/message_loop_proxy.h" - -namespace base { - -// RefCountedDeleteOnMessageLoop is similar to RefCountedThreadSafe, and ensures -// that the object will be deleted on a specified message loop. -// -// Sample usage: -// class Foo : public RefCountedDeleteOnMessageLoop { -// -// Foo(const scoped_refptr& loop) -// : RefCountedDeleteOnMessageLoop(loop) { -// ... -// } -// ... -// private: -// friend class RefCountedDeleteOnMessageLoop; -// friend class DeleteHelper; -// -// ~Foo(); -// }; - -template -class RefCountedDeleteOnMessageLoop : public subtle::RefCountedThreadSafeBase { - public: - RefCountedDeleteOnMessageLoop( - const scoped_refptr& proxy) : proxy_(proxy) { - DCHECK(proxy_.get()); - } - - void AddRef() const { - subtle::RefCountedThreadSafeBase::AddRef(); - } - - void Release() const { - if (subtle::RefCountedThreadSafeBase::Release()) - DestructOnMessageLoop(); - } - - protected: - friend class DeleteHelper; - ~RefCountedDeleteOnMessageLoop() {} - - void DestructOnMessageLoop() const { - const T* t = static_cast(this); - if (proxy_->BelongsToCurrentThread()) - delete t; - else - proxy_->DeleteSoon(FROM_HERE, t); - } - - scoped_refptr proxy_; - - private: - DISALLOW_COPY_AND_ASSIGN(RefCountedDeleteOnMessageLoop); -}; - -} // namespace base - -#endif // BASE_MEMORY_REF_COUNTED_DELETE_ON_MESSAGE_LOOP_H_ diff --git a/base/memory/ref_counted_memory.cc b/base/memory/ref_counted_memory.cc deleted file mode 100644 index b048a6e0d8..0000000000 --- a/base/memory/ref_counted_memory.cc +++ /dev/null @@ -1,77 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "base/memory/ref_counted_memory.h" - -#include "base/logging.h" - -namespace base { - -bool RefCountedMemory::Equals( - const scoped_refptr& other) const { - return other.get() && - size() == other->size() && - (memcmp(front(), other->front(), size()) == 0); -} - -RefCountedMemory::RefCountedMemory() {} - -RefCountedMemory::~RefCountedMemory() {} - -const unsigned char* RefCountedStaticMemory::front() const { - return data_; -} - -size_t RefCountedStaticMemory::size() const { - return length_; -} - -RefCountedStaticMemory::~RefCountedStaticMemory() {} - -RefCountedBytes::RefCountedBytes() {} - -RefCountedBytes::RefCountedBytes(const std::vector& initializer) - : data_(initializer) { -} - -RefCountedBytes* RefCountedBytes::TakeVector( - std::vector* to_destroy) { - RefCountedBytes* bytes = new RefCountedBytes; - bytes->data_.swap(*to_destroy); - return bytes; -} - -const unsigned char* RefCountedBytes::front() const { - // STL will assert if we do front() on an empty vector, but calling code - // expects a NULL. - return size() ? &data_.front() : NULL; -} - -size_t RefCountedBytes::size() const { - return data_.size(); -} - -RefCountedBytes::~RefCountedBytes() {} - -RefCountedString::RefCountedString() {} - -RefCountedString::~RefCountedString() {} - -// static -RefCountedString* RefCountedString::TakeString(std::string* to_destroy) { - RefCountedString* self = new RefCountedString; - to_destroy->swap(self->data_); - return self; -} - -const unsigned char* RefCountedString::front() const { - return data_.empty() ? NULL : - reinterpret_cast(data_.data()); -} - -size_t RefCountedString::size() const { - return data_.size(); -} - -} // namespace base diff --git a/base/memory/ref_counted_memory.h b/base/memory/ref_counted_memory.h deleted file mode 100644 index fd5e8a0b8f..0000000000 --- a/base/memory/ref_counted_memory.h +++ /dev/null @@ -1,118 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef BASE_MEMORY_REF_COUNTED_MEMORY_H_ -#define BASE_MEMORY_REF_COUNTED_MEMORY_H_ - -#include -#include - -#include "base/base_export.h" -#include "base/compiler_specific.h" -#include "base/memory/ref_counted.h" - -namespace base { - -// A generic interface to memory. This object is reference counted because one -// of its two subclasses own the data they carry, and we need to have -// heterogeneous containers of these two types of memory. -class BASE_EXPORT RefCountedMemory - : public base::RefCountedThreadSafe { - public: - // Retrieves a pointer to the beginning of the data we point to. If the data - // is empty, this will return NULL. - virtual const unsigned char* front() const = 0; - - // Size of the memory pointed to. - virtual size_t size() const = 0; - - // Returns true if |other| is byte for byte equal. - bool Equals(const scoped_refptr& other) const; - - protected: - friend class base::RefCountedThreadSafe; - RefCountedMemory(); - virtual ~RefCountedMemory(); -}; - -// An implementation of RefCountedMemory, where the ref counting does not -// matter. -class BASE_EXPORT RefCountedStaticMemory : public RefCountedMemory { - public: - RefCountedStaticMemory() - : data_(NULL), length_(0) {} - RefCountedStaticMemory(const unsigned char* data, size_t length) - : data_(length ? data : NULL), length_(length) {} - - // Overridden from RefCountedMemory: - virtual const unsigned char* front() const OVERRIDE; - virtual size_t size() const OVERRIDE; - - private: - virtual ~RefCountedStaticMemory(); - - const unsigned char* data_; - size_t length_; - - DISALLOW_COPY_AND_ASSIGN(RefCountedStaticMemory); -}; - -// An implementation of RefCountedMemory, where we own our the data in a -// vector. -class BASE_EXPORT RefCountedBytes : public RefCountedMemory { - public: - RefCountedBytes(); - - // Constructs a RefCountedBytes object by _copying_ from |initializer|. - explicit RefCountedBytes(const std::vector& initializer); - - // Constructs a RefCountedBytes object by performing a swap. (To non - // destructively build a RefCountedBytes, use the constructor that takes a - // vector.) - static RefCountedBytes* TakeVector(std::vector* to_destroy); - - // Overridden from RefCountedMemory: - virtual const unsigned char* front() const OVERRIDE; - virtual size_t size() const OVERRIDE; - - const std::vector& data() const { return data_; } - std::vector& data() { return data_; } - - private: - virtual ~RefCountedBytes(); - - std::vector data_; - - DISALLOW_COPY_AND_ASSIGN(RefCountedBytes); -}; - -// An implementation of RefCountedMemory, where the bytes are stored in an STL -// string. Use this if your data naturally arrives in that format. -class BASE_EXPORT RefCountedString : public RefCountedMemory { - public: - RefCountedString(); - - // Constructs a RefCountedString object by performing a swap. (To non - // destructively build a RefCountedString, use the default constructor and - // copy into object->data()). - static RefCountedString* TakeString(std::string* to_destroy); - - // Overridden from RefCountedMemory: - virtual const unsigned char* front() const OVERRIDE; - virtual size_t size() const OVERRIDE; - - const std::string& data() const { return data_; } - std::string& data() { return data_; } - - private: - virtual ~RefCountedString(); - - std::string data_; - - DISALLOW_COPY_AND_ASSIGN(RefCountedString); -}; - -} // namespace base - -#endif // BASE_MEMORY_REF_COUNTED_MEMORY_H_ diff --git a/base/memory/ref_counted_memory_unittest.cc b/base/memory/ref_counted_memory_unittest.cc deleted file mode 100644 index c6f2b9c3d1..0000000000 --- a/base/memory/ref_counted_memory_unittest.cc +++ /dev/null @@ -1,71 +0,0 @@ -// Copyright (c) 2011 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "base/memory/ref_counted_memory.h" - -#include "testing/gtest/include/gtest/gtest.h" - -namespace base { - -TEST(RefCountedMemoryUnitTest, RefCountedStaticMemory) { - scoped_refptr mem = new RefCountedStaticMemory( - reinterpret_cast("static mem00"), 10); - - EXPECT_EQ(10U, mem->size()); - EXPECT_EQ("static mem", - std::string(reinterpret_cast(mem->front()), - mem->size())); -} - -TEST(RefCountedMemoryUnitTest, RefCountedBytes) { - std::vector data; - data.push_back(45); - data.push_back(99); - scoped_refptr mem = RefCountedBytes::TakeVector(&data); - - EXPECT_EQ(0U, data.size()); - - EXPECT_EQ(2U, mem->size()); - EXPECT_EQ(45U, mem->front()[0]); - EXPECT_EQ(99U, mem->front()[1]); -} - -TEST(RefCountedMemoryUnitTest, RefCountedString) { - std::string s("destroy me"); - scoped_refptr mem = RefCountedString::TakeString(&s); - - EXPECT_EQ(0U, s.size()); - - EXPECT_EQ(10U, mem->size()); - EXPECT_EQ('d', mem->front()[0]); - EXPECT_EQ('e', mem->front()[1]); -} - -TEST(RefCountedMemoryUnitTest, Equals) { - std::string s1("same"); - scoped_refptr mem1 = RefCountedString::TakeString(&s1); - - std::vector d2; - d2.push_back('s'); - d2.push_back('a'); - d2.push_back('m'); - d2.push_back('e'); - scoped_refptr mem2 = RefCountedBytes::TakeVector(&d2); - - EXPECT_TRUE(mem1->Equals(mem2)); - - std::string s3("diff"); - scoped_refptr mem3 = RefCountedString::TakeString(&s3); - - EXPECT_FALSE(mem1->Equals(mem3)); - EXPECT_FALSE(mem2->Equals(mem3)); -} - -TEST(RefCountedMemoryUnitTest, EqualsNull) { - std::string s("str"); - scoped_refptr mem = RefCountedString::TakeString(&s); - EXPECT_FALSE(mem->Equals(NULL)); -} - -} // namespace base diff --git a/base/memory/ref_counted_unittest.cc b/base/memory/ref_counted_unittest.cc deleted file mode 100644 index e8eb0fd90f..0000000000 --- a/base/memory/ref_counted_unittest.cc +++ /dev/null @@ -1,62 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "base/memory/ref_counted.h" -#include "testing/gtest/include/gtest/gtest.h" - -namespace { - -class SelfAssign : public base::RefCounted { - friend class base::RefCounted; - - ~SelfAssign() {} -}; - -class CheckDerivedMemberAccess : public scoped_refptr { - public: - CheckDerivedMemberAccess() { - // This shouldn't compile if we don't have access to the member variable. - SelfAssign** pptr = &ptr_; - EXPECT_EQ(*pptr, ptr_); - } -}; - -class ScopedRefPtrToSelf : public base::RefCounted { - public: - ScopedRefPtrToSelf() : self_ptr_(this) {} - - static bool was_destroyed() { return was_destroyed_; } - - void SelfDestruct() { self_ptr_ = NULL; } - - private: - friend class base::RefCounted; - ~ScopedRefPtrToSelf() { was_destroyed_ = true; } - - static bool was_destroyed_; - - scoped_refptr self_ptr_; -}; - -bool ScopedRefPtrToSelf::was_destroyed_ = false; - -} // end namespace - -TEST(RefCountedUnitTest, TestSelfAssignment) { - SelfAssign* p = new SelfAssign; - scoped_refptr var(p); - var = var; - EXPECT_EQ(var.get(), p); -} - -TEST(RefCountedUnitTest, ScopedRefPtrMemberAccess) { - CheckDerivedMemberAccess check; -} - -TEST(RefCountedUnitTest, ScopedRefPtrToSelf) { - ScopedRefPtrToSelf* check = new ScopedRefPtrToSelf(); - EXPECT_FALSE(ScopedRefPtrToSelf::was_destroyed()); - check->SelfDestruct(); - EXPECT_TRUE(ScopedRefPtrToSelf::was_destroyed()); -} diff --git a/base/memory/scoped_handle.h b/base/memory/scoped_handle.h deleted file mode 100644 index b95559dcd8..0000000000 --- a/base/memory/scoped_handle.h +++ /dev/null @@ -1,50 +0,0 @@ -// Copyright (c) 2011 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef BASE_MEMORY_SCOPED_HANDLE_H_ -#define BASE_MEMORY_SCOPED_HANDLE_H_ - -#include - -#include "base/basictypes.h" - -class ScopedStdioHandle { - public: - ScopedStdioHandle() - : handle_(NULL) { } - - explicit ScopedStdioHandle(FILE* handle) - : handle_(handle) { } - - ~ScopedStdioHandle() { - Close(); - } - - void Close() { - if (handle_) { - fclose(handle_); - handle_ = NULL; - } - } - - FILE* get() const { return handle_; } - - FILE* Take() { - FILE* temp = handle_; - handle_ = NULL; - return temp; - } - - void Set(FILE* newhandle) { - Close(); - handle_ = newhandle; - } - - private: - FILE* handle_; - - DISALLOW_COPY_AND_ASSIGN(ScopedStdioHandle); -}; - -#endif // BASE_MEMORY_SCOPED_HANDLE_H_ diff --git a/base/memory/scoped_open_process.h b/base/memory/scoped_open_process.h deleted file mode 100644 index 8bb19e241e..0000000000 --- a/base/memory/scoped_open_process.h +++ /dev/null @@ -1,48 +0,0 @@ -// Copyright (c) 2011 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef BASE_MEMORY_SCOPED_OPEN_PROCESS_H_ -#define BASE_MEMORY_SCOPED_OPEN_PROCESS_H_ - -#include "base/process/process_handle.h" - -namespace base { - -// A class that opens a process from its process id and closes it when the -// instance goes out of scope. -class ScopedOpenProcess { - public: - ScopedOpenProcess() : handle_(kNullProcessHandle) { - } - - // Automatically close the process. - ~ScopedOpenProcess() { - Close(); - } - - // Open a new process by pid. Closes any previously opened process (even if - // opening the new one fails). - bool Open(ProcessId pid) { - Close(); - return OpenProcessHandle(pid, &handle_); - } - - // Close the previously opened process. - void Close() { - if (handle_ == kNullProcessHandle) - return; - - CloseProcessHandle(handle_); - handle_ = kNullProcessHandle; - } - - ProcessHandle handle() const { return handle_; } - - private: - ProcessHandle handle_; - DISALLOW_COPY_AND_ASSIGN(ScopedOpenProcess); -}; -} // namespace base - -#endif // BASE_MEMORY_SCOPED_OPEN_PROCESS_H_ diff --git a/base/memory/scoped_policy.h b/base/memory/scoped_policy.h deleted file mode 100644 index 5dbf2048d6..0000000000 --- a/base/memory/scoped_policy.h +++ /dev/null @@ -1,25 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef BASE_MEMORY_SCOPED_POLICY_H_ -#define BASE_MEMORY_SCOPED_POLICY_H_ - -namespace base { -namespace scoped_policy { - -// Defines the ownership policy for a scoped object. -enum OwnershipPolicy { - // The scoped object takes ownership of an object by taking over an existing - // ownership claim. - ASSUME, - - // The scoped object will retain the the object and any initial ownership is - // not changed. - RETAIN -}; - -} // namespace scoped_policy -} // namespace base - -#endif // BASE_MEMORY_SCOPED_POLICY_H_ diff --git a/base/memory/scoped_ptr.h b/base/memory/scoped_ptr.h deleted file mode 100644 index c1fed9ae45..0000000000 --- a/base/memory/scoped_ptr.h +++ /dev/null @@ -1,709 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -// Scopers help you manage ownership of a pointer, helping you easily manage the -// a pointer within a scope, and automatically destroying the pointer at the -// end of a scope. There are two main classes you will use, which correspond -// to the operators new/delete and new[]/delete[]. -// -// Example usage (scoped_ptr): -// { -// scoped_ptr foo(new Foo("wee")); -// } // foo goes out of scope, releasing the pointer with it. -// -// { -// scoped_ptr foo; // No pointer managed. -// foo.reset(new Foo("wee")); // Now a pointer is managed. -// foo.reset(new Foo("wee2")); // Foo("wee") was destroyed. -// foo.reset(new Foo("wee3")); // Foo("wee2") was destroyed. -// foo->Method(); // Foo::Method() called. -// foo.get()->Method(); // Foo::Method() called. -// SomeFunc(foo.release()); // SomeFunc takes ownership, foo no longer -// // manages a pointer. -// foo.reset(new Foo("wee4")); // foo manages a pointer again. -// foo.reset(); // Foo("wee4") destroyed, foo no longer -// // manages a pointer. -// } // foo wasn't managing a pointer, so nothing was destroyed. -// -// Example usage (scoped_ptr): -// { -// scoped_ptr foo(new Foo[100]); -// foo.get()->Method(); // Foo::Method on the 0th element. -// foo[10].Method(); // Foo::Method on the 10th element. -// } -// -// These scopers also implement part of the functionality of C++11 unique_ptr -// in that they are "movable but not copyable." You can use the scopers in -// the parameter and return types of functions to signify ownership transfer -// in to and out of a function. When calling a function that has a scoper -// as the argument type, it must be called with the result of an analogous -// scoper's Pass() function or another function that generates a temporary; -// passing by copy will NOT work. Here is an example using scoped_ptr: -// -// void TakesOwnership(scoped_ptr arg) { -// // Do something with arg -// } -// scoped_ptr CreateFoo() { -// // No need for calling Pass() because we are constructing a temporary -// // for the return value. -// return scoped_ptr(new Foo("new")); -// } -// scoped_ptr PassThru(scoped_ptr arg) { -// return arg.Pass(); -// } -// -// { -// scoped_ptr ptr(new Foo("yay")); // ptr manages Foo("yay"). -// TakesOwnership(ptr.Pass()); // ptr no longer owns Foo("yay"). -// scoped_ptr ptr2 = CreateFoo(); // ptr2 owns the return Foo. -// scoped_ptr ptr3 = // ptr3 now owns what was in ptr2. -// PassThru(ptr2.Pass()); // ptr2 is correspondingly NULL. -// } -// -// Notice that if you do not call Pass() when returning from PassThru(), or -// when invoking TakesOwnership(), the code will not compile because scopers -// are not copyable; they only implement move semantics which require calling -// the Pass() function to signify a destructive transfer of state. CreateFoo() -// is different though because we are constructing a temporary on the return -// line and thus can avoid needing to call Pass(). -// -// Pass() properly handles upcast in assignment, i.e. you can assign -// scoped_ptr to scoped_ptr: -// -// scoped_ptr foo(new Foo()); -// scoped_ptr parent = foo.Pass(); -// -// PassAs<>() should be used to upcast return value in return statement: -// -// scoped_ptr CreateFoo() { -// scoped_ptr result(new FooChild()); -// return result.PassAs(); -// } -// -// Note that PassAs<>() is implemented only for scoped_ptr, but not for -// scoped_ptr. This is because casting array pointers may not be safe. - -#ifndef BASE_MEMORY_SCOPED_PTR_H_ -#define BASE_MEMORY_SCOPED_PTR_H_ - -// This is an implementation designed to match the anticipated future TR2 -// implementation of the scoped_ptr class and scoped_ptr_malloc (deprecated). - -#include -#include -#include - -#include // For std::swap(). - -#include "base/basictypes.h" -#include "base/compiler_specific.h" -#include "base/move.h" -#include "base/template_util.h" - -namespace base { - -namespace subtle { -class RefCountedBase; -class RefCountedThreadSafeBase; -} // namespace subtle - -// Function object which deletes its parameter, which must be a pointer. -// If C is an array type, invokes 'delete[]' on the parameter; otherwise, -// invokes 'delete'. The default deleter for scoped_ptr. -template -struct DefaultDeleter { - DefaultDeleter() {} - template DefaultDeleter(const DefaultDeleter& other) { - // IMPLEMENTATION NOTE: C++11 20.7.1.1.2p2 only provides this constructor - // if U* is implicitly convertible to T* and U is not an array type. - // - // Correct implementation should use SFINAE to disable this - // constructor. However, since there are no other 1-argument constructors, - // using a COMPILE_ASSERT() based on is_convertible<> and requiring - // complete types is simpler and will cause compile failures for equivalent - // misuses. - // - // Note, the is_convertible check also ensures that U is not an - // array. T is guaranteed to be a non-array, so any U* where U is an array - // cannot convert to T*. - enum { T_must_be_complete = sizeof(T) }; - enum { U_must_be_complete = sizeof(U) }; - COMPILE_ASSERT((base::is_convertible::value), - U_ptr_must_implicitly_convert_to_T_ptr); - } - inline void operator()(T* ptr) const { - enum { type_must_be_complete = sizeof(T) }; - delete ptr; - } -}; - -// Specialization of DefaultDeleter for array types. -template -struct DefaultDeleter { - inline void operator()(T* ptr) const { - enum { type_must_be_complete = sizeof(T) }; - delete[] ptr; - } - - private: - // Disable this operator for any U != T because it is undefined to execute - // an array delete when the static type of the array mismatches the dynamic - // type. - // - // References: - // C++98 [expr.delete]p3 - // http://cplusplus.github.com/LWG/lwg-defects.html#938 - template void operator()(U* array) const; -}; - -template -struct DefaultDeleter { - // Never allow someone to declare something like scoped_ptr. - COMPILE_ASSERT(sizeof(T) == -1, do_not_use_array_with_size_as_type); -}; - -// Function object which invokes 'free' on its parameter, which must be -// a pointer. Can be used to store malloc-allocated pointers in scoped_ptr: -// -// scoped_ptr foo_ptr( -// static_cast(malloc(sizeof(int)))); -struct FreeDeleter { - inline void operator()(void* ptr) const { - free(ptr); - } -}; - -namespace internal { - -template struct IsNotRefCounted { - enum { - value = !base::is_convertible::value && - !base::is_convertible:: - value - }; -}; - -// Minimal implementation of the core logic of scoped_ptr, suitable for -// reuse in both scoped_ptr and its specializations. -template -class scoped_ptr_impl { - public: - explicit scoped_ptr_impl(T* p) : data_(p) { } - - // Initializer for deleters that have data parameters. - scoped_ptr_impl(T* p, const D& d) : data_(p, d) {} - - // Templated constructor that destructively takes the value from another - // scoped_ptr_impl. - template - scoped_ptr_impl(scoped_ptr_impl* other) - : data_(other->release(), other->get_deleter()) { - // We do not support move-only deleters. We could modify our move - // emulation to have base::subtle::move() and base::subtle::forward() - // functions that are imperfect emulations of their C++11 equivalents, - // but until there's a requirement, just assume deleters are copyable. - } - - template - void TakeState(scoped_ptr_impl* other) { - // See comment in templated constructor above regarding lack of support - // for move-only deleters. - reset(other->release()); - get_deleter() = other->get_deleter(); - } - - ~scoped_ptr_impl() { - if (data_.ptr != NULL) { - // Not using get_deleter() saves one function call in non-optimized - // builds. - static_cast(data_)(data_.ptr); - } - } - - void reset(T* p) { - // This is a self-reset, which is no longer allowed: http://crbug.com/162971 - if (p != NULL && p == data_.ptr) - abort(); - - // Note that running data_.ptr = p can lead to undefined behavior if - // get_deleter()(get()) deletes this. In order to pevent this, reset() - // should update the stored pointer before deleting its old value. - // - // However, changing reset() to use that behavior may cause current code to - // break in unexpected ways. If the destruction of the owned object - // dereferences the scoped_ptr when it is destroyed by a call to reset(), - // then it will incorrectly dispatch calls to |p| rather than the original - // value of |data_.ptr|. - // - // During the transition period, set the stored pointer to NULL while - // deleting the object. Eventually, this safety check will be removed to - // prevent the scenario initially described from occuring and - // http://crbug.com/176091 can be closed. - T* old = data_.ptr; - data_.ptr = NULL; - if (old != NULL) - static_cast(data_)(old); - data_.ptr = p; - } - - T* get() const { return data_.ptr; } - - D& get_deleter() { return data_; } - const D& get_deleter() const { return data_; } - - void swap(scoped_ptr_impl& p2) { - // Standard swap idiom: 'using std::swap' ensures that std::swap is - // present in the overload set, but we call swap unqualified so that - // any more-specific overloads can be used, if available. - using std::swap; - swap(static_cast(data_), static_cast(p2.data_)); - swap(data_.ptr, p2.data_.ptr); - } - - T* release() { - T* old_ptr = data_.ptr; - data_.ptr = NULL; - return old_ptr; - } - - private: - // Needed to allow type-converting constructor. - template friend class scoped_ptr_impl; - - // Use the empty base class optimization to allow us to have a D - // member, while avoiding any space overhead for it when D is an - // empty class. See e.g. http://www.cantrip.org/emptyopt.html for a good - // discussion of this technique. - struct Data : public D { - explicit Data(T* ptr_in) : ptr(ptr_in) {} - Data(T* ptr_in, const D& other) : D(other), ptr(ptr_in) {} - T* ptr; - }; - - Data data_; - - DISALLOW_COPY_AND_ASSIGN(scoped_ptr_impl); -}; - -} // namespace internal - -} // namespace base - -// A scoped_ptr is like a T*, except that the destructor of scoped_ptr -// automatically deletes the pointer it holds (if any). -// That is, scoped_ptr owns the T object that it points to. -// Like a T*, a scoped_ptr may hold either NULL or a pointer to a T object. -// Also like T*, scoped_ptr is thread-compatible, and once you -// dereference it, you get the thread safety guarantees of T. -// -// The size of scoped_ptr is small. On most compilers, when using the -// DefaultDeleter, sizeof(scoped_ptr) == sizeof(T*). Custom deleters will -// increase the size proportional to whatever state they need to have. See -// comments inside scoped_ptr_impl<> for details. -// -// Current implementation targets having a strict subset of C++11's -// unique_ptr<> features. Known deficiencies include not supporting move-only -// deleteres, function pointers as deleters, and deleters with reference -// types. -template > -class scoped_ptr { - MOVE_ONLY_TYPE_FOR_CPP_03(scoped_ptr, RValue) - - COMPILE_ASSERT(base::internal::IsNotRefCounted::value, - T_is_refcounted_type_and_needs_scoped_refptr); - - public: - // The element and deleter types. - typedef T element_type; - typedef D deleter_type; - - // Constructor. Defaults to initializing with NULL. - scoped_ptr() : impl_(NULL) { } - - // Constructor. Takes ownership of p. - explicit scoped_ptr(element_type* p) : impl_(p) { } - - // Constructor. Allows initialization of a stateful deleter. - scoped_ptr(element_type* p, const D& d) : impl_(p, d) { } - - // Constructor. Allows construction from a scoped_ptr rvalue for a - // convertible type and deleter. - // - // IMPLEMENTATION NOTE: C++11 unique_ptr<> keeps this constructor distinct - // from the normal move constructor. By C++11 20.7.1.2.1.21, this constructor - // has different post-conditions if D is a reference type. Since this - // implementation does not support deleters with reference type, - // we do not need a separate move constructor allowing us to avoid one - // use of SFINAE. You only need to care about this if you modify the - // implementation of scoped_ptr. - template - scoped_ptr(scoped_ptr other) : impl_(&other.impl_) { - COMPILE_ASSERT(!base::is_array::value, U_cannot_be_an_array); - } - - // Constructor. Move constructor for C++03 move emulation of this type. - scoped_ptr(RValue rvalue) : impl_(&rvalue.object->impl_) { } - - // operator=. Allows assignment from a scoped_ptr rvalue for a convertible - // type and deleter. - // - // IMPLEMENTATION NOTE: C++11 unique_ptr<> keeps this operator= distinct from - // the normal move assignment operator. By C++11 20.7.1.2.3.4, this templated - // form has different requirements on for move-only Deleters. Since this - // implementation does not support move-only Deleters, we do not need a - // separate move assignment operator allowing us to avoid one use of SFINAE. - // You only need to care about this if you modify the implementation of - // scoped_ptr. - template - scoped_ptr& operator=(scoped_ptr rhs) { - COMPILE_ASSERT(!base::is_array::value, U_cannot_be_an_array); - impl_.TakeState(&rhs.impl_); - return *this; - } - - // Reset. Deletes the currently owned object, if any. - // Then takes ownership of a new object, if given. - void reset(element_type* p = NULL) { impl_.reset(p); } - - // Accessors to get the owned object. - // operator* and operator-> will assert() if there is no current object. - element_type& operator*() const { - assert(impl_.get() != NULL); - return *impl_.get(); - } - element_type* operator->() const { - assert(impl_.get() != NULL); - return impl_.get(); - } - element_type* get() const { return impl_.get(); } - - // Access to the deleter. - deleter_type& get_deleter() { return impl_.get_deleter(); } - const deleter_type& get_deleter() const { return impl_.get_deleter(); } - - // Allow scoped_ptr to be used in boolean expressions, but not - // implicitly convertible to a real bool (which is dangerous). - // - // Note that this trick is only safe when the == and != operators - // are declared explicitly, as otherwise "scoped_ptr1 == - // scoped_ptr2" will compile but do the wrong thing (i.e., convert - // to Testable and then do the comparison). - private: - typedef base::internal::scoped_ptr_impl - scoped_ptr::*Testable; - - public: - operator Testable() const { return impl_.get() ? &scoped_ptr::impl_ : NULL; } - - // Comparison operators. - // These return whether two scoped_ptr refer to the same object, not just to - // two different but equal objects. - bool operator==(const element_type* p) const { return impl_.get() == p; } - bool operator!=(const element_type* p) const { return impl_.get() != p; } - - // Swap two scoped pointers. - void swap(scoped_ptr& p2) { - impl_.swap(p2.impl_); - } - - // Release a pointer. - // The return value is the current pointer held by this object. - // If this object holds a NULL pointer, the return value is NULL. - // After this operation, this object will hold a NULL pointer, - // and will not own the object any more. - element_type* release() WARN_UNUSED_RESULT { - return impl_.release(); - } - - // C++98 doesn't support functions templates with default parameters which - // makes it hard to write a PassAs() that understands converting the deleter - // while preserving simple calling semantics. - // - // Until there is a use case for PassAs() with custom deleters, just ignore - // the custom deleter. - template - scoped_ptr PassAs() { - return scoped_ptr(Pass()); - } - - private: - // Needed to reach into |impl_| in the constructor. - template friend class scoped_ptr; - base::internal::scoped_ptr_impl impl_; - - // Forbidden for API compatibility with std::unique_ptr. - explicit scoped_ptr(int disallow_construction_from_null); - - // Forbid comparison of scoped_ptr types. If U != T, it totally - // doesn't make sense, and if U == T, it still doesn't make sense - // because you should never have the same object owned by two different - // scoped_ptrs. - template bool operator==(scoped_ptr const& p2) const; - template bool operator!=(scoped_ptr const& p2) const; -}; - -template -class scoped_ptr { - MOVE_ONLY_TYPE_FOR_CPP_03(scoped_ptr, RValue) - - public: - // The element and deleter types. - typedef T element_type; - typedef D deleter_type; - - // Constructor. Defaults to initializing with NULL. - scoped_ptr() : impl_(NULL) { } - - // Constructor. Stores the given array. Note that the argument's type - // must exactly match T*. In particular: - // - it cannot be a pointer to a type derived from T, because it is - // inherently unsafe in the general case to access an array through a - // pointer whose dynamic type does not match its static type (eg., if - // T and the derived types had different sizes access would be - // incorrectly calculated). Deletion is also always undefined - // (C++98 [expr.delete]p3). If you're doing this, fix your code. - // - it cannot be NULL, because NULL is an integral expression, not a - // pointer to T. Use the no-argument version instead of explicitly - // passing NULL. - // - it cannot be const-qualified differently from T per unique_ptr spec - // (http://cplusplus.github.com/LWG/lwg-active.html#2118). Users wanting - // to work around this may use implicit_cast(). - // However, because of the first bullet in this comment, users MUST - // NOT use implicit_cast() to upcast the static type of the array. - explicit scoped_ptr(element_type* array) : impl_(array) { } - - // Constructor. Move constructor for C++03 move emulation of this type. - scoped_ptr(RValue rvalue) : impl_(&rvalue.object->impl_) { } - - // operator=. Move operator= for C++03 move emulation of this type. - scoped_ptr& operator=(RValue rhs) { - impl_.TakeState(&rhs.object->impl_); - return *this; - } - - // Reset. Deletes the currently owned array, if any. - // Then takes ownership of a new object, if given. - void reset(element_type* array = NULL) { impl_.reset(array); } - - // Accessors to get the owned array. - element_type& operator[](size_t i) const { - assert(impl_.get() != NULL); - return impl_.get()[i]; - } - element_type* get() const { return impl_.get(); } - - // Access to the deleter. - deleter_type& get_deleter() { return impl_.get_deleter(); } - const deleter_type& get_deleter() const { return impl_.get_deleter(); } - - // Allow scoped_ptr to be used in boolean expressions, but not - // implicitly convertible to a real bool (which is dangerous). - private: - typedef base::internal::scoped_ptr_impl - scoped_ptr::*Testable; - - public: - operator Testable() const { return impl_.get() ? &scoped_ptr::impl_ : NULL; } - - // Comparison operators. - // These return whether two scoped_ptr refer to the same object, not just to - // two different but equal objects. - bool operator==(element_type* array) const { return impl_.get() == array; } - bool operator!=(element_type* array) const { return impl_.get() != array; } - - // Swap two scoped pointers. - void swap(scoped_ptr& p2) { - impl_.swap(p2.impl_); - } - - // Release a pointer. - // The return value is the current pointer held by this object. - // If this object holds a NULL pointer, the return value is NULL. - // After this operation, this object will hold a NULL pointer, - // and will not own the object any more. - element_type* release() WARN_UNUSED_RESULT { - return impl_.release(); - } - - private: - // Force element_type to be a complete type. - enum { type_must_be_complete = sizeof(element_type) }; - - // Actually hold the data. - base::internal::scoped_ptr_impl impl_; - - // Disable initialization from any type other than element_type*, by - // providing a constructor that matches such an initialization, but is - // private and has no definition. This is disabled because it is not safe to - // call delete[] on an array whose static type does not match its dynamic - // type. - template explicit scoped_ptr(U* array); - explicit scoped_ptr(int disallow_construction_from_null); - - // Disable reset() from any type other than element_type*, for the same - // reasons as the constructor above. - template void reset(U* array); - void reset(int disallow_reset_from_null); - - // Forbid comparison of scoped_ptr types. If U != T, it totally - // doesn't make sense, and if U == T, it still doesn't make sense - // because you should never have the same object owned by two different - // scoped_ptrs. - template bool operator==(scoped_ptr const& p2) const; - template bool operator!=(scoped_ptr const& p2) const; -}; - -// Free functions -template -void swap(scoped_ptr& p1, scoped_ptr& p2) { - p1.swap(p2); -} - -template -bool operator==(T* p1, const scoped_ptr& p2) { - return p1 == p2.get(); -} - -template -bool operator!=(T* p1, const scoped_ptr& p2) { - return p1 != p2.get(); -} - -// DEPRECATED: Use scoped_ptr instead. -// -// scoped_ptr_malloc<> is similar to scoped_ptr<>, but it accepts a -// second template argument, the functor used to free the object. - -template -class scoped_ptr_malloc { - MOVE_ONLY_TYPE_FOR_CPP_03(scoped_ptr_malloc, RValue) - - public: - - // The element type - typedef C element_type; - - // Constructor. Defaults to initializing with NULL. - // There is no way to create an uninitialized scoped_ptr. - // The input parameter must be allocated with an allocator that matches the - // Free functor. For the default Free functor, this is malloc, calloc, or - // realloc. - explicit scoped_ptr_malloc(C* p = NULL): ptr_(p) {} - - // Constructor. Move constructor for C++03 move emulation of this type. - scoped_ptr_malloc(RValue rvalue) - : ptr_(rvalue.object->release()) { - } - - // Destructor. If there is a C object, call the Free functor. - ~scoped_ptr_malloc() { - reset(); - } - - // operator=. Move operator= for C++03 move emulation of this type. - scoped_ptr_malloc& operator=(RValue rhs) { - reset(rhs.object->release()); - return *this; - } - - // Reset. Calls the Free functor on the current owned object, if any. - // Then takes ownership of a new object, if given. - // this->reset(this->get()) works. - void reset(C* p = NULL) { - if (ptr_ != p) { - if (ptr_ != NULL) { - FreeProc free_proc; - free_proc(ptr_); - } - ptr_ = p; - } - } - - // Get the current object. - // operator* and operator-> will cause an assert() failure if there is - // no current object. - C& operator*() const { - assert(ptr_ != NULL); - return *ptr_; - } - - C* operator->() const { - assert(ptr_ != NULL); - return ptr_; - } - - C* get() const { - return ptr_; - } - - // Allow scoped_ptr_malloc to be used in boolean expressions, but not - // implicitly convertible to a real bool (which is dangerous). - typedef C* scoped_ptr_malloc::*Testable; - operator Testable() const { return ptr_ ? &scoped_ptr_malloc::ptr_ : NULL; } - - // Comparison operators. - // These return whether a scoped_ptr_malloc and a plain pointer refer - // to the same object, not just to two different but equal objects. - // For compatibility with the boost-derived implementation, these - // take non-const arguments. - bool operator==(C* p) const { - return ptr_ == p; - } - - bool operator!=(C* p) const { - return ptr_ != p; - } - - // Swap two scoped pointers. - void swap(scoped_ptr_malloc & b) { - C* tmp = b.ptr_; - b.ptr_ = ptr_; - ptr_ = tmp; - } - - // Release a pointer. - // The return value is the current pointer held by this object. - // If this object holds a NULL pointer, the return value is NULL. - // After this operation, this object will hold a NULL pointer, - // and will not own the object any more. - C* release() WARN_UNUSED_RESULT { - C* tmp = ptr_; - ptr_ = NULL; - return tmp; - } - - private: - C* ptr_; - - // no reason to use these: each scoped_ptr_malloc should have its own object - template - bool operator==(scoped_ptr_malloc const& p) const; - template - bool operator!=(scoped_ptr_malloc const& p) const; -}; - -template inline -void swap(scoped_ptr_malloc& a, scoped_ptr_malloc& b) { - a.swap(b); -} - -template inline -bool operator==(C* p, const scoped_ptr_malloc& b) { - return p == b.get(); -} - -template inline -bool operator!=(C* p, const scoped_ptr_malloc& b) { - return p != b.get(); -} - -// A function to convert T* into scoped_ptr -// Doing e.g. make_scoped_ptr(new FooBarBaz(arg)) is a shorter notation -// for scoped_ptr >(new FooBarBaz(arg)) -template -scoped_ptr make_scoped_ptr(T* ptr) { - return scoped_ptr(ptr); -} - -#endif // BASE_MEMORY_SCOPED_PTR_H_ diff --git a/base/memory/scoped_ptr_unittest.cc b/base/memory/scoped_ptr_unittest.cc deleted file mode 100644 index 22da53d351..0000000000 --- a/base/memory/scoped_ptr_unittest.cc +++ /dev/null @@ -1,606 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "base/memory/scoped_ptr.h" - -#include "base/basictypes.h" -#include "base/bind.h" -#include "base/callback.h" -#include "testing/gtest/include/gtest/gtest.h" - -namespace { - -// Used to test depth subtyping. -class ConDecLoggerParent { - public: - virtual ~ConDecLoggerParent() {} - - virtual void SetPtr(int* ptr) = 0; - - virtual int SomeMeth(int x) const = 0; -}; - -class ConDecLogger : public ConDecLoggerParent { - public: - ConDecLogger() : ptr_(NULL) { } - explicit ConDecLogger(int* ptr) { SetPtr(ptr); } - virtual ~ConDecLogger() { --*ptr_; } - - virtual void SetPtr(int* ptr) OVERRIDE { ptr_ = ptr; ++*ptr_; } - - virtual int SomeMeth(int x) const OVERRIDE { return x; } - - private: - int* ptr_; - - DISALLOW_COPY_AND_ASSIGN(ConDecLogger); -}; - -struct CountingDeleter { - explicit CountingDeleter(int* count) : count_(count) {} - inline void operator()(double* ptr) const { - (*count_)++; - } - int* count_; -}; - -// Used to test assignment of convertible deleters. -struct CountingDeleterChild : public CountingDeleter { - explicit CountingDeleterChild(int* count) : CountingDeleter(count) {} -}; - -class OverloadedNewAndDelete { - public: - void* operator new(size_t size) { - g_new_count++; - return malloc(size); - } - - void operator delete(void* ptr) { - g_delete_count++; - free(ptr); - } - - static void ResetCounters() { - g_new_count = 0; - g_delete_count = 0; - } - - static int new_count() { return g_new_count; } - static int delete_count() { return g_delete_count; } - - private: - static int g_new_count; - static int g_delete_count; -}; - -int OverloadedNewAndDelete::g_new_count = 0; -int OverloadedNewAndDelete::g_delete_count = 0; - -scoped_ptr PassThru(scoped_ptr logger) { - return logger.Pass(); -} - -void GrabAndDrop(scoped_ptr logger) { -} - -// Do not delete this function! It's existence is to test that you can -// return a temporarily constructed version of the scoper. -scoped_ptr TestReturnOfType(int* constructed) { - return scoped_ptr(new ConDecLogger(constructed)); -} - -scoped_ptr UpcastUsingPassAs( - scoped_ptr object) { - return object.PassAs(); -} - -} // namespace - -TEST(ScopedPtrTest, ScopedPtr) { - int constructed = 0; - - // Ensure size of scoped_ptr<> doesn't increase unexpectedly. - COMPILE_ASSERT(sizeof(int*) >= sizeof(scoped_ptr), - scoped_ptr_larger_than_raw_ptr); - - { - scoped_ptr scoper(new ConDecLogger(&constructed)); - EXPECT_EQ(1, constructed); - EXPECT_TRUE(scoper.get()); - - EXPECT_EQ(10, scoper->SomeMeth(10)); - EXPECT_EQ(10, scoper.get()->SomeMeth(10)); - EXPECT_EQ(10, (*scoper).SomeMeth(10)); - } - EXPECT_EQ(0, constructed); - - // Test reset() and release() - { - scoped_ptr scoper(new ConDecLogger(&constructed)); - EXPECT_EQ(1, constructed); - EXPECT_TRUE(scoper.get()); - - scoper.reset(new ConDecLogger(&constructed)); - EXPECT_EQ(1, constructed); - EXPECT_TRUE(scoper.get()); - - scoper.reset(); - EXPECT_EQ(0, constructed); - EXPECT_FALSE(scoper.get()); - - scoper.reset(new ConDecLogger(&constructed)); - EXPECT_EQ(1, constructed); - EXPECT_TRUE(scoper.get()); - - ConDecLogger* take = scoper.release(); - EXPECT_EQ(1, constructed); - EXPECT_FALSE(scoper.get()); - delete take; - EXPECT_EQ(0, constructed); - - scoper.reset(new ConDecLogger(&constructed)); - EXPECT_EQ(1, constructed); - EXPECT_TRUE(scoper.get()); - } - EXPECT_EQ(0, constructed); - - // Test swap(), == and != - { - scoped_ptr scoper1; - scoped_ptr scoper2; - EXPECT_TRUE(scoper1 == scoper2.get()); - EXPECT_FALSE(scoper1 != scoper2.get()); - - ConDecLogger* logger = new ConDecLogger(&constructed); - scoper1.reset(logger); - EXPECT_EQ(logger, scoper1.get()); - EXPECT_FALSE(scoper2.get()); - EXPECT_FALSE(scoper1 == scoper2.get()); - EXPECT_TRUE(scoper1 != scoper2.get()); - - scoper2.swap(scoper1); - EXPECT_EQ(logger, scoper2.get()); - EXPECT_FALSE(scoper1.get()); - EXPECT_FALSE(scoper1 == scoper2.get()); - EXPECT_TRUE(scoper1 != scoper2.get()); - } - EXPECT_EQ(0, constructed); -} - -TEST(ScopedPtrTest, ScopedPtrDepthSubtyping) { - int constructed = 0; - - // Test construction from a scoped_ptr to a derived class. - { - scoped_ptr scoper(new ConDecLogger(&constructed)); - EXPECT_EQ(1, constructed); - EXPECT_TRUE(scoper.get()); - - scoped_ptr scoper_parent(scoper.Pass()); - EXPECT_EQ(1, constructed); - EXPECT_TRUE(scoper_parent.get()); - EXPECT_FALSE(scoper.get()); - - EXPECT_EQ(10, scoper_parent->SomeMeth(10)); - EXPECT_EQ(10, scoper_parent.get()->SomeMeth(10)); - EXPECT_EQ(10, (*scoper_parent).SomeMeth(10)); - } - EXPECT_EQ(0, constructed); - - // Test assignment from a scoped_ptr to a derived class. - { - scoped_ptr scoper(new ConDecLogger(&constructed)); - EXPECT_EQ(1, constructed); - EXPECT_TRUE(scoper.get()); - - scoped_ptr scoper_parent; - scoper_parent = scoper.Pass(); - EXPECT_EQ(1, constructed); - EXPECT_TRUE(scoper_parent.get()); - EXPECT_FALSE(scoper.get()); - } - EXPECT_EQ(0, constructed); - - // Test construction of a scoped_ptr with an additional const annotation. - { - scoped_ptr scoper(new ConDecLogger(&constructed)); - EXPECT_EQ(1, constructed); - EXPECT_TRUE(scoper.get()); - - scoped_ptr scoper_const(scoper.Pass()); - EXPECT_EQ(1, constructed); - EXPECT_TRUE(scoper_const.get()); - EXPECT_FALSE(scoper.get()); - - EXPECT_EQ(10, scoper_const->SomeMeth(10)); - EXPECT_EQ(10, scoper_const.get()->SomeMeth(10)); - EXPECT_EQ(10, (*scoper_const).SomeMeth(10)); - } - EXPECT_EQ(0, constructed); - - // Test assignment to a scoped_ptr with an additional const annotation. - { - scoped_ptr scoper(new ConDecLogger(&constructed)); - EXPECT_EQ(1, constructed); - EXPECT_TRUE(scoper.get()); - - scoped_ptr scoper_const; - scoper_const = scoper.Pass(); - EXPECT_EQ(1, constructed); - EXPECT_TRUE(scoper_const.get()); - EXPECT_FALSE(scoper.get()); - } - EXPECT_EQ(0, constructed); - - // Test assignment to a scoped_ptr deleter of parent type. - { - // Custom deleters never touch these value. - double dummy_value, dummy_value2; - int deletes = 0; - int alternate_deletes = 0; - scoped_ptr scoper(&dummy_value, - CountingDeleter(&deletes)); - scoped_ptr scoper_child( - &dummy_value2, CountingDeleterChild(&alternate_deletes)); - - EXPECT_TRUE(scoper); - EXPECT_TRUE(scoper_child); - EXPECT_EQ(0, deletes); - EXPECT_EQ(0, alternate_deletes); - - // Test this compiles and correctly overwrites the deleter state. - scoper = scoper_child.Pass(); - EXPECT_TRUE(scoper); - EXPECT_FALSE(scoper_child); - EXPECT_EQ(1, deletes); - EXPECT_EQ(0, alternate_deletes); - - scoper.reset(); - EXPECT_FALSE(scoper); - EXPECT_FALSE(scoper_child); - EXPECT_EQ(1, deletes); - EXPECT_EQ(1, alternate_deletes); - - scoper_child.reset(&dummy_value); - EXPECT_TRUE(scoper_child); - EXPECT_EQ(1, deletes); - EXPECT_EQ(1, alternate_deletes); - scoped_ptr scoper_construct(scoper_child.Pass()); - EXPECT_TRUE(scoper_construct); - EXPECT_FALSE(scoper_child); - EXPECT_EQ(1, deletes); - EXPECT_EQ(1, alternate_deletes); - - scoper_construct.reset(); - EXPECT_EQ(1, deletes); - EXPECT_EQ(2, alternate_deletes); - } -} - -TEST(ScopedPtrTest, ScopedPtrWithArray) { - static const int kNumLoggers = 12; - - int constructed = 0; - - { - scoped_ptr scoper(new ConDecLogger[kNumLoggers]); - EXPECT_TRUE(scoper); - EXPECT_EQ(&scoper[0], scoper.get()); - for (int i = 0; i < kNumLoggers; ++i) { - scoper[i].SetPtr(&constructed); - } - EXPECT_EQ(12, constructed); - - EXPECT_EQ(10, scoper.get()->SomeMeth(10)); - EXPECT_EQ(10, scoper[2].SomeMeth(10)); - } - EXPECT_EQ(0, constructed); - - // Test reset() and release() - { - scoped_ptr scoper; - EXPECT_FALSE(scoper.get()); - EXPECT_FALSE(scoper.release()); - EXPECT_FALSE(scoper.get()); - scoper.reset(); - EXPECT_FALSE(scoper.get()); - - scoper.reset(new ConDecLogger[kNumLoggers]); - for (int i = 0; i < kNumLoggers; ++i) { - scoper[i].SetPtr(&constructed); - } - EXPECT_EQ(12, constructed); - scoper.reset(); - EXPECT_EQ(0, constructed); - - scoper.reset(new ConDecLogger[kNumLoggers]); - for (int i = 0; i < kNumLoggers; ++i) { - scoper[i].SetPtr(&constructed); - } - EXPECT_EQ(12, constructed); - ConDecLogger* ptr = scoper.release(); - EXPECT_EQ(12, constructed); - delete[] ptr; - EXPECT_EQ(0, constructed); - } - EXPECT_EQ(0, constructed); - - // Test swap(), ==, !=, and type-safe Boolean. - { - scoped_ptr scoper1; - scoped_ptr scoper2; - EXPECT_TRUE(scoper1 == scoper2.get()); - EXPECT_FALSE(scoper1 != scoper2.get()); - - ConDecLogger* loggers = new ConDecLogger[kNumLoggers]; - for (int i = 0; i < kNumLoggers; ++i) { - loggers[i].SetPtr(&constructed); - } - scoper1.reset(loggers); - EXPECT_TRUE(scoper1); - EXPECT_EQ(loggers, scoper1.get()); - EXPECT_FALSE(scoper2); - EXPECT_FALSE(scoper2.get()); - EXPECT_FALSE(scoper1 == scoper2.get()); - EXPECT_TRUE(scoper1 != scoper2.get()); - - scoper2.swap(scoper1); - EXPECT_EQ(loggers, scoper2.get()); - EXPECT_FALSE(scoper1.get()); - EXPECT_FALSE(scoper1 == scoper2.get()); - EXPECT_TRUE(scoper1 != scoper2.get()); - } - EXPECT_EQ(0, constructed); - - { - ConDecLogger* loggers = new ConDecLogger[kNumLoggers]; - scoped_ptr scoper(loggers); - EXPECT_TRUE(scoper); - for (int i = 0; i < kNumLoggers; ++i) { - scoper[i].SetPtr(&constructed); - } - EXPECT_EQ(kNumLoggers, constructed); - - // Test Pass() with constructor; - scoped_ptr scoper2(scoper.Pass()); - EXPECT_EQ(kNumLoggers, constructed); - - // Test Pass() with assignment; - scoped_ptr scoper3; - scoper3 = scoper2.Pass(); - EXPECT_EQ(kNumLoggers, constructed); - EXPECT_FALSE(scoper); - EXPECT_FALSE(scoper2); - EXPECT_TRUE(scoper3); - } - EXPECT_EQ(0, constructed); -} - -TEST(ScopedPtrTest, PassBehavior) { - int constructed = 0; - { - ConDecLogger* logger = new ConDecLogger(&constructed); - scoped_ptr scoper(logger); - EXPECT_EQ(1, constructed); - - // Test Pass() with constructor; - scoped_ptr scoper2(scoper.Pass()); - EXPECT_EQ(1, constructed); - - // Test Pass() with assignment; - scoped_ptr scoper3; - scoper3 = scoper2.Pass(); - EXPECT_EQ(1, constructed); - EXPECT_FALSE(scoper.get()); - EXPECT_FALSE(scoper2.get()); - EXPECT_TRUE(scoper3.get()); - } - - // Test uncaught Pass() does not leak. - { - ConDecLogger* logger = new ConDecLogger(&constructed); - scoped_ptr scoper(logger); - EXPECT_EQ(1, constructed); - - // Should auto-destruct logger by end of scope. - scoper.Pass(); - EXPECT_FALSE(scoper.get()); - } - EXPECT_EQ(0, constructed); - - // Test that passing to function which does nothing does not leak. - { - ConDecLogger* logger = new ConDecLogger(&constructed); - scoped_ptr scoper(logger); - EXPECT_EQ(1, constructed); - - // Should auto-destruct logger by end of scope. - GrabAndDrop(scoper.Pass()); - EXPECT_FALSE(scoper.get()); - } - EXPECT_EQ(0, constructed); -} - -TEST(ScopedPtrTest, ReturnTypeBehavior) { - int constructed = 0; - - // Test that we can return a scoped_ptr. - { - ConDecLogger* logger = new ConDecLogger(&constructed); - scoped_ptr scoper(logger); - EXPECT_EQ(1, constructed); - - PassThru(scoper.Pass()); - EXPECT_FALSE(scoper.get()); - } - EXPECT_EQ(0, constructed); - - // Test uncaught return type not leak. - { - ConDecLogger* logger = new ConDecLogger(&constructed); - scoped_ptr scoper(logger); - EXPECT_EQ(1, constructed); - - // Should auto-destruct logger by end of scope. - PassThru(scoper.Pass()); - EXPECT_FALSE(scoper.get()); - } - EXPECT_EQ(0, constructed); - - // Call TestReturnOfType() so the compiler doesn't warn for an unused - // function. - { - TestReturnOfType(&constructed); - } - EXPECT_EQ(0, constructed); -} - -TEST(ScopedPtrTest, PassAs) { - int constructed = 0; - { - scoped_ptr scoper(new ConDecLogger(&constructed)); - EXPECT_EQ(1, constructed); - EXPECT_TRUE(scoper.get()); - - scoped_ptr scoper_parent; - scoper_parent = UpcastUsingPassAs(scoper.Pass()); - EXPECT_EQ(1, constructed); - EXPECT_TRUE(scoper_parent.get()); - EXPECT_FALSE(scoper.get()); - } - EXPECT_EQ(0, constructed); -} - -TEST(ScopedPtrTest, CustomDeleter) { - double dummy_value; // Custom deleter never touches this value. - int deletes = 0; - int alternate_deletes = 0; - - // Normal delete support. - { - deletes = 0; - scoped_ptr scoper(&dummy_value, - CountingDeleter(&deletes)); - EXPECT_EQ(0, deletes); - EXPECT_TRUE(scoper.get()); - } - EXPECT_EQ(1, deletes); - - // Test reset() and release(). - deletes = 0; - { - scoped_ptr scoper(NULL, - CountingDeleter(&deletes)); - EXPECT_FALSE(scoper.get()); - EXPECT_FALSE(scoper.release()); - EXPECT_FALSE(scoper.get()); - scoper.reset(); - EXPECT_FALSE(scoper.get()); - EXPECT_EQ(0, deletes); - - scoper.reset(&dummy_value); - scoper.reset(); - EXPECT_EQ(1, deletes); - - scoper.reset(&dummy_value); - EXPECT_EQ(&dummy_value, scoper.release()); - } - EXPECT_EQ(1, deletes); - - // Test get_deleter(). - deletes = 0; - alternate_deletes = 0; - { - scoped_ptr scoper(&dummy_value, - CountingDeleter(&deletes)); - // Call deleter manually. - EXPECT_EQ(0, deletes); - scoper.get_deleter()(&dummy_value); - EXPECT_EQ(1, deletes); - - // Deleter is still there after reset. - scoper.reset(); - EXPECT_EQ(2, deletes); - scoper.get_deleter()(&dummy_value); - EXPECT_EQ(3, deletes); - - // Deleter can be assigned into (matches C++11 unique_ptr<> spec). - scoper.get_deleter() = CountingDeleter(&alternate_deletes); - scoper.reset(&dummy_value); - EXPECT_EQ(0, alternate_deletes); - - } - EXPECT_EQ(3, deletes); - EXPECT_EQ(1, alternate_deletes); - - // Test operator= deleter support. - deletes = 0; - alternate_deletes = 0; - { - double dummy_value2; - scoped_ptr scoper(&dummy_value, - CountingDeleter(&deletes)); - scoped_ptr scoper2( - &dummy_value2, - CountingDeleter(&alternate_deletes)); - EXPECT_EQ(0, deletes); - EXPECT_EQ(0, alternate_deletes); - - // Pass the second deleter through a constructor and an operator=. Then - // reinitialize the empty scopers to ensure that each one is deleting - // properly. - scoped_ptr scoper3(scoper2.Pass()); - scoper = scoper3.Pass(); - EXPECT_EQ(1, deletes); - - scoper2.reset(&dummy_value2); - scoper3.reset(&dummy_value2); - EXPECT_EQ(0, alternate_deletes); - - } - EXPECT_EQ(1, deletes); - EXPECT_EQ(3, alternate_deletes); - - // Test swap(), ==, !=, and type-safe Boolean. - { - scoped_ptr scoper1(NULL, - CountingDeleter(&deletes)); - scoped_ptr scoper2(NULL, - CountingDeleter(&deletes)); - EXPECT_TRUE(scoper1 == scoper2.get()); - EXPECT_FALSE(scoper1 != scoper2.get()); - - scoper1.reset(&dummy_value); - EXPECT_TRUE(scoper1); - EXPECT_EQ(&dummy_value, scoper1.get()); - EXPECT_FALSE(scoper2); - EXPECT_FALSE(scoper2.get()); - EXPECT_FALSE(scoper1 == scoper2.get()); - EXPECT_TRUE(scoper1 != scoper2.get()); - - scoper2.swap(scoper1); - EXPECT_EQ(&dummy_value, scoper2.get()); - EXPECT_FALSE(scoper1.get()); - EXPECT_FALSE(scoper1 == scoper2.get()); - EXPECT_TRUE(scoper1 != scoper2.get()); - } -} - -// Sanity check test for overloaded new and delete operators. Does not do full -// coverage of reset/release/Pass() operations as that is redundant with the -// above. -TEST(ScopedPtrTest, OverloadedNewAndDelete) { - { - OverloadedNewAndDelete::ResetCounters(); - scoped_ptr scoper(new OverloadedNewAndDelete()); - EXPECT_TRUE(scoper.get()); - - scoped_ptr scoper2(scoper.Pass()); - } - EXPECT_EQ(1, OverloadedNewAndDelete::delete_count()); - EXPECT_EQ(1, OverloadedNewAndDelete::new_count()); -} - -// TODO scoped_ptr_malloc diff --git a/base/memory/scoped_ptr_unittest.nc b/base/memory/scoped_ptr_unittest.nc deleted file mode 100644 index 2e2a3e5752..0000000000 --- a/base/memory/scoped_ptr_unittest.nc +++ /dev/null @@ -1,113 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "base/basictypes.h" -#include "base/memory/scoped_ptr.h" -#include "base/memory/ref_counted.h" - -namespace { - -class Parent { -}; - -class Child : public Parent { -}; - -class RefCountedClass : public base::RefCountedThreadSafe { -}; - -} // namespace - -#if defined(NCTEST_NO_PASSAS_DOWNCAST) // [r"invalid conversion from"] - -scoped_ptr DowncastUsingPassAs(scoped_ptr object) { - return object.PassAs(); -} - -#elif defined(NCTEST_NO_REF_COUNTED_SCOPED_PTR) // [r"size of array is negative"] - -// scoped_ptr<> should not work for ref-counted objects. -void WontCompile() { - scoped_ptr x; -} - -#elif defined(NCTEST_NO_ARRAY_WITH_SIZE) // [r"size of array is negative"] - -void WontCompile() { - scoped_ptr x; -} - -#elif defined(NCTEST_NO_PASS_FROM_ARRAY) // [r"size of array is negative"] - -void WontCompile() { - scoped_ptr a; - scoped_ptr b; - b = a.Pass(); -} - -#elif defined(NCTEST_NO_PASS_TO_ARRAY) // [r"no match for 'operator='"] - -void WontCompile() { - scoped_ptr a; - scoped_ptr b; - b = a.Pass(); -} - -#elif defined(NCTEST_NO_CONSTRUCT_FROM_ARRAY) // [r"is private"] - -void WontCompile() { - scoped_ptr a; - scoped_ptr b(a.Pass()); -} - -#elif defined(NCTEST_NO_CONSTRUCT_TO_ARRAY) // [r"no matching function for call"] - -void WontCompile() { - scoped_ptr a; - scoped_ptr b(a.Pass()); -} - -#elif defined(NCTEST_NO_CONSTRUCT_SCOPED_PTR_ARRAY_FROM_NULL) // [r"is ambiguous"] - -void WontCompile() { - scoped_ptr x(NULL); -} - -#elif defined(NCTEST_NO_CONSTRUCT_SCOPED_PTR_ARRAY_FROM_DERIVED) // [r"is private"] - -void WontCompile() { - scoped_ptr x(new Child[1]); -} - -#elif defined(NCTEST_NO_RESET_SCOPED_PTR_ARRAY_FROM_NULL) // [r"is ambiguous"] - -void WontCompile() { - scoped_ptr x; - x.reset(NULL); -} - -#elif defined(NCTEST_NO_RESET_SCOPED_PTR_ARRAY_FROM_DERIVED) // [r"is private"] - -void WontCompile() { - scoped_ptr x; - x.reset(new Child[1]); -} - -#elif defined(NCTEST_NO_DELETER_REFERENCE) // [r"fails to be a struct or class type"] - -struct Deleter { - void operator()(int*) {} -}; - -// Current implementation doesn't support Deleter Reference types. Enabling -// support would require changes to the behavior of the constructors to match -// including the use of SFINAE to discard the type-converting constructor -// as per C++11 20.7.1.2.1.19. -void WontCompile() { - Deleter d; - int n; - scoped_ptr a(&n, d); -} - -#endif diff --git a/base/memory/scoped_vector.h b/base/memory/scoped_vector.h deleted file mode 100644 index 59144c0e82..0000000000 --- a/base/memory/scoped_vector.h +++ /dev/null @@ -1,130 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef BASE_MEMORY_SCOPED_VECTOR_H_ -#define BASE_MEMORY_SCOPED_VECTOR_H_ - -#include - -#include "base/basictypes.h" -#include "base/move.h" -#include "base/stl_util.h" - -// ScopedVector wraps a vector deleting the elements from its -// destructor. -template -class ScopedVector { - MOVE_ONLY_TYPE_FOR_CPP_03(ScopedVector, RValue) - - public: - typedef typename std::vector::allocator_type allocator_type; - typedef typename std::vector::size_type size_type; - typedef typename std::vector::difference_type difference_type; - typedef typename std::vector::pointer pointer; - typedef typename std::vector::const_pointer const_pointer; - typedef typename std::vector::reference reference; - typedef typename std::vector::const_reference const_reference; - typedef typename std::vector::value_type value_type; - typedef typename std::vector::iterator iterator; - typedef typename std::vector::const_iterator const_iterator; - typedef typename std::vector::reverse_iterator reverse_iterator; - typedef typename std::vector::const_reverse_iterator - const_reverse_iterator; - - ScopedVector() {} - ~ScopedVector() { clear(); } - ScopedVector(RValue other) { swap(*other.object); } - - ScopedVector& operator=(RValue rhs) { - swap(*rhs.object); - return *this; - } - - reference operator[](size_t index) { return v_[index]; } - const_reference operator[](size_t index) const { return v_[index]; } - - bool empty() const { return v_.empty(); } - size_t size() const { return v_.size(); } - - reverse_iterator rbegin() { return v_.rbegin(); } - const_reverse_iterator rbegin() const { return v_.rbegin(); } - reverse_iterator rend() { return v_.rend(); } - const_reverse_iterator rend() const { return v_.rend(); } - - iterator begin() { return v_.begin(); } - const_iterator begin() const { return v_.begin(); } - iterator end() { return v_.end(); } - const_iterator end() const { return v_.end(); } - - const_reference front() const { return v_.front(); } - reference front() { return v_.front(); } - const_reference back() const { return v_.back(); } - reference back() { return v_.back(); } - - void push_back(T* elem) { v_.push_back(elem); } - - std::vector& get() { return v_; } - const std::vector& get() const { return v_; } - void swap(std::vector& other) { v_.swap(other); } - void swap(ScopedVector& other) { v_.swap(other.v_); } - void release(std::vector* out) { - out->swap(v_); - v_.clear(); - } - - void reserve(size_t capacity) { v_.reserve(capacity); } - - // Resize, deleting elements in the disappearing range if we are shrinking. - void resize(size_t new_size) { - if (v_.size() > new_size) - STLDeleteContainerPointers(v_.begin() + new_size, v_.end()); - v_.resize(new_size); - } - - template - void assign(InputIterator begin, InputIterator end) { - v_.assign(begin, end); - } - - void clear() { STLDeleteElements(&v_); } - - // Like |clear()|, but doesn't delete any elements. - void weak_clear() { v_.clear(); } - - // Lets the ScopedVector take ownership of |x|. - iterator insert(iterator position, T* x) { - return v_.insert(position, x); - } - - // Lets the ScopedVector take ownership of elements in [first,last). - template - void insert(iterator position, InputIterator first, InputIterator last) { - v_.insert(position, first, last); - } - - iterator erase(iterator position) { - delete *position; - return v_.erase(position); - } - - iterator erase(iterator first, iterator last) { - STLDeleteContainerPointers(first, last); - return v_.erase(first, last); - } - - // Like |erase()|, but doesn't delete the element at |position|. - iterator weak_erase(iterator position) { - return v_.erase(position); - } - - // Like |erase()|, but doesn't delete the elements in [first, last). - iterator weak_erase(iterator first, iterator last) { - return v_.erase(first, last); - } - - private: - std::vector v_; -}; - -#endif // BASE_MEMORY_SCOPED_VECTOR_H_ diff --git a/base/memory/scoped_vector_unittest.cc b/base/memory/scoped_vector_unittest.cc deleted file mode 100644 index 353b52c4e7..0000000000 --- a/base/memory/scoped_vector_unittest.cc +++ /dev/null @@ -1,299 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "base/memory/scoped_vector.h" - -#include "base/bind.h" -#include "base/callback.h" -#include "base/memory/scoped_ptr.h" -#include "testing/gtest/include/gtest/gtest.h" - -namespace { - -// The LifeCycleObject notifies its Observer upon construction & destruction. -class LifeCycleObject { - public: - class Observer { - public: - virtual void OnLifeCycleConstruct(LifeCycleObject* o) = 0; - virtual void OnLifeCycleDestroy(LifeCycleObject* o) = 0; - - protected: - virtual ~Observer() {} - }; - - ~LifeCycleObject() { - observer_->OnLifeCycleDestroy(this); - } - - private: - friend class LifeCycleWatcher; - - explicit LifeCycleObject(Observer* observer) - : observer_(observer) { - observer_->OnLifeCycleConstruct(this); - } - - Observer* observer_; - - DISALLOW_COPY_AND_ASSIGN(LifeCycleObject); -}; - -// The life cycle states we care about for the purposes of testing ScopedVector -// against objects. -enum LifeCycleState { - LC_INITIAL, - LC_CONSTRUCTED, - LC_DESTROYED, -}; - -// Because we wish to watch the life cycle of an object being constructed and -// destroyed, and further wish to test expectations against the state of that -// object, we cannot save state in that object itself. Instead, we use this -// pairing of the watcher, which observes the object and notifies of -// construction & destruction. Since we also may be testing assumptions about -// things not getting freed, this class also acts like a scoping object and -// deletes the |constructed_life_cycle_object_|, if any when the -// LifeCycleWatcher is destroyed. To keep this simple, the only expected state -// changes are: -// INITIAL -> CONSTRUCTED -> DESTROYED. -// Anything more complicated than that should start another test. -class LifeCycleWatcher : public LifeCycleObject::Observer { - public: - LifeCycleWatcher() : life_cycle_state_(LC_INITIAL) {} - virtual ~LifeCycleWatcher() {} - - // Assert INITIAL -> CONSTRUCTED and no LifeCycleObject associated with this - // LifeCycleWatcher. - virtual void OnLifeCycleConstruct(LifeCycleObject* object) OVERRIDE { - ASSERT_EQ(LC_INITIAL, life_cycle_state_); - ASSERT_EQ(NULL, constructed_life_cycle_object_.get()); - life_cycle_state_ = LC_CONSTRUCTED; - constructed_life_cycle_object_.reset(object); - } - - // Assert CONSTRUCTED -> DESTROYED and the |object| being destroyed is the - // same one we saw constructed. - virtual void OnLifeCycleDestroy(LifeCycleObject* object) OVERRIDE { - ASSERT_EQ(LC_CONSTRUCTED, life_cycle_state_); - LifeCycleObject* constructed_life_cycle_object = - constructed_life_cycle_object_.release(); - ASSERT_EQ(constructed_life_cycle_object, object); - life_cycle_state_ = LC_DESTROYED; - } - - LifeCycleState life_cycle_state() const { return life_cycle_state_; } - - // Factory method for creating a new LifeCycleObject tied to this - // LifeCycleWatcher. - LifeCycleObject* NewLifeCycleObject() { - return new LifeCycleObject(this); - } - - // Returns true iff |object| is the same object that this watcher is tracking. - bool IsWatching(LifeCycleObject* object) const { - return object == constructed_life_cycle_object_.get(); - } - - private: - LifeCycleState life_cycle_state_; - scoped_ptr constructed_life_cycle_object_; - - DISALLOW_COPY_AND_ASSIGN(LifeCycleWatcher); -}; - -TEST(ScopedVectorTest, LifeCycleWatcher) { - LifeCycleWatcher watcher; - EXPECT_EQ(LC_INITIAL, watcher.life_cycle_state()); - LifeCycleObject* object = watcher.NewLifeCycleObject(); - EXPECT_EQ(LC_CONSTRUCTED, watcher.life_cycle_state()); - delete object; - EXPECT_EQ(LC_DESTROYED, watcher.life_cycle_state()); -} - -TEST(ScopedVectorTest, Clear) { - LifeCycleWatcher watcher; - EXPECT_EQ(LC_INITIAL, watcher.life_cycle_state()); - ScopedVector scoped_vector; - scoped_vector.push_back(watcher.NewLifeCycleObject()); - EXPECT_EQ(LC_CONSTRUCTED, watcher.life_cycle_state()); - EXPECT_TRUE(watcher.IsWatching(scoped_vector.back())); - scoped_vector.clear(); - EXPECT_EQ(LC_DESTROYED, watcher.life_cycle_state()); - EXPECT_TRUE(scoped_vector.empty()); -} - -TEST(ScopedVectorTest, WeakClear) { - LifeCycleWatcher watcher; - EXPECT_EQ(LC_INITIAL, watcher.life_cycle_state()); - ScopedVector scoped_vector; - scoped_vector.push_back(watcher.NewLifeCycleObject()); - EXPECT_EQ(LC_CONSTRUCTED, watcher.life_cycle_state()); - EXPECT_TRUE(watcher.IsWatching(scoped_vector.back())); - scoped_vector.weak_clear(); - EXPECT_EQ(LC_CONSTRUCTED, watcher.life_cycle_state()); - EXPECT_TRUE(scoped_vector.empty()); -} - -TEST(ScopedVectorTest, ResizeShrink) { - LifeCycleWatcher first_watcher; - EXPECT_EQ(LC_INITIAL, first_watcher.life_cycle_state()); - LifeCycleWatcher second_watcher; - EXPECT_EQ(LC_INITIAL, second_watcher.life_cycle_state()); - ScopedVector scoped_vector; - - scoped_vector.push_back(first_watcher.NewLifeCycleObject()); - EXPECT_EQ(LC_CONSTRUCTED, first_watcher.life_cycle_state()); - EXPECT_EQ(LC_INITIAL, second_watcher.life_cycle_state()); - EXPECT_TRUE(first_watcher.IsWatching(scoped_vector[0])); - EXPECT_FALSE(second_watcher.IsWatching(scoped_vector[0])); - - scoped_vector.push_back(second_watcher.NewLifeCycleObject()); - EXPECT_EQ(LC_CONSTRUCTED, first_watcher.life_cycle_state()); - EXPECT_EQ(LC_CONSTRUCTED, second_watcher.life_cycle_state()); - EXPECT_FALSE(first_watcher.IsWatching(scoped_vector[1])); - EXPECT_TRUE(second_watcher.IsWatching(scoped_vector[1])); - - // Test that shrinking a vector deletes elements in the disappearing range. - scoped_vector.resize(1); - EXPECT_EQ(LC_CONSTRUCTED, first_watcher.life_cycle_state()); - EXPECT_EQ(LC_DESTROYED, second_watcher.life_cycle_state()); - EXPECT_EQ(1u, scoped_vector.size()); - EXPECT_TRUE(first_watcher.IsWatching(scoped_vector[0])); -} - -TEST(ScopedVectorTest, ResizeGrow) { - LifeCycleWatcher watcher; - EXPECT_EQ(LC_INITIAL, watcher.life_cycle_state()); - ScopedVector scoped_vector; - scoped_vector.push_back(watcher.NewLifeCycleObject()); - EXPECT_EQ(LC_CONSTRUCTED, watcher.life_cycle_state()); - EXPECT_TRUE(watcher.IsWatching(scoped_vector.back())); - - scoped_vector.resize(5); - EXPECT_EQ(LC_CONSTRUCTED, watcher.life_cycle_state()); - ASSERT_EQ(5u, scoped_vector.size()); - EXPECT_TRUE(watcher.IsWatching(scoped_vector[0])); - EXPECT_FALSE(watcher.IsWatching(scoped_vector[1])); - EXPECT_FALSE(watcher.IsWatching(scoped_vector[2])); - EXPECT_FALSE(watcher.IsWatching(scoped_vector[3])); - EXPECT_FALSE(watcher.IsWatching(scoped_vector[4])); -} - -TEST(ScopedVectorTest, Scope) { - LifeCycleWatcher watcher; - EXPECT_EQ(LC_INITIAL, watcher.life_cycle_state()); - { - ScopedVector scoped_vector; - scoped_vector.push_back(watcher.NewLifeCycleObject()); - EXPECT_EQ(LC_CONSTRUCTED, watcher.life_cycle_state()); - EXPECT_TRUE(watcher.IsWatching(scoped_vector.back())); - } - EXPECT_EQ(LC_DESTROYED, watcher.life_cycle_state()); -} - -TEST(ScopedVectorTest, MoveConstruct) { - LifeCycleWatcher watcher; - EXPECT_EQ(LC_INITIAL, watcher.life_cycle_state()); - { - ScopedVector scoped_vector; - scoped_vector.push_back(watcher.NewLifeCycleObject()); - EXPECT_FALSE(scoped_vector.empty()); - EXPECT_TRUE(watcher.IsWatching(scoped_vector.back())); - - ScopedVector scoped_vector_copy(scoped_vector.Pass()); - EXPECT_TRUE(scoped_vector.empty()); - EXPECT_FALSE(scoped_vector_copy.empty()); - EXPECT_TRUE(watcher.IsWatching(scoped_vector_copy.back())); - - EXPECT_EQ(LC_CONSTRUCTED, watcher.life_cycle_state()); - } - EXPECT_EQ(LC_DESTROYED, watcher.life_cycle_state()); -} - -TEST(ScopedVectorTest, MoveAssign) { - LifeCycleWatcher watcher; - EXPECT_EQ(LC_INITIAL, watcher.life_cycle_state()); - { - ScopedVector scoped_vector; - scoped_vector.push_back(watcher.NewLifeCycleObject()); - ScopedVector scoped_vector_assign; - EXPECT_FALSE(scoped_vector.empty()); - EXPECT_TRUE(watcher.IsWatching(scoped_vector.back())); - - scoped_vector_assign = scoped_vector.Pass(); - EXPECT_TRUE(scoped_vector.empty()); - EXPECT_FALSE(scoped_vector_assign.empty()); - EXPECT_TRUE(watcher.IsWatching(scoped_vector_assign.back())); - - EXPECT_EQ(LC_CONSTRUCTED, watcher.life_cycle_state()); - } - EXPECT_EQ(LC_DESTROYED, watcher.life_cycle_state()); -} - -class DeleteCounter { - public: - explicit DeleteCounter(int* deletes) - : deletes_(deletes) { - } - - ~DeleteCounter() { - (*deletes_)++; - } - - void VoidMethod0() {} - - private: - int* const deletes_; - - DISALLOW_COPY_AND_ASSIGN(DeleteCounter); -}; - -template -ScopedVector PassThru(ScopedVector scoper) { - return scoper.Pass(); -} - -TEST(ScopedVectorTest, Passed) { - int deletes = 0; - ScopedVector deleter_vector; - deleter_vector.push_back(new DeleteCounter(&deletes)); - EXPECT_EQ(0, deletes); - base::Callback(void)> callback = - base::Bind(&PassThru, base::Passed(&deleter_vector)); - EXPECT_EQ(0, deletes); - ScopedVector result = callback.Run(); - EXPECT_EQ(0, deletes); - result.clear(); - EXPECT_EQ(1, deletes); -}; - -TEST(ScopedVectorTest, InsertRange) { - LifeCycleWatcher watchers[5]; - - std::vector vec; - for(LifeCycleWatcher* it = watchers; it != watchers + arraysize(watchers); - ++it) { - EXPECT_EQ(LC_INITIAL, it->life_cycle_state()); - vec.push_back(it->NewLifeCycleObject()); - EXPECT_EQ(LC_CONSTRUCTED, it->life_cycle_state()); - } - // Start scope for ScopedVector. - { - ScopedVector scoped_vector; - scoped_vector.insert(scoped_vector.end(), vec.begin() + 1, vec.begin() + 3); - for(LifeCycleWatcher* it = watchers; it != watchers + arraysize(watchers); - ++it) - EXPECT_EQ(LC_CONSTRUCTED, it->life_cycle_state()); - } - for(LifeCycleWatcher* it = watchers; it != watchers + 1; ++it) - EXPECT_EQ(LC_CONSTRUCTED, it->life_cycle_state()); - for(LifeCycleWatcher* it = watchers + 1; it != watchers + 3; ++it) - EXPECT_EQ(LC_DESTROYED, it->life_cycle_state()); - for(LifeCycleWatcher* it = watchers + 3; it != watchers + arraysize(watchers); - ++it) - EXPECT_EQ(LC_CONSTRUCTED, it->life_cycle_state()); -} - -} // namespace diff --git a/base/memory/shared_memory.h b/base/memory/shared_memory.h deleted file mode 100644 index 23f6973374..0000000000 --- a/base/memory/shared_memory.h +++ /dev/null @@ -1,281 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef BASE_MEMORY_SHARED_MEMORY_H_ -#define BASE_MEMORY_SHARED_MEMORY_H_ - -#include "build/build_config.h" - -#include - -#if defined(OS_POSIX) -#include -#include -#include -#endif - -#include "base/base_export.h" -#include "base/basictypes.h" -#include "base/process/process_handle.h" - -#if defined(OS_POSIX) -#include "base/file_descriptor_posix.h" -#endif - -namespace base { - -class FilePath; - -// SharedMemoryHandle is a platform specific type which represents -// the underlying OS handle to a shared memory segment. -#if defined(OS_WIN) -typedef HANDLE SharedMemoryHandle; -typedef HANDLE SharedMemoryLock; -#elif defined(OS_POSIX) -// A SharedMemoryId is sufficient to identify a given shared memory segment on a -// system, but insufficient to map it. -typedef FileDescriptor SharedMemoryHandle; -typedef ino_t SharedMemoryId; -// On POSIX, the lock is implemented as a lockf() on the mapped file, -// so no additional member (or definition of SharedMemoryLock) is -// needed. -#endif - -// Options for creating a shared memory object. -struct SharedMemoryCreateOptions { - SharedMemoryCreateOptions() : name(NULL), size(0), open_existing(false), - executable(false) {} - - // If NULL, the object is anonymous. This pointer is owned by the caller - // and must live through the call to Create(). - const std::string* name; - - // Size of the shared memory object to be created. - // When opening an existing object, this has no effect. - size_t size; - - // If true, and the shared memory already exists, Create() will open the - // existing shared memory and ignore the size parameter. If false, - // shared memory must not exist. This flag is meaningless unless name is - // non-NULL. - bool open_existing; - - // If true, mappings might need to be made executable later. - bool executable; -}; - -// Platform abstraction for shared memory. Provides a C++ wrapper -// around the OS primitive for a memory mapped file. -class BASE_EXPORT SharedMemory { - public: - SharedMemory(); - -#if defined(OS_WIN) - // Similar to the default constructor, except that this allows for - // calling Lock() to acquire the named mutex before either Create or Open - // are called on Windows. - explicit SharedMemory(const std::wstring& name); -#endif - - // Create a new SharedMemory object from an existing, open - // shared memory file. - SharedMemory(SharedMemoryHandle handle, bool read_only); - - // Create a new SharedMemory object from an existing, open - // shared memory file that was created by a remote process and not shared - // to the current process. - SharedMemory(SharedMemoryHandle handle, bool read_only, - ProcessHandle process); - - // Closes any open files. - ~SharedMemory(); - - // Return true iff the given handle is valid (i.e. not the distingished - // invalid value; NULL for a HANDLE and -1 for a file descriptor) - static bool IsHandleValid(const SharedMemoryHandle& handle); - - // Returns invalid handle (see comment above for exact definition). - static SharedMemoryHandle NULLHandle(); - - // Closes a shared memory handle. - static void CloseHandle(const SharedMemoryHandle& handle); - - // Returns the maximum number of handles that can be open at once per process. - static size_t GetHandleLimit(); - - // Creates a shared memory object as described by the options struct. - // Returns true on success and false on failure. - bool Create(const SharedMemoryCreateOptions& options); - - // Creates and maps an anonymous shared memory segment of size size. - // Returns true on success and false on failure. - bool CreateAndMapAnonymous(size_t size); - - // Creates an anonymous shared memory segment of size size. - // Returns true on success and false on failure. - bool CreateAnonymous(size_t size) { - SharedMemoryCreateOptions options; - options.size = size; - return Create(options); - } - - // Creates or opens a shared memory segment based on a name. - // If open_existing is true, and the shared memory already exists, - // opens the existing shared memory and ignores the size parameter. - // If open_existing is false, shared memory must not exist. - // size is the size of the block to be created. - // Returns true on success, false on failure. - bool CreateNamed(const std::string& name, bool open_existing, size_t size) { - SharedMemoryCreateOptions options; - options.name = &name; - options.open_existing = open_existing; - options.size = size; - return Create(options); - } - - // Deletes resources associated with a shared memory segment based on name. - // Not all platforms require this call. - bool Delete(const std::string& name); - - // Opens a shared memory segment based on a name. - // If read_only is true, opens for read-only access. - // Returns true on success, false on failure. - bool Open(const std::string& name, bool read_only); - - // Maps the shared memory into the caller's address space. - // Returns true on success, false otherwise. The memory address - // is accessed via the memory() accessor. The mapped address is guaranteed to - // have an alignment of at least MAP_MINIMUM_ALIGNMENT. - bool Map(size_t bytes) { - return MapAt(0, bytes); - } - - // Same as above, but with |offset| to specify from begining of the shared - // memory block to map. - // |offset| must be alignent to value of |SysInfo::VMAllocationGranularity()|. - bool MapAt(off_t offset, size_t bytes); - enum { MAP_MINIMUM_ALIGNMENT = 32 }; - - // Unmaps the shared memory from the caller's address space. - // Returns true if successful; returns false on error or if the - // memory is not mapped. - bool Unmap(); - - // The size requested when the map is first created. - size_t requested_size() const { return requested_size_; } - - // The actual size of the mapped memory (may be larger than requested). - size_t mapped_size() const { return mapped_size_; } - - // Gets a pointer to the opened memory space if it has been - // Mapped via Map(). Returns NULL if it is not mapped. - void *memory() const { return memory_; } - - // Returns the underlying OS handle for this segment. - // Use of this handle for anything other than an opaque - // identifier is not portable. - SharedMemoryHandle handle() const; - -#if defined(OS_POSIX) && !defined(OS_NACL) - // Returns a unique identifier for this shared memory segment. Inode numbers - // are technically only unique to a single filesystem. However, we always - // allocate shared memory backing files from the same directory, so will end - // up on the same filesystem. - SharedMemoryId id() const { return inode_; } -#endif - - // Closes the open shared memory segment. - // It is safe to call Close repeatedly. - void Close(); - - // Shares the shared memory to another process. Attempts - // to create a platform-specific new_handle which can be - // used in a remote process to access the shared memory - // file. new_handle is an ouput parameter to receive - // the handle for use in the remote process. - // Returns true on success, false otherwise. - bool ShareToProcess(ProcessHandle process, - SharedMemoryHandle* new_handle) { - return ShareToProcessCommon(process, new_handle, false); - } - - // Logically equivalent to: - // bool ok = ShareToProcess(process, new_handle); - // Close(); - // return ok; - // Note that the memory is unmapped by calling this method, regardless of the - // return value. - bool GiveToProcess(ProcessHandle process, - SharedMemoryHandle* new_handle) { - return ShareToProcessCommon(process, new_handle, true); - } - - // Locks the shared memory. - // - // WARNING: on POSIX the memory locking primitive only works across - // processes, not across threads. The Lock method is not currently - // used in inner loops, so we protect against multiple threads in a - // critical section using a class global lock. - void Lock(); - -#if defined(OS_WIN) - // A Lock() implementation with a timeout that also allows setting - // security attributes on the mutex. sec_attr may be NULL. - // Returns true if the Lock() has been acquired, false if the timeout was - // reached. - bool Lock(uint32 timeout_ms, SECURITY_ATTRIBUTES* sec_attr); -#endif - - // Releases the shared memory lock. - void Unlock(); - - private: -#if defined(OS_POSIX) && !defined(OS_NACL) - bool PrepareMapFile(FILE *fp); - bool FilePathForMemoryName(const std::string& mem_name, FilePath* path); - void LockOrUnlockCommon(int function); -#endif - bool ShareToProcessCommon(ProcessHandle process, - SharedMemoryHandle* new_handle, - bool close_self); - -#if defined(OS_WIN) - std::wstring name_; - HANDLE mapped_file_; -#elif defined(OS_POSIX) - int mapped_file_; - ino_t inode_; -#endif - size_t mapped_size_; - void* memory_; - bool read_only_; - size_t requested_size_; -#if !defined(OS_POSIX) - SharedMemoryLock lock_; -#endif - - DISALLOW_COPY_AND_ASSIGN(SharedMemory); -}; - -// A helper class that acquires the shared memory lock while -// the SharedMemoryAutoLock is in scope. -class SharedMemoryAutoLock { - public: - explicit SharedMemoryAutoLock(SharedMemory* shared_memory) - : shared_memory_(shared_memory) { - shared_memory_->Lock(); - } - - ~SharedMemoryAutoLock() { - shared_memory_->Unlock(); - } - - private: - SharedMemory* shared_memory_; - DISALLOW_COPY_AND_ASSIGN(SharedMemoryAutoLock); -}; - -} // namespace base - -#endif // BASE_MEMORY_SHARED_MEMORY_H_ diff --git a/base/memory/shared_memory_android.cc b/base/memory/shared_memory_android.cc deleted file mode 100644 index 3ca3c8fa36..0000000000 --- a/base/memory/shared_memory_android.cc +++ /dev/null @@ -1,57 +0,0 @@ -// Copyright (c) 2011 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "base/memory/shared_memory.h" - -#include - -#include "base/logging.h" -#include "third_party/ashmem/ashmem.h" - -namespace base { - -// For Android, we use ashmem to implement SharedMemory. ashmem_create_region -// will automatically pin the region. We never explicitly call pin/unpin. When -// all the file descriptors from different processes associated with the region -// are closed, the memory buffer will go away. - -bool SharedMemory::Create(const SharedMemoryCreateOptions& options) { - DCHECK_EQ(-1, mapped_file_ ); - - if (options.size > static_cast(std::numeric_limits::max())) - return false; - - // "name" is just a label in ashmem. It is visible in /proc/pid/maps. - mapped_file_ = ashmem_create_region( - options.name == NULL ? "" : options.name->c_str(), - options.size); - if (-1 == mapped_file_) { - DLOG(ERROR) << "Shared memory creation failed"; - return false; - } - - int err = ashmem_set_prot_region(mapped_file_, - PROT_READ | PROT_WRITE | PROT_EXEC); - if (err < 0) { - DLOG(ERROR) << "Error " << err << " when setting protection of ashmem"; - return false; - } - requested_size_ = options.size; - - return true; -} - -bool SharedMemory::Delete(const std::string& name) { - // Like on Windows, this is intentionally returning true as ashmem will - // automatically releases the resource when all FDs on it are closed. - return true; -} - -bool SharedMemory::Open(const std::string& name, bool read_only) { - // ashmem doesn't support name mapping - NOTIMPLEMENTED(); - return false; -} - -} // namespace base diff --git a/base/memory/shared_memory_nacl.cc b/base/memory/shared_memory_nacl.cc deleted file mode 100644 index bc2a98dfdf..0000000000 --- a/base/memory/shared_memory_nacl.cc +++ /dev/null @@ -1,158 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "base/memory/shared_memory.h" - -#include -#include -#include -#include -#include - -#include - -#include "base/logging.h" - -namespace base { - -SharedMemory::SharedMemory() - : mapped_file_(-1), - inode_(0), - mapped_size_(0), - memory_(NULL), - read_only_(false), - requested_size_(0) { -} - -SharedMemory::SharedMemory(SharedMemoryHandle handle, bool read_only) - : mapped_file_(handle.fd), - inode_(0), - mapped_size_(0), - memory_(NULL), - read_only_(read_only), - requested_size_(0) { -} - -SharedMemory::SharedMemory(SharedMemoryHandle handle, bool read_only, - ProcessHandle process) - : mapped_file_(handle.fd), - inode_(0), - mapped_size_(0), - memory_(NULL), - read_only_(read_only), - requested_size_(0) { - NOTREACHED(); -} - -SharedMemory::~SharedMemory() { - Close(); -} - -// static -bool SharedMemory::IsHandleValid(const SharedMemoryHandle& handle) { - return handle.fd >= 0; -} - -// static -SharedMemoryHandle SharedMemory::NULLHandle() { - return SharedMemoryHandle(); -} - -// static -void SharedMemory::CloseHandle(const SharedMemoryHandle& handle) { - DCHECK_GE(handle.fd, 0); - if (close(handle.fd) < 0) - DPLOG(ERROR) << "close"; -} - -bool SharedMemory::CreateAndMapAnonymous(size_t size) { - // Untrusted code can't create descriptors or handles. - return false; -} - -bool SharedMemory::Create(const SharedMemoryCreateOptions& options) { - // Untrusted code can't create descriptors or handles. - return false; -} - -bool SharedMemory::Delete(const std::string& name) { - return false; -} - -bool SharedMemory::Open(const std::string& name, bool read_only) { - return false; -} - -bool SharedMemory::MapAt(off_t offset, size_t bytes) { - if (mapped_file_ == -1) - return false; - - if (bytes > static_cast(std::numeric_limits::max())) - return false; - - memory_ = mmap(NULL, bytes, PROT_READ | (read_only_ ? 0 : PROT_WRITE), - MAP_SHARED, mapped_file_, offset); - - bool mmap_succeeded = memory_ != MAP_FAILED && memory_ != NULL; - if (mmap_succeeded) { - mapped_size_ = bytes; - DCHECK_EQ(0U, reinterpret_cast(memory_) & - (SharedMemory::MAP_MINIMUM_ALIGNMENT - 1)); - } else { - memory_ = NULL; - } - - return mmap_succeeded; -} - -bool SharedMemory::Unmap() { - if (memory_ == NULL) - return false; - - if (munmap(memory_, mapped_size_) < 0) - DPLOG(ERROR) << "munmap"; - memory_ = NULL; - mapped_size_ = 0; - return true; -} - -SharedMemoryHandle SharedMemory::handle() const { - return FileDescriptor(mapped_file_, false); -} - -void SharedMemory::Close() { - Unmap(); - if (mapped_file_ > 0) { - if (close(mapped_file_) < 0) - DPLOG(ERROR) << "close"; - mapped_file_ = -1; - } -} - -void SharedMemory::Lock() { - NOTIMPLEMENTED(); -} - -void SharedMemory::Unlock() { - NOTIMPLEMENTED(); -} - -bool SharedMemory::ShareToProcessCommon(ProcessHandle process, - SharedMemoryHandle *new_handle, - bool close_self) { - const int new_fd = dup(mapped_file_); - if (new_fd < 0) { - DPLOG(ERROR) << "dup() failed."; - return false; - } - - new_handle->fd = new_fd; - new_handle->auto_close = true; - - if (close_self) - Close(); - return true; -} - -} // namespace base diff --git a/base/memory/shared_memory_posix.cc b/base/memory/shared_memory_posix.cc deleted file mode 100644 index e6745ea3a7..0000000000 --- a/base/memory/shared_memory_posix.cc +++ /dev/null @@ -1,423 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "base/memory/shared_memory.h" - -#include -#include -#include -#include -#include -#include - -#include "base/file_util.h" -#include "base/lazy_instance.h" -#include "base/logging.h" -#include "base/process/process_metrics.h" -#include "base/safe_strerror_posix.h" -#include "base/strings/utf_string_conversions.h" -#include "base/synchronization/lock.h" -#include "base/threading/platform_thread.h" -#include "base/threading/thread_restrictions.h" - -#if defined(OS_MACOSX) -#include "base/mac/foundation_util.h" -#endif // OS_MACOSX - -#if defined(OS_ANDROID) -#include "base/os_compat_android.h" -#include "third_party/ashmem/ashmem.h" -#endif - -namespace base { - -namespace { - -// Paranoia. Semaphores and shared memory segments should live in different -// namespaces, but who knows what's out there. -const char kSemaphoreSuffix[] = "-sem"; - -LazyInstance::Leaky g_thread_lock_ = LAZY_INSTANCE_INITIALIZER; - -} - -SharedMemory::SharedMemory() - : mapped_file_(-1), - inode_(0), - mapped_size_(0), - memory_(NULL), - read_only_(false), - requested_size_(0) { -} - -SharedMemory::SharedMemory(SharedMemoryHandle handle, bool read_only) - : mapped_file_(handle.fd), - inode_(0), - mapped_size_(0), - memory_(NULL), - read_only_(read_only), - requested_size_(0) { - struct stat st; - if (fstat(handle.fd, &st) == 0) { - // If fstat fails, then the file descriptor is invalid and we'll learn this - // fact when Map() fails. - inode_ = st.st_ino; - } -} - -SharedMemory::SharedMemory(SharedMemoryHandle handle, bool read_only, - ProcessHandle process) - : mapped_file_(handle.fd), - inode_(0), - mapped_size_(0), - memory_(NULL), - read_only_(read_only), - requested_size_(0) { - // We don't handle this case yet (note the ignored parameter); let's die if - // someone comes calling. - NOTREACHED(); -} - -SharedMemory::~SharedMemory() { - Close(); -} - -// static -bool SharedMemory::IsHandleValid(const SharedMemoryHandle& handle) { - return handle.fd >= 0; -} - -// static -SharedMemoryHandle SharedMemory::NULLHandle() { - return SharedMemoryHandle(); -} - -// static -void SharedMemory::CloseHandle(const SharedMemoryHandle& handle) { - DCHECK_GE(handle.fd, 0); - if (HANDLE_EINTR(close(handle.fd)) < 0) - DPLOG(ERROR) << "close"; -} - -// static -size_t SharedMemory::GetHandleLimit() { - return base::GetMaxFds(); -} - -bool SharedMemory::CreateAndMapAnonymous(size_t size) { - return CreateAnonymous(size) && Map(size); -} - -#if !defined(OS_ANDROID) -// Chromium mostly only uses the unique/private shmem as specified by -// "name == L"". The exception is in the StatsTable. -// TODO(jrg): there is no way to "clean up" all unused named shmem if -// we restart from a crash. (That isn't a new problem, but it is a problem.) -// In case we want to delete it later, it may be useful to save the value -// of mem_filename after FilePathForMemoryName(). -bool SharedMemory::Create(const SharedMemoryCreateOptions& options) { - DCHECK_EQ(-1, mapped_file_); - if (options.size == 0) return false; - - if (options.size > static_cast(std::numeric_limits::max())) - return false; - - // This function theoretically can block on the disk, but realistically - // the temporary files we create will just go into the buffer cache - // and be deleted before they ever make it out to disk. - base::ThreadRestrictions::ScopedAllowIO allow_io; - - FILE *fp; - bool fix_size = true; - - FilePath path; - if (options.name == NULL || options.name->empty()) { - // It doesn't make sense to have a open-existing private piece of shmem - DCHECK(!options.open_existing); - // Q: Why not use the shm_open() etc. APIs? - // A: Because they're limited to 4mb on OS X. FFFFFFFUUUUUUUUUUU - fp = file_util::CreateAndOpenTemporaryShmemFile(&path, options.executable); - - // Deleting the file prevents anyone else from mapping it in (making it - // private), and prevents the need for cleanup (once the last fd is closed, - // it is truly freed). - if (fp) { - if (unlink(path.value().c_str())) - PLOG(WARNING) << "unlink"; - } - } else { - if (!FilePathForMemoryName(*options.name, &path)) - return false; - - // Make sure that the file is opened without any permission - // to other users on the system. - const mode_t kOwnerOnly = S_IRUSR | S_IWUSR; - - // First, try to create the file. - int fd = HANDLE_EINTR( - open(path.value().c_str(), O_RDWR | O_CREAT | O_EXCL, kOwnerOnly)); - if (fd == -1 && options.open_existing) { - // If this doesn't work, try and open an existing file in append mode. - // Opening an existing file in a world writable directory has two main - // security implications: - // - Attackers could plant a file under their control, so ownership of - // the file is checked below. - // - Attackers could plant a symbolic link so that an unexpected file - // is opened, so O_NOFOLLOW is passed to open(). - fd = HANDLE_EINTR( - open(path.value().c_str(), O_RDWR | O_APPEND | O_NOFOLLOW)); - - // Check that the current user owns the file. - // If uid != euid, then a more complex permission model is used and this - // API is not appropriate. - const uid_t real_uid = getuid(); - const uid_t effective_uid = geteuid(); - struct stat sb; - if (fd >= 0 && - (fstat(fd, &sb) != 0 || sb.st_uid != real_uid || - sb.st_uid != effective_uid)) { - LOG(ERROR) << - "Invalid owner when opening existing shared memory file."; - HANDLE_EINTR(close(fd)); - return false; - } - - // An existing file was opened, so its size should not be fixed. - fix_size = false; - } - fp = NULL; - if (fd >= 0) { - // "a+" is always appropriate: if it's a new file, a+ is similar to w+. - fp = fdopen(fd, "a+"); - } - } - if (fp && fix_size) { - // Get current size. - struct stat stat; - if (fstat(fileno(fp), &stat) != 0) { - file_util::CloseFile(fp); - return false; - } - const size_t current_size = stat.st_size; - if (current_size != options.size) { - if (HANDLE_EINTR(ftruncate(fileno(fp), options.size)) != 0) { - file_util::CloseFile(fp); - return false; - } - } - requested_size_ = options.size; - } - if (fp == NULL) { -#if !defined(OS_MACOSX) - PLOG(ERROR) << "Creating shared memory in " << path.value() << " failed"; - FilePath dir = path.DirName(); - if (access(dir.value().c_str(), W_OK | X_OK) < 0) { - PLOG(ERROR) << "Unable to access(W_OK|X_OK) " << dir.value(); - if (dir.value() == "/dev/shm") { - LOG(FATAL) << "This is frequently caused by incorrect permissions on " - << "/dev/shm. Try 'sudo chmod 1777 /dev/shm' to fix."; - } - } -#else - PLOG(ERROR) << "Creating shared memory in " << path.value() << " failed"; -#endif - return false; - } - - return PrepareMapFile(fp); -} - -// Our current implementation of shmem is with mmap()ing of files. -// These files need to be deleted explicitly. -// In practice this call is only needed for unit tests. -bool SharedMemory::Delete(const std::string& name) { - FilePath path; - if (!FilePathForMemoryName(name, &path)) - return false; - - if (PathExists(path)) - return base::DeleteFile(path, false); - - // Doesn't exist, so success. - return true; -} - -bool SharedMemory::Open(const std::string& name, bool read_only) { - FilePath path; - if (!FilePathForMemoryName(name, &path)) - return false; - - read_only_ = read_only; - - const char *mode = read_only ? "r" : "r+"; - FILE *fp = file_util::OpenFile(path, mode); - return PrepareMapFile(fp); -} - -#endif // !defined(OS_ANDROID) - -bool SharedMemory::MapAt(off_t offset, size_t bytes) { - if (mapped_file_ == -1) - return false; - - if (bytes > static_cast(std::numeric_limits::max())) - return false; - -#if defined(OS_ANDROID) - // On Android, Map can be called with a size and offset of zero to use the - // ashmem-determined size. - if (bytes == 0) { - DCHECK_EQ(0, offset); - int ashmem_bytes = ashmem_get_size_region(mapped_file_); - if (ashmem_bytes < 0) - return false; - bytes = ashmem_bytes; - } -#endif - - memory_ = mmap(NULL, bytes, PROT_READ | (read_only_ ? 0 : PROT_WRITE), - MAP_SHARED, mapped_file_, offset); - - bool mmap_succeeded = memory_ != (void*)-1 && memory_ != NULL; - if (mmap_succeeded) { - mapped_size_ = bytes; - DCHECK_EQ(0U, reinterpret_cast(memory_) & - (SharedMemory::MAP_MINIMUM_ALIGNMENT - 1)); - } else { - memory_ = NULL; - } - - return mmap_succeeded; -} - -bool SharedMemory::Unmap() { - if (memory_ == NULL) - return false; - - munmap(memory_, mapped_size_); - memory_ = NULL; - mapped_size_ = 0; - return true; -} - -SharedMemoryHandle SharedMemory::handle() const { - return FileDescriptor(mapped_file_, false); -} - -void SharedMemory::Close() { - Unmap(); - - if (mapped_file_ > 0) { - if (HANDLE_EINTR(close(mapped_file_)) < 0) - PLOG(ERROR) << "close"; - mapped_file_ = -1; - } -} - -void SharedMemory::Lock() { - g_thread_lock_.Get().Acquire(); - LockOrUnlockCommon(F_LOCK); -} - -void SharedMemory::Unlock() { - LockOrUnlockCommon(F_ULOCK); - g_thread_lock_.Get().Release(); -} - -#if !defined(OS_ANDROID) -bool SharedMemory::PrepareMapFile(FILE *fp) { - DCHECK_EQ(-1, mapped_file_); - if (fp == NULL) return false; - - // This function theoretically can block on the disk, but realistically - // the temporary files we create will just go into the buffer cache - // and be deleted before they ever make it out to disk. - base::ThreadRestrictions::ScopedAllowIO allow_io; - - file_util::ScopedFILE file_closer(fp); - - mapped_file_ = dup(fileno(fp)); - if (mapped_file_ == -1) { - if (errno == EMFILE) { - LOG(WARNING) << "Shared memory creation failed; out of file descriptors"; - return false; - } else { - NOTREACHED() << "Call to dup failed, errno=" << errno; - } - } - - struct stat st; - if (fstat(mapped_file_, &st)) - NOTREACHED(); - inode_ = st.st_ino; - - return true; -} -#endif - -// For the given shmem named |mem_name|, return a filename to mmap() -// (and possibly create). Modifies |filename|. Return false on -// error, or true of we are happy. -bool SharedMemory::FilePathForMemoryName(const std::string& mem_name, - FilePath* path) { - // mem_name will be used for a filename; make sure it doesn't - // contain anything which will confuse us. - DCHECK_EQ(std::string::npos, mem_name.find('/')); - DCHECK_EQ(std::string::npos, mem_name.find('\0')); - - FilePath temp_dir; - if (!file_util::GetShmemTempDir(&temp_dir, false)) - return false; - -#if !defined(OS_MACOSX) -#if defined(GOOGLE_CHROME_BUILD) - std::string name_base = std::string("com.google.Chrome"); -#else - std::string name_base = std::string("org.chromium.Chromium"); -#endif -#else // OS_MACOSX - std::string name_base = std::string(base::mac::BaseBundleID()); -#endif // OS_MACOSX - *path = temp_dir.AppendASCII(name_base + ".shmem." + mem_name); - return true; -} - -void SharedMemory::LockOrUnlockCommon(int function) { - DCHECK_GE(mapped_file_, 0); - while (lockf(mapped_file_, function, 0) < 0) { - if (errno == EINTR) { - continue; - } else if (errno == ENOLCK) { - // temporary kernel resource exaustion - base::PlatformThread::Sleep(base::TimeDelta::FromMilliseconds(500)); - continue; - } else { - NOTREACHED() << "lockf() failed." - << " function:" << function - << " fd:" << mapped_file_ - << " errno:" << errno - << " msg:" << safe_strerror(errno); - } - } -} - -bool SharedMemory::ShareToProcessCommon(ProcessHandle process, - SharedMemoryHandle *new_handle, - bool close_self) { - const int new_fd = dup(mapped_file_); - if (new_fd < 0) { - DPLOG(ERROR) << "dup() failed."; - return false; - } - - new_handle->fd = new_fd; - new_handle->auto_close = true; - - if (close_self) - Close(); - - return true; -} - -} // namespace base diff --git a/base/memory/shared_memory_unittest.cc b/base/memory/shared_memory_unittest.cc deleted file mode 100644 index 892fd7f1a5..0000000000 --- a/base/memory/shared_memory_unittest.cc +++ /dev/null @@ -1,561 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "base/basictypes.h" -#include "base/memory/scoped_ptr.h" -#include "base/memory/shared_memory.h" -#include "base/process/kill.h" -#include "base/rand_util.h" -#include "base/strings/string_number_conversions.h" -#include "base/sys_info.h" -#include "base/test/multiprocess_test.h" -#include "base/threading/platform_thread.h" -#include "base/time/time.h" -#include "testing/gtest/include/gtest/gtest.h" -#include "testing/multiprocess_func_list.h" - -#if defined(OS_MACOSX) -#include "base/mac/scoped_nsautorelease_pool.h" -#endif - -#if defined(OS_POSIX) -#include -#include -#include -#include -#endif - -static const int kNumThreads = 5; -static const int kNumTasks = 5; - -namespace base { - -namespace { - -// Each thread will open the shared memory. Each thread will take a different 4 -// byte int pointer, and keep changing it, with some small pauses in between. -// Verify that each thread's value in the shared memory is always correct. -class MultipleThreadMain : public PlatformThread::Delegate { - public: - explicit MultipleThreadMain(int16 id) : id_(id) {} - virtual ~MultipleThreadMain() {} - - static void CleanUp() { - SharedMemory memory; - memory.Delete(s_test_name_); - } - - // PlatformThread::Delegate interface. - virtual void ThreadMain() OVERRIDE { -#if defined(OS_MACOSX) - mac::ScopedNSAutoreleasePool pool; -#endif - const uint32 kDataSize = 1024; - SharedMemory memory; - bool rv = memory.CreateNamed(s_test_name_, true, kDataSize); - EXPECT_TRUE(rv); - rv = memory.Map(kDataSize); - EXPECT_TRUE(rv); - int *ptr = static_cast(memory.memory()) + id_; - EXPECT_EQ(0, *ptr); - - for (int idx = 0; idx < 100; idx++) { - *ptr = idx; - PlatformThread::Sleep(base::TimeDelta::FromMilliseconds(1)); - EXPECT_EQ(*ptr, idx); - } - // Reset back to 0 for the next test that uses the same name. - *ptr = 0; - - memory.Close(); - } - - private: - int16 id_; - - static const char* const s_test_name_; - - DISALLOW_COPY_AND_ASSIGN(MultipleThreadMain); -}; - -const char* const MultipleThreadMain::s_test_name_ = - "SharedMemoryOpenThreadTest"; - -// TODO(port): -// This test requires the ability to pass file descriptors between processes. -// We haven't done that yet in Chrome for POSIX. -#if defined(OS_WIN) -// Each thread will open the shared memory. Each thread will take the memory, -// and keep changing it while trying to lock it, with some small pauses in -// between. Verify that each thread's value in the shared memory is always -// correct. -class MultipleLockThread : public PlatformThread::Delegate { - public: - explicit MultipleLockThread(int id) : id_(id) {} - virtual ~MultipleLockThread() {} - - // PlatformThread::Delegate interface. - virtual void ThreadMain() OVERRIDE { - const uint32 kDataSize = sizeof(int); - SharedMemoryHandle handle = NULL; - { - SharedMemory memory1; - EXPECT_TRUE(memory1.CreateNamed("SharedMemoryMultipleLockThreadTest", - true, kDataSize)); - EXPECT_TRUE(memory1.ShareToProcess(GetCurrentProcess(), &handle)); - // TODO(paulg): Implement this once we have a posix version of - // SharedMemory::ShareToProcess. - EXPECT_TRUE(true); - } - - SharedMemory memory2(handle, false); - EXPECT_TRUE(memory2.Map(kDataSize)); - volatile int* const ptr = static_cast(memory2.memory()); - - for (int idx = 0; idx < 20; idx++) { - memory2.Lock(); - int i = (id_ << 16) + idx; - *ptr = i; - PlatformThread::Sleep(TimeDelta::FromMilliseconds(1)); - EXPECT_EQ(*ptr, i); - memory2.Unlock(); - } - - memory2.Close(); - } - - private: - int id_; - - DISALLOW_COPY_AND_ASSIGN(MultipleLockThread); -}; -#endif - -} // namespace - -// Android doesn't support SharedMemory::Open/Delete/ -// CreateNamed(openExisting=true) -#if !defined(OS_ANDROID) -TEST(SharedMemoryTest, OpenClose) { - const uint32 kDataSize = 1024; - std::string test_name = "SharedMemoryOpenCloseTest"; - - // Open two handles to a memory segment, confirm that they are mapped - // separately yet point to the same space. - SharedMemory memory1; - bool rv = memory1.Delete(test_name); - EXPECT_TRUE(rv); - rv = memory1.Delete(test_name); - EXPECT_TRUE(rv); - rv = memory1.Open(test_name, false); - EXPECT_FALSE(rv); - rv = memory1.CreateNamed(test_name, false, kDataSize); - EXPECT_TRUE(rv); - rv = memory1.Map(kDataSize); - EXPECT_TRUE(rv); - SharedMemory memory2; - rv = memory2.Open(test_name, false); - EXPECT_TRUE(rv); - rv = memory2.Map(kDataSize); - EXPECT_TRUE(rv); - EXPECT_NE(memory1.memory(), memory2.memory()); // Compare the pointers. - - // Make sure we don't segfault. (it actually happened!) - ASSERT_NE(memory1.memory(), static_cast(NULL)); - ASSERT_NE(memory2.memory(), static_cast(NULL)); - - // Write data to the first memory segment, verify contents of second. - memset(memory1.memory(), '1', kDataSize); - EXPECT_EQ(memcmp(memory1.memory(), memory2.memory(), kDataSize), 0); - - // Close the first memory segment, and verify the second has the right data. - memory1.Close(); - char *start_ptr = static_cast(memory2.memory()); - char *end_ptr = start_ptr + kDataSize; - for (char* ptr = start_ptr; ptr < end_ptr; ptr++) - EXPECT_EQ(*ptr, '1'); - - // Close the second memory segment. - memory2.Close(); - - rv = memory1.Delete(test_name); - EXPECT_TRUE(rv); - rv = memory2.Delete(test_name); - EXPECT_TRUE(rv); -} - -TEST(SharedMemoryTest, OpenExclusive) { - const uint32 kDataSize = 1024; - const uint32 kDataSize2 = 2048; - std::ostringstream test_name_stream; - test_name_stream << "SharedMemoryOpenExclusiveTest." - << Time::Now().ToDoubleT(); - std::string test_name = test_name_stream.str(); - - // Open two handles to a memory segment and check that open_existing works - // as expected. - SharedMemory memory1; - bool rv = memory1.CreateNamed(test_name, false, kDataSize); - EXPECT_TRUE(rv); - - // Memory1 knows it's size because it created it. - EXPECT_EQ(memory1.requested_size(), kDataSize); - - rv = memory1.Map(kDataSize); - EXPECT_TRUE(rv); - - // The mapped memory1 must be at least the size we asked for. - EXPECT_GE(memory1.mapped_size(), kDataSize); - - // The mapped memory1 shouldn't exceed rounding for allocation granularity. - EXPECT_LT(memory1.mapped_size(), - kDataSize + base::SysInfo::VMAllocationGranularity()); - - memset(memory1.memory(), 'G', kDataSize); - - SharedMemory memory2; - // Should not be able to create if openExisting is false. - rv = memory2.CreateNamed(test_name, false, kDataSize2); - EXPECT_FALSE(rv); - - // Should be able to create with openExisting true. - rv = memory2.CreateNamed(test_name, true, kDataSize2); - EXPECT_TRUE(rv); - - // Memory2 shouldn't know the size because we didn't create it. - EXPECT_EQ(memory2.requested_size(), 0U); - - // We should be able to map the original size. - rv = memory2.Map(kDataSize); - EXPECT_TRUE(rv); - - // The mapped memory2 must be at least the size of the original. - EXPECT_GE(memory2.mapped_size(), kDataSize); - - // The mapped memory2 shouldn't exceed rounding for allocation granularity. - EXPECT_LT(memory2.mapped_size(), - kDataSize2 + base::SysInfo::VMAllocationGranularity()); - - // Verify that opening memory2 didn't truncate or delete memory 1. - char *start_ptr = static_cast(memory2.memory()); - char *end_ptr = start_ptr + kDataSize; - for (char* ptr = start_ptr; ptr < end_ptr; ptr++) { - EXPECT_EQ(*ptr, 'G'); - } - - memory1.Close(); - memory2.Close(); - - rv = memory1.Delete(test_name); - EXPECT_TRUE(rv); -} -#endif - -// Create a set of N threads to each open a shared memory segment and write to -// it. Verify that they are always reading/writing consistent data. -TEST(SharedMemoryTest, MultipleThreads) { - MultipleThreadMain::CleanUp(); - // On POSIX we have a problem when 2 threads try to create the shmem - // (a file) at exactly the same time, since create both creates the - // file and zerofills it. We solve the problem for this unit test - // (make it not flaky) by starting with 1 thread, then - // intentionally don't clean up its shmem before running with - // kNumThreads. - - int threadcounts[] = { 1, kNumThreads }; - for (size_t i = 0; i < arraysize(threadcounts); i++) { - int numthreads = threadcounts[i]; - scoped_ptr thread_handles; - scoped_ptr thread_delegates; - - thread_handles.reset(new PlatformThreadHandle[numthreads]); - thread_delegates.reset(new MultipleThreadMain*[numthreads]); - - // Spawn the threads. - for (int16 index = 0; index < numthreads; index++) { - PlatformThreadHandle pth; - thread_delegates[index] = new MultipleThreadMain(index); - EXPECT_TRUE(PlatformThread::Create(0, thread_delegates[index], &pth)); - thread_handles[index] = pth; - } - - // Wait for the threads to finish. - for (int index = 0; index < numthreads; index++) { - PlatformThread::Join(thread_handles[index]); - delete thread_delegates[index]; - } - } - MultipleThreadMain::CleanUp(); -} - -// TODO(port): this test requires the MultipleLockThread class -// (defined above), which requires the ability to pass file -// descriptors between processes. We haven't done that yet in Chrome -// for POSIX. -#if defined(OS_WIN) -// Create a set of threads to each open a shared memory segment and write to it -// with the lock held. Verify that they are always reading/writing consistent -// data. -TEST(SharedMemoryTest, Lock) { - PlatformThreadHandle thread_handles[kNumThreads]; - MultipleLockThread* thread_delegates[kNumThreads]; - - // Spawn the threads. - for (int index = 0; index < kNumThreads; ++index) { - PlatformThreadHandle pth; - thread_delegates[index] = new MultipleLockThread(index); - EXPECT_TRUE(PlatformThread::Create(0, thread_delegates[index], &pth)); - thread_handles[index] = pth; - } - - // Wait for the threads to finish. - for (int index = 0; index < kNumThreads; ++index) { - PlatformThread::Join(thread_handles[index]); - delete thread_delegates[index]; - } -} -#endif - -// Allocate private (unique) shared memory with an empty string for a -// name. Make sure several of them don't point to the same thing as -// we might expect if the names are equal. -TEST(SharedMemoryTest, AnonymousPrivate) { - int i, j; - int count = 4; - bool rv; - const uint32 kDataSize = 8192; - - scoped_ptr memories(new SharedMemory[count]); - scoped_ptr pointers(new int*[count]); - ASSERT_TRUE(memories.get()); - ASSERT_TRUE(pointers.get()); - - for (i = 0; i < count; i++) { - rv = memories[i].CreateAndMapAnonymous(kDataSize); - EXPECT_TRUE(rv); - int *ptr = static_cast(memories[i].memory()); - EXPECT_TRUE(ptr); - pointers[i] = ptr; - } - - for (i = 0; i < count; i++) { - // zero out the first int in each except for i; for that one, make it 100. - for (j = 0; j < count; j++) { - if (i == j) - pointers[j][0] = 100; - else - pointers[j][0] = 0; - } - // make sure there is no bleeding of the 100 into the other pointers - for (j = 0; j < count; j++) { - if (i == j) - EXPECT_EQ(100, pointers[j][0]); - else - EXPECT_EQ(0, pointers[j][0]); - } - } - - for (int i = 0; i < count; i++) { - memories[i].Close(); - } -} - -TEST(SharedMemoryTest, MapAt) { - ASSERT_TRUE(SysInfo::VMAllocationGranularity() >= sizeof(uint32)); - const size_t kCount = SysInfo::VMAllocationGranularity(); - const size_t kDataSize = kCount * sizeof(uint32); - - SharedMemory memory; - ASSERT_TRUE(memory.CreateAndMapAnonymous(kDataSize)); - ASSERT_TRUE(memory.Map(kDataSize)); - uint32* ptr = static_cast(memory.memory()); - ASSERT_NE(ptr, static_cast(NULL)); - - for (size_t i = 0; i < kCount; ++i) { - ptr[i] = i; - } - - memory.Unmap(); - - off_t offset = SysInfo::VMAllocationGranularity(); - ASSERT_TRUE(memory.MapAt(offset, kDataSize - offset)); - offset /= sizeof(uint32); - ptr = static_cast(memory.memory()); - ASSERT_NE(ptr, static_cast(NULL)); - for (size_t i = offset; i < kCount; ++i) { - EXPECT_EQ(ptr[i - offset], i); - } -} - -#if defined(OS_POSIX) -// Create a shared memory object, mmap it, and mprotect it to PROT_EXEC. -TEST(SharedMemoryTest, AnonymousExecutable) { - const uint32 kTestSize = 1 << 16; - - SharedMemory shared_memory; - SharedMemoryCreateOptions options; - options.size = kTestSize; - options.executable = true; - - EXPECT_TRUE(shared_memory.Create(options)); - EXPECT_TRUE(shared_memory.Map(shared_memory.requested_size())); - - EXPECT_EQ(0, mprotect(shared_memory.memory(), shared_memory.requested_size(), - PROT_READ | PROT_EXEC)); -} - -// Android supports a different permission model than POSIX for its "ashmem" -// shared memory implementation. So the tests about file permissions are not -// included on Android. -#if !defined(OS_ANDROID) - -// Set a umask and restore the old mask on destruction. -class ScopedUmaskSetter { - public: - explicit ScopedUmaskSetter(mode_t target_mask) { - old_umask_ = umask(target_mask); - } - ~ScopedUmaskSetter() { umask(old_umask_); } - private: - mode_t old_umask_; - DISALLOW_IMPLICIT_CONSTRUCTORS(ScopedUmaskSetter); -}; - -// Create a shared memory object, check its permissions. -TEST(SharedMemoryTest, FilePermissionsAnonymous) { - const uint32 kTestSize = 1 << 8; - - SharedMemory shared_memory; - SharedMemoryCreateOptions options; - options.size = kTestSize; - // Set a file mode creation mask that gives all permissions. - ScopedUmaskSetter permissive_mask(S_IWGRP | S_IWOTH); - - EXPECT_TRUE(shared_memory.Create(options)); - - int shm_fd = shared_memory.handle().fd; - struct stat shm_stat; - EXPECT_EQ(0, fstat(shm_fd, &shm_stat)); - // Neither the group, nor others should be able to read the shared memory - // file. - EXPECT_FALSE(shm_stat.st_mode & S_IRWXO); - EXPECT_FALSE(shm_stat.st_mode & S_IRWXG); -} - -// Create a shared memory object, check its permissions. -TEST(SharedMemoryTest, FilePermissionsNamed) { - const uint32 kTestSize = 1 << 8; - - SharedMemory shared_memory; - SharedMemoryCreateOptions options; - options.size = kTestSize; - std::string shared_mem_name = "shared_perm_test-" + IntToString(getpid()) + - "-" + Uint64ToString(RandUint64()); - options.name = &shared_mem_name; - // Set a file mode creation mask that gives all permissions. - ScopedUmaskSetter permissive_mask(S_IWGRP | S_IWOTH); - - EXPECT_TRUE(shared_memory.Create(options)); - // Clean-up the backing file name immediately, we don't need it. - EXPECT_TRUE(shared_memory.Delete(shared_mem_name)); - - int shm_fd = shared_memory.handle().fd; - struct stat shm_stat; - EXPECT_EQ(0, fstat(shm_fd, &shm_stat)); - // Neither the group, nor others should have been able to open the shared - // memory file while its name existed. - EXPECT_FALSE(shm_stat.st_mode & S_IRWXO); - EXPECT_FALSE(shm_stat.st_mode & S_IRWXG); -} -#endif // !defined(OS_ANDROID) - -#endif // defined(OS_POSIX) - -// Map() will return addresses which are aligned to the platform page size, this -// varies from platform to platform though. Since we'd like to advertise a -// minimum alignment that callers can count on, test for it here. -TEST(SharedMemoryTest, MapMinimumAlignment) { - static const int kDataSize = 8192; - - SharedMemory shared_memory; - ASSERT_TRUE(shared_memory.CreateAndMapAnonymous(kDataSize)); - EXPECT_EQ(0U, reinterpret_cast( - shared_memory.memory()) & (SharedMemory::MAP_MINIMUM_ALIGNMENT - 1)); - shared_memory.Close(); -} - -#if !defined(OS_IOS) // iOS does not allow multiple processes. - -// On POSIX it is especially important we test shmem across processes, -// not just across threads. But the test is enabled on all platforms. -class SharedMemoryProcessTest : public MultiProcessTest { - public: - - static void CleanUp() { - SharedMemory memory; - memory.Delete(s_test_name_); - } - - static int TaskTestMain() { - int errors = 0; -#if defined(OS_MACOSX) - mac::ScopedNSAutoreleasePool pool; -#endif - const uint32 kDataSize = 1024; - SharedMemory memory; - bool rv = memory.CreateNamed(s_test_name_, true, kDataSize); - EXPECT_TRUE(rv); - if (rv != true) - errors++; - rv = memory.Map(kDataSize); - EXPECT_TRUE(rv); - if (rv != true) - errors++; - int *ptr = static_cast(memory.memory()); - - for (int idx = 0; idx < 20; idx++) { - memory.Lock(); - int i = (1 << 16) + idx; - *ptr = i; - PlatformThread::Sleep(TimeDelta::FromMilliseconds(10)); - if (*ptr != i) - errors++; - memory.Unlock(); - } - - memory.Close(); - return errors; - } - - private: - static const char* const s_test_name_; -}; - -const char* const SharedMemoryProcessTest::s_test_name_ = "MPMem"; - -TEST_F(SharedMemoryProcessTest, Tasks) { - SharedMemoryProcessTest::CleanUp(); - - ProcessHandle handles[kNumTasks]; - for (int index = 0; index < kNumTasks; ++index) { - handles[index] = SpawnChild("SharedMemoryTestMain", false); - ASSERT_TRUE(handles[index]); - } - - int exit_code = 0; - for (int index = 0; index < kNumTasks; ++index) { - EXPECT_TRUE(WaitForExitCode(handles[index], &exit_code)); - EXPECT_EQ(0, exit_code); - } - - SharedMemoryProcessTest::CleanUp(); -} - -MULTIPROCESS_TEST_MAIN(SharedMemoryTestMain) { - return SharedMemoryProcessTest::TaskTestMain(); -} - -#endif // !OS_IOS - -} // namespace base diff --git a/base/memory/shared_memory_win.cc b/base/memory/shared_memory_win.cc deleted file mode 100644 index 42e0b046b9..0000000000 --- a/base/memory/shared_memory_win.cc +++ /dev/null @@ -1,260 +0,0 @@ -// Copyright (c) 2011 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "base/memory/shared_memory.h" - -#include "base/logging.h" -#include "base/strings/utf_string_conversions.h" - -namespace { - -// Returns the length of the memory section starting at the supplied address. -size_t GetMemorySectionSize(void* address) { - MEMORY_BASIC_INFORMATION memory_info; - if (!::VirtualQuery(address, &memory_info, sizeof(memory_info))) - return 0; - return memory_info.RegionSize - (static_cast(address) - - static_cast(memory_info.AllocationBase)); -} - -} // namespace. - -namespace base { - -SharedMemory::SharedMemory() - : mapped_file_(NULL), - memory_(NULL), - read_only_(false), - mapped_size_(0), - requested_size_(0), - lock_(NULL) { -} - -SharedMemory::SharedMemory(const std::wstring& name) - : mapped_file_(NULL), - memory_(NULL), - read_only_(false), - requested_size_(0), - mapped_size_(0), - lock_(NULL), - name_(name) { -} - -SharedMemory::SharedMemory(SharedMemoryHandle handle, bool read_only) - : mapped_file_(handle), - memory_(NULL), - read_only_(read_only), - requested_size_(0), - mapped_size_(0), - lock_(NULL) { -} - -SharedMemory::SharedMemory(SharedMemoryHandle handle, bool read_only, - ProcessHandle process) - : mapped_file_(NULL), - memory_(NULL), - read_only_(read_only), - requested_size_(0), - mapped_size_(0), - lock_(NULL) { - ::DuplicateHandle(process, handle, - GetCurrentProcess(), &mapped_file_, - STANDARD_RIGHTS_REQUIRED | - (read_only_ ? FILE_MAP_READ : FILE_MAP_ALL_ACCESS), - FALSE, 0); -} - -SharedMemory::~SharedMemory() { - Close(); - if (lock_ != NULL) - CloseHandle(lock_); -} - -// static -bool SharedMemory::IsHandleValid(const SharedMemoryHandle& handle) { - return handle != NULL; -} - -// static -SharedMemoryHandle SharedMemory::NULLHandle() { - return NULL; -} - -// static -void SharedMemory::CloseHandle(const SharedMemoryHandle& handle) { - DCHECK(handle != NULL); - ::CloseHandle(handle); -} - -// static -size_t SharedMemory::GetHandleLimit() { - // Rounded down from value reported here: - // http://blogs.technet.com/b/markrussinovich/archive/2009/09/29/3283844.aspx - return static_cast(1 << 23); -} - -bool SharedMemory::CreateAndMapAnonymous(size_t size) { - return CreateAnonymous(size) && Map(size); -} - -bool SharedMemory::Create(const SharedMemoryCreateOptions& options) { - // TODO(bsy,sehr): crbug.com/210609 NaCl forces us to round up 64k here, - // wasting 32k per mapping on average. - static const size_t kSectionMask = 65536 - 1; - DCHECK(!options.executable); - DCHECK(!mapped_file_); - if (options.size == 0) - return false; - - // Check maximum accounting for overflow. - if (options.size > - static_cast(std::numeric_limits::max()) - kSectionMask) - return false; - - size_t rounded_size = (options.size + kSectionMask) & ~kSectionMask; - name_ = ASCIIToWide(options.name == NULL ? "" : *options.name); - mapped_file_ = CreateFileMapping(INVALID_HANDLE_VALUE, NULL, - PAGE_READWRITE, 0, static_cast(rounded_size), - name_.empty() ? NULL : name_.c_str()); - if (!mapped_file_) - return false; - - requested_size_ = options.size; - - // Check if the shared memory pre-exists. - if (GetLastError() == ERROR_ALREADY_EXISTS) { - // If the file already existed, set requested_size_ to 0 to show that - // we don't know the size. - requested_size_ = 0; - if (!options.open_existing) { - Close(); - return false; - } - } - - return true; -} - -bool SharedMemory::Delete(const std::string& name) { - // intentionally empty -- there is nothing for us to do on Windows. - return true; -} - -bool SharedMemory::Open(const std::string& name, bool read_only) { - DCHECK(!mapped_file_); - - name_ = ASCIIToWide(name); - read_only_ = read_only; - mapped_file_ = OpenFileMapping( - read_only_ ? FILE_MAP_READ : FILE_MAP_ALL_ACCESS, false, - name_.empty() ? NULL : name_.c_str()); - if (mapped_file_ != NULL) { - // Note: size_ is not set in this case. - return true; - } - return false; -} - -bool SharedMemory::MapAt(off_t offset, size_t bytes) { - if (mapped_file_ == NULL) - return false; - - if (bytes > static_cast(std::numeric_limits::max())) - return false; - - memory_ = MapViewOfFile(mapped_file_, - read_only_ ? FILE_MAP_READ : FILE_MAP_ALL_ACCESS, - static_cast(offset) >> 32, - static_cast(offset), - bytes); - if (memory_ != NULL) { - DCHECK_EQ(0U, reinterpret_cast(memory_) & - (SharedMemory::MAP_MINIMUM_ALIGNMENT - 1)); - mapped_size_ = GetMemorySectionSize(memory_); - return true; - } - return false; -} - -bool SharedMemory::Unmap() { - if (memory_ == NULL) - return false; - - UnmapViewOfFile(memory_); - memory_ = NULL; - return true; -} - -bool SharedMemory::ShareToProcessCommon(ProcessHandle process, - SharedMemoryHandle *new_handle, - bool close_self) { - *new_handle = 0; - DWORD access = STANDARD_RIGHTS_REQUIRED | FILE_MAP_READ; - DWORD options = 0; - HANDLE mapped_file = mapped_file_; - HANDLE result; - if (!read_only_) - access |= FILE_MAP_WRITE; - if (close_self) { - // DUPLICATE_CLOSE_SOURCE causes DuplicateHandle to close mapped_file. - options = DUPLICATE_CLOSE_SOURCE; - mapped_file_ = NULL; - Unmap(); - } - - if (process == GetCurrentProcess() && close_self) { - *new_handle = mapped_file; - return true; - } - - if (!DuplicateHandle(GetCurrentProcess(), mapped_file, process, - &result, access, FALSE, options)) - return false; - *new_handle = result; - return true; -} - - -void SharedMemory::Close() { - if (memory_ != NULL) { - UnmapViewOfFile(memory_); - memory_ = NULL; - } - - if (mapped_file_ != NULL) { - CloseHandle(mapped_file_); - mapped_file_ = NULL; - } -} - -void SharedMemory::Lock() { - Lock(INFINITE, NULL); -} - -bool SharedMemory::Lock(uint32 timeout_ms, SECURITY_ATTRIBUTES* sec_attr) { - if (lock_ == NULL) { - std::wstring name = name_; - name.append(L"lock"); - lock_ = CreateMutex(sec_attr, FALSE, name.c_str()); - if (lock_ == NULL) { - DPLOG(ERROR) << "Could not create mutex."; - return false; // there is nothing good we can do here. - } - } - DWORD result = WaitForSingleObject(lock_, timeout_ms); - - // Return false for WAIT_ABANDONED, WAIT_TIMEOUT or WAIT_FAILED. - return (result == WAIT_OBJECT_0); -} - -void SharedMemory::Unlock() { - DCHECK(lock_ != NULL); - ReleaseMutex(lock_); -} - -SharedMemoryHandle SharedMemory::handle() const { - return mapped_file_; -} - -} // namespace base diff --git a/base/memory/singleton.cc b/base/memory/singleton.cc deleted file mode 100644 index ee5e58d005..0000000000 --- a/base/memory/singleton.cc +++ /dev/null @@ -1,31 +0,0 @@ -// Copyright (c) 2011 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "base/memory/singleton.h" -#include "base/threading/platform_thread.h" - -namespace base { -namespace internal { - -subtle::AtomicWord WaitForInstance(subtle::AtomicWord* instance) { - // Handle the race. Another thread beat us and either: - // - Has the object in BeingCreated state - // - Already has the object created... - // We know value != NULL. It could be kBeingCreatedMarker, or a valid ptr. - // Unless your constructor can be very time consuming, it is very unlikely - // to hit this race. When it does, we just spin and yield the thread until - // the object has been created. - subtle::AtomicWord value; - while (true) { - value = subtle::NoBarrier_Load(instance); - if (value != kBeingCreatedMarker) - break; - PlatformThread::YieldCurrentThread(); - } - return value; -} - -} // namespace internal -} // namespace base - diff --git a/base/memory/singleton.h b/base/memory/singleton.h deleted file mode 100644 index 0d4fc8990c..0000000000 --- a/base/memory/singleton.h +++ /dev/null @@ -1,285 +0,0 @@ -// Copyright (c) 2011 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -// PLEASE READ: Do you really need a singleton? -// -// Singletons make it hard to determine the lifetime of an object, which can -// lead to buggy code and spurious crashes. -// -// Instead of adding another singleton into the mix, try to identify either: -// a) An existing singleton that can manage your object's lifetime -// b) Locations where you can deterministically create the object and pass -// into other objects -// -// If you absolutely need a singleton, please keep them as trivial as possible -// and ideally a leaf dependency. Singletons get problematic when they attempt -// to do too much in their destructor or have circular dependencies. - -#ifndef BASE_MEMORY_SINGLETON_H_ -#define BASE_MEMORY_SINGLETON_H_ - -#include "base/at_exit.h" -#include "base/atomicops.h" -#include "base/base_export.h" -#include "base/memory/aligned_memory.h" -#include "base/third_party/dynamic_annotations/dynamic_annotations.h" -#include "base/threading/thread_restrictions.h" - -namespace base { -namespace internal { - -// Our AtomicWord doubles as a spinlock, where a value of -// kBeingCreatedMarker means the spinlock is being held for creation. -static const subtle::AtomicWord kBeingCreatedMarker = 1; - -// We pull out some of the functionality into a non-templated function, so that -// we can implement the more complicated pieces out of line in the .cc file. -BASE_EXPORT subtle::AtomicWord WaitForInstance(subtle::AtomicWord* instance); - -} // namespace internal -} // namespace base - -// TODO(joth): Move more of this file into namespace base - -// Default traits for Singleton. Calls operator new and operator delete on -// the object. Registers automatic deletion at process exit. -// Overload if you need arguments or another memory allocation function. -template -struct DefaultSingletonTraits { - // Allocates the object. - static Type* New() { - // The parenthesis is very important here; it forces POD type - // initialization. - return new Type(); - } - - // Destroys the object. - static void Delete(Type* x) { - delete x; - } - - // Set to true to automatically register deletion of the object on process - // exit. See below for the required call that makes this happen. - static const bool kRegisterAtExit = true; - - // Set to false to disallow access on a non-joinable thread. This is - // different from kRegisterAtExit because StaticMemorySingletonTraits allows - // access on non-joinable threads, and gracefully handles this. - static const bool kAllowedToAccessOnNonjoinableThread = false; -}; - - -// Alternate traits for use with the Singleton. Identical to -// DefaultSingletonTraits except that the Singleton will not be cleaned up -// at exit. -template -struct LeakySingletonTraits : public DefaultSingletonTraits { - static const bool kRegisterAtExit = false; - static const bool kAllowedToAccessOnNonjoinableThread = true; -}; - - -// Alternate traits for use with the Singleton. Allocates memory -// for the singleton instance from a static buffer. The singleton will -// be cleaned up at exit, but can't be revived after destruction unless -// the Resurrect() method is called. -// -// This is useful for a certain category of things, notably logging and -// tracing, where the singleton instance is of a type carefully constructed to -// be safe to access post-destruction. -// In logging and tracing you'll typically get stray calls at odd times, like -// during static destruction, thread teardown and the like, and there's a -// termination race on the heap-based singleton - e.g. if one thread calls -// get(), but then another thread initiates AtExit processing, the first thread -// may call into an object residing in unallocated memory. If the instance is -// allocated from the data segment, then this is survivable. -// -// The destructor is to deallocate system resources, in this case to unregister -// a callback the system will invoke when logging levels change. Note that -// this is also used in e.g. Chrome Frame, where you have to allow for the -// possibility of loading briefly into someone else's process space, and -// so leaking is not an option, as that would sabotage the state of your host -// process once you've unloaded. -template -struct StaticMemorySingletonTraits { - // WARNING: User has to deal with get() in the singleton class - // this is traits for returning NULL. - static Type* New() { - // Only constructs once and returns pointer; otherwise returns NULL. - if (base::subtle::NoBarrier_AtomicExchange(&dead_, 1)) - return NULL; - - return new(buffer_.void_data()) Type(); - } - - static void Delete(Type* p) { - if (p != NULL) - p->Type::~Type(); - } - - static const bool kRegisterAtExit = true; - static const bool kAllowedToAccessOnNonjoinableThread = true; - - // Exposed for unittesting. - static void Resurrect() { - base::subtle::NoBarrier_Store(&dead_, 0); - } - - private: - static base::AlignedMemory buffer_; - // Signal the object was already deleted, so it is not revived. - static base::subtle::Atomic32 dead_; -}; - -template base::AlignedMemory - StaticMemorySingletonTraits::buffer_; -template base::subtle::Atomic32 - StaticMemorySingletonTraits::dead_ = 0; - -// The Singleton class manages a single -// instance of Type which will be created on first use and will be destroyed at -// normal process exit). The Trait::Delete function will not be called on -// abnormal process exit. -// -// DifferentiatingType is used as a key to differentiate two different -// singletons having the same memory allocation functions but serving a -// different purpose. This is mainly used for Locks serving different purposes. -// -// Example usage: -// -// In your header: -// template struct DefaultSingletonTraits; -// class FooClass { -// public: -// static FooClass* GetInstance(); <-- See comment below on this. -// void Bar() { ... } -// private: -// FooClass() { ... } -// friend struct DefaultSingletonTraits; -// -// DISALLOW_COPY_AND_ASSIGN(FooClass); -// }; -// -// In your source file: -// #include "base/memory/singleton.h" -// FooClass* FooClass::GetInstance() { -// return Singleton::get(); -// } -// -// And to call methods on FooClass: -// FooClass::GetInstance()->Bar(); -// -// NOTE: The method accessing Singleton::get() has to be named as GetInstance -// and it is important that FooClass::GetInstance() is not inlined in the -// header. This makes sure that when source files from multiple targets include -// this header they don't end up with different copies of the inlined code -// creating multiple copies of the singleton. -// -// Singleton<> has no non-static members and doesn't need to actually be -// instantiated. -// -// This class is itself thread-safe. The underlying Type must of course be -// thread-safe if you want to use it concurrently. Two parameters may be tuned -// depending on the user's requirements. -// -// Glossary: -// RAE = kRegisterAtExit -// -// On every platform, if Traits::RAE is true, the singleton will be destroyed at -// process exit. More precisely it uses base::AtExitManager which requires an -// object of this type to be instantiated. AtExitManager mimics the semantics -// of atexit() such as LIFO order but under Windows is safer to call. For more -// information see at_exit.h. -// -// If Traits::RAE is false, the singleton will not be freed at process exit, -// thus the singleton will be leaked if it is ever accessed. Traits::RAE -// shouldn't be false unless absolutely necessary. Remember that the heap where -// the object is allocated may be destroyed by the CRT anyway. -// -// Caveats: -// (a) Every call to get(), operator->() and operator*() incurs some overhead -// (16ns on my P4/2.8GHz) to check whether the object has already been -// initialized. You may wish to cache the result of get(); it will not -// change. -// -// (b) Your factory function must never throw an exception. This class is not -// exception-safe. -// -template , - typename DifferentiatingType = Type> -class Singleton { - private: - // Classes using the Singleton pattern should declare a GetInstance() - // method and call Singleton::get() from within that. - friend Type* Type::GetInstance(); - - // Allow TraceLog tests to test tracing after OnExit. - friend class DeleteTraceLogForTesting; - - // This class is safe to be constructed and copy-constructed since it has no - // member. - - // Return a pointer to the one true instance of the class. - static Type* get() { -#ifndef NDEBUG - // Avoid making TLS lookup on release builds. - if (!Traits::kAllowedToAccessOnNonjoinableThread) - base::ThreadRestrictions::AssertSingletonAllowed(); -#endif - - base::subtle::AtomicWord value = base::subtle::NoBarrier_Load(&instance_); - if (value != 0 && value != base::internal::kBeingCreatedMarker) { - // See the corresponding HAPPENS_BEFORE below. - ANNOTATE_HAPPENS_AFTER(&instance_); - return reinterpret_cast(value); - } - - // Object isn't created yet, maybe we will get to create it, let's try... - if (base::subtle::Acquire_CompareAndSwap( - &instance_, 0, base::internal::kBeingCreatedMarker) == 0) { - // instance_ was NULL and is now kBeingCreatedMarker. Only one thread - // will ever get here. Threads might be spinning on us, and they will - // stop right after we do this store. - Type* newval = Traits::New(); - - // This annotation helps race detectors recognize correct lock-less - // synchronization between different threads calling get(). - // See the corresponding HAPPENS_AFTER below and above. - ANNOTATE_HAPPENS_BEFORE(&instance_); - base::subtle::Release_Store( - &instance_, reinterpret_cast(newval)); - - if (newval != NULL && Traits::kRegisterAtExit) - base::AtExitManager::RegisterCallback(OnExit, NULL); - - return newval; - } - - // We hit a race. Wait for the other thread to complete it. - value = base::internal::WaitForInstance(&instance_); - - // See the corresponding HAPPENS_BEFORE above. - ANNOTATE_HAPPENS_AFTER(&instance_); - return reinterpret_cast(value); - } - - // Adapter function for use with AtExit(). This should be called single - // threaded, so don't use atomic operations. - // Calling OnExit while singleton is in use by other threads is a mistake. - static void OnExit(void* /*unused*/) { - // AtExit should only ever be register after the singleton instance was - // created. We should only ever get here with a valid instance_ pointer. - Traits::Delete( - reinterpret_cast(base::subtle::NoBarrier_Load(&instance_))); - instance_ = 0; - } - static base::subtle::AtomicWord instance_; -}; - -template -base::subtle::AtomicWord Singleton:: - instance_ = 0; - -#endif // BASE_MEMORY_SINGLETON_H_ diff --git a/base/memory/singleton_objc.h b/base/memory/singleton_objc.h deleted file mode 100644 index 6df3f7757e..0000000000 --- a/base/memory/singleton_objc.h +++ /dev/null @@ -1,60 +0,0 @@ -// Copyright (c) 2011 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -// Support for using the Singleton pattern with Objective-C objects. A -// SingletonObjC is the same as a Singleton, except the default traits are -// appropriate for Objective-C objects. A typical Objective-C object of type -// NSExampleType can be maintained as a singleton and accessed with: -// -// NSExampleType* exampleSingleton = SingletonObjC::get(); -// -// The first time this is used, it will create exampleSingleton as the result -// of [[NSExampleType alloc] init]. Subsequent calls will return the same -// NSExampleType* object. The object will be released by calling -// -[NSExampleType release] when Singleton's atexit routines run -// (see singleton.h). -// -// For Objective-C objects initialized through means other than the -// no-parameter -init selector, DefaultSingletonObjCTraits may be extended -// as needed: -// -// struct FooSingletonTraits : public DefaultSingletonObjCTraits { -// static Foo* New() { -// return [[Foo alloc] initWithName:@"selecty"]; -// } -// }; -// ... -// Foo* widgetSingleton = SingletonObjC::get(); - -#ifndef BASE_MEMORY_SINGLETON_OBJC_H_ -#define BASE_MEMORY_SINGLETON_OBJC_H_ - -#import -#include "base/memory/singleton.h" - -// Singleton traits usable to manage traditional Objective-C objects, which -// are instantiated by sending |alloc| and |init| messages, and are deallocated -// in a memory-managed environment when their retain counts drop to 0 by -// sending |release| messages. -template -struct DefaultSingletonObjCTraits : public DefaultSingletonTraits { - static Type* New() { - return [[Type alloc] init]; - } - - static void Delete(Type* object) { - [object release]; - } -}; - -// Exactly like Singleton, but without the DefaultSingletonObjCTraits as the -// default trait class. This makes it straightforward for Objective-C++ code -// to hold Objective-C objects as singletons. -template, - typename DifferentiatingType = Type> -class SingletonObjC : public Singleton { -}; - -#endif // BASE_MEMORY_SINGLETON_OBJC_H_ diff --git a/base/memory/singleton_unittest.cc b/base/memory/singleton_unittest.cc deleted file mode 100644 index 5d059043af..0000000000 --- a/base/memory/singleton_unittest.cc +++ /dev/null @@ -1,288 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "base/at_exit.h" -#include "base/memory/singleton.h" -#include "base/path_service.h" -#include "testing/gtest/include/gtest/gtest.h" - -namespace { - -COMPILE_ASSERT(DefaultSingletonTraits::kRegisterAtExit == true, a); - -typedef void (*CallbackFunc)(); - -class IntSingleton { - public: - static IntSingleton* GetInstance() { - return Singleton::get(); - } - - int value_; -}; - -class Init5Singleton { - public: - struct Trait; - - static Init5Singleton* GetInstance() { - return Singleton::get(); - } - - int value_; -}; - -struct Init5Singleton::Trait : public DefaultSingletonTraits { - static Init5Singleton* New() { - Init5Singleton* instance = new Init5Singleton(); - instance->value_ = 5; - return instance; - } -}; - -int* SingletonInt() { - return &IntSingleton::GetInstance()->value_; -} - -int* SingletonInt5() { - return &Init5Singleton::GetInstance()->value_; -} - -template -struct CallbackTrait : public DefaultSingletonTraits { - static void Delete(Type* instance) { - if (instance->callback_) - (instance->callback_)(); - DefaultSingletonTraits::Delete(instance); - } -}; - -class CallbackSingleton { - public: - CallbackSingleton() : callback_(NULL) { } - CallbackFunc callback_; -}; - -class CallbackSingletonWithNoLeakTrait : public CallbackSingleton { - public: - struct Trait : public CallbackTrait { }; - - CallbackSingletonWithNoLeakTrait() : CallbackSingleton() { } - - static CallbackSingletonWithNoLeakTrait* GetInstance() { - return Singleton::get(); - } -}; - -class CallbackSingletonWithLeakTrait : public CallbackSingleton { - public: - struct Trait : public CallbackTrait { - static const bool kRegisterAtExit = false; - }; - - CallbackSingletonWithLeakTrait() : CallbackSingleton() { } - - static CallbackSingletonWithLeakTrait* GetInstance() { - return Singleton::get(); - } -}; - -class CallbackSingletonWithStaticTrait : public CallbackSingleton { - public: - struct Trait; - - CallbackSingletonWithStaticTrait() : CallbackSingleton() { } - - static CallbackSingletonWithStaticTrait* GetInstance() { - return Singleton::get(); - } -}; - -struct CallbackSingletonWithStaticTrait::Trait - : public StaticMemorySingletonTraits { - static void Delete(CallbackSingletonWithStaticTrait* instance) { - if (instance->callback_) - (instance->callback_)(); - StaticMemorySingletonTraits::Delete( - instance); - } -}; - -template -class AlignedTestSingleton { - public: - AlignedTestSingleton() {} - ~AlignedTestSingleton() {} - static AlignedTestSingleton* GetInstance() { - return Singleton >::get(); - } - - Type type_; -}; - - -void SingletonNoLeak(CallbackFunc CallOnQuit) { - CallbackSingletonWithNoLeakTrait::GetInstance()->callback_ = CallOnQuit; -} - -void SingletonLeak(CallbackFunc CallOnQuit) { - CallbackSingletonWithLeakTrait::GetInstance()->callback_ = CallOnQuit; -} - -CallbackFunc* GetLeakySingleton() { - return &CallbackSingletonWithLeakTrait::GetInstance()->callback_; -} - -void DeleteLeakySingleton() { - DefaultSingletonTraits::Delete( - CallbackSingletonWithLeakTrait::GetInstance()); -} - -void SingletonStatic(CallbackFunc CallOnQuit) { - CallbackSingletonWithStaticTrait::GetInstance()->callback_ = CallOnQuit; -} - -CallbackFunc* GetStaticSingleton() { - return &CallbackSingletonWithStaticTrait::GetInstance()->callback_; -} - -} // namespace - -class SingletonTest : public testing::Test { - public: - SingletonTest() {} - - virtual void SetUp() OVERRIDE { - non_leak_called_ = false; - leaky_called_ = false; - static_called_ = false; - } - - protected: - void VerifiesCallbacks() { - EXPECT_TRUE(non_leak_called_); - EXPECT_FALSE(leaky_called_); - EXPECT_TRUE(static_called_); - non_leak_called_ = false; - leaky_called_ = false; - static_called_ = false; - } - - void VerifiesCallbacksNotCalled() { - EXPECT_FALSE(non_leak_called_); - EXPECT_FALSE(leaky_called_); - EXPECT_FALSE(static_called_); - non_leak_called_ = false; - leaky_called_ = false; - static_called_ = false; - } - - static void CallbackNoLeak() { - non_leak_called_ = true; - } - - static void CallbackLeak() { - leaky_called_ = true; - } - - static void CallbackStatic() { - static_called_ = true; - } - - private: - static bool non_leak_called_; - static bool leaky_called_; - static bool static_called_; -}; - -bool SingletonTest::non_leak_called_ = false; -bool SingletonTest::leaky_called_ = false; -bool SingletonTest::static_called_ = false; - -TEST_F(SingletonTest, Basic) { - int* singleton_int; - int* singleton_int_5; - CallbackFunc* leaky_singleton; - CallbackFunc* static_singleton; - - { - base::ShadowingAtExitManager sem; - { - singleton_int = SingletonInt(); - } - // Ensure POD type initialization. - EXPECT_EQ(*singleton_int, 0); - *singleton_int = 1; - - EXPECT_EQ(singleton_int, SingletonInt()); - EXPECT_EQ(*singleton_int, 1); - - { - singleton_int_5 = SingletonInt5(); - } - // Is default initialized to 5. - EXPECT_EQ(*singleton_int_5, 5); - - SingletonNoLeak(&CallbackNoLeak); - SingletonLeak(&CallbackLeak); - SingletonStatic(&CallbackStatic); - static_singleton = GetStaticSingleton(); - leaky_singleton = GetLeakySingleton(); - EXPECT_TRUE(leaky_singleton); - } - - // Verify that only the expected callback has been called. - VerifiesCallbacks(); - // Delete the leaky singleton. - DeleteLeakySingleton(); - - // The static singleton can't be acquired post-atexit. - EXPECT_EQ(NULL, GetStaticSingleton()); - - { - base::ShadowingAtExitManager sem; - // Verifiy that the variables were reset. - { - singleton_int = SingletonInt(); - EXPECT_EQ(*singleton_int, 0); - } - { - singleton_int_5 = SingletonInt5(); - EXPECT_EQ(*singleton_int_5, 5); - } - { - // Resurrect the static singleton, and assert that it - // still points to the same (static) memory. - CallbackSingletonWithStaticTrait::Trait::Resurrect(); - EXPECT_EQ(GetStaticSingleton(), static_singleton); - } - } - // The leaky singleton shouldn't leak since SingletonLeak has not been called. - VerifiesCallbacksNotCalled(); -} - -#define EXPECT_ALIGNED(ptr, align) \ - EXPECT_EQ(0u, reinterpret_cast(ptr) & (align - 1)) - -TEST_F(SingletonTest, Alignment) { - using base::AlignedMemory; - - // Create some static singletons with increasing sizes and alignment - // requirements. By ordering this way, the linker will need to do some work to - // ensure proper alignment of the static data. - AlignedTestSingleton* align4 = - AlignedTestSingleton::GetInstance(); - AlignedTestSingleton >* align32 = - AlignedTestSingleton >::GetInstance(); - AlignedTestSingleton >* align128 = - AlignedTestSingleton >::GetInstance(); - AlignedTestSingleton >* align4096 = - AlignedTestSingleton >::GetInstance(); - - EXPECT_ALIGNED(align4, 4); - EXPECT_ALIGNED(align32, 32); - EXPECT_ALIGNED(align128, 128); - EXPECT_ALIGNED(align4096, 4096); -} diff --git a/base/memory/weak_ptr.cc b/base/memory/weak_ptr.cc deleted file mode 100644 index d9ce86ad18..0000000000 --- a/base/memory/weak_ptr.cc +++ /dev/null @@ -1,77 +0,0 @@ -// Copyright (c) 2011 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "base/memory/weak_ptr.h" - -namespace base { -namespace internal { - -WeakReference::Flag::Flag() : is_valid_(true) { - // Flags only become bound when checked for validity, or invalidated, - // so that we can check that later validity/invalidation operations on - // the same Flag take place on the same sequenced thread. - sequence_checker_.DetachFromSequence(); -} - -void WeakReference::Flag::Invalidate() { - // The flag being invalidated with a single ref implies that there are no - // weak pointers in existence. Allow deletion on other thread in this case. - DCHECK(sequence_checker_.CalledOnValidSequencedThread() || HasOneRef()) - << "WeakPtrs must be invalidated on the same sequenced thread."; - is_valid_ = false; -} - -bool WeakReference::Flag::IsValid() const { - DCHECK(sequence_checker_.CalledOnValidSequencedThread()) - << "WeakPtrs must be checked on the same sequenced thread."; - return is_valid_; -} - -WeakReference::Flag::~Flag() { -} - -WeakReference::WeakReference() { -} - -WeakReference::WeakReference(const Flag* flag) : flag_(flag) { -} - -WeakReference::~WeakReference() { -} - -bool WeakReference::is_valid() const { return flag_.get() && flag_->IsValid(); } - -WeakReferenceOwner::WeakReferenceOwner() { -} - -WeakReferenceOwner::~WeakReferenceOwner() { - Invalidate(); -} - -WeakReference WeakReferenceOwner::GetRef() const { - // If we hold the last reference to the Flag then create a new one. - if (!HasRefs()) - flag_ = new WeakReference::Flag(); - - return WeakReference(flag_.get()); -} - -void WeakReferenceOwner::Invalidate() { - if (flag_.get()) { - flag_->Invalidate(); - flag_ = NULL; - } -} - -WeakPtrBase::WeakPtrBase() { -} - -WeakPtrBase::~WeakPtrBase() { -} - -WeakPtrBase::WeakPtrBase(const WeakReference& ref) : ref_(ref) { -} - -} // namespace internal -} // namespace base diff --git a/base/memory/weak_ptr.h b/base/memory/weak_ptr.h deleted file mode 100644 index 1675889e22..0000000000 --- a/base/memory/weak_ptr.h +++ /dev/null @@ -1,338 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -// Weak pointers are pointers to an object that do not affect its lifetime, -// and which may be invalidated (i.e. reset to NULL) by the object, or its -// owner, at any time, most commonly when the object is about to be deleted. - -// Weak pointers are useful when an object needs to be accessed safely by one -// or more objects other than its owner, and those callers can cope with the -// object vanishing and e.g. tasks posted to it being silently dropped. -// Reference-counting such an object would complicate the ownership graph and -// make it harder to reason about the object's lifetime. - -// EXAMPLE: -// -// class Controller { -// public: -// void SpawnWorker() { Worker::StartNew(weak_factory_.GetWeakPtr()); } -// void WorkComplete(const Result& result) { ... } -// private: -// // Member variables should appear before the WeakPtrFactory, to ensure -// // that any WeakPtrs to Controller are invalidated before its members -// // variable's destructors are executed, rendering them invalid. -// WeakPtrFactory weak_factory_; -// }; -// -// class Worker { -// public: -// static void StartNew(const WeakPtr& controller) { -// Worker* worker = new Worker(controller); -// // Kick off asynchronous processing... -// } -// private: -// Worker(const WeakPtr& controller) -// : controller_(controller) {} -// void DidCompleteAsynchronousProcessing(const Result& result) { -// if (controller_) -// controller_->WorkComplete(result); -// } -// WeakPtr controller_; -// }; -// -// With this implementation a caller may use SpawnWorker() to dispatch multiple -// Workers and subsequently delete the Controller, without waiting for all -// Workers to have completed. - -// ------------------------- IMPORTANT: Thread-safety ------------------------- - -// Weak pointers may be passed safely between threads, but must always be -// dereferenced and invalidated on the same thread otherwise checking the -// pointer would be racey. -// -// To ensure correct use, the first time a WeakPtr issued by a WeakPtrFactory -// is dereferenced, the factory and its WeakPtrs become bound to the calling -// thread, and cannot be dereferenced or invalidated on any other thread. Bound -// WeakPtrs can still be handed off to other threads, e.g. to use to post tasks -// back to object on the bound thread. -// -// Invalidating the factory's WeakPtrs un-binds it from the thread, allowing it -// to be passed for a different thread to use or delete it. - -#ifndef BASE_MEMORY_WEAK_PTR_H_ -#define BASE_MEMORY_WEAK_PTR_H_ - -#include "base/basictypes.h" -#include "base/base_export.h" -#include "base/logging.h" -#include "base/memory/ref_counted.h" -#include "base/sequence_checker.h" -#include "base/template_util.h" - -namespace base { - -template class SupportsWeakPtr; -template class WeakPtr; - -namespace internal { -// These classes are part of the WeakPtr implementation. -// DO NOT USE THESE CLASSES DIRECTLY YOURSELF. - -class BASE_EXPORT WeakReference { - public: - // Although Flag is bound to a specific thread, it may be deleted from another - // via base::WeakPtr::~WeakPtr(). - class Flag : public RefCountedThreadSafe { - public: - Flag(); - - void Invalidate(); - bool IsValid() const; - - private: - friend class base::RefCountedThreadSafe; - - ~Flag(); - - SequenceChecker sequence_checker_; - bool is_valid_; - }; - - WeakReference(); - explicit WeakReference(const Flag* flag); - ~WeakReference(); - - bool is_valid() const; - - private: - scoped_refptr flag_; -}; - -class BASE_EXPORT WeakReferenceOwner { - public: - WeakReferenceOwner(); - ~WeakReferenceOwner(); - - WeakReference GetRef() const; - - bool HasRefs() const { - return flag_.get() && !flag_->HasOneRef(); - } - - void Invalidate(); - - private: - mutable scoped_refptr flag_; -}; - -// This class simplifies the implementation of WeakPtr's type conversion -// constructor by avoiding the need for a public accessor for ref_. A -// WeakPtr cannot access the private members of WeakPtr, so this -// base class gives us a way to access ref_ in a protected fashion. -class BASE_EXPORT WeakPtrBase { - public: - WeakPtrBase(); - ~WeakPtrBase(); - - protected: - explicit WeakPtrBase(const WeakReference& ref); - - WeakReference ref_; -}; - -// This class provides a common implementation of common functions that would -// otherwise get instantiated separately for each distinct instantiation of -// SupportsWeakPtr<>. -class SupportsWeakPtrBase { - public: - // A safe static downcast of a WeakPtr to WeakPtr. This - // conversion will only compile if there is exists a Base which inherits - // from SupportsWeakPtr. See base::AsWeakPtr() below for a helper - // function that makes calling this easier. - template - static WeakPtr StaticAsWeakPtr(Derived* t) { - typedef - is_convertible convertible; - COMPILE_ASSERT(convertible::value, - AsWeakPtr_argument_inherits_from_SupportsWeakPtr); - return AsWeakPtrImpl(t, *t); - } - - private: - // This template function uses type inference to find a Base of Derived - // which is an instance of SupportsWeakPtr. We can then safely - // static_cast the Base* to a Derived*. - template - static WeakPtr AsWeakPtrImpl( - Derived* t, const SupportsWeakPtr&) { - WeakPtr ptr = t->Base::AsWeakPtr(); - return WeakPtr(ptr.ref_, static_cast(ptr.ptr_)); - } -}; - -} // namespace internal - -template class WeakPtrFactory; - -// The WeakPtr class holds a weak reference to |T*|. -// -// This class is designed to be used like a normal pointer. You should always -// null-test an object of this class before using it or invoking a method that -// may result in the underlying object being destroyed. -// -// EXAMPLE: -// -// class Foo { ... }; -// WeakPtr foo; -// if (foo) -// foo->method(); -// -template -class WeakPtr : public internal::WeakPtrBase { - public: - WeakPtr() : ptr_(NULL) { - } - - // Allow conversion from U to T provided U "is a" T. Note that this - // is separate from the (implicit) copy constructor. - template - WeakPtr(const WeakPtr& other) : WeakPtrBase(other), ptr_(other.ptr_) { - } - - T* get() const { return ref_.is_valid() ? ptr_ : NULL; } - - T& operator*() const { - DCHECK(get() != NULL); - return *get(); - } - T* operator->() const { - DCHECK(get() != NULL); - return get(); - } - - // Allow WeakPtr to be used in boolean expressions, but not - // implicitly convertible to a real bool (which is dangerous). - // - // Note that this trick is only safe when the == and != operators - // are declared explicitly, as otherwise "weak_ptr1 == weak_ptr2" - // will compile but do the wrong thing (i.e., convert to Testable - // and then do the comparison). - private: - typedef T* WeakPtr::*Testable; - - public: - operator Testable() const { return get() ? &WeakPtr::ptr_ : NULL; } - - void reset() { - ref_ = internal::WeakReference(); - ptr_ = NULL; - } - - private: - // Explicitly declare comparison operators as required by the bool - // trick, but keep them private. - template bool operator==(WeakPtr const&) const; - template bool operator!=(WeakPtr const&) const; - - friend class internal::SupportsWeakPtrBase; - template friend class WeakPtr; - friend class SupportsWeakPtr; - friend class WeakPtrFactory; - - WeakPtr(const internal::WeakReference& ref, T* ptr) - : WeakPtrBase(ref), - ptr_(ptr) { - } - - // This pointer is only valid when ref_.is_valid() is true. Otherwise, its - // value is undefined (as opposed to NULL). - T* ptr_; -}; - -// A class may be composed of a WeakPtrFactory and thereby -// control how it exposes weak pointers to itself. This is helpful if you only -// need weak pointers within the implementation of a class. This class is also -// useful when working with primitive types. For example, you could have a -// WeakPtrFactory that is used to pass around a weak reference to a bool. -template -class WeakPtrFactory { - public: - explicit WeakPtrFactory(T* ptr) : ptr_(ptr) { - } - - ~WeakPtrFactory() { - ptr_ = NULL; - } - - WeakPtr GetWeakPtr() { - DCHECK(ptr_); - return WeakPtr(weak_reference_owner_.GetRef(), ptr_); - } - - // Call this method to invalidate all existing weak pointers. - void InvalidateWeakPtrs() { - DCHECK(ptr_); - weak_reference_owner_.Invalidate(); - } - - // Call this method to determine if any weak pointers exist. - bool HasWeakPtrs() const { - DCHECK(ptr_); - return weak_reference_owner_.HasRefs(); - } - - private: - internal::WeakReferenceOwner weak_reference_owner_; - T* ptr_; - DISALLOW_IMPLICIT_CONSTRUCTORS(WeakPtrFactory); -}; - -// A class may extend from SupportsWeakPtr to let others take weak pointers to -// it. This avoids the class itself implementing boilerplate to dispense weak -// pointers. However, since SupportsWeakPtr's destructor won't invalidate -// weak pointers to the class until after the derived class' members have been -// destroyed, its use can lead to subtle use-after-destroy issues. -template -class SupportsWeakPtr : public internal::SupportsWeakPtrBase { - public: - SupportsWeakPtr() {} - - WeakPtr AsWeakPtr() { - return WeakPtr(weak_reference_owner_.GetRef(), static_cast(this)); - } - - protected: - ~SupportsWeakPtr() {} - - private: - internal::WeakReferenceOwner weak_reference_owner_; - DISALLOW_COPY_AND_ASSIGN(SupportsWeakPtr); -}; - -// Helper function that uses type deduction to safely return a WeakPtr -// when Derived doesn't directly extend SupportsWeakPtr, instead it -// extends a Base that extends SupportsWeakPtr. -// -// EXAMPLE: -// class Base : public base::SupportsWeakPtr {}; -// class Derived : public Base {}; -// -// Derived derived; -// base::WeakPtr ptr = base::AsWeakPtr(&derived); -// -// Note that the following doesn't work (invalid type conversion) since -// Derived::AsWeakPtr() is WeakPtr SupportsWeakPtr::AsWeakPtr(), -// and there's no way to safely cast WeakPtr to WeakPtr at -// the caller. -// -// base::WeakPtr ptr = derived.AsWeakPtr(); // Fails. - -template -WeakPtr AsWeakPtr(Derived* t) { - return internal::SupportsWeakPtrBase::StaticAsWeakPtr(t); -} - -} // namespace base - -#endif // BASE_MEMORY_WEAK_PTR_H_ diff --git a/base/memory/weak_ptr_unittest.cc b/base/memory/weak_ptr_unittest.cc deleted file mode 100644 index e7e12a272d..0000000000 --- a/base/memory/weak_ptr_unittest.cc +++ /dev/null @@ -1,606 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "base/memory/weak_ptr.h" - -#include - -#include "base/bind.h" -#include "base/debug/leak_annotations.h" -#include "base/memory/scoped_ptr.h" -#include "base/message_loop/message_loop.h" -#include "base/synchronization/waitable_event.h" -#include "base/threading/thread.h" -#include "testing/gtest/include/gtest/gtest.h" - -namespace base { -namespace { - -template -class OffThreadObjectCreator { - public: - static T* NewObject() { - T* result; - { - Thread creator_thread("creator_thread"); - creator_thread.Start(); - creator_thread.message_loop()->PostTask( - FROM_HERE, - base::Bind(OffThreadObjectCreator::CreateObject, &result)); - } - DCHECK(result); // We synchronized on thread destruction above. - return result; - } - private: - static void CreateObject(T** result) { - *result = new T; - } -}; - -struct Base { - std::string member; -}; -struct Derived : public Base {}; - -struct TargetBase {}; -struct Target : public TargetBase, public SupportsWeakPtr {}; -struct DerivedTarget : public Target {}; -struct Arrow { - WeakPtr target; -}; -struct TargetWithFactory : public Target { - TargetWithFactory() : factory(this) {} - WeakPtrFactory factory; -}; - -// Helper class to create and destroy weak pointer copies -// and delete objects on a background thread. -class BackgroundThread : public Thread { - public: - BackgroundThread() : Thread("owner_thread") {} - - virtual ~BackgroundThread() { - Stop(); - } - - void CreateArrowFromTarget(Arrow** arrow, Target* target) { - WaitableEvent completion(true, false); - message_loop()->PostTask( - FROM_HERE, - base::Bind(&BackgroundThread::DoCreateArrowFromTarget, - arrow, target, &completion)); - completion.Wait(); - } - - void CreateArrowFromArrow(Arrow** arrow, const Arrow* other) { - WaitableEvent completion(true, false); - message_loop()->PostTask( - FROM_HERE, - base::Bind(&BackgroundThread::DoCreateArrowFromArrow, - arrow, other, &completion)); - completion.Wait(); - } - - void DeleteTarget(Target* object) { - WaitableEvent completion(true, false); - message_loop()->PostTask( - FROM_HERE, - base::Bind(&BackgroundThread::DoDeleteTarget, object, &completion)); - completion.Wait(); - } - - void CopyAndAssignArrow(Arrow* object) { - WaitableEvent completion(true, false); - message_loop()->PostTask( - FROM_HERE, - base::Bind(&BackgroundThread::DoCopyAndAssignArrow, - object, &completion)); - completion.Wait(); - } - - void CopyAndAssignArrowBase(Arrow* object) { - WaitableEvent completion(true, false); - message_loop()->PostTask( - FROM_HERE, - base::Bind(&BackgroundThread::DoCopyAndAssignArrowBase, - object, &completion)); - completion.Wait(); - } - - void DeleteArrow(Arrow* object) { - WaitableEvent completion(true, false); - message_loop()->PostTask( - FROM_HERE, - base::Bind(&BackgroundThread::DoDeleteArrow, object, &completion)); - completion.Wait(); - } - - Target* DeRef(const Arrow* arrow) { - WaitableEvent completion(true, false); - Target* result = NULL; - message_loop()->PostTask( - FROM_HERE, - base::Bind(&BackgroundThread::DoDeRef, arrow, &result, &completion)); - completion.Wait(); - return result; - } - - protected: - static void DoCreateArrowFromArrow(Arrow** arrow, - const Arrow* other, - WaitableEvent* completion) { - *arrow = new Arrow; - **arrow = *other; - completion->Signal(); - } - - static void DoCreateArrowFromTarget(Arrow** arrow, - Target* target, - WaitableEvent* completion) { - *arrow = new Arrow; - (*arrow)->target = target->AsWeakPtr(); - completion->Signal(); - } - - static void DoDeRef(const Arrow* arrow, - Target** result, - WaitableEvent* completion) { - *result = arrow->target.get(); - completion->Signal(); - } - - static void DoDeleteTarget(Target* object, WaitableEvent* completion) { - delete object; - completion->Signal(); - } - - static void DoCopyAndAssignArrow(Arrow* object, WaitableEvent* completion) { - // Copy constructor. - Arrow a = *object; - // Assignment operator. - *object = a; - completion->Signal(); - } - - static void DoCopyAndAssignArrowBase( - Arrow* object, - WaitableEvent* completion) { - // Copy constructor. - WeakPtr b = object->target; - // Assignment operator. - WeakPtr c; - c = object->target; - completion->Signal(); - } - - static void DoDeleteArrow(Arrow* object, WaitableEvent* completion) { - delete object; - completion->Signal(); - } -}; - -} // namespace - -TEST(WeakPtrFactoryTest, Basic) { - int data; - WeakPtrFactory factory(&data); - WeakPtr ptr = factory.GetWeakPtr(); - EXPECT_EQ(&data, ptr.get()); -} - -TEST(WeakPtrFactoryTest, Comparison) { - int data; - WeakPtrFactory factory(&data); - WeakPtr ptr = factory.GetWeakPtr(); - WeakPtr ptr2 = ptr; - EXPECT_EQ(ptr.get(), ptr2.get()); -} - -TEST(WeakPtrFactoryTest, OutOfScope) { - WeakPtr ptr; - EXPECT_EQ(NULL, ptr.get()); - { - int data; - WeakPtrFactory factory(&data); - ptr = factory.GetWeakPtr(); - } - EXPECT_EQ(NULL, ptr.get()); -} - -TEST(WeakPtrFactoryTest, Multiple) { - WeakPtr a, b; - { - int data; - WeakPtrFactory factory(&data); - a = factory.GetWeakPtr(); - b = factory.GetWeakPtr(); - EXPECT_EQ(&data, a.get()); - EXPECT_EQ(&data, b.get()); - } - EXPECT_EQ(NULL, a.get()); - EXPECT_EQ(NULL, b.get()); -} - -TEST(WeakPtrFactoryTest, MultipleStaged) { - WeakPtr a; - { - int data; - WeakPtrFactory factory(&data); - a = factory.GetWeakPtr(); - { - WeakPtr b = factory.GetWeakPtr(); - } - EXPECT_TRUE(NULL != a.get()); - } - EXPECT_EQ(NULL, a.get()); -} - -TEST(WeakPtrFactoryTest, Dereference) { - Base data; - data.member = "123456"; - WeakPtrFactory factory(&data); - WeakPtr ptr = factory.GetWeakPtr(); - EXPECT_EQ(&data, ptr.get()); - EXPECT_EQ(data.member, (*ptr).member); - EXPECT_EQ(data.member, ptr->member); -} - -TEST(WeakPtrFactoryTest, UpCast) { - Derived data; - WeakPtrFactory factory(&data); - WeakPtr ptr = factory.GetWeakPtr(); - ptr = factory.GetWeakPtr(); - EXPECT_EQ(ptr.get(), &data); -} - -TEST(WeakPtrTest, SupportsWeakPtr) { - Target target; - WeakPtr ptr = target.AsWeakPtr(); - EXPECT_EQ(&target, ptr.get()); -} - -TEST(WeakPtrTest, DerivedTarget) { - DerivedTarget target; - WeakPtr ptr = AsWeakPtr(&target); - EXPECT_EQ(&target, ptr.get()); -} - -TEST(WeakPtrTest, InvalidateWeakPtrs) { - int data; - WeakPtrFactory factory(&data); - WeakPtr ptr = factory.GetWeakPtr(); - EXPECT_EQ(&data, ptr.get()); - EXPECT_TRUE(factory.HasWeakPtrs()); - factory.InvalidateWeakPtrs(); - EXPECT_EQ(NULL, ptr.get()); - EXPECT_FALSE(factory.HasWeakPtrs()); -} - -TEST(WeakPtrTest, HasWeakPtrs) { - int data; - WeakPtrFactory factory(&data); - { - WeakPtr ptr = factory.GetWeakPtr(); - EXPECT_TRUE(factory.HasWeakPtrs()); - } - EXPECT_FALSE(factory.HasWeakPtrs()); -} - -TEST(WeakPtrTest, ObjectAndWeakPtrOnDifferentThreads) { - // Test that it is OK to create an object that supports WeakPtr on one thread, - // but use it on another. This tests that we do not trip runtime checks that - // ensure that a WeakPtr is not used by multiple threads. - scoped_ptr target(OffThreadObjectCreator::NewObject()); - WeakPtr weak_ptr = target->AsWeakPtr(); - EXPECT_EQ(target.get(), weak_ptr.get()); -} - -TEST(WeakPtrTest, WeakPtrInitiateAndUseOnDifferentThreads) { - // Test that it is OK to create an object that has a WeakPtr member on one - // thread, but use it on another. This tests that we do not trip runtime - // checks that ensure that a WeakPtr is not used by multiple threads. - scoped_ptr arrow(OffThreadObjectCreator::NewObject()); - Target target; - arrow->target = target.AsWeakPtr(); - EXPECT_EQ(&target, arrow->target.get()); -} - -TEST(WeakPtrTest, MoveOwnershipImplicitly) { - // Move object ownership to another thread by releasing all weak pointers - // on the original thread first, and then establish WeakPtr on a different - // thread. - BackgroundThread background; - background.Start(); - - Target* target = new Target(); - { - WeakPtr weak_ptr = target->AsWeakPtr(); - // Main thread deletes the WeakPtr, then the thread ownership of the - // object can be implicitly moved. - } - Arrow* arrow; - - // Background thread creates WeakPtr(and implicitly owns the object). - background.CreateArrowFromTarget(&arrow, target); - EXPECT_EQ(background.DeRef(arrow), target); - - { - // Main thread creates another WeakPtr, but this does not trigger implicitly - // thread ownership move. - Arrow arrow; - arrow.target = target->AsWeakPtr(); - - // The new WeakPtr is owned by background thread. - EXPECT_EQ(target, background.DeRef(&arrow)); - } - - // Target can only be deleted on background thread. - background.DeleteTarget(target); - background.DeleteArrow(arrow); -} - -TEST(WeakPtrTest, MoveOwnershipOfUnreferencedObject) { - BackgroundThread background; - background.Start(); - - Arrow* arrow; - { - Target target; - // Background thread creates WeakPtr. - background.CreateArrowFromTarget(&arrow, &target); - - // Bind to background thread. - EXPECT_EQ(&target, background.DeRef(arrow)); - - // Release the only WeakPtr. - arrow->target.reset(); - - // Now we should be able to create a new reference from this thread. - arrow->target = target.AsWeakPtr(); - - // Re-bind to main thread. - EXPECT_EQ(&target, arrow->target.get()); - - // And the main thread can now delete the target. - } - - delete arrow; -} - -TEST(WeakPtrTest, MoveOwnershipAfterInvalidate) { - BackgroundThread background; - background.Start(); - - Arrow arrow; - scoped_ptr target(new TargetWithFactory); - - // Bind to main thread. - arrow.target = target->factory.GetWeakPtr(); - EXPECT_EQ(target.get(), arrow.target.get()); - - target->factory.InvalidateWeakPtrs(); - EXPECT_EQ(NULL, arrow.target.get()); - - arrow.target = target->factory.GetWeakPtr(); - // Re-bind to background thread. - EXPECT_EQ(target.get(), background.DeRef(&arrow)); - - // And the background thread can now delete the target. - background.DeleteTarget(target.release()); -} - -TEST(WeakPtrTest, MainThreadRefOutlivesBackgroundThreadRef) { - // Originating thread has a WeakPtr that outlives others. - // - Main thread creates a WeakPtr - // - Background thread creates a WeakPtr copy from the one in main thread - // - Destruct the WeakPtr on background thread - // - Destruct the WeakPtr on main thread - BackgroundThread background; - background.Start(); - - Target target; - Arrow arrow; - arrow.target = target.AsWeakPtr(); - - Arrow* arrow_copy; - background.CreateArrowFromArrow(&arrow_copy, &arrow); - EXPECT_EQ(arrow_copy->target.get(), &target); - background.DeleteArrow(arrow_copy); -} - -TEST(WeakPtrTest, BackgroundThreadRefOutlivesMainThreadRef) { - // Originating thread drops all references before another thread. - // - Main thread creates a WeakPtr and passes copy to background thread - // - Destruct the pointer on main thread - // - Destruct the pointer on background thread - BackgroundThread background; - background.Start(); - - Target target; - Arrow* arrow_copy; - { - Arrow arrow; - arrow.target = target.AsWeakPtr(); - background.CreateArrowFromArrow(&arrow_copy, &arrow); - } - EXPECT_EQ(arrow_copy->target.get(), &target); - background.DeleteArrow(arrow_copy); -} - -TEST(WeakPtrTest, OwnerThreadDeletesObject) { - // Originating thread invalidates WeakPtrs while its held by other thread. - // - Main thread creates WeakPtr and passes Copy to background thread - // - Object gets destroyed on main thread - // (invalidates WeakPtr on background thread) - // - WeakPtr gets destroyed on Thread B - BackgroundThread background; - background.Start(); - Arrow* arrow_copy; - { - Target target; - Arrow arrow; - arrow.target = target.AsWeakPtr(); - background.CreateArrowFromArrow(&arrow_copy, &arrow); - } - EXPECT_EQ(NULL, arrow_copy->target.get()); - background.DeleteArrow(arrow_copy); -} - -TEST(WeakPtrTest, NonOwnerThreadCanCopyAndAssignWeakPtr) { - // Main thread creates a Target object. - Target target; - // Main thread creates an arrow referencing the Target. - Arrow *arrow = new Arrow(); - arrow->target = target.AsWeakPtr(); - - // Background can copy and assign arrow (as well as the WeakPtr inside). - BackgroundThread background; - background.Start(); - background.CopyAndAssignArrow(arrow); - background.DeleteArrow(arrow); -} - -TEST(WeakPtrTest, NonOwnerThreadCanCopyAndAssignWeakPtrBase) { - // Main thread creates a Target object. - Target target; - // Main thread creates an arrow referencing the Target. - Arrow *arrow = new Arrow(); - arrow->target = target.AsWeakPtr(); - - // Background can copy and assign arrow's WeakPtr to a base class WeakPtr. - BackgroundThread background; - background.Start(); - background.CopyAndAssignArrowBase(arrow); - background.DeleteArrow(arrow); -} - -TEST(WeakPtrTest, NonOwnerThreadCanDeleteWeakPtr) { - // Main thread creates a Target object. - Target target; - // Main thread creates an arrow referencing the Target. - Arrow* arrow = new Arrow(); - arrow->target = target.AsWeakPtr(); - - // Background can delete arrow (as well as the WeakPtr inside). - BackgroundThread background; - background.Start(); - background.DeleteArrow(arrow); -} - -#if (!defined(NDEBUG) || defined(DCHECK_ALWAYS_ON)) && GTEST_HAS_DEATH_TEST - -TEST(WeakPtrDeathTest, WeakPtrCopyDoesNotChangeThreadBinding) { - // The default style "fast" does not support multi-threaded tests - // (introduces deadlock on Linux). - ::testing::FLAGS_gtest_death_test_style = "threadsafe"; - - BackgroundThread background; - background.Start(); - - // Main thread creates a Target object. - Target target; - // Main thread creates an arrow referencing the Target. - Arrow arrow; - arrow.target = target.AsWeakPtr(); - - // Background copies the WeakPtr. - Arrow* arrow_copy; - background.CreateArrowFromArrow(&arrow_copy, &arrow); - - // The copy is still bound to main thread so I can deref. - EXPECT_EQ(arrow.target.get(), arrow_copy->target.get()); - - // Although background thread created the copy, it can not deref the copied - // WeakPtr. - ASSERT_DEATH(background.DeRef(arrow_copy), ""); - - background.DeleteArrow(arrow_copy); -} - -TEST(WeakPtrDeathTest, NonOwnerThreadDereferencesWeakPtrAfterReference) { - // The default style "fast" does not support multi-threaded tests - // (introduces deadlock on Linux). - ::testing::FLAGS_gtest_death_test_style = "threadsafe"; - - // Main thread creates a Target object. - Target target; - - // Main thread creates an arrow referencing the Target (so target's - // thread ownership can not be implicitly moved). - Arrow arrow; - arrow.target = target.AsWeakPtr(); - arrow.target.get(); - - // Background thread tries to deref target, which violates thread ownership. - BackgroundThread background; - background.Start(); - ASSERT_DEATH(background.DeRef(&arrow), ""); -} - -TEST(WeakPtrDeathTest, NonOwnerThreadDeletesWeakPtrAfterReference) { - // The default style "fast" does not support multi-threaded tests - // (introduces deadlock on Linux). - ::testing::FLAGS_gtest_death_test_style = "threadsafe"; - - scoped_ptr target(new Target()); - - // Main thread creates an arrow referencing the Target. - Arrow arrow; - arrow.target = target->AsWeakPtr(); - - // Background thread tries to deref target, binding it to the thread. - BackgroundThread background; - background.Start(); - background.DeRef(&arrow); - - // Main thread deletes Target, violating thread binding. - ASSERT_DEATH(target.reset(), ""); - - // |target.reset()| died so |target| still holds the object, so we - // must pass it to the background thread to teardown. - background.DeleteTarget(target.release()); -} - -TEST(WeakPtrDeathTest, NonOwnerThreadDeletesObjectAfterReference) { - // The default style "fast" does not support multi-threaded tests - // (introduces deadlock on Linux). - ::testing::FLAGS_gtest_death_test_style = "threadsafe"; - - scoped_ptr target(new Target()); - - // Main thread creates an arrow referencing the Target, and references it, so - // that it becomes bound to the thread. - Arrow arrow; - arrow.target = target->AsWeakPtr(); - arrow.target.get(); - - // Background thread tries to delete target, volating thread binding. - BackgroundThread background; - background.Start(); - ASSERT_DEATH(background.DeleteTarget(target.release()), ""); -} - -TEST(WeakPtrDeathTest, NonOwnerThreadReferencesObjectAfterDeletion) { - // The default style "fast" does not support multi-threaded tests - // (introduces deadlock on Linux). - ::testing::FLAGS_gtest_death_test_style = "threadsafe"; - - scoped_ptr target(new Target()); - - // Main thread creates an arrow referencing the Target. - Arrow arrow; - arrow.target = target->AsWeakPtr(); - - // Background thread tries to delete target, binding the object to the thread. - BackgroundThread background; - background.Start(); - background.DeleteTarget(target.release()); - - // Main thread attempts to dereference the target, violating thread binding. - ASSERT_DEATH(arrow.target.get(), ""); -} - -#endif - -} // namespace base diff --git a/base/memory/weak_ptr_unittest.nc b/base/memory/weak_ptr_unittest.nc deleted file mode 100644 index a2da8e9779..0000000000 --- a/base/memory/weak_ptr_unittest.nc +++ /dev/null @@ -1,138 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "base/memory/weak_ptr.h" - -namespace base { - -struct Producer : SupportsWeakPtr {}; -struct DerivedProducer : Producer {}; -struct OtherDerivedProducer : Producer {}; -struct MultiplyDerivedProducer : Producer, - SupportsWeakPtr {}; -struct Unrelated {}; -struct DerivedUnrelated : Unrelated {}; - -#if defined(NCTEST_AUTO_DOWNCAST) // [r"invalid conversion from"] - -void WontCompile() { - Producer f; - WeakPtr ptr = f.AsWeakPtr(); - WeakPtr derived_ptr = ptr; -} - -#elif defined(NCTEST_STATIC_DOWNCAST) // [r"invalid conversion from"] - -void WontCompile() { - Producer f; - WeakPtr ptr = f.AsWeakPtr(); - WeakPtr derived_ptr = - static_cast >(ptr); -} - -#elif defined(NCTEST_AUTO_REF_DOWNCAST) // [r"invalid initialization of reference"] - -void WontCompile() { - Producer f; - WeakPtr ptr = f.AsWeakPtr(); - WeakPtr& derived_ptr = ptr; -} - -#elif defined(NCTEST_STATIC_REF_DOWNCAST) // [r"invalid static_cast"] - -void WontCompile() { - Producer f; - WeakPtr ptr = f.AsWeakPtr(); - WeakPtr& derived_ptr = - static_cast&>(ptr); -} - -#elif defined(NCTEST_STATIC_ASWEAKPTR_DOWNCAST) // [r"no matching function"] - -void WontCompile() { - Producer f; - WeakPtr ptr = - SupportsWeakPtr::StaticAsWeakPtr(&f); -} - -#elif defined(NCTEST_UNSAFE_HELPER_DOWNCAST) // [r"invalid conversion from"] - -void WontCompile() { - Producer f; - WeakPtr ptr = AsWeakPtr(&f); -} - -#elif defined(NCTEST_UNSAFE_INSTANTIATED_HELPER_DOWNCAST) // [r"no matching function"] - -void WontCompile() { - Producer f; - WeakPtr ptr = AsWeakPtr(&f); -} - -#elif defined(NCTEST_UNSAFE_WRONG_INSANTIATED_HELPER_DOWNCAST) // [r"invalid conversion from"] - -void WontCompile() { - Producer f; - WeakPtr ptr = AsWeakPtr(&f); -} - -#elif defined(NCTEST_UNSAFE_HELPER_CAST) // [r"cannot convert"] - -void WontCompile() { - DerivedProducer f; - WeakPtr ptr = AsWeakPtr(&f); -} - -#elif defined(NCTEST_UNSAFE_INSTANTIATED_HELPER_SIDECAST) // [r"no matching function"] - -void WontCompile() { - DerivedProducer f; - WeakPtr ptr = AsWeakPtr(&f); -} - -#elif defined(NCTEST_UNSAFE_WRONG_INSTANTIATED_HELPER_SIDECAST) // [r"cannot convert"] - -void WontCompile() { - DerivedProducer f; - WeakPtr ptr = AsWeakPtr(&f); -} - -#elif defined(NCTEST_UNRELATED_HELPER) // [r"cannot convert"] - -void WontCompile() { - DerivedProducer f; - WeakPtr ptr = AsWeakPtr(&f); -} - -#elif defined(NCTEST_UNRELATED_INSTANTIATED_HELPER) // [r"no matching function"] - -void WontCompile() { - DerivedProducer f; - WeakPtr ptr = AsWeakPtr(&f); -} - -#elif defined(NCTEST_COMPLETELY_UNRELATED_HELPER) // [r"size of array is negative"] - -void WontCompile() { - Unrelated f; - WeakPtr ptr = AsWeakPtr(&f); -} - -#elif defined(NCTEST_DERIVED_COMPLETELY_UNRELATED_HELPER) // [r"size of array is negative"] - -void WontCompile() { - DerivedUnrelated f; - WeakPtr ptr = AsWeakPtr(&f); -} - -#elif defined(NCTEST_AMBIGUOUS_ANCESTORS) // [r"ambiguous base"] - -void WontCompile() { - MultiplyDerivedProducer f; - WeakPtr ptr = AsWeakPtr(&f); -} - -#endif - -} diff --git a/base/message_loop/incoming_task_queue.cc b/base/message_loop/incoming_task_queue.cc deleted file mode 100644 index db99d8750c..0000000000 --- a/base/message_loop/incoming_task_queue.cc +++ /dev/null @@ -1,169 +0,0 @@ -// Copyright 2013 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "base/message_loop/incoming_task_queue.h" - -#include "base/debug/trace_event.h" -#include "base/location.h" -#include "base/message_loop/message_loop.h" -#include "base/synchronization/waitable_event.h" - -namespace base { -namespace internal { - -IncomingTaskQueue::IncomingTaskQueue(MessageLoop* message_loop) - : message_loop_(message_loop), - next_sequence_num_(0) { -} - -bool IncomingTaskQueue::AddToIncomingQueue( - const tracked_objects::Location& from_here, - const Closure& task, - TimeDelta delay, - bool nestable) { - AutoLock locked(incoming_queue_lock_); - PendingTask pending_task( - from_here, task, CalculateDelayedRuntime(delay), nestable); - return PostPendingTask(&pending_task); -} - -bool IncomingTaskQueue::TryAddToIncomingQueue( - const tracked_objects::Location& from_here, - const Closure& task) { - if (!incoming_queue_lock_.Try()) { - // Reset |task|. - Closure local_task = task; - return false; - } - - AutoLock locked(incoming_queue_lock_, AutoLock::AlreadyAcquired()); - PendingTask pending_task( - from_here, task, CalculateDelayedRuntime(TimeDelta()), true); - return PostPendingTask(&pending_task); -} - -bool IncomingTaskQueue::IsHighResolutionTimerEnabledForTesting() { -#if defined(OS_WIN) - return !high_resolution_timer_expiration_.is_null(); -#else - return true; -#endif -} - -bool IncomingTaskQueue::IsIdleForTesting() { - AutoLock lock(incoming_queue_lock_); - return incoming_queue_.empty(); -} - -void IncomingTaskQueue::LockWaitUnLockForTesting(WaitableEvent* caller_wait, - WaitableEvent* caller_signal) { - AutoLock lock(incoming_queue_lock_); - caller_wait->Signal(); - caller_signal->Wait(); -} - -void IncomingTaskQueue::ReloadWorkQueue(TaskQueue* work_queue) { - // Make sure no tasks are lost. - DCHECK(work_queue->empty()); - - // Acquire all we can from the inter-thread queue with one lock acquisition. - AutoLock lock(incoming_queue_lock_); - if (!incoming_queue_.empty()) - incoming_queue_.Swap(work_queue); // Constant time - - DCHECK(incoming_queue_.empty()); -} - -void IncomingTaskQueue::WillDestroyCurrentMessageLoop() { -#if defined(OS_WIN) - // If we left the high-resolution timer activated, deactivate it now. - // Doing this is not-critical, it is mainly to make sure we track - // the high resolution timer activations properly in our unit tests. - if (!high_resolution_timer_expiration_.is_null()) { - Time::ActivateHighResolutionTimer(false); - high_resolution_timer_expiration_ = TimeTicks(); - } -#endif - - AutoLock lock(incoming_queue_lock_); - message_loop_ = NULL; -} - -IncomingTaskQueue::~IncomingTaskQueue() { - // Verify that WillDestroyCurrentMessageLoop() has been called. - DCHECK(!message_loop_); -} - -TimeTicks IncomingTaskQueue::CalculateDelayedRuntime(TimeDelta delay) { - TimeTicks delayed_run_time; - if (delay > TimeDelta()) { - delayed_run_time = TimeTicks::Now() + delay; - -#if defined(OS_WIN) - if (high_resolution_timer_expiration_.is_null()) { - // Windows timers are granular to 15.6ms. If we only set high-res - // timers for those under 15.6ms, then a 18ms timer ticks at ~32ms, - // which as a percentage is pretty inaccurate. So enable high - // res timers for any timer which is within 2x of the granularity. - // This is a tradeoff between accuracy and power management. - bool needs_high_res_timers = delay.InMilliseconds() < - (2 * Time::kMinLowResolutionThresholdMs); - if (needs_high_res_timers) { - if (Time::ActivateHighResolutionTimer(true)) { - high_resolution_timer_expiration_ = TimeTicks::Now() + - TimeDelta::FromMilliseconds( - MessageLoop::kHighResolutionTimerModeLeaseTimeMs); - } - } - } -#endif - } else { - DCHECK_EQ(delay.InMilliseconds(), 0) << "delay should not be negative"; - } - -#if defined(OS_WIN) - if (!high_resolution_timer_expiration_.is_null()) { - if (TimeTicks::Now() > high_resolution_timer_expiration_) { - Time::ActivateHighResolutionTimer(false); - high_resolution_timer_expiration_ = TimeTicks(); - } - } -#endif - - return delayed_run_time; -} - -bool IncomingTaskQueue::PostPendingTask(PendingTask* pending_task) { - // Warning: Don't try to short-circuit, and handle this thread's tasks more - // directly, as it could starve handling of foreign threads. Put every task - // into this queue. - - // This should only be called while the lock is taken. - incoming_queue_lock_.AssertAcquired(); - - if (!message_loop_) { - pending_task->task.Reset(); - return false; - } - - // Initialize the sequence number. The sequence number is used for delayed - // tasks (to faciliate FIFO sorting when two tasks have the same - // delayed_run_time value) and for identifying the task in about:tracing. - pending_task->sequence_num = next_sequence_num_++; - - TRACE_EVENT_FLOW_BEGIN0("task", "MessageLoop::PostTask", - TRACE_ID_MANGLE(message_loop_->GetTaskTraceID(*pending_task))); - - bool was_empty = incoming_queue_.empty(); - incoming_queue_.push(*pending_task); - pending_task->task.Reset(); - - // Wake up the pump. - message_loop_->ScheduleWork(was_empty); - - return true; -} - -} // namespace internal -} // namespace base diff --git a/base/message_loop/incoming_task_queue.h b/base/message_loop/incoming_task_queue.h deleted file mode 100644 index d831a71a3f..0000000000 --- a/base/message_loop/incoming_task_queue.h +++ /dev/null @@ -1,104 +0,0 @@ -// Copyright 2013 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef BASE_MESSAGE_LOOP_INCOMING_TASK_QUEUE_H_ -#define BASE_MESSAGE_LOOP_INCOMING_TASK_QUEUE_H_ - -#include "base/base_export.h" -#include "base/memory/ref_counted.h" -#include "base/pending_task.h" -#include "base/synchronization/lock.h" -#include "base/time/time.h" - -namespace base { - -class MessageLoop; -class WaitableEvent; - -namespace internal { - -// Implements a queue of tasks posted to the message loop running on the current -// thread. This class takes care of synchronizing posting tasks from different -// threads and together with MessageLoop ensures clean shutdown. -class BASE_EXPORT IncomingTaskQueue - : public RefCountedThreadSafe { - public: - explicit IncomingTaskQueue(MessageLoop* message_loop); - - // Appends a task to the incoming queue. Posting of all tasks is routed though - // AddToIncomingQueue() or TryAddToIncomingQueue() to make sure that posting - // task is properly synchronized between different threads. - // - // Returns true if the task was successfully added to the queue, otherwise - // returns false. In all cases, the ownership of |task| is transferred to the - // called method. - bool AddToIncomingQueue(const tracked_objects::Location& from_here, - const Closure& task, - TimeDelta delay, - bool nestable); - - // Same as AddToIncomingQueue() except that it will avoid blocking if the lock - // is already held, and will in that case (when the lock is contended) fail to - // add the task, and will return false. - bool TryAddToIncomingQueue(const tracked_objects::Location& from_here, - const Closure& task); - - // Returns true if the message loop has high resolution timers enabled. - // Provided for testing. - bool IsHighResolutionTimerEnabledForTesting(); - - // Returns true if the message loop is "idle". Provided for testing. - bool IsIdleForTesting(); - - // Takes the incoming queue lock, signals |caller_wait| and waits until - // |caller_signal| is signalled. - void LockWaitUnLockForTesting(WaitableEvent* caller_wait, - WaitableEvent* caller_signal); - - // Loads tasks from the |incoming_queue_| into |*work_queue|. Must be called - // from the thread that is running the loop. - void ReloadWorkQueue(TaskQueue* work_queue); - - // Disconnects |this| from the parent message loop. - void WillDestroyCurrentMessageLoop(); - - private: - friend class RefCountedThreadSafe; - virtual ~IncomingTaskQueue(); - - // Calculates the time at which a PendingTask should run. - TimeTicks CalculateDelayedRuntime(TimeDelta delay); - - // Adds a task to |incoming_queue_|. The caller retains ownership of - // |pending_task|, but this function will reset the value of - // |pending_task->task|. This is needed to ensure that the posting call stack - // does not retain |pending_task->task| beyond this function call. - bool PostPendingTask(PendingTask* pending_task); - -#if defined(OS_WIN) - TimeTicks high_resolution_timer_expiration_; -#endif - - // The lock that protects access to |incoming_queue_|, |message_loop_| and - // |next_sequence_num_|. - base::Lock incoming_queue_lock_; - - // An incoming queue of tasks that are acquired under a mutex for processing - // on this instance's thread. These tasks have not yet been been pushed to - // |message_loop_|. - TaskQueue incoming_queue_; - - // Points to the message loop that owns |this|. - MessageLoop* message_loop_; - - // The next sequence number to use for delayed tasks. - int next_sequence_num_; - - DISALLOW_COPY_AND_ASSIGN(IncomingTaskQueue); -}; - -} // namespace internal -} // namespace base - -#endif // BASE_MESSAGE_LOOP_INCOMING_TASK_QUEUE_H_ diff --git a/base/message_loop/message_loop.cc b/base/message_loop/message_loop.cc deleted file mode 100644 index 826c7573ee..0000000000 --- a/base/message_loop/message_loop.cc +++ /dev/null @@ -1,754 +0,0 @@ -// Copyright 2013 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "base/message_loop/message_loop.h" - -#include - -#include "base/bind.h" -#include "base/compiler_specific.h" -#include "base/debug/alias.h" -#include "base/debug/trace_event.h" -#include "base/lazy_instance.h" -#include "base/logging.h" -#include "base/memory/scoped_ptr.h" -#include "base/message_loop/message_pump_default.h" -#include "base/metrics/histogram.h" -#include "base/metrics/statistics_recorder.h" -#include "base/run_loop.h" -#include "base/third_party/dynamic_annotations/dynamic_annotations.h" -#include "base/thread_task_runner_handle.h" -#include "base/threading/thread_local.h" -#include "base/time/time.h" -#include "base/tracked_objects.h" - -#if defined(OS_MACOSX) -#include "base/message_loop/message_pump_mac.h" -#endif -#if defined(OS_POSIX) && !defined(OS_IOS) -#include "base/message_loop/message_pump_libevent.h" -#endif -#if defined(OS_ANDROID) -#include "base/message_loop/message_pump_android.h" -#endif - -#if defined(TOOLKIT_GTK) -#include -#include -#endif - -namespace base { - -namespace { - -// A lazily created thread local storage for quick access to a thread's message -// loop, if one exists. This should be safe and free of static constructors. -LazyInstance > lazy_tls_ptr = - LAZY_INSTANCE_INITIALIZER; - -// Logical events for Histogram profiling. Run with -message-loop-histogrammer -// to get an accounting of messages and actions taken on each thread. -const int kTaskRunEvent = 0x1; -const int kTimerEvent = 0x2; - -// Provide range of message IDs for use in histogramming and debug display. -const int kLeastNonZeroMessageId = 1; -const int kMaxMessageId = 1099; -const int kNumberOfDistinctMessagesDisplayed = 1100; - -// Provide a macro that takes an expression (such as a constant, or macro -// constant) and creates a pair to initalize an array of pairs. In this case, -// our pair consists of the expressions value, and the "stringized" version -// of the expression (i.e., the exrpression put in quotes). For example, if -// we have: -// #define FOO 2 -// #define BAR 5 -// then the following: -// VALUE_TO_NUMBER_AND_NAME(FOO + BAR) -// will expand to: -// {7, "FOO + BAR"} -// We use the resulting array as an argument to our histogram, which reads the -// number as a bucket identifier, and proceeds to use the corresponding name -// in the pair (i.e., the quoted string) when printing out a histogram. -#define VALUE_TO_NUMBER_AND_NAME(name) {name, #name}, - -const LinearHistogram::DescriptionPair event_descriptions_[] = { - // Provide some pretty print capability in our histogram for our internal - // messages. - - // A few events we handle (kindred to messages), and used to profile actions. - VALUE_TO_NUMBER_AND_NAME(kTaskRunEvent) - VALUE_TO_NUMBER_AND_NAME(kTimerEvent) - - {-1, NULL} // The list must be null terminated, per API to histogram. -}; - -bool enable_histogrammer_ = false; - -MessageLoop::MessagePumpFactory* message_pump_for_ui_factory_ = NULL; - -// Returns true if MessagePump::ScheduleWork() must be called one -// time for every task that is added to the MessageLoop incoming queue. -bool AlwaysNotifyPump(MessageLoop::Type type) { -#if defined(OS_ANDROID) - return type == MessageLoop::TYPE_UI || type == MessageLoop::TYPE_JAVA; -#else - return false; -#endif -} - -} // namespace - -//------------------------------------------------------------------------------ - -#if defined(OS_WIN) - -// Upon a SEH exception in this thread, it restores the original unhandled -// exception filter. -static int SEHFilter(LPTOP_LEVEL_EXCEPTION_FILTER old_filter) { - ::SetUnhandledExceptionFilter(old_filter); - return EXCEPTION_CONTINUE_SEARCH; -} - -// Retrieves a pointer to the current unhandled exception filter. There -// is no standalone getter method. -static LPTOP_LEVEL_EXCEPTION_FILTER GetTopSEHFilter() { - LPTOP_LEVEL_EXCEPTION_FILTER top_filter = NULL; - top_filter = ::SetUnhandledExceptionFilter(0); - ::SetUnhandledExceptionFilter(top_filter); - return top_filter; -} - -#endif // defined(OS_WIN) - -//------------------------------------------------------------------------------ - -MessageLoop::TaskObserver::TaskObserver() { -} - -MessageLoop::TaskObserver::~TaskObserver() { -} - -MessageLoop::DestructionObserver::~DestructionObserver() { -} - -//------------------------------------------------------------------------------ - -MessageLoop::MessageLoop(Type type) - : type_(type), - exception_restoration_(false), - nestable_tasks_allowed_(true), -#if defined(OS_WIN) - os_modal_loop_(false), -#endif // OS_WIN - message_histogram_(NULL), - run_loop_(NULL) { - DCHECK(!current()) << "should only have one message loop per thread"; - lazy_tls_ptr.Pointer()->Set(this); - - incoming_task_queue_ = new internal::IncomingTaskQueue(this); - message_loop_proxy_ = - new internal::MessageLoopProxyImpl(incoming_task_queue_); - thread_task_runner_handle_.reset( - new ThreadTaskRunnerHandle(message_loop_proxy_)); - -// TODO(rvargas): Get rid of the OS guards. -#if defined(OS_WIN) -#define MESSAGE_PUMP_UI new MessagePumpForUI() -#define MESSAGE_PUMP_IO new MessagePumpForIO() -#elif defined(OS_IOS) -#define MESSAGE_PUMP_UI MessagePumpMac::Create() -#define MESSAGE_PUMP_IO new MessagePumpIOSForIO() -#elif defined(OS_MACOSX) -#define MESSAGE_PUMP_UI MessagePumpMac::Create() -#define MESSAGE_PUMP_IO new MessagePumpLibevent() -#elif defined(OS_NACL) -// Currently NaCl doesn't have a UI MessageLoop. -// TODO(abarth): Figure out if we need this. -#define MESSAGE_PUMP_UI NULL -// ipc_channel_nacl.cc uses a worker thread to do socket reads currently, and -// doesn't require extra support for watching file descriptors. -#define MESSAGE_PUMP_IO new MessagePumpDefault() -#elif defined(OS_POSIX) // POSIX but not MACOSX. -#define MESSAGE_PUMP_UI new MessagePumpForUI() -#define MESSAGE_PUMP_IO new MessagePumpLibevent() -#else -#error Not implemented -#endif - - if (type_ == TYPE_UI) { - if (message_pump_for_ui_factory_) - pump_.reset(message_pump_for_ui_factory_()); - else - pump_.reset(MESSAGE_PUMP_UI); - } else if (type_ == TYPE_IO) { - pump_.reset(MESSAGE_PUMP_IO); -#if defined(OS_ANDROID) - } else if (type_ == TYPE_JAVA) { - pump_.reset(MESSAGE_PUMP_UI); -#endif - } else { - DCHECK_EQ(TYPE_DEFAULT, type_); - pump_.reset(new MessagePumpDefault()); - } -} - -MessageLoop::~MessageLoop() { - DCHECK_EQ(this, current()); - - DCHECK(!run_loop_); - - // Clean up any unprocessed tasks, but take care: deleting a task could - // result in the addition of more tasks (e.g., via DeleteSoon). We set a - // limit on the number of times we will allow a deleted task to generate more - // tasks. Normally, we should only pass through this loop once or twice. If - // we end up hitting the loop limit, then it is probably due to one task that - // is being stubborn. Inspect the queues to see who is left. - bool did_work; - for (int i = 0; i < 100; ++i) { - DeletePendingTasks(); - ReloadWorkQueue(); - // If we end up with empty queues, then break out of the loop. - did_work = DeletePendingTasks(); - if (!did_work) - break; - } - DCHECK(!did_work); - - // Let interested parties have one last shot at accessing this. - FOR_EACH_OBSERVER(DestructionObserver, destruction_observers_, - WillDestroyCurrentMessageLoop()); - - thread_task_runner_handle_.reset(); - - // Tell the incoming queue that we are dying. - incoming_task_queue_->WillDestroyCurrentMessageLoop(); - incoming_task_queue_ = NULL; - message_loop_proxy_ = NULL; - - // OK, now make it so that no one can find us. - lazy_tls_ptr.Pointer()->Set(NULL); -} - -// static -MessageLoop* MessageLoop::current() { - // TODO(darin): sadly, we cannot enable this yet since people call us even - // when they have no intention of using us. - // DCHECK(loop) << "Ouch, did you forget to initialize me?"; - return lazy_tls_ptr.Pointer()->Get(); -} - -// static -void MessageLoop::EnableHistogrammer(bool enable) { - enable_histogrammer_ = enable; -} - -// static -bool MessageLoop::InitMessagePumpForUIFactory(MessagePumpFactory* factory) { - if (message_pump_for_ui_factory_) - return false; - - message_pump_for_ui_factory_ = factory; - return true; -} - -void MessageLoop::AddDestructionObserver( - DestructionObserver* destruction_observer) { - DCHECK_EQ(this, current()); - destruction_observers_.AddObserver(destruction_observer); -} - -void MessageLoop::RemoveDestructionObserver( - DestructionObserver* destruction_observer) { - DCHECK_EQ(this, current()); - destruction_observers_.RemoveObserver(destruction_observer); -} - -void MessageLoop::PostTask( - const tracked_objects::Location& from_here, - const Closure& task) { - DCHECK(!task.is_null()) << from_here.ToString(); - incoming_task_queue_->AddToIncomingQueue(from_here, task, TimeDelta(), true); -} - -bool MessageLoop::TryPostTask( - const tracked_objects::Location& from_here, - const Closure& task) { - DCHECK(!task.is_null()) << from_here.ToString(); - return incoming_task_queue_->TryAddToIncomingQueue(from_here, task); -} - -void MessageLoop::PostDelayedTask( - const tracked_objects::Location& from_here, - const Closure& task, - TimeDelta delay) { - DCHECK(!task.is_null()) << from_here.ToString(); - incoming_task_queue_->AddToIncomingQueue(from_here, task, delay, true); -} - -void MessageLoop::PostNonNestableTask( - const tracked_objects::Location& from_here, - const Closure& task) { - DCHECK(!task.is_null()) << from_here.ToString(); - incoming_task_queue_->AddToIncomingQueue(from_here, task, TimeDelta(), false); -} - -void MessageLoop::PostNonNestableDelayedTask( - const tracked_objects::Location& from_here, - const Closure& task, - TimeDelta delay) { - DCHECK(!task.is_null()) << from_here.ToString(); - incoming_task_queue_->AddToIncomingQueue(from_here, task, delay, false); -} - -void MessageLoop::Run() { - RunLoop run_loop; - run_loop.Run(); -} - -void MessageLoop::RunUntilIdle() { - RunLoop run_loop; - run_loop.RunUntilIdle(); -} - -void MessageLoop::QuitWhenIdle() { - DCHECK_EQ(this, current()); - if (run_loop_) { - run_loop_->quit_when_idle_received_ = true; - } else { - NOTREACHED() << "Must be inside Run to call Quit"; - } -} - -void MessageLoop::QuitNow() { - DCHECK_EQ(this, current()); - if (run_loop_) { - pump_->Quit(); - } else { - NOTREACHED() << "Must be inside Run to call Quit"; - } -} - -bool MessageLoop::IsType(Type type) const { - return type_ == type; -} - -static void QuitCurrentWhenIdle() { - MessageLoop::current()->QuitWhenIdle(); -} - -// static -Closure MessageLoop::QuitWhenIdleClosure() { - return Bind(&QuitCurrentWhenIdle); -} - -void MessageLoop::SetNestableTasksAllowed(bool allowed) { - if (nestable_tasks_allowed_ != allowed) { - nestable_tasks_allowed_ = allowed; - if (!nestable_tasks_allowed_) - return; - // Start the native pump if we are not already pumping. - pump_->ScheduleWork(); - } -} - -bool MessageLoop::NestableTasksAllowed() const { - return nestable_tasks_allowed_; -} - -bool MessageLoop::IsNested() { - return run_loop_->run_depth_ > 1; -} - -void MessageLoop::AddTaskObserver(TaskObserver* task_observer) { - DCHECK_EQ(this, current()); - task_observers_.AddObserver(task_observer); -} - -void MessageLoop::RemoveTaskObserver(TaskObserver* task_observer) { - DCHECK_EQ(this, current()); - task_observers_.RemoveObserver(task_observer); -} - -bool MessageLoop::is_running() const { - DCHECK_EQ(this, current()); - return run_loop_ != NULL; -} - -bool MessageLoop::IsHighResolutionTimerEnabledForTesting() { - return incoming_task_queue_->IsHighResolutionTimerEnabledForTesting(); -} - -bool MessageLoop::IsIdleForTesting() { - // We only check the imcoming queue|, since we don't want to lock the work - // queue. - return incoming_task_queue_->IsIdleForTesting(); -} - -void MessageLoop::LockWaitUnLockForTesting(WaitableEvent* caller_wait, - WaitableEvent* caller_signal) { - incoming_task_queue_->LockWaitUnLockForTesting(caller_wait, caller_signal); -} - -//------------------------------------------------------------------------------ - -// Runs the loop in two different SEH modes: -// enable_SEH_restoration_ = false : any unhandled exception goes to the last -// one that calls SetUnhandledExceptionFilter(). -// enable_SEH_restoration_ = true : any unhandled exception goes to the filter -// that was existed before the loop was run. -void MessageLoop::RunHandler() { -#if defined(OS_WIN) - if (exception_restoration_) { - RunInternalInSEHFrame(); - return; - } -#endif - - RunInternal(); -} - -#if defined(OS_WIN) -__declspec(noinline) void MessageLoop::RunInternalInSEHFrame() { - LPTOP_LEVEL_EXCEPTION_FILTER current_filter = GetTopSEHFilter(); - __try { - RunInternal(); - } __except(SEHFilter(current_filter)) { - } - return; -} -#endif - -void MessageLoop::RunInternal() { - DCHECK_EQ(this, current()); - - StartHistogrammer(); - -#if !defined(OS_MACOSX) && !defined(OS_ANDROID) - if (run_loop_->dispatcher_ && type() == TYPE_UI) { - static_cast(pump_.get())-> - RunWithDispatcher(this, run_loop_->dispatcher_); - return; - } -#endif - - pump_->Run(this); -} - -bool MessageLoop::ProcessNextDelayedNonNestableTask() { - if (run_loop_->run_depth_ != 1) - return false; - - if (deferred_non_nestable_work_queue_.empty()) - return false; - - PendingTask pending_task = deferred_non_nestable_work_queue_.front(); - deferred_non_nestable_work_queue_.pop(); - - RunTask(pending_task); - return true; -} - -void MessageLoop::RunTask(const PendingTask& pending_task) { - tracked_objects::TrackedTime start_time = - tracked_objects::ThreadData::NowForStartOfRun(pending_task.birth_tally); - - TRACE_EVENT_FLOW_END1("task", "MessageLoop::PostTask", - TRACE_ID_MANGLE(GetTaskTraceID(pending_task)), - "queue_duration", - (start_time - pending_task.EffectiveTimePosted()).InMilliseconds()); - TRACE_EVENT2("task", "MessageLoop::RunTask", - "src_file", pending_task.posted_from.file_name(), - "src_func", pending_task.posted_from.function_name()); - - DCHECK(nestable_tasks_allowed_); - // Execute the task and assume the worst: It is probably not reentrant. - nestable_tasks_allowed_ = false; - - // Before running the task, store the program counter where it was posted - // and deliberately alias it to ensure it is on the stack if the task - // crashes. Be careful not to assume that the variable itself will have the - // expected value when displayed by the optimizer in an optimized build. - // Look at a memory dump of the stack. - const void* program_counter = - pending_task.posted_from.program_counter(); - debug::Alias(&program_counter); - - HistogramEvent(kTaskRunEvent); - - FOR_EACH_OBSERVER(TaskObserver, task_observers_, - WillProcessTask(pending_task)); - pending_task.task.Run(); - FOR_EACH_OBSERVER(TaskObserver, task_observers_, - DidProcessTask(pending_task)); - - tracked_objects::ThreadData::TallyRunOnNamedThreadIfTracking(pending_task, - start_time, tracked_objects::ThreadData::NowForEndOfRun()); - - nestable_tasks_allowed_ = true; -} - -bool MessageLoop::DeferOrRunPendingTask(const PendingTask& pending_task) { - if (pending_task.nestable || run_loop_->run_depth_ == 1) { - RunTask(pending_task); - // Show that we ran a task (Note: a new one might arrive as a - // consequence!). - return true; - } - - // We couldn't run the task now because we're in a nested message loop - // and the task isn't nestable. - deferred_non_nestable_work_queue_.push(pending_task); - return false; -} - -void MessageLoop::AddToDelayedWorkQueue(const PendingTask& pending_task) { - // Move to the delayed work queue. - delayed_work_queue_.push(pending_task); -} - -bool MessageLoop::DeletePendingTasks() { - bool did_work = !work_queue_.empty(); - while (!work_queue_.empty()) { - PendingTask pending_task = work_queue_.front(); - work_queue_.pop(); - if (!pending_task.delayed_run_time.is_null()) { - // We want to delete delayed tasks in the same order in which they would - // normally be deleted in case of any funny dependencies between delayed - // tasks. - AddToDelayedWorkQueue(pending_task); - } - } - did_work |= !deferred_non_nestable_work_queue_.empty(); - while (!deferred_non_nestable_work_queue_.empty()) { - deferred_non_nestable_work_queue_.pop(); - } - did_work |= !delayed_work_queue_.empty(); - - // Historically, we always delete the task regardless of valgrind status. It's - // not completely clear why we want to leak them in the loops above. This - // code is replicating legacy behavior, and should not be considered - // absolutely "correct" behavior. See TODO above about deleting all tasks - // when it's safe. - while (!delayed_work_queue_.empty()) { - delayed_work_queue_.pop(); - } - return did_work; -} - -uint64 MessageLoop::GetTaskTraceID(const PendingTask& task) { - return (static_cast(task.sequence_num) << 32) | - static_cast(reinterpret_cast(this)); -} - -void MessageLoop::ReloadWorkQueue() { - // We can improve performance of our loading tasks from the incoming queue to - // |*work_queue| by waiting until the last minute (|*work_queue| is empty) to - // load. That reduces the number of locks-per-task significantly when our - // queues get large. - if (work_queue_.empty()) - incoming_task_queue_->ReloadWorkQueue(&work_queue_); -} - -void MessageLoop::ScheduleWork(bool was_empty) { - // The Android UI message loop needs to get notified each time - // a task is added to the incoming queue. - if (was_empty || AlwaysNotifyPump(type_)) - pump_->ScheduleWork(); -} - -//------------------------------------------------------------------------------ -// Method and data for histogramming events and actions taken by each instance -// on each thread. - -void MessageLoop::StartHistogrammer() { -#if !defined(OS_NACL) // NaCl build has no metrics code. - if (enable_histogrammer_ && !message_histogram_ - && StatisticsRecorder::IsActive()) { - DCHECK(!thread_name_.empty()); - message_histogram_ = LinearHistogram::FactoryGetWithRangeDescription( - "MsgLoop:" + thread_name_, - kLeastNonZeroMessageId, kMaxMessageId, - kNumberOfDistinctMessagesDisplayed, - message_histogram_->kHexRangePrintingFlag, - event_descriptions_); - } -#endif -} - -void MessageLoop::HistogramEvent(int event) { -#if !defined(OS_NACL) - if (message_histogram_) - message_histogram_->Add(event); -#endif -} - -bool MessageLoop::DoWork() { - if (!nestable_tasks_allowed_) { - // Task can't be executed right now. - return false; - } - - for (;;) { - ReloadWorkQueue(); - if (work_queue_.empty()) - break; - - // Execute oldest task. - do { - PendingTask pending_task = work_queue_.front(); - work_queue_.pop(); - if (!pending_task.delayed_run_time.is_null()) { - AddToDelayedWorkQueue(pending_task); - // If we changed the topmost task, then it is time to reschedule. - if (delayed_work_queue_.top().task.Equals(pending_task.task)) - pump_->ScheduleDelayedWork(pending_task.delayed_run_time); - } else { - if (DeferOrRunPendingTask(pending_task)) - return true; - } - } while (!work_queue_.empty()); - } - - // Nothing happened. - return false; -} - -bool MessageLoop::DoDelayedWork(TimeTicks* next_delayed_work_time) { - if (!nestable_tasks_allowed_ || delayed_work_queue_.empty()) { - recent_time_ = *next_delayed_work_time = TimeTicks(); - return false; - } - - // When we "fall behind," there will be a lot of tasks in the delayed work - // queue that are ready to run. To increase efficiency when we fall behind, - // we will only call Time::Now() intermittently, and then process all tasks - // that are ready to run before calling it again. As a result, the more we - // fall behind (and have a lot of ready-to-run delayed tasks), the more - // efficient we'll be at handling the tasks. - - TimeTicks next_run_time = delayed_work_queue_.top().delayed_run_time; - if (next_run_time > recent_time_) { - recent_time_ = TimeTicks::Now(); // Get a better view of Now(); - if (next_run_time > recent_time_) { - *next_delayed_work_time = next_run_time; - return false; - } - } - - PendingTask pending_task = delayed_work_queue_.top(); - delayed_work_queue_.pop(); - - if (!delayed_work_queue_.empty()) - *next_delayed_work_time = delayed_work_queue_.top().delayed_run_time; - - return DeferOrRunPendingTask(pending_task); -} - -bool MessageLoop::DoIdleWork() { - if (ProcessNextDelayedNonNestableTask()) - return true; - - if (run_loop_->quit_when_idle_received_) - pump_->Quit(); - - return false; -} - -void MessageLoop::DeleteSoonInternal(const tracked_objects::Location& from_here, - void(*deleter)(const void*), - const void* object) { - PostNonNestableTask(from_here, Bind(deleter, object)); -} - -void MessageLoop::ReleaseSoonInternal( - const tracked_objects::Location& from_here, - void(*releaser)(const void*), - const void* object) { - PostNonNestableTask(from_here, Bind(releaser, object)); -} - -//------------------------------------------------------------------------------ -// MessageLoopForUI - -#if defined(OS_WIN) -void MessageLoopForUI::DidProcessMessage(const MSG& message) { - pump_win()->DidProcessMessage(message); -} -#endif // defined(OS_WIN) - -#if defined(OS_ANDROID) -void MessageLoopForUI::Start() { - // No Histogram support for UI message loop as it is managed by Java side - static_cast(pump_.get())->Start(this); -} -#endif - -#if defined(OS_IOS) -void MessageLoopForUI::Attach() { - static_cast(pump_.get())->Attach(this); -} -#endif - -#if !defined(OS_MACOSX) && !defined(OS_NACL) && !defined(OS_ANDROID) -void MessageLoopForUI::AddObserver(Observer* observer) { - pump_ui()->AddObserver(observer); -} - -void MessageLoopForUI::RemoveObserver(Observer* observer) { - pump_ui()->RemoveObserver(observer); -} - -#endif // !defined(OS_MACOSX) && !defined(OS_NACL) && !defined(OS_ANDROID) - -//------------------------------------------------------------------------------ -// MessageLoopForIO - -#if defined(OS_WIN) - -void MessageLoopForIO::RegisterIOHandler(HANDLE file, IOHandler* handler) { - pump_io()->RegisterIOHandler(file, handler); -} - -bool MessageLoopForIO::RegisterJobObject(HANDLE job, IOHandler* handler) { - return pump_io()->RegisterJobObject(job, handler); -} - -bool MessageLoopForIO::WaitForIOCompletion(DWORD timeout, IOHandler* filter) { - return pump_io()->WaitForIOCompletion(timeout, filter); -} - -#elif defined(OS_IOS) - -bool MessageLoopForIO::WatchFileDescriptor(int fd, - bool persistent, - Mode mode, - FileDescriptorWatcher *controller, - Watcher *delegate) { - return pump_io()->WatchFileDescriptor( - fd, - persistent, - mode, - controller, - delegate); -} - -#elif defined(OS_POSIX) && !defined(OS_NACL) - -bool MessageLoopForIO::WatchFileDescriptor(int fd, - bool persistent, - Mode mode, - FileDescriptorWatcher *controller, - Watcher *delegate) { - return pump_libevent()->WatchFileDescriptor( - fd, - persistent, - mode, - controller, - delegate); -} - -#endif - -} // namespace base diff --git a/base/message_loop/message_loop.h b/base/message_loop/message_loop.h deleted file mode 100644 index f22c9044d1..0000000000 --- a/base/message_loop/message_loop.h +++ /dev/null @@ -1,719 +0,0 @@ -// Copyright 2013 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef BASE_MESSAGE_LOOP_MESSAGE_LOOP_H_ -#define BASE_MESSAGE_LOOP_MESSAGE_LOOP_H_ - -#include -#include - -#include "base/base_export.h" -#include "base/basictypes.h" -#include "base/callback_forward.h" -#include "base/location.h" -#include "base/memory/ref_counted.h" -#include "base/memory/scoped_ptr.h" -#include "base/message_loop/incoming_task_queue.h" -#include "base/message_loop/message_loop_proxy.h" -#include "base/message_loop/message_loop_proxy_impl.h" -#include "base/message_loop/message_pump.h" -#include "base/observer_list.h" -#include "base/pending_task.h" -#include "base/sequenced_task_runner_helpers.h" -#include "base/synchronization/lock.h" -#include "base/time/time.h" -#include "base/tracking_info.h" - -#if defined(OS_WIN) -// We need this to declare base::MessagePumpWin::Dispatcher, which we should -// really just eliminate. -#include "base/message_loop/message_pump_win.h" -#elif defined(OS_IOS) -#include "base/message_loop/message_pump_io_ios.h" -#elif defined(OS_POSIX) -#include "base/message_loop/message_pump_libevent.h" -#if !defined(OS_MACOSX) && !defined(OS_ANDROID) - -#if defined(USE_AURA) && defined(USE_X11) && !defined(OS_NACL) -#include "base/message_loop/message_pump_aurax11.h" -#elif defined(USE_OZONE) && !defined(OS_NACL) -#include "base/message_loop/message_pump_ozone.h" -#else -#include "base/message_loop/message_pump_gtk.h" -#endif - -#endif -#endif - -namespace base { - -class HistogramBase; -class RunLoop; -class ThreadTaskRunnerHandle; -#if defined(OS_ANDROID) -class MessagePumpForUI; -#endif -class WaitableEvent; - -// A MessageLoop is used to process events for a particular thread. There is -// at most one MessageLoop instance per thread. -// -// Events include at a minimum Task instances submitted to PostTask and its -// variants. Depending on the type of message pump used by the MessageLoop -// other events such as UI messages may be processed. On Windows APC calls (as -// time permits) and signals sent to a registered set of HANDLEs may also be -// processed. -// -// NOTE: Unless otherwise specified, a MessageLoop's methods may only be called -// on the thread where the MessageLoop's Run method executes. -// -// NOTE: MessageLoop has task reentrancy protection. This means that if a -// task is being processed, a second task cannot start until the first task is -// finished. Reentrancy can happen when processing a task, and an inner -// message pump is created. That inner pump then processes native messages -// which could implicitly start an inner task. Inner message pumps are created -// with dialogs (DialogBox), common dialogs (GetOpenFileName), OLE functions -// (DoDragDrop), printer functions (StartDoc) and *many* others. -// -// Sample workaround when inner task processing is needed: -// HRESULT hr; -// { -// MessageLoop::ScopedNestableTaskAllower allow(MessageLoop::current()); -// hr = DoDragDrop(...); // Implicitly runs a modal message loop. -// } -// // Process |hr| (the result returned by DoDragDrop()). -// -// Please be SURE your task is reentrant (nestable) and all global variables -// are stable and accessible before calling SetNestableTasksAllowed(true). -// -class BASE_EXPORT MessageLoop : public MessagePump::Delegate { - public: - -#if !defined(OS_MACOSX) && !defined(OS_ANDROID) - typedef MessagePumpDispatcher Dispatcher; - typedef MessagePumpObserver Observer; -#endif - - // A MessageLoop has a particular type, which indicates the set of - // asynchronous events it may process in addition to tasks and timers. - // - // TYPE_DEFAULT - // This type of ML only supports tasks and timers. - // - // TYPE_UI - // This type of ML also supports native UI events (e.g., Windows messages). - // See also MessageLoopForUI. - // - // TYPE_IO - // This type of ML also supports asynchronous IO. See also - // MessageLoopForIO. - // - // TYPE_JAVA - // This type of ML is backed by a Java message handler which is responsible - // for running the tasks added to the ML. This is only for use on Android. - // TYPE_JAVA behaves in essence like TYPE_UI, except during construction - // where it does not use the main thread specific pump factory. - // - enum Type { - TYPE_DEFAULT, - TYPE_UI, - TYPE_IO, -#if defined(OS_ANDROID) - TYPE_JAVA, -#endif // defined(OS_ANDROID) - }; - - // Normally, it is not necessary to instantiate a MessageLoop. Instead, it - // is typical to make use of the current thread's MessageLoop instance. - explicit MessageLoop(Type type = TYPE_DEFAULT); - virtual ~MessageLoop(); - - // Returns the MessageLoop object for the current thread, or null if none. - static MessageLoop* current(); - - static void EnableHistogrammer(bool enable_histogrammer); - - typedef MessagePump* (MessagePumpFactory)(); - // Uses the given base::MessagePumpForUIFactory to override the default - // MessagePump implementation for 'TYPE_UI'. Returns true if the factory - // was successfully registered. - static bool InitMessagePumpForUIFactory(MessagePumpFactory* factory); - - // A DestructionObserver is notified when the current MessageLoop is being - // destroyed. These observers are notified prior to MessageLoop::current() - // being changed to return NULL. This gives interested parties the chance to - // do final cleanup that depends on the MessageLoop. - // - // NOTE: Any tasks posted to the MessageLoop during this notification will - // not be run. Instead, they will be deleted. - // - class BASE_EXPORT DestructionObserver { - public: - virtual void WillDestroyCurrentMessageLoop() = 0; - - protected: - virtual ~DestructionObserver(); - }; - - // Add a DestructionObserver, which will start receiving notifications - // immediately. - void AddDestructionObserver(DestructionObserver* destruction_observer); - - // Remove a DestructionObserver. It is safe to call this method while a - // DestructionObserver is receiving a notification callback. - void RemoveDestructionObserver(DestructionObserver* destruction_observer); - - // The "PostTask" family of methods call the task's Run method asynchronously - // from within a message loop at some point in the future. - // - // With the PostTask variant, tasks are invoked in FIFO order, inter-mixed - // with normal UI or IO event processing. With the PostDelayedTask variant, - // tasks are called after at least approximately 'delay_ms' have elapsed. - // - // The NonNestable variants work similarly except that they promise never to - // dispatch the task from a nested invocation of MessageLoop::Run. Instead, - // such tasks get deferred until the top-most MessageLoop::Run is executing. - // - // The MessageLoop takes ownership of the Task, and deletes it after it has - // been Run(). - // - // PostTask(from_here, task) is equivalent to - // PostDelayedTask(from_here, task, 0). - // - // The TryPostTask is meant for the cases where the calling thread cannot - // block. If posting the task will block, the call returns false, the task - // is not posted but the task is consumed anyways. - // - // NOTE: These methods may be called on any thread. The Task will be invoked - // on the thread that executes MessageLoop::Run(). - void PostTask(const tracked_objects::Location& from_here, - const Closure& task); - - bool TryPostTask(const tracked_objects::Location& from_here, - const Closure& task); - - void PostDelayedTask(const tracked_objects::Location& from_here, - const Closure& task, - TimeDelta delay); - - void PostNonNestableTask(const tracked_objects::Location& from_here, - const Closure& task); - - void PostNonNestableDelayedTask(const tracked_objects::Location& from_here, - const Closure& task, - TimeDelta delay); - - // A variant on PostTask that deletes the given object. This is useful - // if the object needs to live until the next run of the MessageLoop (for - // example, deleting a RenderProcessHost from within an IPC callback is not - // good). - // - // NOTE: This method may be called on any thread. The object will be deleted - // on the thread that executes MessageLoop::Run(). If this is not the same - // as the thread that calls PostDelayedTask(FROM_HERE, ), then T MUST inherit - // from RefCountedThreadSafe! - template - void DeleteSoon(const tracked_objects::Location& from_here, const T* object) { - base::subtle::DeleteHelperInternal::DeleteViaSequencedTaskRunner( - this, from_here, object); - } - - // A variant on PostTask that releases the given reference counted object - // (by calling its Release method). This is useful if the object needs to - // live until the next run of the MessageLoop, or if the object needs to be - // released on a particular thread. - // - // NOTE: This method may be called on any thread. The object will be - // released (and thus possibly deleted) on the thread that executes - // MessageLoop::Run(). If this is not the same as the thread that calls - // PostDelayedTask(FROM_HERE, ), then T MUST inherit from - // RefCountedThreadSafe! - template - void ReleaseSoon(const tracked_objects::Location& from_here, - const T* object) { - base::subtle::ReleaseHelperInternal::ReleaseViaSequencedTaskRunner( - this, from_here, object); - } - - // Deprecated: use RunLoop instead. - // Run the message loop. - void Run(); - - // Deprecated: use RunLoop instead. - // Process all pending tasks, windows messages, etc., but don't wait/sleep. - // Return as soon as all items that can be run are taken care of. - void RunUntilIdle(); - - // TODO(jbates) remove this. crbug.com/131220. See QuitWhenIdle(). - void Quit() { QuitWhenIdle(); } - - // Deprecated: use RunLoop instead. - // - // Signals the Run method to return when it becomes idle. It will continue to - // process pending messages and future messages as long as they are enqueued. - // Warning: if the MessageLoop remains busy, it may never quit. Only use this - // Quit method when looping procedures (such as web pages) have been shut - // down. - // - // This method may only be called on the same thread that called Run, and Run - // must still be on the call stack. - // - // Use QuitClosure variants if you need to Quit another thread's MessageLoop, - // but note that doing so is fairly dangerous if the target thread makes - // nested calls to MessageLoop::Run. The problem being that you won't know - // which nested run loop you are quitting, so be careful! - void QuitWhenIdle(); - - // Deprecated: use RunLoop instead. - // - // This method is a variant of Quit, that does not wait for pending messages - // to be processed before returning from Run. - void QuitNow(); - - // TODO(jbates) remove this. crbug.com/131220. See QuitWhenIdleClosure(). - static Closure QuitClosure() { return QuitWhenIdleClosure(); } - - // Deprecated: use RunLoop instead. - // Construct a Closure that will call QuitWhenIdle(). Useful to schedule an - // arbitrary MessageLoop to QuitWhenIdle. - static Closure QuitWhenIdleClosure(); - - // Returns true if this loop is |type|. This allows subclasses (especially - // those in tests) to specialize how they are identified. - virtual bool IsType(Type type) const; - - // Returns the type passed to the constructor. - Type type() const { return type_; } - - // Optional call to connect the thread name with this loop. - void set_thread_name(const std::string& thread_name) { - DCHECK(thread_name_.empty()) << "Should not rename this thread!"; - thread_name_ = thread_name; - } - const std::string& thread_name() const { return thread_name_; } - - // Gets the message loop proxy associated with this message loop. - scoped_refptr message_loop_proxy() { - return message_loop_proxy_; - } - - // Enables or disables the recursive task processing. This happens in the case - // of recursive message loops. Some unwanted message loop may occurs when - // using common controls or printer functions. By default, recursive task - // processing is disabled. - // - // Please utilize |ScopedNestableTaskAllower| instead of calling these methods - // directly. In general nestable message loops are to be avoided. They are - // dangerous and difficult to get right, so please use with extreme caution. - // - // The specific case where tasks get queued is: - // - The thread is running a message loop. - // - It receives a task #1 and execute it. - // - The task #1 implicitly start a message loop, like a MessageBox in the - // unit test. This can also be StartDoc or GetSaveFileName. - // - The thread receives a task #2 before or while in this second message - // loop. - // - With NestableTasksAllowed set to true, the task #2 will run right away. - // Otherwise, it will get executed right after task #1 completes at "thread - // message loop level". - void SetNestableTasksAllowed(bool allowed); - bool NestableTasksAllowed() const; - - // Enables nestable tasks on |loop| while in scope. - class ScopedNestableTaskAllower { - public: - explicit ScopedNestableTaskAllower(MessageLoop* loop) - : loop_(loop), - old_state_(loop_->NestableTasksAllowed()) { - loop_->SetNestableTasksAllowed(true); - } - ~ScopedNestableTaskAllower() { - loop_->SetNestableTasksAllowed(old_state_); - } - - private: - MessageLoop* loop_; - bool old_state_; - }; - - // Enables or disables the restoration during an exception of the unhandled - // exception filter that was active when Run() was called. This can happen - // if some third party code call SetUnhandledExceptionFilter() and never - // restores the previous filter. - void set_exception_restoration(bool restore) { - exception_restoration_ = restore; - } - - // Returns true if we are currently running a nested message loop. - bool IsNested(); - - // A TaskObserver is an object that receives task notifications from the - // MessageLoop. - // - // NOTE: A TaskObserver implementation should be extremely fast! - class BASE_EXPORT TaskObserver { - public: - TaskObserver(); - - // This method is called before processing a task. - virtual void WillProcessTask(const PendingTask& pending_task) = 0; - - // This method is called after processing a task. - virtual void DidProcessTask(const PendingTask& pending_task) = 0; - - protected: - virtual ~TaskObserver(); - }; - - // These functions can only be called on the same thread that |this| is - // running on. - void AddTaskObserver(TaskObserver* task_observer); - void RemoveTaskObserver(TaskObserver* task_observer); - - // When we go into high resolution timer mode, we will stay in hi-res mode - // for at least 1s. - static const int kHighResolutionTimerModeLeaseTimeMs = 1000; - -#if defined(OS_WIN) - void set_os_modal_loop(bool os_modal_loop) { - os_modal_loop_ = os_modal_loop; - } - - bool os_modal_loop() const { - return os_modal_loop_; - } -#endif // OS_WIN - - // Can only be called from the thread that owns the MessageLoop. - bool is_running() const; - - // Returns true if the message loop has high resolution timers enabled. - // Provided for testing. - bool IsHighResolutionTimerEnabledForTesting(); - - // Returns true if the message loop is "idle". Provided for testing. - bool IsIdleForTesting(); - - // Takes the incoming queue lock, signals |caller_wait| and waits until - // |caller_signal| is signalled. - void LockWaitUnLockForTesting(WaitableEvent* caller_wait, - WaitableEvent* caller_signal); - - //---------------------------------------------------------------------------- - protected: - -#if defined(OS_WIN) - MessagePumpWin* pump_win() { - return static_cast(pump_.get()); - } -#elif defined(OS_POSIX) && !defined(OS_IOS) - MessagePumpLibevent* pump_libevent() { - return static_cast(pump_.get()); - } -#endif - - scoped_ptr pump_; - - private: - friend class internal::IncomingTaskQueue; - friend class RunLoop; - - // A function to encapsulate all the exception handling capability in the - // stacks around the running of a main message loop. It will run the message - // loop in a SEH try block or not depending on the set_SEH_restoration() - // flag invoking respectively RunInternalInSEHFrame() or RunInternal(). - void RunHandler(); - -#if defined(OS_WIN) - __declspec(noinline) void RunInternalInSEHFrame(); -#endif - - // A surrounding stack frame around the running of the message loop that - // supports all saving and restoring of state, as is needed for any/all (ugly) - // recursive calls. - void RunInternal(); - - // Called to process any delayed non-nestable tasks. - bool ProcessNextDelayedNonNestableTask(); - - // Runs the specified PendingTask. - void RunTask(const PendingTask& pending_task); - - // Calls RunTask or queues the pending_task on the deferred task list if it - // cannot be run right now. Returns true if the task was run. - bool DeferOrRunPendingTask(const PendingTask& pending_task); - - // Adds the pending task to delayed_work_queue_. - void AddToDelayedWorkQueue(const PendingTask& pending_task); - - // Delete tasks that haven't run yet without running them. Used in the - // destructor to make sure all the task's destructors get called. Returns - // true if some work was done. - bool DeletePendingTasks(); - - // Creates a process-wide unique ID to represent this task in trace events. - // This will be mangled with a Process ID hash to reduce the likelyhood of - // colliding with MessageLoop pointers on other processes. - uint64 GetTaskTraceID(const PendingTask& task); - - // Loads tasks from the incoming queue to |work_queue_| if the latter is - // empty. - void ReloadWorkQueue(); - - // Wakes up the message pump. Can be called on any thread. The caller is - // responsible for synchronizing ScheduleWork() calls. - void ScheduleWork(bool was_empty); - - // Start recording histogram info about events and action IF it was enabled - // and IF the statistics recorder can accept a registration of our histogram. - void StartHistogrammer(); - - // Add occurrence of event to our histogram, so that we can see what is being - // done in a specific MessageLoop instance (i.e., specific thread). - // If message_histogram_ is NULL, this is a no-op. - void HistogramEvent(int event); - - // MessagePump::Delegate methods: - virtual bool DoWork() OVERRIDE; - virtual bool DoDelayedWork(TimeTicks* next_delayed_work_time) OVERRIDE; - virtual bool DoIdleWork() OVERRIDE; - - Type type_; - - // A list of tasks that need to be processed by this instance. Note that - // this queue is only accessed (push/pop) by our current thread. - TaskQueue work_queue_; - - // Contains delayed tasks, sorted by their 'delayed_run_time' property. - DelayedTaskQueue delayed_work_queue_; - - // A recent snapshot of Time::Now(), used to check delayed_work_queue_. - TimeTicks recent_time_; - - // A queue of non-nestable tasks that we had to defer because when it came - // time to execute them we were in a nested message loop. They will execute - // once we're out of nested message loops. - TaskQueue deferred_non_nestable_work_queue_; - - ObserverList destruction_observers_; - - bool exception_restoration_; - - // A recursion block that prevents accidentally running additional tasks when - // insider a (accidentally induced?) nested message pump. - bool nestable_tasks_allowed_; - -#if defined(OS_WIN) - // Should be set to true before calling Windows APIs like TrackPopupMenu, etc - // which enter a modal message loop. - bool os_modal_loop_; -#endif - - std::string thread_name_; - // A profiling histogram showing the counts of various messages and events. - HistogramBase* message_histogram_; - - RunLoop* run_loop_; - - ObserverList task_observers_; - - scoped_refptr incoming_task_queue_; - - // The message loop proxy associated with this message loop. - scoped_refptr message_loop_proxy_; - scoped_ptr thread_task_runner_handle_; - - template friend class base::subtle::DeleteHelperInternal; - template friend class base::subtle::ReleaseHelperInternal; - - void DeleteSoonInternal(const tracked_objects::Location& from_here, - void(*deleter)(const void*), - const void* object); - void ReleaseSoonInternal(const tracked_objects::Location& from_here, - void(*releaser)(const void*), - const void* object); - - DISALLOW_COPY_AND_ASSIGN(MessageLoop); -}; - -//----------------------------------------------------------------------------- -// MessageLoopForUI extends MessageLoop with methods that are particular to a -// MessageLoop instantiated with TYPE_UI. -// -// This class is typically used like so: -// MessageLoopForUI::current()->...call some method... -// -class BASE_EXPORT MessageLoopForUI : public MessageLoop { - public: -#if defined(OS_WIN) - typedef MessagePumpForUI::MessageFilter MessageFilter; -#endif - - MessageLoopForUI() : MessageLoop(TYPE_UI) { - } - - // Returns the MessageLoopForUI of the current thread. - static MessageLoopForUI* current() { - MessageLoop* loop = MessageLoop::current(); - DCHECK(loop); - DCHECK_EQ(MessageLoop::TYPE_UI, loop->type()); - return static_cast(loop); - } - -#if defined(OS_WIN) - void DidProcessMessage(const MSG& message); -#endif // defined(OS_WIN) - -#if defined(OS_IOS) - // On iOS, the main message loop cannot be Run(). Instead call Attach(), - // which connects this MessageLoop to the UI thread's CFRunLoop and allows - // PostTask() to work. - void Attach(); -#endif - -#if defined(OS_ANDROID) - // On Android, the UI message loop is handled by Java side. So Run() should - // never be called. Instead use Start(), which will forward all the native UI - // events to the Java message loop. - void Start(); -#elif !defined(OS_MACOSX) - - // Please see message_pump_win/message_pump_glib for definitions of these - // methods. - void AddObserver(Observer* observer); - void RemoveObserver(Observer* observer); - -#if defined(OS_WIN) - // Plese see MessagePumpForUI for definitions of this method. - void SetMessageFilter(scoped_ptr message_filter) { - pump_ui()->SetMessageFilter(message_filter.Pass()); - } -#endif - - protected: -#if defined(USE_AURA) && defined(USE_X11) && !defined(OS_NACL) - friend class MessagePumpAuraX11; -#endif -#if defined(USE_OZONE) && !defined(OS_NACL) - friend class MessagePumpOzone; -#endif - - // TODO(rvargas): Make this platform independent. - MessagePumpForUI* pump_ui() { - return static_cast(pump_.get()); - } -#endif // !defined(OS_MACOSX) -}; - -// Do not add any member variables to MessageLoopForUI! This is important b/c -// MessageLoopForUI is often allocated via MessageLoop(TYPE_UI). Any extra -// data that you need should be stored on the MessageLoop's pump_ instance. -COMPILE_ASSERT(sizeof(MessageLoop) == sizeof(MessageLoopForUI), - MessageLoopForUI_should_not_have_extra_member_variables); - -//----------------------------------------------------------------------------- -// MessageLoopForIO extends MessageLoop with methods that are particular to a -// MessageLoop instantiated with TYPE_IO. -// -// This class is typically used like so: -// MessageLoopForIO::current()->...call some method... -// -class BASE_EXPORT MessageLoopForIO : public MessageLoop { - public: -#if defined(OS_WIN) - typedef MessagePumpForIO::IOHandler IOHandler; - typedef MessagePumpForIO::IOContext IOContext; - typedef MessagePumpForIO::IOObserver IOObserver; -#elif defined(OS_IOS) - typedef MessagePumpIOSForIO::Watcher Watcher; - typedef MessagePumpIOSForIO::FileDescriptorWatcher - FileDescriptorWatcher; - typedef MessagePumpIOSForIO::IOObserver IOObserver; - - enum Mode { - WATCH_READ = MessagePumpIOSForIO::WATCH_READ, - WATCH_WRITE = MessagePumpIOSForIO::WATCH_WRITE, - WATCH_READ_WRITE = MessagePumpIOSForIO::WATCH_READ_WRITE - }; -#elif defined(OS_POSIX) - typedef MessagePumpLibevent::Watcher Watcher; - typedef MessagePumpLibevent::FileDescriptorWatcher - FileDescriptorWatcher; - typedef MessagePumpLibevent::IOObserver IOObserver; - - enum Mode { - WATCH_READ = MessagePumpLibevent::WATCH_READ, - WATCH_WRITE = MessagePumpLibevent::WATCH_WRITE, - WATCH_READ_WRITE = MessagePumpLibevent::WATCH_READ_WRITE - }; - -#endif - - MessageLoopForIO() : MessageLoop(TYPE_IO) { - } - - // Returns the MessageLoopForIO of the current thread. - static MessageLoopForIO* current() { - MessageLoop* loop = MessageLoop::current(); - DCHECK_EQ(MessageLoop::TYPE_IO, loop->type()); - return static_cast(loop); - } - - void AddIOObserver(IOObserver* io_observer) { - pump_io()->AddIOObserver(io_observer); - } - - void RemoveIOObserver(IOObserver* io_observer) { - pump_io()->RemoveIOObserver(io_observer); - } - -#if defined(OS_WIN) - // Please see MessagePumpWin for definitions of these methods. - void RegisterIOHandler(HANDLE file, IOHandler* handler); - bool RegisterJobObject(HANDLE job, IOHandler* handler); - bool WaitForIOCompletion(DWORD timeout, IOHandler* filter); - - protected: - // TODO(rvargas): Make this platform independent. - MessagePumpForIO* pump_io() { - return static_cast(pump_.get()); - } - -#elif defined(OS_IOS) - // Please see MessagePumpIOSForIO for definition. - bool WatchFileDescriptor(int fd, - bool persistent, - Mode mode, - FileDescriptorWatcher *controller, - Watcher *delegate); - - private: - MessagePumpIOSForIO* pump_io() { - return static_cast(pump_.get()); - } - -#elif defined(OS_POSIX) - // Please see MessagePumpLibevent for definition. - bool WatchFileDescriptor(int fd, - bool persistent, - Mode mode, - FileDescriptorWatcher* controller, - Watcher* delegate); - - private: - MessagePumpLibevent* pump_io() { - return static_cast(pump_.get()); - } -#endif // defined(OS_POSIX) -}; - -// Do not add any member variables to MessageLoopForIO! This is important b/c -// MessageLoopForIO is often allocated via MessageLoop(TYPE_IO). Any extra -// data that you need should be stored on the MessageLoop's pump_ instance. -COMPILE_ASSERT(sizeof(MessageLoop) == sizeof(MessageLoopForIO), - MessageLoopForIO_should_not_have_extra_member_variables); - -} // namespace base - -#endif // BASE_MESSAGE_LOOP_MESSAGE_LOOP_H_ diff --git a/base/message_loop/message_loop_proxy.cc b/base/message_loop/message_loop_proxy.cc deleted file mode 100644 index e5f0142633..0000000000 --- a/base/message_loop/message_loop_proxy.cc +++ /dev/null @@ -1,17 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "base/message_loop/message_loop_proxy.h" - -#include "base/bind.h" - -namespace base { - -MessageLoopProxy::MessageLoopProxy() { -} - -MessageLoopProxy::~MessageLoopProxy() { -} - -} // namespace base diff --git a/base/message_loop/message_loop_proxy.h b/base/message_loop/message_loop_proxy.h deleted file mode 100644 index 4ace8026db..0000000000 --- a/base/message_loop/message_loop_proxy.h +++ /dev/null @@ -1,38 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef BASE_MESSAGE_LOOP_MESSAGE_LOOP_PROXY_H_ -#define BASE_MESSAGE_LOOP_MESSAGE_LOOP_PROXY_H_ - -#include "base/base_export.h" -#include "base/compiler_specific.h" -#include "base/memory/ref_counted.h" -#include "base/single_thread_task_runner.h" - -namespace base { - -// This class provides a thread-safe refcounted interface to the Post* methods -// of a message loop. This class can outlive the target message loop. -// MessageLoopProxy objects are constructed automatically for all MessageLoops. -// So, to access them, you can use any of the following: -// Thread::message_loop_proxy() -// MessageLoop::current()->message_loop_proxy() -// MessageLoopProxy::current() -// -// TODO(akalin): Now that we have the *TaskRunner interfaces, we can -// merge this with MessageLoopProxyImpl. -class BASE_EXPORT MessageLoopProxy : public SingleThreadTaskRunner { - public: - // Gets the MessageLoopProxy for the current message loop, creating one if - // needed. - static scoped_refptr current(); - - protected: - MessageLoopProxy(); - virtual ~MessageLoopProxy(); -}; - -} // namespace base - -#endif // BASE_MESSAGE_LOOP_MESSAGE_LOOP_PROXY_H_ diff --git a/base/message_loop/message_loop_proxy_impl.cc b/base/message_loop/message_loop_proxy_impl.cc deleted file mode 100644 index b7abca377e..0000000000 --- a/base/message_loop/message_loop_proxy_impl.cc +++ /dev/null @@ -1,54 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "base/message_loop/message_loop_proxy_impl.h" - -#include "base/location.h" -#include "base/logging.h" -#include "base/message_loop/incoming_task_queue.h" -#include "base/message_loop/message_loop.h" - -namespace base { -namespace internal { - -MessageLoopProxyImpl::MessageLoopProxyImpl( - scoped_refptr incoming_queue) - : incoming_queue_(incoming_queue), - valid_thread_id_(PlatformThread::CurrentId()) { -} - -bool MessageLoopProxyImpl::PostDelayedTask( - const tracked_objects::Location& from_here, - const base::Closure& task, - base::TimeDelta delay) { - DCHECK(!task.is_null()) << from_here.ToString(); - return incoming_queue_->AddToIncomingQueue(from_here, task, delay, true); -} - -bool MessageLoopProxyImpl::PostNonNestableDelayedTask( - const tracked_objects::Location& from_here, - const base::Closure& task, - base::TimeDelta delay) { - DCHECK(!task.is_null()) << from_here.ToString(); - return incoming_queue_->AddToIncomingQueue(from_here, task, delay, false); -} - -bool MessageLoopProxyImpl::RunsTasksOnCurrentThread() const { - return valid_thread_id_ == PlatformThread::CurrentId(); -} - -MessageLoopProxyImpl::~MessageLoopProxyImpl() { -} - -} // namespace internal - -scoped_refptr -MessageLoopProxy::current() { - MessageLoop* cur_loop = MessageLoop::current(); - if (!cur_loop) - return NULL; - return cur_loop->message_loop_proxy(); -} - -} // namespace base diff --git a/base/message_loop/message_loop_proxy_impl.h b/base/message_loop/message_loop_proxy_impl.h deleted file mode 100644 index b7f62b9770..0000000000 --- a/base/message_loop/message_loop_proxy_impl.h +++ /dev/null @@ -1,53 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef BASE_MESSAGE_LOOP_MESSAGE_LOOP_PROXY_IMPL_H_ -#define BASE_MESSAGE_LOOP_MESSAGE_LOOP_PROXY_IMPL_H_ - -#include "base/base_export.h" -#include "base/memory/ref_counted.h" -#include "base/message_loop/message_loop_proxy.h" -#include "base/pending_task.h" -#include "base/threading/platform_thread.h" - -namespace base { -namespace internal { - -class IncomingTaskQueue; - -// A stock implementation of MessageLoopProxy that is created and managed by a -// MessageLoop. For now a MessageLoopProxyImpl can only be created as part of a -// MessageLoop. -class BASE_EXPORT MessageLoopProxyImpl : public MessageLoopProxy { - public: - explicit MessageLoopProxyImpl( - scoped_refptr incoming_queue); - - // MessageLoopProxy implementation - virtual bool PostDelayedTask(const tracked_objects::Location& from_here, - const base::Closure& task, - base::TimeDelta delay) OVERRIDE; - virtual bool PostNonNestableDelayedTask( - const tracked_objects::Location& from_here, - const base::Closure& task, - base::TimeDelta delay) OVERRIDE; - virtual bool RunsTasksOnCurrentThread() const OVERRIDE; - - private: - friend class RefCountedThreadSafe; - virtual ~MessageLoopProxyImpl(); - - // THe incoming queue receiving all posted tasks. - scoped_refptr incoming_queue_; - - // ID of the thread |this| was created on. - PlatformThreadId valid_thread_id_; - - DISALLOW_COPY_AND_ASSIGN(MessageLoopProxyImpl); -}; - -} // namespace internal -} // namespace base - -#endif // BASE_MESSAGE_LOOP_MESSAGE_LOOP_PROXY_IMPL_H_ diff --git a/base/message_loop/message_loop_proxy_impl_unittest.cc b/base/message_loop/message_loop_proxy_impl_unittest.cc deleted file mode 100644 index 81c9b0c51b..0000000000 --- a/base/message_loop/message_loop_proxy_impl_unittest.cc +++ /dev/null @@ -1,129 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "base/message_loop/message_loop_proxy_impl.h" - -#include "base/bind.h" -#include "base/memory/scoped_ptr.h" -#include "base/message_loop/message_loop.h" -#include "base/message_loop/message_loop_proxy.h" -#include "base/threading/thread.h" -#include "testing/gtest/include/gtest/gtest.h" -#include "testing/platform_test.h" - -namespace base { - -class MessageLoopProxyImplTest : public testing::Test { - public: - void Release() const { - AssertOnIOThread(); - Quit(); - } - - void Quit() const { - loop_.PostTask(FROM_HERE, MessageLoop::QuitWhenIdleClosure()); - } - - void AssertOnIOThread() const { - ASSERT_TRUE(io_thread_->message_loop_proxy()->BelongsToCurrentThread()); - ASSERT_EQ(io_thread_->message_loop_proxy(), - MessageLoopProxy::current()); - } - - void AssertOnFileThread() const { - ASSERT_TRUE(file_thread_->message_loop_proxy()->BelongsToCurrentThread()); - ASSERT_EQ(file_thread_->message_loop_proxy(), - MessageLoopProxy::current()); - } - - protected: - virtual void SetUp() OVERRIDE { - io_thread_.reset(new Thread("MessageLoopProxyImplTest_IO")); - file_thread_.reset(new Thread("MessageLoopProxyImplTest_File")); - io_thread_->Start(); - file_thread_->Start(); - } - - virtual void TearDown() OVERRIDE { - io_thread_->Stop(); - file_thread_->Stop(); - } - - static void BasicFunction(MessageLoopProxyImplTest* test) { - test->AssertOnFileThread(); - test->Quit(); - } - - static void AssertNotRun() { - FAIL() << "Callback Should not get executed."; - } - - class DeletedOnFile { - public: - explicit DeletedOnFile(MessageLoopProxyImplTest* test) : test_(test) {} - - ~DeletedOnFile() { - test_->AssertOnFileThread(); - test_->Quit(); - } - - private: - MessageLoopProxyImplTest* test_; - }; - - scoped_ptr io_thread_; - scoped_ptr file_thread_; - - private: - mutable MessageLoop loop_; -}; - -TEST_F(MessageLoopProxyImplTest, Release) { - EXPECT_TRUE(io_thread_->message_loop_proxy()->ReleaseSoon(FROM_HERE, this)); - MessageLoop::current()->Run(); -} - -TEST_F(MessageLoopProxyImplTest, Delete) { - DeletedOnFile* deleted_on_file = new DeletedOnFile(this); - EXPECT_TRUE(file_thread_->message_loop_proxy()->DeleteSoon( - FROM_HERE, deleted_on_file)); - MessageLoop::current()->Run(); -} - -TEST_F(MessageLoopProxyImplTest, PostTask) { - EXPECT_TRUE(file_thread_->message_loop_proxy()->PostTask( - FROM_HERE, Bind(&MessageLoopProxyImplTest::BasicFunction, - Unretained(this)))); - MessageLoop::current()->Run(); -} - -TEST_F(MessageLoopProxyImplTest, PostTaskAfterThreadExits) { - scoped_ptr test_thread( - new Thread("MessageLoopProxyImplTest_Dummy")); - test_thread->Start(); - scoped_refptr message_loop_proxy = - test_thread->message_loop_proxy(); - test_thread->Stop(); - - bool ret = message_loop_proxy->PostTask( - FROM_HERE, - Bind(&MessageLoopProxyImplTest::AssertNotRun)); - EXPECT_FALSE(ret); -} - -TEST_F(MessageLoopProxyImplTest, PostTaskAfterThreadIsDeleted) { - scoped_refptr message_loop_proxy; - { - scoped_ptr test_thread( - new Thread("MessageLoopProxyImplTest_Dummy")); - test_thread->Start(); - message_loop_proxy = test_thread->message_loop_proxy(); - } - bool ret = message_loop_proxy->PostTask( - FROM_HERE, - Bind(&MessageLoopProxyImplTest::AssertNotRun)); - EXPECT_FALSE(ret); -} - -} // namespace base diff --git a/base/message_loop/message_loop_proxy_unittest.cc b/base/message_loop/message_loop_proxy_unittest.cc deleted file mode 100644 index ada9080811..0000000000 --- a/base/message_loop/message_loop_proxy_unittest.cc +++ /dev/null @@ -1,266 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "base/message_loop/message_loop_proxy.h" - -#include "base/atomic_sequence_num.h" -#include "base/bind.h" -#include "base/debug/leak_annotations.h" -#include "base/memory/ref_counted.h" -#include "base/memory/scoped_ptr.h" -#include "base/message_loop/message_loop.h" -#include "base/synchronization/waitable_event.h" -#include "base/threading/thread.h" -#include "testing/gtest/include/gtest/gtest.h" - -namespace base { - -namespace { - -class MessageLoopProxyTest : public testing::Test { - public: - MessageLoopProxyTest() - : current_loop_(new MessageLoop()), - task_thread_("task_thread"), - thread_sync_(true, false) { - } - - void DeleteCurrentMessageLoop() { - current_loop_.reset(); - } - - protected: - virtual void SetUp() OVERRIDE { - // Use SetUp() instead of the constructor to avoid posting a task to a - // partialy constructed object. - task_thread_.Start(); - - // Allow us to pause the |task_thread_|'s MessageLoop. - task_thread_.message_loop()->PostTask( - FROM_HERE, - Bind(&MessageLoopProxyTest::BlockTaskThreadHelper, Unretained(this))); - } - - virtual void TearDown() OVERRIDE { - // Make sure the |task_thread_| is not blocked, and stop the thread - // fully before destuction because its tasks may still depend on the - // |thread_sync_| event. - thread_sync_.Signal(); - task_thread_.Stop(); - DeleteCurrentMessageLoop(); - } - - // Make LoopRecorder threadsafe so that there is defined behavior even if a - // threading mistake sneaks into the PostTaskAndReplyRelay implementation. - class LoopRecorder : public RefCountedThreadSafe { - public: - LoopRecorder(MessageLoop** run_on, MessageLoop** deleted_on, - int* destruct_order) - : run_on_(run_on), - deleted_on_(deleted_on), - destruct_order_(destruct_order) { - } - - void RecordRun() { - *run_on_ = MessageLoop::current(); - } - - private: - friend class RefCountedThreadSafe; - ~LoopRecorder() { - *deleted_on_ = MessageLoop::current(); - *destruct_order_ = g_order.GetNext(); - } - - MessageLoop** run_on_; - MessageLoop** deleted_on_; - int* destruct_order_; - }; - - static void RecordLoop(scoped_refptr recorder) { - recorder->RecordRun(); - } - - static void RecordLoopAndQuit(scoped_refptr recorder) { - recorder->RecordRun(); - MessageLoop::current()->QuitWhenIdle(); - } - - void UnblockTaskThread() { - thread_sync_.Signal(); - } - - void BlockTaskThreadHelper() { - thread_sync_.Wait(); - } - - static StaticAtomicSequenceNumber g_order; - - scoped_ptr current_loop_; - Thread task_thread_; - - private: - base::WaitableEvent thread_sync_; -}; - -StaticAtomicSequenceNumber MessageLoopProxyTest::g_order; - -TEST_F(MessageLoopProxyTest, PostTaskAndReply_Basic) { - MessageLoop* task_run_on = NULL; - MessageLoop* task_deleted_on = NULL; - int task_delete_order = -1; - MessageLoop* reply_run_on = NULL; - MessageLoop* reply_deleted_on = NULL; - int reply_delete_order = -1; - - scoped_refptr task_recoder = - new LoopRecorder(&task_run_on, &task_deleted_on, &task_delete_order); - scoped_refptr reply_recoder = - new LoopRecorder(&reply_run_on, &reply_deleted_on, &reply_delete_order); - - ASSERT_TRUE(task_thread_.message_loop_proxy()->PostTaskAndReply( - FROM_HERE, - Bind(&RecordLoop, task_recoder), - Bind(&RecordLoopAndQuit, reply_recoder))); - - // Die if base::Bind doesn't retain a reference to the recorders. - task_recoder = NULL; - reply_recoder = NULL; - ASSERT_FALSE(task_deleted_on); - ASSERT_FALSE(reply_deleted_on); - - UnblockTaskThread(); - current_loop_->Run(); - - EXPECT_EQ(task_thread_.message_loop(), task_run_on); - EXPECT_EQ(current_loop_.get(), task_deleted_on); - EXPECT_EQ(current_loop_.get(), reply_run_on); - EXPECT_EQ(current_loop_.get(), reply_deleted_on); - EXPECT_LT(task_delete_order, reply_delete_order); -} - -TEST_F(MessageLoopProxyTest, PostTaskAndReplyOnDeletedThreadDoesNotLeak) { - MessageLoop* task_run_on = NULL; - MessageLoop* task_deleted_on = NULL; - int task_delete_order = -1; - MessageLoop* reply_run_on = NULL; - MessageLoop* reply_deleted_on = NULL; - int reply_delete_order = -1; - - scoped_refptr task_recoder = - new LoopRecorder(&task_run_on, &task_deleted_on, &task_delete_order); - scoped_refptr reply_recoder = - new LoopRecorder(&reply_run_on, &reply_deleted_on, &reply_delete_order); - - // Grab a MessageLoopProxy to a dead MessageLoop. - scoped_refptr task_loop_proxy = - task_thread_.message_loop_proxy(); - UnblockTaskThread(); - task_thread_.Stop(); - - ASSERT_FALSE(task_loop_proxy->PostTaskAndReply( - FROM_HERE, - Bind(&RecordLoop, task_recoder), - Bind(&RecordLoopAndQuit, reply_recoder))); - - // The relay should have properly deleted its resources leaving us as the only - // reference. - EXPECT_EQ(task_delete_order, reply_delete_order); - ASSERT_TRUE(task_recoder->HasOneRef()); - ASSERT_TRUE(reply_recoder->HasOneRef()); - - // Nothing should have run though. - EXPECT_FALSE(task_run_on); - EXPECT_FALSE(reply_run_on); -} - -TEST_F(MessageLoopProxyTest, PostTaskAndReply_SameLoop) { - MessageLoop* task_run_on = NULL; - MessageLoop* task_deleted_on = NULL; - int task_delete_order = -1; - MessageLoop* reply_run_on = NULL; - MessageLoop* reply_deleted_on = NULL; - int reply_delete_order = -1; - - scoped_refptr task_recoder = - new LoopRecorder(&task_run_on, &task_deleted_on, &task_delete_order); - scoped_refptr reply_recoder = - new LoopRecorder(&reply_run_on, &reply_deleted_on, &reply_delete_order); - - // Enqueue the relay. - ASSERT_TRUE(current_loop_->message_loop_proxy()->PostTaskAndReply( - FROM_HERE, - Bind(&RecordLoop, task_recoder), - Bind(&RecordLoopAndQuit, reply_recoder))); - - // Die if base::Bind doesn't retain a reference to the recorders. - task_recoder = NULL; - reply_recoder = NULL; - ASSERT_FALSE(task_deleted_on); - ASSERT_FALSE(reply_deleted_on); - - current_loop_->Run(); - - EXPECT_EQ(current_loop_.get(), task_run_on); - EXPECT_EQ(current_loop_.get(), task_deleted_on); - EXPECT_EQ(current_loop_.get(), reply_run_on); - EXPECT_EQ(current_loop_.get(), reply_deleted_on); - EXPECT_LT(task_delete_order, reply_delete_order); -} - -TEST_F(MessageLoopProxyTest, PostTaskAndReply_DeadReplyLoopDoesNotDelete) { - // Annotate the scope as having memory leaks to suppress heapchecker reports. - ANNOTATE_SCOPED_MEMORY_LEAK; - MessageLoop* task_run_on = NULL; - MessageLoop* task_deleted_on = NULL; - int task_delete_order = -1; - MessageLoop* reply_run_on = NULL; - MessageLoop* reply_deleted_on = NULL; - int reply_delete_order = -1; - - scoped_refptr task_recoder = - new LoopRecorder(&task_run_on, &task_deleted_on, &task_delete_order); - scoped_refptr reply_recoder = - new LoopRecorder(&reply_run_on, &reply_deleted_on, &reply_delete_order); - - // Enqueue the relay. - task_thread_.message_loop_proxy()->PostTaskAndReply( - FROM_HERE, - Bind(&RecordLoop, task_recoder), - Bind(&RecordLoopAndQuit, reply_recoder)); - - // Die if base::Bind doesn't retain a reference to the recorders. - task_recoder = NULL; - reply_recoder = NULL; - ASSERT_FALSE(task_deleted_on); - ASSERT_FALSE(reply_deleted_on); - - UnblockTaskThread(); - - // Mercilessly whack the current loop before |reply| gets to run. - current_loop_.reset(); - - // This should ensure the relay has been run. We need to record the - // MessageLoop pointer before stopping the thread because Thread::Stop() will - // NULL out its own pointer. - MessageLoop* task_loop = task_thread_.message_loop(); - task_thread_.Stop(); - - EXPECT_EQ(task_loop, task_run_on); - ASSERT_FALSE(task_deleted_on); - EXPECT_FALSE(reply_run_on); - ASSERT_FALSE(reply_deleted_on); - EXPECT_EQ(task_delete_order, reply_delete_order); - - // The PostTaskAndReplyRelay is leaked here. Even if we had a reference to - // it, we cannot just delete it because PostTaskAndReplyRelay's destructor - // checks that MessageLoop::current() is the the same as when the - // PostTaskAndReplyRelay object was constructed. However, this loop must have - // aleady been deleted in order to perform this test. See - // http://crbug.com/86301. -} - -} // namespace - -} // namespace base diff --git a/base/message_loop/message_loop_unittest.cc b/base/message_loop/message_loop_unittest.cc deleted file mode 100644 index ab05b3cb5a..0000000000 --- a/base/message_loop/message_loop_unittest.cc +++ /dev/null @@ -1,2104 +0,0 @@ -// Copyright 2013 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include - -#include "base/bind.h" -#include "base/bind_helpers.h" -#include "base/compiler_specific.h" -#include "base/logging.h" -#include "base/memory/ref_counted.h" -#include "base/message_loop/message_loop.h" -#include "base/message_loop/message_loop_proxy_impl.h" -#include "base/pending_task.h" -#include "base/posix/eintr_wrapper.h" -#include "base/run_loop.h" -#include "base/synchronization/waitable_event.h" -#include "base/thread_task_runner_handle.h" -#include "base/threading/platform_thread.h" -#include "base/threading/thread.h" -#include "testing/gtest/include/gtest/gtest.h" - -#if defined(OS_WIN) -#include "base/message_loop/message_pump_win.h" -#include "base/win/scoped_handle.h" -#endif - -namespace base { - -// TODO(darin): Platform-specific MessageLoop tests should be grouped together -// to avoid chopping this file up with so many #ifdefs. - -namespace { - -class Foo : public RefCounted { - public: - Foo() : test_count_(0) { - } - - void Test0() { - ++test_count_; - } - - void Test1ConstRef(const std::string& a) { - ++test_count_; - result_.append(a); - } - - void Test1Ptr(std::string* a) { - ++test_count_; - result_.append(*a); - } - - void Test1Int(int a) { - test_count_ += a; - } - - void Test2Ptr(std::string* a, std::string* b) { - ++test_count_; - result_.append(*a); - result_.append(*b); - } - - void Test2Mixed(const std::string& a, std::string* b) { - ++test_count_; - result_.append(a); - result_.append(*b); - } - - int test_count() const { return test_count_; } - const std::string& result() const { return result_; } - - private: - friend class RefCounted; - - ~Foo() {} - - int test_count_; - std::string result_; -}; - -void RunTest_PostTask(MessageLoop::Type message_loop_type) { - MessageLoop loop(message_loop_type); - - // Add tests to message loop - scoped_refptr foo(new Foo()); - std::string a("a"), b("b"), c("c"), d("d"); - MessageLoop::current()->PostTask(FROM_HERE, Bind( - &Foo::Test0, foo.get())); - MessageLoop::current()->PostTask(FROM_HERE, Bind( - &Foo::Test1ConstRef, foo.get(), a)); - MessageLoop::current()->PostTask(FROM_HERE, Bind( - &Foo::Test1Ptr, foo.get(), &b)); - MessageLoop::current()->PostTask(FROM_HERE, Bind( - &Foo::Test1Int, foo.get(), 100)); - MessageLoop::current()->PostTask(FROM_HERE, Bind( - &Foo::Test2Ptr, foo.get(), &a, &c)); - - // TryPost with no contention. It must succeed. - EXPECT_TRUE(MessageLoop::current()->TryPostTask(FROM_HERE, Bind( - &Foo::Test2Mixed, foo.get(), a, &d))); - - // TryPost with simulated contention. It must fail. We wait for a helper - // thread to lock the queue, we TryPost on this thread and finally we - // signal the helper to unlock and exit. - WaitableEvent wait(true, false); - WaitableEvent signal(true, false); - Thread thread("RunTest_PostTask_helper"); - thread.Start(); - thread.message_loop()->PostTask( - FROM_HERE, - Bind(&MessageLoop::LockWaitUnLockForTesting, - base::Unretained(MessageLoop::current()), - &wait, - &signal)); - - wait.Wait(); - EXPECT_FALSE(MessageLoop::current()->TryPostTask(FROM_HERE, Bind( - &Foo::Test2Mixed, foo.get(), a, &d))); - signal.Signal(); - - // After all tests, post a message that will shut down the message loop - MessageLoop::current()->PostTask(FROM_HERE, Bind( - &MessageLoop::Quit, Unretained(MessageLoop::current()))); - - // Now kick things off - MessageLoop::current()->Run(); - - EXPECT_EQ(foo->test_count(), 105); - EXPECT_EQ(foo->result(), "abacad"); -} - -void RunTest_PostTask_SEH(MessageLoop::Type message_loop_type) { - MessageLoop loop(message_loop_type); - - // Add tests to message loop - scoped_refptr foo(new Foo()); - std::string a("a"), b("b"), c("c"), d("d"); - MessageLoop::current()->PostTask(FROM_HERE, Bind( - &Foo::Test0, foo.get())); - MessageLoop::current()->PostTask(FROM_HERE, Bind( - &Foo::Test1ConstRef, foo.get(), a)); - MessageLoop::current()->PostTask(FROM_HERE, Bind( - &Foo::Test1Ptr, foo.get(), &b)); - MessageLoop::current()->PostTask(FROM_HERE, Bind( - &Foo::Test1Int, foo.get(), 100)); - MessageLoop::current()->PostTask(FROM_HERE, Bind( - &Foo::Test2Ptr, foo.get(), &a, &c)); - MessageLoop::current()->PostTask(FROM_HERE, Bind( - &Foo::Test2Mixed, foo.get(), a, &d)); - - // After all tests, post a message that will shut down the message loop - MessageLoop::current()->PostTask(FROM_HERE, Bind( - &MessageLoop::Quit, Unretained(MessageLoop::current()))); - - // Now kick things off with the SEH block active. - MessageLoop::current()->set_exception_restoration(true); - MessageLoop::current()->Run(); - MessageLoop::current()->set_exception_restoration(false); - - EXPECT_EQ(foo->test_count(), 105); - EXPECT_EQ(foo->result(), "abacad"); -} - -// This function runs slowly to simulate a large amount of work being done. -static void SlowFunc(TimeDelta pause, int* quit_counter) { - PlatformThread::Sleep(pause); - if (--(*quit_counter) == 0) - MessageLoop::current()->QuitWhenIdle(); -} - -// This function records the time when Run was called in a Time object, which is -// useful for building a variety of MessageLoop tests. -static void RecordRunTimeFunc(Time* run_time, int* quit_counter) { - *run_time = Time::Now(); - - // Cause our Run function to take some time to execute. As a result we can - // count on subsequent RecordRunTimeFunc()s running at a future time, - // without worry about the resolution of our system clock being an issue. - SlowFunc(TimeDelta::FromMilliseconds(10), quit_counter); -} - -void RunTest_PostDelayedTask_Basic(MessageLoop::Type message_loop_type) { - MessageLoop loop(message_loop_type); - - // Test that PostDelayedTask results in a delayed task. - - const TimeDelta kDelay = TimeDelta::FromMilliseconds(100); - - int num_tasks = 1; - Time run_time; - - loop.PostDelayedTask( - FROM_HERE, Bind(&RecordRunTimeFunc, &run_time, &num_tasks), - kDelay); - - Time time_before_run = Time::Now(); - loop.Run(); - Time time_after_run = Time::Now(); - - EXPECT_EQ(0, num_tasks); - EXPECT_LT(kDelay, time_after_run - time_before_run); -} - -void RunTest_PostDelayedTask_InDelayOrder( - MessageLoop::Type message_loop_type) { - MessageLoop loop(message_loop_type); - - // Test that two tasks with different delays run in the right order. - int num_tasks = 2; - Time run_time1, run_time2; - - loop.PostDelayedTask( - FROM_HERE, - Bind(&RecordRunTimeFunc, &run_time1, &num_tasks), - TimeDelta::FromMilliseconds(200)); - // If we get a large pause in execution (due to a context switch) here, this - // test could fail. - loop.PostDelayedTask( - FROM_HERE, - Bind(&RecordRunTimeFunc, &run_time2, &num_tasks), - TimeDelta::FromMilliseconds(10)); - - loop.Run(); - EXPECT_EQ(0, num_tasks); - - EXPECT_TRUE(run_time2 < run_time1); -} - -void RunTest_PostDelayedTask_InPostOrder( - MessageLoop::Type message_loop_type) { - MessageLoop loop(message_loop_type); - - // Test that two tasks with the same delay run in the order in which they - // were posted. - // - // NOTE: This is actually an approximate test since the API only takes a - // "delay" parameter, so we are not exactly simulating two tasks that get - // posted at the exact same time. It would be nice if the API allowed us to - // specify the desired run time. - - const TimeDelta kDelay = TimeDelta::FromMilliseconds(100); - - int num_tasks = 2; - Time run_time1, run_time2; - - loop.PostDelayedTask( - FROM_HERE, - Bind(&RecordRunTimeFunc, &run_time1, &num_tasks), kDelay); - loop.PostDelayedTask( - FROM_HERE, - Bind(&RecordRunTimeFunc, &run_time2, &num_tasks), kDelay); - - loop.Run(); - EXPECT_EQ(0, num_tasks); - - EXPECT_TRUE(run_time1 < run_time2); -} - -void RunTest_PostDelayedTask_InPostOrder_2( - MessageLoop::Type message_loop_type) { - MessageLoop loop(message_loop_type); - - // Test that a delayed task still runs after a normal tasks even if the - // normal tasks take a long time to run. - - const TimeDelta kPause = TimeDelta::FromMilliseconds(50); - - int num_tasks = 2; - Time run_time; - - loop.PostTask(FROM_HERE, Bind(&SlowFunc, kPause, &num_tasks)); - loop.PostDelayedTask( - FROM_HERE, - Bind(&RecordRunTimeFunc, &run_time, &num_tasks), - TimeDelta::FromMilliseconds(10)); - - Time time_before_run = Time::Now(); - loop.Run(); - Time time_after_run = Time::Now(); - - EXPECT_EQ(0, num_tasks); - - EXPECT_LT(kPause, time_after_run - time_before_run); -} - -void RunTest_PostDelayedTask_InPostOrder_3( - MessageLoop::Type message_loop_type) { - MessageLoop loop(message_loop_type); - - // Test that a delayed task still runs after a pile of normal tasks. The key - // difference between this test and the previous one is that here we return - // the MessageLoop a lot so we give the MessageLoop plenty of opportunities - // to maybe run the delayed task. It should know not to do so until the - // delayed task's delay has passed. - - int num_tasks = 11; - Time run_time1, run_time2; - - // Clutter the ML with tasks. - for (int i = 1; i < num_tasks; ++i) - loop.PostTask(FROM_HERE, - Bind(&RecordRunTimeFunc, &run_time1, &num_tasks)); - - loop.PostDelayedTask( - FROM_HERE, Bind(&RecordRunTimeFunc, &run_time2, &num_tasks), - TimeDelta::FromMilliseconds(1)); - - loop.Run(); - EXPECT_EQ(0, num_tasks); - - EXPECT_TRUE(run_time2 > run_time1); -} - -void RunTest_PostDelayedTask_SharedTimer( - MessageLoop::Type message_loop_type) { - MessageLoop loop(message_loop_type); - - // Test that the interval of the timer, used to run the next delayed task, is - // set to a value corresponding to when the next delayed task should run. - - // By setting num_tasks to 1, we ensure that the first task to run causes the - // run loop to exit. - int num_tasks = 1; - Time run_time1, run_time2; - - loop.PostDelayedTask( - FROM_HERE, - Bind(&RecordRunTimeFunc, &run_time1, &num_tasks), - TimeDelta::FromSeconds(1000)); - loop.PostDelayedTask( - FROM_HERE, - Bind(&RecordRunTimeFunc, &run_time2, &num_tasks), - TimeDelta::FromMilliseconds(10)); - - Time start_time = Time::Now(); - - loop.Run(); - EXPECT_EQ(0, num_tasks); - - // Ensure that we ran in far less time than the slower timer. - TimeDelta total_time = Time::Now() - start_time; - EXPECT_GT(5000, total_time.InMilliseconds()); - - // In case both timers somehow run at nearly the same time, sleep a little - // and then run all pending to force them both to have run. This is just - // encouraging flakiness if there is any. - PlatformThread::Sleep(TimeDelta::FromMilliseconds(100)); - RunLoop().RunUntilIdle(); - - EXPECT_TRUE(run_time1.is_null()); - EXPECT_FALSE(run_time2.is_null()); -} - -#if defined(OS_WIN) - -void SubPumpFunc() { - MessageLoop::current()->SetNestableTasksAllowed(true); - MSG msg; - while (GetMessage(&msg, NULL, 0, 0)) { - TranslateMessage(&msg); - DispatchMessage(&msg); - } - MessageLoop::current()->QuitWhenIdle(); -} - -void RunTest_PostDelayedTask_SharedTimer_SubPump() { - MessageLoop loop(MessageLoop::TYPE_UI); - - // Test that the interval of the timer, used to run the next delayed task, is - // set to a value corresponding to when the next delayed task should run. - - // By setting num_tasks to 1, we ensure that the first task to run causes the - // run loop to exit. - int num_tasks = 1; - Time run_time; - - loop.PostTask(FROM_HERE, Bind(&SubPumpFunc)); - - // This very delayed task should never run. - loop.PostDelayedTask( - FROM_HERE, - Bind(&RecordRunTimeFunc, &run_time, &num_tasks), - TimeDelta::FromSeconds(1000)); - - // This slightly delayed task should run from within SubPumpFunc). - loop.PostDelayedTask( - FROM_HERE, - Bind(&PostQuitMessage, 0), - TimeDelta::FromMilliseconds(10)); - - Time start_time = Time::Now(); - - loop.Run(); - EXPECT_EQ(1, num_tasks); - - // Ensure that we ran in far less time than the slower timer. - TimeDelta total_time = Time::Now() - start_time; - EXPECT_GT(5000, total_time.InMilliseconds()); - - // In case both timers somehow run at nearly the same time, sleep a little - // and then run all pending to force them both to have run. This is just - // encouraging flakiness if there is any. - PlatformThread::Sleep(TimeDelta::FromMilliseconds(100)); - RunLoop().RunUntilIdle(); - - EXPECT_TRUE(run_time.is_null()); -} - -#endif // defined(OS_WIN) - -// This is used to inject a test point for recording the destructor calls for -// Closure objects send to MessageLoop::PostTask(). It is awkward usage since we -// are trying to hook the actual destruction, which is not a common operation. -class RecordDeletionProbe : public RefCounted { - public: - RecordDeletionProbe(RecordDeletionProbe* post_on_delete, bool* was_deleted) - : post_on_delete_(post_on_delete), was_deleted_(was_deleted) { - } - void Run() {} - - private: - friend class RefCounted; - - ~RecordDeletionProbe() { - *was_deleted_ = true; - if (post_on_delete_.get()) - MessageLoop::current()->PostTask( - FROM_HERE, Bind(&RecordDeletionProbe::Run, post_on_delete_.get())); - } - - scoped_refptr post_on_delete_; - bool* was_deleted_; -}; - -void RunTest_EnsureDeletion(MessageLoop::Type message_loop_type) { - bool a_was_deleted = false; - bool b_was_deleted = false; - { - MessageLoop loop(message_loop_type); - loop.PostTask( - FROM_HERE, Bind(&RecordDeletionProbe::Run, - new RecordDeletionProbe(NULL, &a_was_deleted))); - // TODO(ajwong): Do we really need 1000ms here? - loop.PostDelayedTask( - FROM_HERE, Bind(&RecordDeletionProbe::Run, - new RecordDeletionProbe(NULL, &b_was_deleted)), - TimeDelta::FromMilliseconds(1000)); - } - EXPECT_TRUE(a_was_deleted); - EXPECT_TRUE(b_was_deleted); -} - -void RunTest_EnsureDeletion_Chain(MessageLoop::Type message_loop_type) { - bool a_was_deleted = false; - bool b_was_deleted = false; - bool c_was_deleted = false; - { - MessageLoop loop(message_loop_type); - // The scoped_refptr for each of the below is held either by the chained - // RecordDeletionProbe, or the bound RecordDeletionProbe::Run() callback. - RecordDeletionProbe* a = new RecordDeletionProbe(NULL, &a_was_deleted); - RecordDeletionProbe* b = new RecordDeletionProbe(a, &b_was_deleted); - RecordDeletionProbe* c = new RecordDeletionProbe(b, &c_was_deleted); - loop.PostTask(FROM_HERE, Bind(&RecordDeletionProbe::Run, c)); - } - EXPECT_TRUE(a_was_deleted); - EXPECT_TRUE(b_was_deleted); - EXPECT_TRUE(c_was_deleted); -} - -void NestingFunc(int* depth) { - if (*depth > 0) { - *depth -= 1; - MessageLoop::current()->PostTask(FROM_HERE, - Bind(&NestingFunc, depth)); - - MessageLoop::current()->SetNestableTasksAllowed(true); - MessageLoop::current()->Run(); - } - MessageLoop::current()->QuitWhenIdle(); -} - -#if defined(OS_WIN) - -LONG WINAPI BadExceptionHandler(EXCEPTION_POINTERS *ex_info) { - ADD_FAILURE() << "bad exception handler"; - ::ExitProcess(ex_info->ExceptionRecord->ExceptionCode); - return EXCEPTION_EXECUTE_HANDLER; -} - -// This task throws an SEH exception: initially write to an invalid address. -// If the right SEH filter is installed, it will fix the error. -class Crasher : public RefCounted { - public: - // Ctor. If trash_SEH_handler is true, the task will override the unhandled - // exception handler with one sure to crash this test. - explicit Crasher(bool trash_SEH_handler) - : trash_SEH_handler_(trash_SEH_handler) { - } - - void Run() { - PlatformThread::Sleep(TimeDelta::FromMilliseconds(1)); - if (trash_SEH_handler_) - ::SetUnhandledExceptionFilter(&BadExceptionHandler); - // Generate a SEH fault. We do it in asm to make sure we know how to undo - // the damage. - -#if defined(_M_IX86) - - __asm { - mov eax, dword ptr [Crasher::bad_array_] - mov byte ptr [eax], 66 - } - -#elif defined(_M_X64) - - bad_array_[0] = 66; - -#else -#error "needs architecture support" -#endif - - MessageLoop::current()->QuitWhenIdle(); - } - // Points the bad array to a valid memory location. - static void FixError() { - bad_array_ = &valid_store_; - } - - private: - bool trash_SEH_handler_; - static volatile char* bad_array_; - static char valid_store_; -}; - -volatile char* Crasher::bad_array_ = 0; -char Crasher::valid_store_ = 0; - -// This SEH filter fixes the problem and retries execution. Fixing requires -// that the last instruction: mov eax, [Crasher::bad_array_] to be retried -// so we move the instruction pointer 5 bytes back. -LONG WINAPI HandleCrasherException(EXCEPTION_POINTERS *ex_info) { - if (ex_info->ExceptionRecord->ExceptionCode != EXCEPTION_ACCESS_VIOLATION) - return EXCEPTION_EXECUTE_HANDLER; - - Crasher::FixError(); - -#if defined(_M_IX86) - - ex_info->ContextRecord->Eip -= 5; - -#elif defined(_M_X64) - - ex_info->ContextRecord->Rip -= 5; - -#endif - - return EXCEPTION_CONTINUE_EXECUTION; -} - -void RunTest_Crasher(MessageLoop::Type message_loop_type) { - MessageLoop loop(message_loop_type); - - if (::IsDebuggerPresent()) - return; - - LPTOP_LEVEL_EXCEPTION_FILTER old_SEH_filter = - ::SetUnhandledExceptionFilter(&HandleCrasherException); - - MessageLoop::current()->PostTask( - FROM_HERE, - Bind(&Crasher::Run, new Crasher(false))); - MessageLoop::current()->set_exception_restoration(true); - MessageLoop::current()->Run(); - MessageLoop::current()->set_exception_restoration(false); - - ::SetUnhandledExceptionFilter(old_SEH_filter); -} - -void RunTest_CrasherNasty(MessageLoop::Type message_loop_type) { - MessageLoop loop(message_loop_type); - - if (::IsDebuggerPresent()) - return; - - LPTOP_LEVEL_EXCEPTION_FILTER old_SEH_filter = - ::SetUnhandledExceptionFilter(&HandleCrasherException); - - MessageLoop::current()->PostTask( - FROM_HERE, - Bind(&Crasher::Run, new Crasher(true))); - MessageLoop::current()->set_exception_restoration(true); - MessageLoop::current()->Run(); - MessageLoop::current()->set_exception_restoration(false); - - ::SetUnhandledExceptionFilter(old_SEH_filter); -} - -#endif // defined(OS_WIN) - -void RunTest_Nesting(MessageLoop::Type message_loop_type) { - MessageLoop loop(message_loop_type); - - int depth = 100; - MessageLoop::current()->PostTask(FROM_HERE, - Bind(&NestingFunc, &depth)); - MessageLoop::current()->Run(); - EXPECT_EQ(depth, 0); -} - -const wchar_t* const kMessageBoxTitle = L"MessageLoop Unit Test"; - -enum TaskType { - MESSAGEBOX, - ENDDIALOG, - RECURSIVE, - TIMEDMESSAGELOOP, - QUITMESSAGELOOP, - ORDERED, - PUMPS, - SLEEP, - RUNS, -}; - -// Saves the order in which the tasks executed. -struct TaskItem { - TaskItem(TaskType t, int c, bool s) - : type(t), - cookie(c), - start(s) { - } - - TaskType type; - int cookie; - bool start; - - bool operator == (const TaskItem& other) const { - return type == other.type && cookie == other.cookie && start == other.start; - } -}; - -std::ostream& operator <<(std::ostream& os, TaskType type) { - switch (type) { - case MESSAGEBOX: os << "MESSAGEBOX"; break; - case ENDDIALOG: os << "ENDDIALOG"; break; - case RECURSIVE: os << "RECURSIVE"; break; - case TIMEDMESSAGELOOP: os << "TIMEDMESSAGELOOP"; break; - case QUITMESSAGELOOP: os << "QUITMESSAGELOOP"; break; - case ORDERED: os << "ORDERED"; break; - case PUMPS: os << "PUMPS"; break; - case SLEEP: os << "SLEEP"; break; - default: - NOTREACHED(); - os << "Unknown TaskType"; - break; - } - return os; -} - -std::ostream& operator <<(std::ostream& os, const TaskItem& item) { - if (item.start) - return os << item.type << " " << item.cookie << " starts"; - else - return os << item.type << " " << item.cookie << " ends"; -} - -class TaskList { - public: - void RecordStart(TaskType type, int cookie) { - TaskItem item(type, cookie, true); - DVLOG(1) << item; - task_list_.push_back(item); - } - - void RecordEnd(TaskType type, int cookie) { - TaskItem item(type, cookie, false); - DVLOG(1) << item; - task_list_.push_back(item); - } - - size_t Size() { - return task_list_.size(); - } - - TaskItem Get(int n) { - return task_list_[n]; - } - - private: - std::vector task_list_; -}; - -// Saves the order the tasks ran. -void OrderedFunc(TaskList* order, int cookie) { - order->RecordStart(ORDERED, cookie); - order->RecordEnd(ORDERED, cookie); -} - -#if defined(OS_WIN) - -// MessageLoop implicitly start a "modal message loop". Modal dialog boxes, -// common controls (like OpenFile) and StartDoc printing function can cause -// implicit message loops. -void MessageBoxFunc(TaskList* order, int cookie, bool is_reentrant) { - order->RecordStart(MESSAGEBOX, cookie); - if (is_reentrant) - MessageLoop::current()->SetNestableTasksAllowed(true); - MessageBox(NULL, L"Please wait...", kMessageBoxTitle, MB_OK); - order->RecordEnd(MESSAGEBOX, cookie); -} - -// Will end the MessageBox. -void EndDialogFunc(TaskList* order, int cookie) { - order->RecordStart(ENDDIALOG, cookie); - HWND window = GetActiveWindow(); - if (window != NULL) { - EXPECT_NE(EndDialog(window, IDCONTINUE), 0); - // Cheap way to signal that the window wasn't found if RunEnd() isn't - // called. - order->RecordEnd(ENDDIALOG, cookie); - } -} - -#endif // defined(OS_WIN) - -void RecursiveFunc(TaskList* order, int cookie, int depth, - bool is_reentrant) { - order->RecordStart(RECURSIVE, cookie); - if (depth > 0) { - if (is_reentrant) - MessageLoop::current()->SetNestableTasksAllowed(true); - MessageLoop::current()->PostTask( - FROM_HERE, - Bind(&RecursiveFunc, order, cookie, depth - 1, is_reentrant)); - } - order->RecordEnd(RECURSIVE, cookie); -} - -void RecursiveSlowFunc(TaskList* order, int cookie, int depth, - bool is_reentrant) { - RecursiveFunc(order, cookie, depth, is_reentrant); - PlatformThread::Sleep(TimeDelta::FromMilliseconds(10)); -} - -void QuitFunc(TaskList* order, int cookie) { - order->RecordStart(QUITMESSAGELOOP, cookie); - MessageLoop::current()->QuitWhenIdle(); - order->RecordEnd(QUITMESSAGELOOP, cookie); -} - -void SleepFunc(TaskList* order, int cookie, TimeDelta delay) { - order->RecordStart(SLEEP, cookie); - PlatformThread::Sleep(delay); - order->RecordEnd(SLEEP, cookie); -} - -#if defined(OS_WIN) -void RecursiveFuncWin(MessageLoop* target, - HANDLE event, - bool expect_window, - TaskList* order, - bool is_reentrant) { - target->PostTask(FROM_HERE, - Bind(&RecursiveFunc, order, 1, 2, is_reentrant)); - target->PostTask(FROM_HERE, - Bind(&MessageBoxFunc, order, 2, is_reentrant)); - target->PostTask(FROM_HERE, - Bind(&RecursiveFunc, order, 3, 2, is_reentrant)); - // The trick here is that for recursive task processing, this task will be - // ran _inside_ the MessageBox message loop, dismissing the MessageBox - // without a chance. - // For non-recursive task processing, this will be executed _after_ the - // MessageBox will have been dismissed by the code below, where - // expect_window_ is true. - target->PostTask(FROM_HERE, - Bind(&EndDialogFunc, order, 4)); - target->PostTask(FROM_HERE, - Bind(&QuitFunc, order, 5)); - - // Enforce that every tasks are sent before starting to run the main thread - // message loop. - ASSERT_TRUE(SetEvent(event)); - - // Poll for the MessageBox. Don't do this at home! At the speed we do it, - // you will never realize one MessageBox was shown. - for (; expect_window;) { - HWND window = FindWindow(L"#32770", kMessageBoxTitle); - if (window) { - // Dismiss it. - for (;;) { - HWND button = FindWindowEx(window, NULL, L"Button", NULL); - if (button != NULL) { - EXPECT_EQ(0, SendMessage(button, WM_LBUTTONDOWN, 0, 0)); - EXPECT_EQ(0, SendMessage(button, WM_LBUTTONUP, 0, 0)); - break; - } - } - break; - } - } -} - -#endif // defined(OS_WIN) - -void RunTest_RecursiveDenial1(MessageLoop::Type message_loop_type) { - MessageLoop loop(message_loop_type); - - EXPECT_TRUE(MessageLoop::current()->NestableTasksAllowed()); - TaskList order; - MessageLoop::current()->PostTask( - FROM_HERE, - Bind(&RecursiveFunc, &order, 1, 2, false)); - MessageLoop::current()->PostTask( - FROM_HERE, - Bind(&RecursiveFunc, &order, 2, 2, false)); - MessageLoop::current()->PostTask( - FROM_HERE, - Bind(&QuitFunc, &order, 3)); - - MessageLoop::current()->Run(); - - // FIFO order. - ASSERT_EQ(14U, order.Size()); - EXPECT_EQ(order.Get(0), TaskItem(RECURSIVE, 1, true)); - EXPECT_EQ(order.Get(1), TaskItem(RECURSIVE, 1, false)); - EXPECT_EQ(order.Get(2), TaskItem(RECURSIVE, 2, true)); - EXPECT_EQ(order.Get(3), TaskItem(RECURSIVE, 2, false)); - EXPECT_EQ(order.Get(4), TaskItem(QUITMESSAGELOOP, 3, true)); - EXPECT_EQ(order.Get(5), TaskItem(QUITMESSAGELOOP, 3, false)); - EXPECT_EQ(order.Get(6), TaskItem(RECURSIVE, 1, true)); - EXPECT_EQ(order.Get(7), TaskItem(RECURSIVE, 1, false)); - EXPECT_EQ(order.Get(8), TaskItem(RECURSIVE, 2, true)); - EXPECT_EQ(order.Get(9), TaskItem(RECURSIVE, 2, false)); - EXPECT_EQ(order.Get(10), TaskItem(RECURSIVE, 1, true)); - EXPECT_EQ(order.Get(11), TaskItem(RECURSIVE, 1, false)); - EXPECT_EQ(order.Get(12), TaskItem(RECURSIVE, 2, true)); - EXPECT_EQ(order.Get(13), TaskItem(RECURSIVE, 2, false)); -} - -void RunTest_RecursiveDenial3(MessageLoop::Type message_loop_type) { - MessageLoop loop(message_loop_type); - - EXPECT_TRUE(MessageLoop::current()->NestableTasksAllowed()); - TaskList order; - MessageLoop::current()->PostTask( - FROM_HERE, Bind(&RecursiveSlowFunc, &order, 1, 2, false)); - MessageLoop::current()->PostTask( - FROM_HERE, Bind(&RecursiveSlowFunc, &order, 2, 2, false)); - MessageLoop::current()->PostDelayedTask( - FROM_HERE, - Bind(&OrderedFunc, &order, 3), - TimeDelta::FromMilliseconds(5)); - MessageLoop::current()->PostDelayedTask( - FROM_HERE, - Bind(&QuitFunc, &order, 4), - TimeDelta::FromMilliseconds(5)); - - MessageLoop::current()->Run(); - - // FIFO order. - ASSERT_EQ(16U, order.Size()); - EXPECT_EQ(order.Get(0), TaskItem(RECURSIVE, 1, true)); - EXPECT_EQ(order.Get(1), TaskItem(RECURSIVE, 1, false)); - EXPECT_EQ(order.Get(2), TaskItem(RECURSIVE, 2, true)); - EXPECT_EQ(order.Get(3), TaskItem(RECURSIVE, 2, false)); - EXPECT_EQ(order.Get(4), TaskItem(RECURSIVE, 1, true)); - EXPECT_EQ(order.Get(5), TaskItem(RECURSIVE, 1, false)); - EXPECT_EQ(order.Get(6), TaskItem(ORDERED, 3, true)); - EXPECT_EQ(order.Get(7), TaskItem(ORDERED, 3, false)); - EXPECT_EQ(order.Get(8), TaskItem(RECURSIVE, 2, true)); - EXPECT_EQ(order.Get(9), TaskItem(RECURSIVE, 2, false)); - EXPECT_EQ(order.Get(10), TaskItem(QUITMESSAGELOOP, 4, true)); - EXPECT_EQ(order.Get(11), TaskItem(QUITMESSAGELOOP, 4, false)); - EXPECT_EQ(order.Get(12), TaskItem(RECURSIVE, 1, true)); - EXPECT_EQ(order.Get(13), TaskItem(RECURSIVE, 1, false)); - EXPECT_EQ(order.Get(14), TaskItem(RECURSIVE, 2, true)); - EXPECT_EQ(order.Get(15), TaskItem(RECURSIVE, 2, false)); -} - -void RunTest_RecursiveSupport1(MessageLoop::Type message_loop_type) { - MessageLoop loop(message_loop_type); - - TaskList order; - MessageLoop::current()->PostTask( - FROM_HERE, Bind(&RecursiveFunc, &order, 1, 2, true)); - MessageLoop::current()->PostTask( - FROM_HERE, Bind(&RecursiveFunc, &order, 2, 2, true)); - MessageLoop::current()->PostTask( - FROM_HERE, Bind(&QuitFunc, &order, 3)); - - MessageLoop::current()->Run(); - - // FIFO order. - ASSERT_EQ(14U, order.Size()); - EXPECT_EQ(order.Get(0), TaskItem(RECURSIVE, 1, true)); - EXPECT_EQ(order.Get(1), TaskItem(RECURSIVE, 1, false)); - EXPECT_EQ(order.Get(2), TaskItem(RECURSIVE, 2, true)); - EXPECT_EQ(order.Get(3), TaskItem(RECURSIVE, 2, false)); - EXPECT_EQ(order.Get(4), TaskItem(QUITMESSAGELOOP, 3, true)); - EXPECT_EQ(order.Get(5), TaskItem(QUITMESSAGELOOP, 3, false)); - EXPECT_EQ(order.Get(6), TaskItem(RECURSIVE, 1, true)); - EXPECT_EQ(order.Get(7), TaskItem(RECURSIVE, 1, false)); - EXPECT_EQ(order.Get(8), TaskItem(RECURSIVE, 2, true)); - EXPECT_EQ(order.Get(9), TaskItem(RECURSIVE, 2, false)); - EXPECT_EQ(order.Get(10), TaskItem(RECURSIVE, 1, true)); - EXPECT_EQ(order.Get(11), TaskItem(RECURSIVE, 1, false)); - EXPECT_EQ(order.Get(12), TaskItem(RECURSIVE, 2, true)); - EXPECT_EQ(order.Get(13), TaskItem(RECURSIVE, 2, false)); -} - -#if defined(OS_WIN) -// TODO(darin): These tests need to be ported since they test critical -// message loop functionality. - -// A side effect of this test is the generation a beep. Sorry. -void RunTest_RecursiveDenial2(MessageLoop::Type message_loop_type) { - MessageLoop loop(message_loop_type); - - Thread worker("RecursiveDenial2_worker"); - Thread::Options options; - options.message_loop_type = message_loop_type; - ASSERT_EQ(true, worker.StartWithOptions(options)); - TaskList order; - win::ScopedHandle event(CreateEvent(NULL, FALSE, FALSE, NULL)); - worker.message_loop()->PostTask(FROM_HERE, - Bind(&RecursiveFuncWin, - MessageLoop::current(), - event.Get(), - true, - &order, - false)); - // Let the other thread execute. - WaitForSingleObject(event, INFINITE); - MessageLoop::current()->Run(); - - ASSERT_EQ(order.Size(), 17); - EXPECT_EQ(order.Get(0), TaskItem(RECURSIVE, 1, true)); - EXPECT_EQ(order.Get(1), TaskItem(RECURSIVE, 1, false)); - EXPECT_EQ(order.Get(2), TaskItem(MESSAGEBOX, 2, true)); - EXPECT_EQ(order.Get(3), TaskItem(MESSAGEBOX, 2, false)); - EXPECT_EQ(order.Get(4), TaskItem(RECURSIVE, 3, true)); - EXPECT_EQ(order.Get(5), TaskItem(RECURSIVE, 3, false)); - // When EndDialogFunc is processed, the window is already dismissed, hence no - // "end" entry. - EXPECT_EQ(order.Get(6), TaskItem(ENDDIALOG, 4, true)); - EXPECT_EQ(order.Get(7), TaskItem(QUITMESSAGELOOP, 5, true)); - EXPECT_EQ(order.Get(8), TaskItem(QUITMESSAGELOOP, 5, false)); - EXPECT_EQ(order.Get(9), TaskItem(RECURSIVE, 1, true)); - EXPECT_EQ(order.Get(10), TaskItem(RECURSIVE, 1, false)); - EXPECT_EQ(order.Get(11), TaskItem(RECURSIVE, 3, true)); - EXPECT_EQ(order.Get(12), TaskItem(RECURSIVE, 3, false)); - EXPECT_EQ(order.Get(13), TaskItem(RECURSIVE, 1, true)); - EXPECT_EQ(order.Get(14), TaskItem(RECURSIVE, 1, false)); - EXPECT_EQ(order.Get(15), TaskItem(RECURSIVE, 3, true)); - EXPECT_EQ(order.Get(16), TaskItem(RECURSIVE, 3, false)); -} - -// A side effect of this test is the generation a beep. Sorry. This test also -// needs to process windows messages on the current thread. -void RunTest_RecursiveSupport2(MessageLoop::Type message_loop_type) { - MessageLoop loop(message_loop_type); - - Thread worker("RecursiveSupport2_worker"); - Thread::Options options; - options.message_loop_type = message_loop_type; - ASSERT_EQ(true, worker.StartWithOptions(options)); - TaskList order; - win::ScopedHandle event(CreateEvent(NULL, FALSE, FALSE, NULL)); - worker.message_loop()->PostTask(FROM_HERE, - Bind(&RecursiveFuncWin, - MessageLoop::current(), - event.Get(), - false, - &order, - true)); - // Let the other thread execute. - WaitForSingleObject(event, INFINITE); - MessageLoop::current()->Run(); - - ASSERT_EQ(order.Size(), 18); - EXPECT_EQ(order.Get(0), TaskItem(RECURSIVE, 1, true)); - EXPECT_EQ(order.Get(1), TaskItem(RECURSIVE, 1, false)); - EXPECT_EQ(order.Get(2), TaskItem(MESSAGEBOX, 2, true)); - // Note that this executes in the MessageBox modal loop. - EXPECT_EQ(order.Get(3), TaskItem(RECURSIVE, 3, true)); - EXPECT_EQ(order.Get(4), TaskItem(RECURSIVE, 3, false)); - EXPECT_EQ(order.Get(5), TaskItem(ENDDIALOG, 4, true)); - EXPECT_EQ(order.Get(6), TaskItem(ENDDIALOG, 4, false)); - EXPECT_EQ(order.Get(7), TaskItem(MESSAGEBOX, 2, false)); - /* The order can subtly change here. The reason is that when RecursiveFunc(1) - is called in the main thread, if it is faster than getting to the - PostTask(FROM_HERE, Bind(&QuitFunc) execution, the order of task - execution can change. We don't care anyway that the order isn't correct. - EXPECT_EQ(order.Get(8), TaskItem(QUITMESSAGELOOP, 5, true)); - EXPECT_EQ(order.Get(9), TaskItem(QUITMESSAGELOOP, 5, false)); - EXPECT_EQ(order.Get(10), TaskItem(RECURSIVE, 1, true)); - EXPECT_EQ(order.Get(11), TaskItem(RECURSIVE, 1, false)); - */ - EXPECT_EQ(order.Get(12), TaskItem(RECURSIVE, 3, true)); - EXPECT_EQ(order.Get(13), TaskItem(RECURSIVE, 3, false)); - EXPECT_EQ(order.Get(14), TaskItem(RECURSIVE, 1, true)); - EXPECT_EQ(order.Get(15), TaskItem(RECURSIVE, 1, false)); - EXPECT_EQ(order.Get(16), TaskItem(RECURSIVE, 3, true)); - EXPECT_EQ(order.Get(17), TaskItem(RECURSIVE, 3, false)); -} - -#endif // defined(OS_WIN) - -void FuncThatPumps(TaskList* order, int cookie) { - order->RecordStart(PUMPS, cookie); - { - MessageLoop::ScopedNestableTaskAllower allow(MessageLoop::current()); - RunLoop().RunUntilIdle(); - } - order->RecordEnd(PUMPS, cookie); -} - -void FuncThatRuns(TaskList* order, int cookie, RunLoop* run_loop) { - order->RecordStart(RUNS, cookie); - { - MessageLoop::ScopedNestableTaskAllower allow(MessageLoop::current()); - run_loop->Run(); - } - order->RecordEnd(RUNS, cookie); -} - -void FuncThatQuitsNow() { - MessageLoop::current()->QuitNow(); -} - -// Tests that non nestable tasks run in FIFO if there are no nested loops. -void RunTest_NonNestableWithNoNesting( - MessageLoop::Type message_loop_type) { - MessageLoop loop(message_loop_type); - - TaskList order; - - MessageLoop::current()->PostNonNestableTask( - FROM_HERE, - Bind(&OrderedFunc, &order, 1)); - MessageLoop::current()->PostTask(FROM_HERE, - Bind(&OrderedFunc, &order, 2)); - MessageLoop::current()->PostTask(FROM_HERE, - Bind(&QuitFunc, &order, 3)); - MessageLoop::current()->Run(); - - // FIFO order. - ASSERT_EQ(6U, order.Size()); - EXPECT_EQ(order.Get(0), TaskItem(ORDERED, 1, true)); - EXPECT_EQ(order.Get(1), TaskItem(ORDERED, 1, false)); - EXPECT_EQ(order.Get(2), TaskItem(ORDERED, 2, true)); - EXPECT_EQ(order.Get(3), TaskItem(ORDERED, 2, false)); - EXPECT_EQ(order.Get(4), TaskItem(QUITMESSAGELOOP, 3, true)); - EXPECT_EQ(order.Get(5), TaskItem(QUITMESSAGELOOP, 3, false)); -} - -// Tests that non nestable tasks don't run when there's code in the call stack. -void RunTest_NonNestableInNestedLoop(MessageLoop::Type message_loop_type, - bool use_delayed) { - MessageLoop loop(message_loop_type); - - TaskList order; - - MessageLoop::current()->PostTask( - FROM_HERE, - Bind(&FuncThatPumps, &order, 1)); - if (use_delayed) { - MessageLoop::current()->PostNonNestableDelayedTask( - FROM_HERE, - Bind(&OrderedFunc, &order, 2), - TimeDelta::FromMilliseconds(1)); - } else { - MessageLoop::current()->PostNonNestableTask( - FROM_HERE, - Bind(&OrderedFunc, &order, 2)); - } - MessageLoop::current()->PostTask(FROM_HERE, - Bind(&OrderedFunc, &order, 3)); - MessageLoop::current()->PostTask( - FROM_HERE, - Bind(&SleepFunc, &order, 4, TimeDelta::FromMilliseconds(50))); - MessageLoop::current()->PostTask(FROM_HERE, - Bind(&OrderedFunc, &order, 5)); - if (use_delayed) { - MessageLoop::current()->PostNonNestableDelayedTask( - FROM_HERE, - Bind(&QuitFunc, &order, 6), - TimeDelta::FromMilliseconds(2)); - } else { - MessageLoop::current()->PostNonNestableTask( - FROM_HERE, - Bind(&QuitFunc, &order, 6)); - } - - MessageLoop::current()->Run(); - - // FIFO order. - ASSERT_EQ(12U, order.Size()); - EXPECT_EQ(order.Get(0), TaskItem(PUMPS, 1, true)); - EXPECT_EQ(order.Get(1), TaskItem(ORDERED, 3, true)); - EXPECT_EQ(order.Get(2), TaskItem(ORDERED, 3, false)); - EXPECT_EQ(order.Get(3), TaskItem(SLEEP, 4, true)); - EXPECT_EQ(order.Get(4), TaskItem(SLEEP, 4, false)); - EXPECT_EQ(order.Get(5), TaskItem(ORDERED, 5, true)); - EXPECT_EQ(order.Get(6), TaskItem(ORDERED, 5, false)); - EXPECT_EQ(order.Get(7), TaskItem(PUMPS, 1, false)); - EXPECT_EQ(order.Get(8), TaskItem(ORDERED, 2, true)); - EXPECT_EQ(order.Get(9), TaskItem(ORDERED, 2, false)); - EXPECT_EQ(order.Get(10), TaskItem(QUITMESSAGELOOP, 6, true)); - EXPECT_EQ(order.Get(11), TaskItem(QUITMESSAGELOOP, 6, false)); -} - -// Tests RunLoopQuit only quits the corresponding MessageLoop::Run. -void RunTest_QuitNow(MessageLoop::Type message_loop_type) { - MessageLoop loop(message_loop_type); - - TaskList order; - - RunLoop run_loop; - - MessageLoop::current()->PostTask(FROM_HERE, - Bind(&FuncThatRuns, &order, 1, Unretained(&run_loop))); - MessageLoop::current()->PostTask( - FROM_HERE, Bind(&OrderedFunc, &order, 2)); - MessageLoop::current()->PostTask( - FROM_HERE, Bind(&FuncThatQuitsNow)); - MessageLoop::current()->PostTask( - FROM_HERE, Bind(&OrderedFunc, &order, 3)); - MessageLoop::current()->PostTask( - FROM_HERE, Bind(&FuncThatQuitsNow)); - MessageLoop::current()->PostTask( - FROM_HERE, Bind(&OrderedFunc, &order, 4)); // never runs - - MessageLoop::current()->Run(); - - ASSERT_EQ(6U, order.Size()); - int task_index = 0; - EXPECT_EQ(order.Get(task_index++), TaskItem(RUNS, 1, true)); - EXPECT_EQ(order.Get(task_index++), TaskItem(ORDERED, 2, true)); - EXPECT_EQ(order.Get(task_index++), TaskItem(ORDERED, 2, false)); - EXPECT_EQ(order.Get(task_index++), TaskItem(RUNS, 1, false)); - EXPECT_EQ(order.Get(task_index++), TaskItem(ORDERED, 3, true)); - EXPECT_EQ(order.Get(task_index++), TaskItem(ORDERED, 3, false)); - EXPECT_EQ(static_cast(task_index), order.Size()); -} - -// Tests RunLoopQuit works before RunWithID. -void RunTest_RunLoopQuitOrderBefore(MessageLoop::Type message_loop_type) { - MessageLoop loop(message_loop_type); - - TaskList order; - - RunLoop run_loop; - - run_loop.Quit(); - - MessageLoop::current()->PostTask( - FROM_HERE, Bind(&OrderedFunc, &order, 1)); // never runs - MessageLoop::current()->PostTask( - FROM_HERE, Bind(&FuncThatQuitsNow)); // never runs - - run_loop.Run(); - - ASSERT_EQ(0U, order.Size()); -} - -// Tests RunLoopQuit works during RunWithID. -void RunTest_RunLoopQuitOrderDuring(MessageLoop::Type message_loop_type) { - MessageLoop loop(message_loop_type); - - TaskList order; - - RunLoop run_loop; - - MessageLoop::current()->PostTask( - FROM_HERE, Bind(&OrderedFunc, &order, 1)); - MessageLoop::current()->PostTask( - FROM_HERE, run_loop.QuitClosure()); - MessageLoop::current()->PostTask( - FROM_HERE, Bind(&OrderedFunc, &order, 2)); // never runs - MessageLoop::current()->PostTask( - FROM_HERE, Bind(&FuncThatQuitsNow)); // never runs - - run_loop.Run(); - - ASSERT_EQ(2U, order.Size()); - int task_index = 0; - EXPECT_EQ(order.Get(task_index++), TaskItem(ORDERED, 1, true)); - EXPECT_EQ(order.Get(task_index++), TaskItem(ORDERED, 1, false)); - EXPECT_EQ(static_cast(task_index), order.Size()); -} - -// Tests RunLoopQuit works after RunWithID. -void RunTest_RunLoopQuitOrderAfter(MessageLoop::Type message_loop_type) { - MessageLoop loop(message_loop_type); - - TaskList order; - - RunLoop run_loop; - - MessageLoop::current()->PostTask(FROM_HERE, - Bind(&FuncThatRuns, &order, 1, Unretained(&run_loop))); - MessageLoop::current()->PostTask( - FROM_HERE, Bind(&OrderedFunc, &order, 2)); - MessageLoop::current()->PostTask( - FROM_HERE, Bind(&FuncThatQuitsNow)); - MessageLoop::current()->PostTask( - FROM_HERE, Bind(&OrderedFunc, &order, 3)); - MessageLoop::current()->PostTask( - FROM_HERE, run_loop.QuitClosure()); // has no affect - MessageLoop::current()->PostTask( - FROM_HERE, Bind(&OrderedFunc, &order, 4)); - MessageLoop::current()->PostTask( - FROM_HERE, Bind(&FuncThatQuitsNow)); - - RunLoop outer_run_loop; - outer_run_loop.Run(); - - ASSERT_EQ(8U, order.Size()); - int task_index = 0; - EXPECT_EQ(order.Get(task_index++), TaskItem(RUNS, 1, true)); - EXPECT_EQ(order.Get(task_index++), TaskItem(ORDERED, 2, true)); - EXPECT_EQ(order.Get(task_index++), TaskItem(ORDERED, 2, false)); - EXPECT_EQ(order.Get(task_index++), TaskItem(RUNS, 1, false)); - EXPECT_EQ(order.Get(task_index++), TaskItem(ORDERED, 3, true)); - EXPECT_EQ(order.Get(task_index++), TaskItem(ORDERED, 3, false)); - EXPECT_EQ(order.Get(task_index++), TaskItem(ORDERED, 4, true)); - EXPECT_EQ(order.Get(task_index++), TaskItem(ORDERED, 4, false)); - EXPECT_EQ(static_cast(task_index), order.Size()); -} - -// Tests RunLoopQuit only quits the corresponding MessageLoop::Run. -void RunTest_RunLoopQuitTop(MessageLoop::Type message_loop_type) { - MessageLoop loop(message_loop_type); - - TaskList order; - - RunLoop outer_run_loop; - RunLoop nested_run_loop; - - MessageLoop::current()->PostTask(FROM_HERE, - Bind(&FuncThatRuns, &order, 1, Unretained(&nested_run_loop))); - MessageLoop::current()->PostTask( - FROM_HERE, outer_run_loop.QuitClosure()); - MessageLoop::current()->PostTask( - FROM_HERE, Bind(&OrderedFunc, &order, 2)); - MessageLoop::current()->PostTask( - FROM_HERE, nested_run_loop.QuitClosure()); - - outer_run_loop.Run(); - - ASSERT_EQ(4U, order.Size()); - int task_index = 0; - EXPECT_EQ(order.Get(task_index++), TaskItem(RUNS, 1, true)); - EXPECT_EQ(order.Get(task_index++), TaskItem(ORDERED, 2, true)); - EXPECT_EQ(order.Get(task_index++), TaskItem(ORDERED, 2, false)); - EXPECT_EQ(order.Get(task_index++), TaskItem(RUNS, 1, false)); - EXPECT_EQ(static_cast(task_index), order.Size()); -} - -// Tests RunLoopQuit only quits the corresponding MessageLoop::Run. -void RunTest_RunLoopQuitNested(MessageLoop::Type message_loop_type) { - MessageLoop loop(message_loop_type); - - TaskList order; - - RunLoop outer_run_loop; - RunLoop nested_run_loop; - - MessageLoop::current()->PostTask(FROM_HERE, - Bind(&FuncThatRuns, &order, 1, Unretained(&nested_run_loop))); - MessageLoop::current()->PostTask( - FROM_HERE, nested_run_loop.QuitClosure()); - MessageLoop::current()->PostTask( - FROM_HERE, Bind(&OrderedFunc, &order, 2)); - MessageLoop::current()->PostTask( - FROM_HERE, outer_run_loop.QuitClosure()); - - outer_run_loop.Run(); - - ASSERT_EQ(4U, order.Size()); - int task_index = 0; - EXPECT_EQ(order.Get(task_index++), TaskItem(RUNS, 1, true)); - EXPECT_EQ(order.Get(task_index++), TaskItem(RUNS, 1, false)); - EXPECT_EQ(order.Get(task_index++), TaskItem(ORDERED, 2, true)); - EXPECT_EQ(order.Get(task_index++), TaskItem(ORDERED, 2, false)); - EXPECT_EQ(static_cast(task_index), order.Size()); -} - -// Tests RunLoopQuit only quits the corresponding MessageLoop::Run. -void RunTest_RunLoopQuitBogus(MessageLoop::Type message_loop_type) { - MessageLoop loop(message_loop_type); - - TaskList order; - - RunLoop outer_run_loop; - RunLoop nested_run_loop; - RunLoop bogus_run_loop; - - MessageLoop::current()->PostTask(FROM_HERE, - Bind(&FuncThatRuns, &order, 1, Unretained(&nested_run_loop))); - MessageLoop::current()->PostTask( - FROM_HERE, bogus_run_loop.QuitClosure()); - MessageLoop::current()->PostTask( - FROM_HERE, Bind(&OrderedFunc, &order, 2)); - MessageLoop::current()->PostTask( - FROM_HERE, outer_run_loop.QuitClosure()); - MessageLoop::current()->PostTask( - FROM_HERE, nested_run_loop.QuitClosure()); - - outer_run_loop.Run(); - - ASSERT_EQ(4U, order.Size()); - int task_index = 0; - EXPECT_EQ(order.Get(task_index++), TaskItem(RUNS, 1, true)); - EXPECT_EQ(order.Get(task_index++), TaskItem(ORDERED, 2, true)); - EXPECT_EQ(order.Get(task_index++), TaskItem(ORDERED, 2, false)); - EXPECT_EQ(order.Get(task_index++), TaskItem(RUNS, 1, false)); - EXPECT_EQ(static_cast(task_index), order.Size()); -} - -// Tests RunLoopQuit only quits the corresponding MessageLoop::Run. -void RunTest_RunLoopQuitDeep(MessageLoop::Type message_loop_type) { - MessageLoop loop(message_loop_type); - - TaskList order; - - RunLoop outer_run_loop; - RunLoop nested_loop1; - RunLoop nested_loop2; - RunLoop nested_loop3; - RunLoop nested_loop4; - - MessageLoop::current()->PostTask(FROM_HERE, - Bind(&FuncThatRuns, &order, 1, Unretained(&nested_loop1))); - MessageLoop::current()->PostTask(FROM_HERE, - Bind(&FuncThatRuns, &order, 2, Unretained(&nested_loop2))); - MessageLoop::current()->PostTask(FROM_HERE, - Bind(&FuncThatRuns, &order, 3, Unretained(&nested_loop3))); - MessageLoop::current()->PostTask(FROM_HERE, - Bind(&FuncThatRuns, &order, 4, Unretained(&nested_loop4))); - MessageLoop::current()->PostTask( - FROM_HERE, Bind(&OrderedFunc, &order, 5)); - MessageLoop::current()->PostTask( - FROM_HERE, outer_run_loop.QuitClosure()); - MessageLoop::current()->PostTask( - FROM_HERE, Bind(&OrderedFunc, &order, 6)); - MessageLoop::current()->PostTask( - FROM_HERE, nested_loop1.QuitClosure()); - MessageLoop::current()->PostTask( - FROM_HERE, Bind(&OrderedFunc, &order, 7)); - MessageLoop::current()->PostTask( - FROM_HERE, nested_loop2.QuitClosure()); - MessageLoop::current()->PostTask( - FROM_HERE, Bind(&OrderedFunc, &order, 8)); - MessageLoop::current()->PostTask( - FROM_HERE, nested_loop3.QuitClosure()); - MessageLoop::current()->PostTask( - FROM_HERE, Bind(&OrderedFunc, &order, 9)); - MessageLoop::current()->PostTask( - FROM_HERE, nested_loop4.QuitClosure()); - MessageLoop::current()->PostTask( - FROM_HERE, Bind(&OrderedFunc, &order, 10)); - - outer_run_loop.Run(); - - ASSERT_EQ(18U, order.Size()); - int task_index = 0; - EXPECT_EQ(order.Get(task_index++), TaskItem(RUNS, 1, true)); - EXPECT_EQ(order.Get(task_index++), TaskItem(RUNS, 2, true)); - EXPECT_EQ(order.Get(task_index++), TaskItem(RUNS, 3, true)); - EXPECT_EQ(order.Get(task_index++), TaskItem(RUNS, 4, true)); - EXPECT_EQ(order.Get(task_index++), TaskItem(ORDERED, 5, true)); - EXPECT_EQ(order.Get(task_index++), TaskItem(ORDERED, 5, false)); - EXPECT_EQ(order.Get(task_index++), TaskItem(ORDERED, 6, true)); - EXPECT_EQ(order.Get(task_index++), TaskItem(ORDERED, 6, false)); - EXPECT_EQ(order.Get(task_index++), TaskItem(ORDERED, 7, true)); - EXPECT_EQ(order.Get(task_index++), TaskItem(ORDERED, 7, false)); - EXPECT_EQ(order.Get(task_index++), TaskItem(ORDERED, 8, true)); - EXPECT_EQ(order.Get(task_index++), TaskItem(ORDERED, 8, false)); - EXPECT_EQ(order.Get(task_index++), TaskItem(ORDERED, 9, true)); - EXPECT_EQ(order.Get(task_index++), TaskItem(ORDERED, 9, false)); - EXPECT_EQ(order.Get(task_index++), TaskItem(RUNS, 4, false)); - EXPECT_EQ(order.Get(task_index++), TaskItem(RUNS, 3, false)); - EXPECT_EQ(order.Get(task_index++), TaskItem(RUNS, 2, false)); - EXPECT_EQ(order.Get(task_index++), TaskItem(RUNS, 1, false)); - EXPECT_EQ(static_cast(task_index), order.Size()); -} - -void PostNTasksThenQuit(int posts_remaining) { - if (posts_remaining > 1) { - MessageLoop::current()->PostTask( - FROM_HERE, - Bind(&PostNTasksThenQuit, posts_remaining - 1)); - } else { - MessageLoop::current()->QuitWhenIdle(); - } -} - -void RunTest_RecursivePosts(MessageLoop::Type message_loop_type, - int num_times) { - MessageLoop loop(message_loop_type); - loop.PostTask(FROM_HERE, Bind(&PostNTasksThenQuit, num_times)); - loop.Run(); -} - -#if defined(OS_WIN) - -class DispatcherImpl : public MessageLoopForUI::Dispatcher { - public: - DispatcherImpl() : dispatch_count_(0) {} - - virtual bool Dispatch(const NativeEvent& msg) OVERRIDE { - ::TranslateMessage(&msg); - ::DispatchMessage(&msg); - // Do not count WM_TIMER since it is not what we post and it will cause - // flakiness. - if (msg.message != WM_TIMER) - ++dispatch_count_; - // We treat WM_LBUTTONUP as the last message. - return msg.message != WM_LBUTTONUP; - } - - int dispatch_count_; -}; - -void MouseDownUp() { - PostMessage(NULL, WM_LBUTTONDOWN, 0, 0); - PostMessage(NULL, WM_LBUTTONUP, 'A', 0); -} - -void RunTest_Dispatcher(MessageLoop::Type message_loop_type) { - MessageLoop loop(message_loop_type); - - MessageLoop::current()->PostDelayedTask( - FROM_HERE, - Bind(&MouseDownUp), - TimeDelta::FromMilliseconds(100)); - DispatcherImpl dispatcher; - RunLoop run_loop(&dispatcher); - run_loop.Run(); - ASSERT_EQ(2, dispatcher.dispatch_count_); -} - -LRESULT CALLBACK MsgFilterProc(int code, WPARAM wparam, LPARAM lparam) { - if (code == MessagePumpForUI::kMessageFilterCode) { - MSG* msg = reinterpret_cast(lparam); - if (msg->message == WM_LBUTTONDOWN) - return TRUE; - } - return FALSE; -} - -void RunTest_DispatcherWithMessageHook(MessageLoop::Type message_loop_type) { - MessageLoop loop(message_loop_type); - - MessageLoop::current()->PostDelayedTask( - FROM_HERE, - Bind(&MouseDownUp), - TimeDelta::FromMilliseconds(100)); - HHOOK msg_hook = SetWindowsHookEx(WH_MSGFILTER, - MsgFilterProc, - NULL, - GetCurrentThreadId()); - DispatcherImpl dispatcher; - RunLoop run_loop(&dispatcher); - run_loop.Run(); - ASSERT_EQ(1, dispatcher.dispatch_count_); - UnhookWindowsHookEx(msg_hook); -} - -class TestIOHandler : public MessageLoopForIO::IOHandler { - public: - TestIOHandler(const wchar_t* name, HANDLE signal, bool wait); - - virtual void OnIOCompleted(MessageLoopForIO::IOContext* context, - DWORD bytes_transfered, DWORD error); - - void Init(); - void WaitForIO(); - OVERLAPPED* context() { return &context_.overlapped; } - DWORD size() { return sizeof(buffer_); } - - private: - char buffer_[48]; - MessageLoopForIO::IOContext context_; - HANDLE signal_; - win::ScopedHandle file_; - bool wait_; -}; - -TestIOHandler::TestIOHandler(const wchar_t* name, HANDLE signal, bool wait) - : signal_(signal), wait_(wait) { - memset(buffer_, 0, sizeof(buffer_)); - memset(&context_, 0, sizeof(context_)); - context_.handler = this; - - file_.Set(CreateFile(name, GENERIC_READ, 0, NULL, OPEN_EXISTING, - FILE_FLAG_OVERLAPPED, NULL)); - EXPECT_TRUE(file_.IsValid()); -} - -void TestIOHandler::Init() { - MessageLoopForIO::current()->RegisterIOHandler(file_, this); - - DWORD read; - EXPECT_FALSE(ReadFile(file_, buffer_, size(), &read, context())); - EXPECT_EQ(ERROR_IO_PENDING, GetLastError()); - if (wait_) - WaitForIO(); -} - -void TestIOHandler::OnIOCompleted(MessageLoopForIO::IOContext* context, - DWORD bytes_transfered, DWORD error) { - ASSERT_TRUE(context == &context_); - ASSERT_TRUE(SetEvent(signal_)); -} - -void TestIOHandler::WaitForIO() { - EXPECT_TRUE(MessageLoopForIO::current()->WaitForIOCompletion(300, this)); - EXPECT_TRUE(MessageLoopForIO::current()->WaitForIOCompletion(400, this)); -} - -void RunTest_IOHandler() { - win::ScopedHandle callback_called(CreateEvent(NULL, TRUE, FALSE, NULL)); - ASSERT_TRUE(callback_called.IsValid()); - - const wchar_t* kPipeName = L"\\\\.\\pipe\\iohandler_pipe"; - win::ScopedHandle server( - CreateNamedPipe(kPipeName, PIPE_ACCESS_OUTBOUND, 0, 1, 0, 0, 0, NULL)); - ASSERT_TRUE(server.IsValid()); - - Thread thread("IOHandler test"); - Thread::Options options; - options.message_loop_type = MessageLoop::TYPE_IO; - ASSERT_TRUE(thread.StartWithOptions(options)); - - MessageLoop* thread_loop = thread.message_loop(); - ASSERT_TRUE(NULL != thread_loop); - - TestIOHandler handler(kPipeName, callback_called, false); - thread_loop->PostTask(FROM_HERE, Bind(&TestIOHandler::Init, - Unretained(&handler))); - // Make sure the thread runs and sleeps for lack of work. - PlatformThread::Sleep(TimeDelta::FromMilliseconds(100)); - - const char buffer[] = "Hello there!"; - DWORD written; - EXPECT_TRUE(WriteFile(server, buffer, sizeof(buffer), &written, NULL)); - - DWORD result = WaitForSingleObject(callback_called, 1000); - EXPECT_EQ(WAIT_OBJECT_0, result); - - thread.Stop(); -} - -void RunTest_WaitForIO() { - win::ScopedHandle callback1_called( - CreateEvent(NULL, TRUE, FALSE, NULL)); - win::ScopedHandle callback2_called( - CreateEvent(NULL, TRUE, FALSE, NULL)); - ASSERT_TRUE(callback1_called.IsValid()); - ASSERT_TRUE(callback2_called.IsValid()); - - const wchar_t* kPipeName1 = L"\\\\.\\pipe\\iohandler_pipe1"; - const wchar_t* kPipeName2 = L"\\\\.\\pipe\\iohandler_pipe2"; - win::ScopedHandle server1( - CreateNamedPipe(kPipeName1, PIPE_ACCESS_OUTBOUND, 0, 1, 0, 0, 0, NULL)); - win::ScopedHandle server2( - CreateNamedPipe(kPipeName2, PIPE_ACCESS_OUTBOUND, 0, 1, 0, 0, 0, NULL)); - ASSERT_TRUE(server1.IsValid()); - ASSERT_TRUE(server2.IsValid()); - - Thread thread("IOHandler test"); - Thread::Options options; - options.message_loop_type = MessageLoop::TYPE_IO; - ASSERT_TRUE(thread.StartWithOptions(options)); - - MessageLoop* thread_loop = thread.message_loop(); - ASSERT_TRUE(NULL != thread_loop); - - TestIOHandler handler1(kPipeName1, callback1_called, false); - TestIOHandler handler2(kPipeName2, callback2_called, true); - thread_loop->PostTask(FROM_HERE, Bind(&TestIOHandler::Init, - Unretained(&handler1))); - // TODO(ajwong): Do we really need such long Sleeps in ths function? - // Make sure the thread runs and sleeps for lack of work. - TimeDelta delay = TimeDelta::FromMilliseconds(100); - PlatformThread::Sleep(delay); - thread_loop->PostTask(FROM_HERE, Bind(&TestIOHandler::Init, - Unretained(&handler2))); - PlatformThread::Sleep(delay); - - // At this time handler1 is waiting to be called, and the thread is waiting - // on the Init method of handler2, filtering only handler2 callbacks. - - const char buffer[] = "Hello there!"; - DWORD written; - EXPECT_TRUE(WriteFile(server1, buffer, sizeof(buffer), &written, NULL)); - PlatformThread::Sleep(2 * delay); - EXPECT_EQ(WAIT_TIMEOUT, WaitForSingleObject(callback1_called, 0)) << - "handler1 has not been called"; - - EXPECT_TRUE(WriteFile(server2, buffer, sizeof(buffer), &written, NULL)); - - HANDLE objects[2] = { callback1_called.Get(), callback2_called.Get() }; - DWORD result = WaitForMultipleObjects(2, objects, TRUE, 1000); - EXPECT_EQ(WAIT_OBJECT_0, result); - - thread.Stop(); -} - -#endif // defined(OS_WIN) - -} // namespace - -//----------------------------------------------------------------------------- -// Each test is run against each type of MessageLoop. That way we are sure -// that message loops work properly in all configurations. Of course, in some -// cases, a unit test may only be for a particular type of loop. - -TEST(MessageLoopTest, PostTask) { - RunTest_PostTask(MessageLoop::TYPE_DEFAULT); - RunTest_PostTask(MessageLoop::TYPE_UI); - RunTest_PostTask(MessageLoop::TYPE_IO); -} - -TEST(MessageLoopTest, PostTask_SEH) { - RunTest_PostTask_SEH(MessageLoop::TYPE_DEFAULT); - RunTest_PostTask_SEH(MessageLoop::TYPE_UI); - RunTest_PostTask_SEH(MessageLoop::TYPE_IO); -} - -TEST(MessageLoopTest, PostDelayedTask_Basic) { - RunTest_PostDelayedTask_Basic(MessageLoop::TYPE_DEFAULT); - RunTest_PostDelayedTask_Basic(MessageLoop::TYPE_UI); - RunTest_PostDelayedTask_Basic(MessageLoop::TYPE_IO); -} - -TEST(MessageLoopTest, PostDelayedTask_InDelayOrder) { - RunTest_PostDelayedTask_InDelayOrder(MessageLoop::TYPE_DEFAULT); - RunTest_PostDelayedTask_InDelayOrder(MessageLoop::TYPE_UI); - RunTest_PostDelayedTask_InDelayOrder(MessageLoop::TYPE_IO); -} - -TEST(MessageLoopTest, PostDelayedTask_InPostOrder) { - RunTest_PostDelayedTask_InPostOrder(MessageLoop::TYPE_DEFAULT); - RunTest_PostDelayedTask_InPostOrder(MessageLoop::TYPE_UI); - RunTest_PostDelayedTask_InPostOrder(MessageLoop::TYPE_IO); -} - -TEST(MessageLoopTest, PostDelayedTask_InPostOrder_2) { - RunTest_PostDelayedTask_InPostOrder_2(MessageLoop::TYPE_DEFAULT); - RunTest_PostDelayedTask_InPostOrder_2(MessageLoop::TYPE_UI); - RunTest_PostDelayedTask_InPostOrder_2(MessageLoop::TYPE_IO); -} - -TEST(MessageLoopTest, PostDelayedTask_InPostOrder_3) { - RunTest_PostDelayedTask_InPostOrder_3(MessageLoop::TYPE_DEFAULT); - RunTest_PostDelayedTask_InPostOrder_3(MessageLoop::TYPE_UI); - RunTest_PostDelayedTask_InPostOrder_3(MessageLoop::TYPE_IO); -} - -TEST(MessageLoopTest, PostDelayedTask_SharedTimer) { - RunTest_PostDelayedTask_SharedTimer(MessageLoop::TYPE_DEFAULT); - RunTest_PostDelayedTask_SharedTimer(MessageLoop::TYPE_UI); - RunTest_PostDelayedTask_SharedTimer(MessageLoop::TYPE_IO); -} - -#if defined(OS_WIN) -TEST(MessageLoopTest, PostDelayedTask_SharedTimer_SubPump) { - RunTest_PostDelayedTask_SharedTimer_SubPump(); -} -#endif - -// TODO(darin): MessageLoop does not support deleting all tasks in the -// destructor. -// Fails, http://crbug.com/50272. -TEST(MessageLoopTest, DISABLED_EnsureDeletion) { - RunTest_EnsureDeletion(MessageLoop::TYPE_DEFAULT); - RunTest_EnsureDeletion(MessageLoop::TYPE_UI); - RunTest_EnsureDeletion(MessageLoop::TYPE_IO); -} - -// TODO(darin): MessageLoop does not support deleting all tasks in the -// destructor. -// Fails, http://crbug.com/50272. -TEST(MessageLoopTest, DISABLED_EnsureDeletion_Chain) { - RunTest_EnsureDeletion_Chain(MessageLoop::TYPE_DEFAULT); - RunTest_EnsureDeletion_Chain(MessageLoop::TYPE_UI); - RunTest_EnsureDeletion_Chain(MessageLoop::TYPE_IO); -} - -#if defined(OS_WIN) -TEST(MessageLoopTest, Crasher) { - RunTest_Crasher(MessageLoop::TYPE_DEFAULT); - RunTest_Crasher(MessageLoop::TYPE_UI); - RunTest_Crasher(MessageLoop::TYPE_IO); -} - -TEST(MessageLoopTest, CrasherNasty) { - RunTest_CrasherNasty(MessageLoop::TYPE_DEFAULT); - RunTest_CrasherNasty(MessageLoop::TYPE_UI); - RunTest_CrasherNasty(MessageLoop::TYPE_IO); -} -#endif // defined(OS_WIN) - -TEST(MessageLoopTest, Nesting) { - RunTest_Nesting(MessageLoop::TYPE_DEFAULT); - RunTest_Nesting(MessageLoop::TYPE_UI); - RunTest_Nesting(MessageLoop::TYPE_IO); -} - -TEST(MessageLoopTest, RecursiveDenial1) { - RunTest_RecursiveDenial1(MessageLoop::TYPE_DEFAULT); - RunTest_RecursiveDenial1(MessageLoop::TYPE_UI); - RunTest_RecursiveDenial1(MessageLoop::TYPE_IO); -} - -TEST(MessageLoopTest, RecursiveDenial3) { - RunTest_RecursiveDenial3(MessageLoop::TYPE_DEFAULT); - RunTest_RecursiveDenial3(MessageLoop::TYPE_UI); - RunTest_RecursiveDenial3(MessageLoop::TYPE_IO); -} - -TEST(MessageLoopTest, RecursiveSupport1) { - RunTest_RecursiveSupport1(MessageLoop::TYPE_DEFAULT); - RunTest_RecursiveSupport1(MessageLoop::TYPE_UI); - RunTest_RecursiveSupport1(MessageLoop::TYPE_IO); -} - -#if defined(OS_WIN) -// This test occasionally hangs http://crbug.com/44567 -TEST(MessageLoopTest, DISABLED_RecursiveDenial2) { - RunTest_RecursiveDenial2(MessageLoop::TYPE_DEFAULT); - RunTest_RecursiveDenial2(MessageLoop::TYPE_UI); - RunTest_RecursiveDenial2(MessageLoop::TYPE_IO); -} - -TEST(MessageLoopTest, RecursiveSupport2) { - // This test requires a UI loop - RunTest_RecursiveSupport2(MessageLoop::TYPE_UI); -} -#endif // defined(OS_WIN) - -TEST(MessageLoopTest, NonNestableWithNoNesting) { - RunTest_NonNestableWithNoNesting(MessageLoop::TYPE_DEFAULT); - RunTest_NonNestableWithNoNesting(MessageLoop::TYPE_UI); - RunTest_NonNestableWithNoNesting(MessageLoop::TYPE_IO); -} - -TEST(MessageLoopTest, NonNestableInNestedLoop) { - RunTest_NonNestableInNestedLoop(MessageLoop::TYPE_DEFAULT, false); - RunTest_NonNestableInNestedLoop(MessageLoop::TYPE_UI, false); - RunTest_NonNestableInNestedLoop(MessageLoop::TYPE_IO, false); -} - -TEST(MessageLoopTest, NonNestableDelayedInNestedLoop) { - RunTest_NonNestableInNestedLoop(MessageLoop::TYPE_DEFAULT, true); - RunTest_NonNestableInNestedLoop(MessageLoop::TYPE_UI, true); - RunTest_NonNestableInNestedLoop(MessageLoop::TYPE_IO, true); -} - -TEST(MessageLoopTest, QuitNow) { - RunTest_QuitNow(MessageLoop::TYPE_DEFAULT); - RunTest_QuitNow(MessageLoop::TYPE_UI); - RunTest_QuitNow(MessageLoop::TYPE_IO); -} - -TEST(MessageLoopTest, RunLoopQuitTop) { - RunTest_RunLoopQuitTop(MessageLoop::TYPE_DEFAULT); - RunTest_RunLoopQuitTop(MessageLoop::TYPE_UI); - RunTest_RunLoopQuitTop(MessageLoop::TYPE_IO); -} - -TEST(MessageLoopTest, RunLoopQuitNested) { - RunTest_RunLoopQuitNested(MessageLoop::TYPE_DEFAULT); - RunTest_RunLoopQuitNested(MessageLoop::TYPE_UI); - RunTest_RunLoopQuitNested(MessageLoop::TYPE_IO); -} - -TEST(MessageLoopTest, RunLoopQuitBogus) { - RunTest_RunLoopQuitBogus(MessageLoop::TYPE_DEFAULT); - RunTest_RunLoopQuitBogus(MessageLoop::TYPE_UI); - RunTest_RunLoopQuitBogus(MessageLoop::TYPE_IO); -} - -TEST(MessageLoopTest, RunLoopQuitDeep) { - RunTest_RunLoopQuitDeep(MessageLoop::TYPE_DEFAULT); - RunTest_RunLoopQuitDeep(MessageLoop::TYPE_UI); - RunTest_RunLoopQuitDeep(MessageLoop::TYPE_IO); -} - -TEST(MessageLoopTest, RunLoopQuitOrderBefore) { - RunTest_RunLoopQuitOrderBefore(MessageLoop::TYPE_DEFAULT); - RunTest_RunLoopQuitOrderBefore(MessageLoop::TYPE_UI); - RunTest_RunLoopQuitOrderBefore(MessageLoop::TYPE_IO); -} - -TEST(MessageLoopTest, RunLoopQuitOrderDuring) { - RunTest_RunLoopQuitOrderDuring(MessageLoop::TYPE_DEFAULT); - RunTest_RunLoopQuitOrderDuring(MessageLoop::TYPE_UI); - RunTest_RunLoopQuitOrderDuring(MessageLoop::TYPE_IO); -} - -TEST(MessageLoopTest, RunLoopQuitOrderAfter) { - RunTest_RunLoopQuitOrderAfter(MessageLoop::TYPE_DEFAULT); - RunTest_RunLoopQuitOrderAfter(MessageLoop::TYPE_UI); - RunTest_RunLoopQuitOrderAfter(MessageLoop::TYPE_IO); -} - -class DummyTaskObserver : public MessageLoop::TaskObserver { - public: - explicit DummyTaskObserver(int num_tasks) - : num_tasks_started_(0), - num_tasks_processed_(0), - num_tasks_(num_tasks) {} - - virtual ~DummyTaskObserver() {} - - virtual void WillProcessTask(const PendingTask& pending_task) OVERRIDE { - num_tasks_started_++; - EXPECT_TRUE(pending_task.time_posted != TimeTicks()); - EXPECT_LE(num_tasks_started_, num_tasks_); - EXPECT_EQ(num_tasks_started_, num_tasks_processed_ + 1); - } - - virtual void DidProcessTask(const PendingTask& pending_task) OVERRIDE { - num_tasks_processed_++; - EXPECT_TRUE(pending_task.time_posted != TimeTicks()); - EXPECT_LE(num_tasks_started_, num_tasks_); - EXPECT_EQ(num_tasks_started_, num_tasks_processed_); - } - - int num_tasks_started() const { return num_tasks_started_; } - int num_tasks_processed() const { return num_tasks_processed_; } - - private: - int num_tasks_started_; - int num_tasks_processed_; - const int num_tasks_; - - DISALLOW_COPY_AND_ASSIGN(DummyTaskObserver); -}; - -TEST(MessageLoopTest, TaskObserver) { - const int kNumPosts = 6; - DummyTaskObserver observer(kNumPosts); - - MessageLoop loop; - loop.AddTaskObserver(&observer); - loop.PostTask(FROM_HERE, Bind(&PostNTasksThenQuit, kNumPosts)); - loop.Run(); - loop.RemoveTaskObserver(&observer); - - EXPECT_EQ(kNumPosts, observer.num_tasks_started()); - EXPECT_EQ(kNumPosts, observer.num_tasks_processed()); -} - -#if defined(OS_WIN) -TEST(MessageLoopTest, Dispatcher) { - // This test requires a UI loop - RunTest_Dispatcher(MessageLoop::TYPE_UI); -} - -TEST(MessageLoopTest, DispatcherWithMessageHook) { - // This test requires a UI loop - RunTest_DispatcherWithMessageHook(MessageLoop::TYPE_UI); -} - -TEST(MessageLoopTest, IOHandler) { - RunTest_IOHandler(); -} - -TEST(MessageLoopTest, WaitForIO) { - RunTest_WaitForIO(); -} - -TEST(MessageLoopTest, HighResolutionTimer) { - MessageLoop loop; - - const TimeDelta kFastTimer = TimeDelta::FromMilliseconds(5); - const TimeDelta kSlowTimer = TimeDelta::FromMilliseconds(100); - - EXPECT_FALSE(loop.IsHighResolutionTimerEnabledForTesting()); - - // Post a fast task to enable the high resolution timers. - loop.PostDelayedTask(FROM_HERE, Bind(&PostNTasksThenQuit, 1), - kFastTimer); - loop.Run(); - EXPECT_TRUE(loop.IsHighResolutionTimerEnabledForTesting()); - - // Post a slow task and verify high resolution timers - // are still enabled. - loop.PostDelayedTask(FROM_HERE, Bind(&PostNTasksThenQuit, 1), - kSlowTimer); - loop.Run(); - EXPECT_TRUE(loop.IsHighResolutionTimerEnabledForTesting()); - - // Wait for a while so that high-resolution mode elapses. - PlatformThread::Sleep(TimeDelta::FromMilliseconds( - MessageLoop::kHighResolutionTimerModeLeaseTimeMs)); - - // Post a slow task to disable the high resolution timers. - loop.PostDelayedTask(FROM_HERE, Bind(&PostNTasksThenQuit, 1), - kSlowTimer); - loop.Run(); - EXPECT_FALSE(loop.IsHighResolutionTimerEnabledForTesting()); -} - -#endif // defined(OS_WIN) - -#if defined(OS_POSIX) && !defined(OS_NACL) - -namespace { - -class QuitDelegate : public MessageLoopForIO::Watcher { - public: - virtual void OnFileCanWriteWithoutBlocking(int fd) OVERRIDE { - MessageLoop::current()->QuitWhenIdle(); - } - virtual void OnFileCanReadWithoutBlocking(int fd) OVERRIDE { - MessageLoop::current()->QuitWhenIdle(); - } -}; - -TEST(MessageLoopTest, FileDescriptorWatcherOutlivesMessageLoop) { - // Simulate a MessageLoop that dies before an FileDescriptorWatcher. - // This could happen when people use the Singleton pattern or atexit. - - // Create a file descriptor. Doesn't need to be readable or writable, - // as we don't need to actually get any notifications. - // pipe() is just the easiest way to do it. - int pipefds[2]; - int err = pipe(pipefds); - ASSERT_EQ(0, err); - int fd = pipefds[1]; - { - // Arrange for controller to live longer than message loop. - MessageLoopForIO::FileDescriptorWatcher controller; - { - MessageLoopForIO message_loop; - - QuitDelegate delegate; - message_loop.WatchFileDescriptor(fd, - true, MessageLoopForIO::WATCH_WRITE, &controller, &delegate); - // and don't run the message loop, just destroy it. - } - } - if (HANDLE_EINTR(close(pipefds[0])) < 0) - PLOG(ERROR) << "close"; - if (HANDLE_EINTR(close(pipefds[1])) < 0) - PLOG(ERROR) << "close"; -} - -TEST(MessageLoopTest, FileDescriptorWatcherDoubleStop) { - // Verify that it's ok to call StopWatchingFileDescriptor(). - // (Errors only showed up in valgrind.) - int pipefds[2]; - int err = pipe(pipefds); - ASSERT_EQ(0, err); - int fd = pipefds[1]; - { - // Arrange for message loop to live longer than controller. - MessageLoopForIO message_loop; - { - MessageLoopForIO::FileDescriptorWatcher controller; - - QuitDelegate delegate; - message_loop.WatchFileDescriptor(fd, - true, MessageLoopForIO::WATCH_WRITE, &controller, &delegate); - controller.StopWatchingFileDescriptor(); - } - } - if (HANDLE_EINTR(close(pipefds[0])) < 0) - PLOG(ERROR) << "close"; - if (HANDLE_EINTR(close(pipefds[1])) < 0) - PLOG(ERROR) << "close"; -} - -} // namespace - -#endif // defined(OS_POSIX) && !defined(OS_NACL) - -namespace { -// Inject a test point for recording the destructor calls for Closure objects -// send to MessageLoop::PostTask(). It is awkward usage since we are trying to -// hook the actual destruction, which is not a common operation. -class DestructionObserverProbe : - public RefCounted { - public: - DestructionObserverProbe(bool* task_destroyed, - bool* destruction_observer_called) - : task_destroyed_(task_destroyed), - destruction_observer_called_(destruction_observer_called) { - } - virtual void Run() { - // This task should never run. - ADD_FAILURE(); - } - private: - friend class RefCounted; - - virtual ~DestructionObserverProbe() { - EXPECT_FALSE(*destruction_observer_called_); - *task_destroyed_ = true; - } - - bool* task_destroyed_; - bool* destruction_observer_called_; -}; - -class MLDestructionObserver : public MessageLoop::DestructionObserver { - public: - MLDestructionObserver(bool* task_destroyed, bool* destruction_observer_called) - : task_destroyed_(task_destroyed), - destruction_observer_called_(destruction_observer_called), - task_destroyed_before_message_loop_(false) { - } - virtual void WillDestroyCurrentMessageLoop() OVERRIDE { - task_destroyed_before_message_loop_ = *task_destroyed_; - *destruction_observer_called_ = true; - } - bool task_destroyed_before_message_loop() const { - return task_destroyed_before_message_loop_; - } - private: - bool* task_destroyed_; - bool* destruction_observer_called_; - bool task_destroyed_before_message_loop_; -}; - -} // namespace - -TEST(MessageLoopTest, DestructionObserverTest) { - // Verify that the destruction observer gets called at the very end (after - // all the pending tasks have been destroyed). - MessageLoop* loop = new MessageLoop; - const TimeDelta kDelay = TimeDelta::FromMilliseconds(100); - - bool task_destroyed = false; - bool destruction_observer_called = false; - - MLDestructionObserver observer(&task_destroyed, &destruction_observer_called); - loop->AddDestructionObserver(&observer); - loop->PostDelayedTask( - FROM_HERE, - Bind(&DestructionObserverProbe::Run, - new DestructionObserverProbe(&task_destroyed, - &destruction_observer_called)), - kDelay); - delete loop; - EXPECT_TRUE(observer.task_destroyed_before_message_loop()); - // The task should have been destroyed when we deleted the loop. - EXPECT_TRUE(task_destroyed); - EXPECT_TRUE(destruction_observer_called); -} - - -// Verify that MessageLoop sets ThreadMainTaskRunner::current() and it -// posts tasks on that message loop. -TEST(MessageLoopTest, ThreadMainTaskRunner) { - MessageLoop loop; - - scoped_refptr foo(new Foo()); - std::string a("a"); - ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE, Bind( - &Foo::Test1ConstRef, foo.get(), a)); - - // Post quit task; - MessageLoop::current()->PostTask(FROM_HERE, Bind( - &MessageLoop::Quit, Unretained(MessageLoop::current()))); - - // Now kick things off - MessageLoop::current()->Run(); - - EXPECT_EQ(foo->test_count(), 1); - EXPECT_EQ(foo->result(), "a"); -} - -TEST(MessageLoopTest, IsType) { - MessageLoop loop(MessageLoop::TYPE_UI); - EXPECT_TRUE(loop.IsType(MessageLoop::TYPE_UI)); - EXPECT_FALSE(loop.IsType(MessageLoop::TYPE_IO)); - EXPECT_FALSE(loop.IsType(MessageLoop::TYPE_DEFAULT)); -} - -TEST(MessageLoopTest, RecursivePosts) { - // There was a bug in the MessagePumpGLib where posting tasks recursively - // caused the message loop to hang, due to the buffer of the internal pipe - // becoming full. Test all MessageLoop types to ensure this issue does not - // exist in other MessagePumps. - - // On Linux, the pipe buffer size is 64KiB by default. The bug caused one - // byte accumulated in the pipe per two posts, so we should repeat 128K - // times to reproduce the bug. - const int kNumTimes = 1 << 17; - RunTest_RecursivePosts(MessageLoop::TYPE_DEFAULT, kNumTimes); - RunTest_RecursivePosts(MessageLoop::TYPE_UI, kNumTimes); - RunTest_RecursivePosts(MessageLoop::TYPE_IO, kNumTimes); -} - -} // namespace base diff --git a/base/message_loop/message_pump.cc b/base/message_loop/message_pump.cc deleted file mode 100644 index 7ffc2b170d..0000000000 --- a/base/message_loop/message_pump.cc +++ /dev/null @@ -1,15 +0,0 @@ -// Copyright (c) 2010 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "base/message_loop/message_pump.h" - -namespace base { - -MessagePump::MessagePump() { -} - -MessagePump::~MessagePump() { -} - -} // namespace base diff --git a/base/message_loop/message_pump.h b/base/message_loop/message_pump.h deleted file mode 100644 index 0ebba3a3e6..0000000000 --- a/base/message_loop/message_pump.h +++ /dev/null @@ -1,126 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef BASE_MESSAGE_LOOP_MESSAGE_PUMP_H_ -#define BASE_MESSAGE_LOOP_MESSAGE_PUMP_H_ - -#include "base/base_export.h" -#include "base/threading/non_thread_safe.h" - -namespace base { - -class TimeTicks; - -class BASE_EXPORT MessagePump : public NonThreadSafe { - public: - // Please see the comments above the Run method for an illustration of how - // these delegate methods are used. - class BASE_EXPORT Delegate { - public: - virtual ~Delegate() {} - - // Called from within Run in response to ScheduleWork or when the message - // pump would otherwise call DoDelayedWork. Returns true to indicate that - // work was done. DoDelayedWork will still be called if DoWork returns - // true, but DoIdleWork will not. - virtual bool DoWork() = 0; - - // Called from within Run in response to ScheduleDelayedWork or when the - // message pump would otherwise sleep waiting for more work. Returns true - // to indicate that delayed work was done. DoIdleWork will not be called - // if DoDelayedWork returns true. Upon return |next_delayed_work_time| - // indicates the time when DoDelayedWork should be called again. If - // |next_delayed_work_time| is null (per Time::is_null), then the queue of - // future delayed work (timer events) is currently empty, and no additional - // calls to this function need to be scheduled. - virtual bool DoDelayedWork(TimeTicks* next_delayed_work_time) = 0; - - // Called from within Run just before the message pump goes to sleep. - // Returns true to indicate that idle work was done. - virtual bool DoIdleWork() = 0; - }; - - MessagePump(); - virtual ~MessagePump(); - - // The Run method is called to enter the message pump's run loop. - // - // Within the method, the message pump is responsible for processing native - // messages as well as for giving cycles to the delegate periodically. The - // message pump should take care to mix delegate callbacks with native - // message processing so neither type of event starves the other of cycles. - // - // The anatomy of a typical run loop: - // - // for (;;) { - // bool did_work = DoInternalWork(); - // if (should_quit_) - // break; - // - // did_work |= delegate_->DoWork(); - // if (should_quit_) - // break; - // - // TimeTicks next_time; - // did_work |= delegate_->DoDelayedWork(&next_time); - // if (should_quit_) - // break; - // - // if (did_work) - // continue; - // - // did_work = delegate_->DoIdleWork(); - // if (should_quit_) - // break; - // - // if (did_work) - // continue; - // - // WaitForWork(); - // } - // - // Here, DoInternalWork is some private method of the message pump that is - // responsible for dispatching the next UI message or notifying the next IO - // completion (for example). WaitForWork is a private method that simply - // blocks until there is more work of any type to do. - // - // Notice that the run loop cycles between calling DoInternalWork, DoWork, - // and DoDelayedWork methods. This helps ensure that none of these work - // queues starve the others. This is important for message pumps that are - // used to drive animations, for example. - // - // Notice also that after each callout to foreign code, the run loop checks - // to see if it should quit. The Quit method is responsible for setting this - // flag. No further work is done once the quit flag is set. - // - // NOTE: Care must be taken to handle Run being called again from within any - // of the callouts to foreign code. Native message pumps may also need to - // deal with other native message pumps being run outside their control - // (e.g., the MessageBox API on Windows pumps UI messages!). To be specific, - // the callouts (DoWork and DoDelayedWork) MUST still be provided even in - // nested sub-loops that are "seemingly" outside the control of this message - // pump. DoWork in particular must never be starved for time slices unless - // it returns false (meaning it has run out of things to do). - // - virtual void Run(Delegate* delegate) = 0; - - // Quit immediately from the most recently entered run loop. This method may - // only be used on the thread that called Run. - virtual void Quit() = 0; - - // Schedule a DoWork callback to happen reasonably soon. Does nothing if a - // DoWork callback is already scheduled. This method may be called from any - // thread. Once this call is made, DoWork should not be "starved" at least - // until it returns a value of false. - virtual void ScheduleWork() = 0; - - // Schedule a DoDelayedWork callback to happen at the specified time, - // cancelling any pending DoDelayedWork callback. This method may only be - // used on the thread that called Run. - virtual void ScheduleDelayedWork(const TimeTicks& delayed_work_time) = 0; -}; - -} // namespace base - -#endif // BASE_MESSAGE_LOOP_MESSAGE_PUMP_H_ diff --git a/base/message_loop/message_pump_android.cc b/base/message_loop/message_pump_android.cc deleted file mode 100644 index f3f1c9bcb4..0000000000 --- a/base/message_loop/message_pump_android.cc +++ /dev/null @@ -1,133 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "base/message_loop/message_pump_android.h" - -#include - -#include "base/android/jni_android.h" -#include "base/android/scoped_java_ref.h" -#include "base/lazy_instance.h" -#include "base/logging.h" -#include "base/run_loop.h" -#include "base/time/time.h" -#include "jni/SystemMessageHandler_jni.h" - -using base::android::ScopedJavaLocalRef; - -// ---------------------------------------------------------------------------- -// Native JNI methods called by Java. -// ---------------------------------------------------------------------------- -// This method can not move to anonymous namespace as it has been declared as -// 'static' in system_message_handler_jni.h. -static void DoRunLoopOnce(JNIEnv* env, jobject obj, jint native_delegate) { - base::MessagePump::Delegate* delegate = - reinterpret_cast(native_delegate); - DCHECK(delegate); - // This is based on MessagePumpForUI::DoRunLoop() from desktop. - // Note however that our system queue is handled in the java side. - // In desktop we inspect and process a single system message and then - // we call DoWork() / DoDelayedWork(). - // On Android, the java message queue may contain messages for other handlers - // that will be processed before calling here again. - bool did_work = delegate->DoWork(); - - // This is the time when we need to do delayed work. - base::TimeTicks delayed_work_time; - did_work |= delegate->DoDelayedWork(&delayed_work_time); - - // Always call this if there is a delayed message waiting in the queue - // since is at most one delayed message in the Java message handler, and this - // function call may be the result of that message being handled. - if (!delayed_work_time.is_null()) { - Java_SystemMessageHandler_setDelayedTimer(env, obj, - (delayed_work_time - base::TimeTicks::Now()).InMillisecondsRoundedUp()); - } - - // This is a major difference between android and other platforms: since we - // can't inspect it and process just one single message, instead we'll yeld - // the callstack. - if (did_work) - return; - - delegate->DoIdleWork(); -} - -namespace base { - -MessagePumpForUI::MessagePumpForUI() - : run_loop_(NULL) { -} - -MessagePumpForUI::~MessagePumpForUI() { -} - -void MessagePumpForUI::Run(Delegate* delegate) { - NOTREACHED() << "UnitTests should rely on MessagePumpForUIStub in" - " test_stub_android.h"; -} - -void MessagePumpForUI::Start(Delegate* delegate) { - run_loop_ = new RunLoop(); - // Since the RunLoop was just created above, BeforeRun should be guaranteed to - // return true (it only returns false if the RunLoop has been Quit already). - if (!run_loop_->BeforeRun()) - NOTREACHED(); - - DCHECK(system_message_handler_obj_.is_null()); - - JNIEnv* env = base::android::AttachCurrentThread(); - DCHECK(env); - - system_message_handler_obj_.Reset( - Java_SystemMessageHandler_create(env, reinterpret_cast(delegate))); -} - -void MessagePumpForUI::Quit() { - if (!system_message_handler_obj_.is_null()) { - JNIEnv* env = base::android::AttachCurrentThread(); - DCHECK(env); - - Java_SystemMessageHandler_removeTimer(env, - system_message_handler_obj_.obj()); - system_message_handler_obj_.Reset(); - } - - if (run_loop_) { - run_loop_->AfterRun(); - delete run_loop_; - run_loop_ = NULL; - } -} - -void MessagePumpForUI::ScheduleWork() { - DCHECK(!system_message_handler_obj_.is_null()); - - JNIEnv* env = base::android::AttachCurrentThread(); - DCHECK(env); - - Java_SystemMessageHandler_setTimer(env, - system_message_handler_obj_.obj()); -} - -void MessagePumpForUI::ScheduleDelayedWork(const TimeTicks& delayed_work_time) { - DCHECK(!system_message_handler_obj_.is_null()); - - JNIEnv* env = base::android::AttachCurrentThread(); - DCHECK(env); - - jlong millis = - (delayed_work_time - TimeTicks::Now()).InMillisecondsRoundedUp(); - // Note that we're truncating to milliseconds as required by the java side, - // even though delayed_work_time is microseconds resolution. - Java_SystemMessageHandler_setDelayedTimer(env, - system_message_handler_obj_.obj(), millis); -} - -// static -bool MessagePumpForUI::RegisterBindings(JNIEnv* env) { - return RegisterNativesImpl(env); -} - -} // namespace base diff --git a/base/message_loop/message_pump_android.h b/base/message_loop/message_pump_android.h deleted file mode 100644 index 8a07a0f6e4..0000000000 --- a/base/message_loop/message_pump_android.h +++ /dev/null @@ -1,45 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef BASE_MESSAGE_LOOP_MESSAGE_PUMP_ANDROID_H_ -#define BASE_MESSAGE_LOOP_MESSAGE_PUMP_ANDROID_H_ - -#include - -#include "base/android/scoped_java_ref.h" -#include "base/base_export.h" -#include "base/compiler_specific.h" -#include "base/message_loop/message_pump.h" - -namespace base { - -class RunLoop; -class TimeTicks; - -// This class implements a MessagePump needed for TYPE_UI MessageLoops on -// OS_ANDROID platform. -class BASE_EXPORT MessagePumpForUI : public MessagePump { - public: - MessagePumpForUI(); - virtual ~MessagePumpForUI(); - - virtual void Run(Delegate* delegate) OVERRIDE; - virtual void Quit() OVERRIDE; - virtual void ScheduleWork() OVERRIDE; - virtual void ScheduleDelayedWork(const TimeTicks& delayed_work_time) OVERRIDE; - - virtual void Start(Delegate* delegate); - - static bool RegisterBindings(JNIEnv* env); - - private: - RunLoop* run_loop_; - base::android::ScopedJavaGlobalRef system_message_handler_obj_; - - DISALLOW_COPY_AND_ASSIGN(MessagePumpForUI); -}; - -} // namespace base - -#endif // BASE_MESSAGE_LOOP_MESSAGE_PUMP_ANDROID_H_ diff --git a/base/message_loop/message_pump_aurax11.cc b/base/message_loop/message_pump_aurax11.cc deleted file mode 100644 index 1f91a0e359..0000000000 --- a/base/message_loop/message_pump_aurax11.cc +++ /dev/null @@ -1,307 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "base/message_loop/message_pump_aurax11.h" - -#include -#include -#include -#include - -#include "base/basictypes.h" -#include "base/message_loop/message_loop.h" - -namespace base { - -namespace { - -gboolean XSourcePrepare(GSource* source, gint* timeout_ms) { - if (XPending(MessagePumpAuraX11::GetDefaultXDisplay())) - *timeout_ms = 0; - else - *timeout_ms = -1; - return FALSE; -} - -gboolean XSourceCheck(GSource* source) { - return XPending(MessagePumpAuraX11::GetDefaultXDisplay()); -} - -gboolean XSourceDispatch(GSource* source, - GSourceFunc unused_func, - gpointer data) { - MessagePumpAuraX11* pump = static_cast(data); - return pump->DispatchXEvents(); -} - -GSourceFuncs XSourceFuncs = { - XSourcePrepare, - XSourceCheck, - XSourceDispatch, - NULL -}; - -// The connection is essentially a global that's accessed through a static -// method and destroyed whenever ~MessagePumpAuraX11() is called. We do this -// for historical reasons so user code can call -// MessagePumpForUI::GetDefaultXDisplay() where MessagePumpForUI is a typedef -// to whatever type in the current build. -// -// TODO(erg): This can be changed to something more sane like -// MessagePumpAuraX11::Current()->display() once MessagePumpGtk goes away. -Display* g_xdisplay = NULL; -int g_xinput_opcode = -1; - -bool InitializeXInput2Internal() { - Display* display = MessagePumpAuraX11::GetDefaultXDisplay(); - if (!display) - return false; - - int event, err; - - int xiopcode; - if (!XQueryExtension(display, "XInputExtension", &xiopcode, &event, &err)) { - DVLOG(1) << "X Input extension not available."; - return false; - } - g_xinput_opcode = xiopcode; - -#if defined(USE_XI2_MT) - // USE_XI2_MT also defines the required XI2 minor minimum version. - int major = 2, minor = USE_XI2_MT; -#else - int major = 2, minor = 0; -#endif - if (XIQueryVersion(display, &major, &minor) == BadRequest) { - DVLOG(1) << "XInput2 not supported in the server."; - return false; - } -#if defined(USE_XI2_MT) - if (major < 2 || (major == 2 && minor < USE_XI2_MT)) { - DVLOG(1) << "XI version on server is " << major << "." << minor << ". " - << "But 2." << USE_XI2_MT << " is required."; - return false; - } -#endif - - return true; -} - -Window FindEventTarget(const NativeEvent& xev) { - Window target = xev->xany.window; - if (xev->type == GenericEvent && - static_cast(xev->xcookie.data)->extension == g_xinput_opcode) { - target = static_cast(xev->xcookie.data)->event; - } - return target; -} - -bool InitializeXInput2() { - static bool xinput2_supported = InitializeXInput2Internal(); - return xinput2_supported; -} - -bool InitializeXkb() { - Display* display = MessagePumpAuraX11::GetDefaultXDisplay(); - if (!display) - return false; - - int opcode, event, error; - int major = XkbMajorVersion; - int minor = XkbMinorVersion; - if (!XkbQueryExtension(display, &opcode, &event, &error, &major, &minor)) { - DVLOG(1) << "Xkb extension not available."; - return false; - } - - // Ask the server not to send KeyRelease event when the user holds down a key. - // crbug.com/138092 - Bool supported_return; - if (!XkbSetDetectableAutoRepeat(display, True, &supported_return)) { - DVLOG(1) << "XKB not supported in the server."; - return false; - } - - return true; -} - -} // namespace - -MessagePumpAuraX11::MessagePumpAuraX11() : MessagePumpGlib(), - x_source_(NULL) { - InitializeXInput2(); - InitializeXkb(); - InitXSource(); - - // Can't put this in the initializer list because g_xdisplay may not exist - // until after InitXSource(). - x_root_window_ = DefaultRootWindow(g_xdisplay); -} - -MessagePumpAuraX11::~MessagePumpAuraX11() { - g_source_destroy(x_source_); - g_source_unref(x_source_); - XCloseDisplay(g_xdisplay); - g_xdisplay = NULL; -} - -// static -Display* MessagePumpAuraX11::GetDefaultXDisplay() { - if (!g_xdisplay) - g_xdisplay = XOpenDisplay(NULL); - return g_xdisplay; -} - -// static -bool MessagePumpAuraX11::HasXInput2() { - return InitializeXInput2(); -} - -// static -MessagePumpAuraX11* MessagePumpAuraX11::Current() { - MessageLoopForUI* loop = MessageLoopForUI::current(); - return static_cast(loop->pump_ui()); -} - -void MessagePumpAuraX11::AddDispatcherForWindow( - MessagePumpDispatcher* dispatcher, - unsigned long xid) { - dispatchers_.insert(std::make_pair(xid, dispatcher)); -} - -void MessagePumpAuraX11::RemoveDispatcherForWindow(unsigned long xid) { - dispatchers_.erase(xid); -} - -void MessagePumpAuraX11::AddDispatcherForRootWindow( - MessagePumpDispatcher* dispatcher) { - root_window_dispatchers_.AddObserver(dispatcher); -} - -void MessagePumpAuraX11::RemoveDispatcherForRootWindow( - MessagePumpDispatcher* dispatcher) { - root_window_dispatchers_.RemoveObserver(dispatcher); -} - -bool MessagePumpAuraX11::DispatchXEvents() { - Display* display = GetDefaultXDisplay(); - DCHECK(display); - MessagePumpDispatcher* dispatcher = - GetDispatcher() ? GetDispatcher() : this; - - // In the general case, we want to handle all pending events before running - // the tasks. This is what happens in the message_pump_glib case. - while (XPending(display)) { - XEvent xev; - XNextEvent(display, &xev); - if (dispatcher && ProcessXEvent(dispatcher, &xev)) - return TRUE; - } - return TRUE; -} - -void MessagePumpAuraX11::BlockUntilWindowMapped(unsigned long xid) { - XEvent event; - - Display* display = GetDefaultXDisplay(); - DCHECK(display); - - MessagePumpDispatcher* dispatcher = - GetDispatcher() ? GetDispatcher() : this; - - do { - // Block until there's a message of |event_mask| type on |w|. Then remove - // it from the queue and stuff it in |event|. - XWindowEvent(display, xid, StructureNotifyMask, &event); - ProcessXEvent(dispatcher, &event); - } while (event.type != MapNotify); -} - -void MessagePumpAuraX11::InitXSource() { - // CHECKs are to help track down crbug.com/113106. - CHECK(!x_source_); - Display* display = GetDefaultXDisplay(); - CHECK(display) << "Unable to get connection to X server"; - x_poll_.reset(new GPollFD()); - CHECK(x_poll_.get()); - x_poll_->fd = ConnectionNumber(display); - x_poll_->events = G_IO_IN; - - x_source_ = g_source_new(&XSourceFuncs, sizeof(GSource)); - g_source_add_poll(x_source_, x_poll_.get()); - g_source_set_can_recurse(x_source_, TRUE); - g_source_set_callback(x_source_, NULL, this, NULL); - g_source_attach(x_source_, g_main_context_default()); -} - -bool MessagePumpAuraX11::ProcessXEvent(MessagePumpDispatcher* dispatcher, - XEvent* xev) { - bool should_quit = false; - - bool have_cookie = false; - if (xev->type == GenericEvent && - XGetEventData(xev->xgeneric.display, &xev->xcookie)) { - have_cookie = true; - } - - if (!WillProcessXEvent(xev)) { - if (!dispatcher->Dispatch(xev)) { - should_quit = true; - Quit(); - } - DidProcessXEvent(xev); - } - - if (have_cookie) { - XFreeEventData(xev->xgeneric.display, &xev->xcookie); - } - - return should_quit; -} - -bool MessagePumpAuraX11::WillProcessXEvent(XEvent* xevent) { - if (!observers().might_have_observers()) - return false; - ObserverListBase::Iterator it(observers()); - MessagePumpObserver* obs; - while ((obs = it.GetNext()) != NULL) { - if (obs->WillProcessEvent(xevent)) - return true; - } - return false; -} - -void MessagePumpAuraX11::DidProcessXEvent(XEvent* xevent) { - FOR_EACH_OBSERVER(MessagePumpObserver, observers(), DidProcessEvent(xevent)); -} - -MessagePumpDispatcher* MessagePumpAuraX11::GetDispatcherForXEvent( - const NativeEvent& xev) const { - ::Window x_window = FindEventTarget(xev); - DispatchersMap::const_iterator it = dispatchers_.find(x_window); - return it != dispatchers_.end() ? it->second : NULL; -} - -bool MessagePumpAuraX11::Dispatch(const NativeEvent& xev) { - // MappingNotify events (meaning that the keyboard or pointer buttons have - // been remapped) aren't associated with a window; send them to all - // dispatchers. - if (xev->type == MappingNotify) { - for (DispatchersMap::const_iterator it = dispatchers_.begin(); - it != dispatchers_.end(); ++it) { - it->second->Dispatch(xev); - } - return true; - } - - if (FindEventTarget(xev) == x_root_window_) { - FOR_EACH_OBSERVER(MessagePumpDispatcher, root_window_dispatchers_, - Dispatch(xev)); - return true; - } - MessagePumpDispatcher* dispatcher = GetDispatcherForXEvent(xev); - return dispatcher ? dispatcher->Dispatch(xev) : true; -} - -} // namespace base diff --git a/base/message_loop/message_pump_aurax11.h b/base/message_loop/message_pump_aurax11.h deleted file mode 100644 index 89089ad535..0000000000 --- a/base/message_loop/message_pump_aurax11.h +++ /dev/null @@ -1,120 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef BASE_MESSAGE_LOOP_MESSAGE_PUMP_AURAX11_H -#define BASE_MESSAGE_LOOP_MESSAGE_PUMP_AURAX11_H - -#include -#include - -#include "base/memory/scoped_ptr.h" -#include "base/message_loop/message_pump.h" -#include "base/message_loop/message_pump_dispatcher.h" -#include "base/message_loop/message_pump_glib.h" -#include "base/message_loop/message_pump_observer.h" -#include "base/observer_list.h" - -// It would be nice to include the X11 headers here so that we use Window -// instead of its typedef of unsigned long, but we can't because everything in -// chrome includes us through base/message_loop/message_loop.h, and X11's crappy -// #define heavy headers muck up half of chrome. - -typedef struct _GPollFD GPollFD; -typedef struct _GSource GSource; -typedef struct _XDisplay Display; - -namespace base { - -// This class implements a message-pump for dispatching X events. -// -// If there's a current dispatcher given through RunWithDispatcher(), that -// dispatcher receives events. Otherwise, we route to messages to dispatchers -// who have subscribed to messages from a specific X11 window. -class BASE_EXPORT MessagePumpAuraX11 : public MessagePumpGlib, - public MessagePumpDispatcher { - public: - MessagePumpAuraX11(); - virtual ~MessagePumpAuraX11(); - - // Returns default X Display. - static Display* GetDefaultXDisplay(); - - // Returns true if the system supports XINPUT2. - static bool HasXInput2(); - - // Returns the UI message pump. - static MessagePumpAuraX11* Current(); - - // Adds/Removes |dispatcher| for the |xid|. This will route all messages from - // the window |xid| to |dispatcher. - void AddDispatcherForWindow(MessagePumpDispatcher* dispatcher, - unsigned long xid); - void RemoveDispatcherForWindow(unsigned long xid); - - // Adds/Removes |dispatcher| to receive all events sent to the X root - // window. A root window can have multiple dispatchers, and events on root - // windows will be dispatched to all. - void AddDispatcherForRootWindow(MessagePumpDispatcher* dispatcher); - void RemoveDispatcherForRootWindow(MessagePumpDispatcher* dispatcher); - - // Internal function. Called by the glib source dispatch function. Processes - // all available X events. - bool DispatchXEvents(); - - // Blocks on the X11 event queue until we receive notification from the - // xserver that |w| has been mapped; StructureNotifyMask events on |w| are - // pulled out from the queue and dispatched out of order. - // - // For those that know X11, this is really a wrapper around XWindowEvent - // which still makes sure the preempted event is dispatched instead of - // dropped on the floor. This method exists because mapping a window is - // asynchronous (and we receive an XEvent when mapped), while there are also - // functions which require a mapped window. - void BlockUntilWindowMapped(unsigned long xid); - - private: - typedef std::map DispatchersMap; - - // Initializes the glib event source for X. - void InitXSource(); - - // Dispatches the XEvent and returns true if we should exit the current loop - // of message processing. - bool ProcessXEvent(MessagePumpDispatcher* dispatcher, XEvent* event); - - // Sends the event to the observers. If an observer returns true, then it does - // not send the event to any other observers and returns true. Returns false - // if no observer returns true. - bool WillProcessXEvent(XEvent* xevent); - void DidProcessXEvent(XEvent* xevent); - - // Returns the Dispatcher based on the event's target window. - MessagePumpDispatcher* GetDispatcherForXEvent(const NativeEvent& xev) const; - - // Overridden from MessagePumpDispatcher: - virtual bool Dispatch(const NativeEvent& event) OVERRIDE; - - // The event source for X events. - GSource* x_source_; - - // The poll attached to |x_source_|. - scoped_ptr x_poll_; - - DispatchersMap dispatchers_; - - // Dispatch calls can cause addition of new dispatchers as we iterate - // through them. Use ObserverList to ensure the iterator remains valid across - // additions. - ObserverList root_window_dispatchers_; - - unsigned long x_root_window_; - - DISALLOW_COPY_AND_ASSIGN(MessagePumpAuraX11); -}; - -typedef MessagePumpAuraX11 MessagePumpForUI; - -} // namespace base - -#endif // BASE_MESSAGE_LOOP_MESSAGE_PUMP_AURAX11_H diff --git a/base/message_loop/message_pump_default.cc b/base/message_loop/message_pump_default.cc deleted file mode 100644 index 27c19e0227..0000000000 --- a/base/message_loop/message_pump_default.cc +++ /dev/null @@ -1,88 +0,0 @@ -// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "base/message_loop/message_pump_default.h" - -#include "base/logging.h" -#include "base/threading/thread_restrictions.h" - -#if defined(OS_MACOSX) -#include "base/mac/scoped_nsautorelease_pool.h" -#endif - -namespace base { - -MessagePumpDefault::MessagePumpDefault() - : keep_running_(true), - event_(false, false) { -} - -MessagePumpDefault::~MessagePumpDefault() { -} - -void MessagePumpDefault::Run(Delegate* delegate) { - DCHECK(keep_running_) << "Quit must have been called outside of Run!"; - - for (;;) { -#if defined(OS_MACOSX) - mac::ScopedNSAutoreleasePool autorelease_pool; -#endif - - bool did_work = delegate->DoWork(); - if (!keep_running_) - break; - - did_work |= delegate->DoDelayedWork(&delayed_work_time_); - if (!keep_running_) - break; - - if (did_work) - continue; - - did_work = delegate->DoIdleWork(); - if (!keep_running_) - break; - - if (did_work) - continue; - - ThreadRestrictions::ScopedAllowWait allow_wait; - if (delayed_work_time_.is_null()) { - event_.Wait(); - } else { - TimeDelta delay = delayed_work_time_ - TimeTicks::Now(); - if (delay > TimeDelta()) { - event_.TimedWait(delay); - } else { - // It looks like delayed_work_time_ indicates a time in the past, so we - // need to call DoDelayedWork now. - delayed_work_time_ = TimeTicks(); - } - } - // Since event_ is auto-reset, we don't need to do anything special here - // other than service each delegate method. - } - - keep_running_ = true; -} - -void MessagePumpDefault::Quit() { - keep_running_ = false; -} - -void MessagePumpDefault::ScheduleWork() { - // Since this can be called on any thread, we need to ensure that our Run - // loop wakes up. - event_.Signal(); -} - -void MessagePumpDefault::ScheduleDelayedWork( - const TimeTicks& delayed_work_time) { - // We know that we can't be blocked on Wait right now since this method can - // only be called on the same thread as Run, so we only need to update our - // record of how long to sleep when we do sleep. - delayed_work_time_ = delayed_work_time; -} - -} // namespace base diff --git a/base/message_loop/message_pump_default.h b/base/message_loop/message_pump_default.h deleted file mode 100644 index a9b83e8de7..0000000000 --- a/base/message_loop/message_pump_default.h +++ /dev/null @@ -1,40 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef BASE_MESSAGE_LOOP_MESSAGE_PUMP_DEFAULT_H_ -#define BASE_MESSAGE_LOOP_MESSAGE_PUMP_DEFAULT_H_ - -#include "base/message_loop/message_pump.h" -#include "base/synchronization/waitable_event.h" -#include "base/time/time.h" - -namespace base { - -class MessagePumpDefault : public MessagePump { - public: - MessagePumpDefault(); - virtual ~MessagePumpDefault(); - - // MessagePump methods: - virtual void Run(Delegate* delegate) OVERRIDE; - virtual void Quit() OVERRIDE; - virtual void ScheduleWork() OVERRIDE; - virtual void ScheduleDelayedWork(const TimeTicks& delayed_work_time) OVERRIDE; - - private: - // This flag is set to false when Run should return. - bool keep_running_; - - // Used to sleep until there is more work to do. - WaitableEvent event_; - - // The time at which we should call DoDelayedWork. - TimeTicks delayed_work_time_; - - DISALLOW_COPY_AND_ASSIGN(MessagePumpDefault); -}; - -} // namespace base - -#endif // BASE__MESSAGE_LOOPMESSAGE_PUMP_DEFAULT_H_ diff --git a/base/message_loop/message_pump_dispatcher.h b/base/message_loop/message_pump_dispatcher.h deleted file mode 100644 index e49fa4f15d..0000000000 --- a/base/message_loop/message_pump_dispatcher.h +++ /dev/null @@ -1,32 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef BASE_MESSAGE_LOOP_MESSAGE_PUMP_DISPATCHER_H -#define BASE_MESSAGE_LOOP_MESSAGE_PUMP_DISPATCHER_H - -#include "base/base_export.h" -#include "base/event_types.h" - -namespace base { - -// Dispatcher is used during a nested invocation of Run to dispatch events when -// |RunLoop(dispatcher).Run()| is used. If |RunLoop().Run()| is invoked, -// MessageLoop does not dispatch events (or invoke TranslateMessage), rather -// every message is passed to Dispatcher's Dispatch method for dispatch. It is -// up to the Dispatcher whether or not to dispatch the event. -// -// The nested loop is exited by either posting a quit, or returning false -// from Dispatch. -class BASE_EXPORT MessagePumpDispatcher { - public: - virtual ~MessagePumpDispatcher() {} - - // Dispatches the event. If true is returned processing continues as - // normal. If false is returned, the nested loop exits immediately. - virtual bool Dispatch(const NativeEvent& event) = 0; -}; - -} // namespace base - -#endif // BASE_MESSAGE_LOOP_MESSAGE_PUMP_DISPATCHER_H diff --git a/base/message_loop/message_pump_glib.cc b/base/message_loop/message_pump_glib.cc deleted file mode 100644 index cfacb7b09a..0000000000 --- a/base/message_loop/message_pump_glib.cc +++ /dev/null @@ -1,334 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "base/message_loop/message_pump_glib.h" - -#include -#include - -#include - -#include "base/logging.h" -#include "base/posix/eintr_wrapper.h" -#include "base/threading/platform_thread.h" - -namespace base { - -namespace { - -// Return a timeout suitable for the glib loop, -1 to block forever, -// 0 to return right away, or a timeout in milliseconds from now. -int GetTimeIntervalMilliseconds(const TimeTicks& from) { - if (from.is_null()) - return -1; - - // Be careful here. TimeDelta has a precision of microseconds, but we want a - // value in milliseconds. If there are 5.5ms left, should the delay be 5 or - // 6? It should be 6 to avoid executing delayed work too early. - int delay = static_cast( - ceil((from - TimeTicks::Now()).InMillisecondsF())); - - // If this value is negative, then we need to run delayed work soon. - return delay < 0 ? 0 : delay; -} - -// A brief refresher on GLib: -// GLib sources have four callbacks: Prepare, Check, Dispatch and Finalize. -// On each iteration of the GLib pump, it calls each source's Prepare function. -// This function should return TRUE if it wants GLib to call its Dispatch, and -// FALSE otherwise. It can also set a timeout in this case for the next time -// Prepare should be called again (it may be called sooner). -// After the Prepare calls, GLib does a poll to check for events from the -// system. File descriptors can be attached to the sources. The poll may block -// if none of the Prepare calls returned TRUE. It will block indefinitely, or -// by the minimum time returned by a source in Prepare. -// After the poll, GLib calls Check for each source that returned FALSE -// from Prepare. The return value of Check has the same meaning as for Prepare, -// making Check a second chance to tell GLib we are ready for Dispatch. -// Finally, GLib calls Dispatch for each source that is ready. If Dispatch -// returns FALSE, GLib will destroy the source. Dispatch calls may be recursive -// (i.e., you can call Run from them), but Prepare and Check cannot. -// Finalize is called when the source is destroyed. -// NOTE: It is common for subsytems to want to process pending events while -// doing intensive work, for example the flash plugin. They usually use the -// following pattern (recommended by the GTK docs): -// while (gtk_events_pending()) { -// gtk_main_iteration(); -// } -// -// gtk_events_pending just calls g_main_context_pending, which does the -// following: -// - Call prepare on all the sources. -// - Do the poll with a timeout of 0 (not blocking). -// - Call check on all the sources. -// - *Does not* call dispatch on the sources. -// - Return true if any of prepare() or check() returned true. -// -// gtk_main_iteration just calls g_main_context_iteration, which does the whole -// thing, respecting the timeout for the poll (and block, although it is -// expected not to if gtk_events_pending returned true), and call dispatch. -// -// Thus it is important to only return true from prepare or check if we -// actually have events or work to do. We also need to make sure we keep -// internal state consistent so that if prepare/check return true when called -// from gtk_events_pending, they will still return true when called right -// after, from gtk_main_iteration. -// -// For the GLib pump we try to follow the Windows UI pump model: -// - Whenever we receive a wakeup event or the timer for delayed work expires, -// we run DoWork and/or DoDelayedWork. That part will also run in the other -// event pumps. -// - We also run DoWork, DoDelayedWork, and possibly DoIdleWork in the main -// loop, around event handling. - -struct WorkSource : public GSource { - MessagePumpGlib* pump; -}; - -gboolean WorkSourcePrepare(GSource* source, - gint* timeout_ms) { - *timeout_ms = static_cast(source)->pump->HandlePrepare(); - // We always return FALSE, so that our timeout is honored. If we were - // to return TRUE, the timeout would be considered to be 0 and the poll - // would never block. Once the poll is finished, Check will be called. - return FALSE; -} - -gboolean WorkSourceCheck(GSource* source) { - // Only return TRUE if Dispatch should be called. - return static_cast(source)->pump->HandleCheck(); -} - -gboolean WorkSourceDispatch(GSource* source, - GSourceFunc unused_func, - gpointer unused_data) { - - static_cast(source)->pump->HandleDispatch(); - // Always return TRUE so our source stays registered. - return TRUE; -} - -// I wish these could be const, but g_source_new wants non-const. -GSourceFuncs WorkSourceFuncs = { - WorkSourcePrepare, - WorkSourceCheck, - WorkSourceDispatch, - NULL -}; - -} // namespace - -struct MessagePumpGlib::RunState { - Delegate* delegate; - MessagePumpDispatcher* dispatcher; - - // Used to flag that the current Run() invocation should return ASAP. - bool should_quit; - - // Used to count how many Run() invocations are on the stack. - int run_depth; - - // This keeps the state of whether the pump got signaled that there was new - // work to be done. Since we eat the message on the wake up pipe as soon as - // we get it, we keep that state here to stay consistent. - bool has_work; -}; - -MessagePumpGlib::MessagePumpGlib() - : state_(NULL), - context_(g_main_context_default()), - wakeup_gpollfd_(new GPollFD) { - // Create our wakeup pipe, which is used to flag when work was scheduled. - int fds[2]; - int ret = pipe(fds); - DCHECK_EQ(ret, 0); - (void)ret; // Prevent warning in release mode. - - wakeup_pipe_read_ = fds[0]; - wakeup_pipe_write_ = fds[1]; - wakeup_gpollfd_->fd = wakeup_pipe_read_; - wakeup_gpollfd_->events = G_IO_IN; - - work_source_ = g_source_new(&WorkSourceFuncs, sizeof(WorkSource)); - static_cast(work_source_)->pump = this; - g_source_add_poll(work_source_, wakeup_gpollfd_.get()); - // Use a low priority so that we let other events in the queue go first. - g_source_set_priority(work_source_, G_PRIORITY_DEFAULT_IDLE); - // This is needed to allow Run calls inside Dispatch. - g_source_set_can_recurse(work_source_, TRUE); - g_source_attach(work_source_, context_); -} - -MessagePumpGlib::~MessagePumpGlib() { - g_source_destroy(work_source_); - g_source_unref(work_source_); - close(wakeup_pipe_read_); - close(wakeup_pipe_write_); -} - -void MessagePumpGlib::RunWithDispatcher(Delegate* delegate, - MessagePumpDispatcher* dispatcher) { -#ifndef NDEBUG - // Make sure we only run this on one thread. X/GTK only has one message pump - // so we can only have one UI loop per process. - static PlatformThreadId thread_id = PlatformThread::CurrentId(); - DCHECK(thread_id == PlatformThread::CurrentId()) << - "Running MessagePumpGlib on two different threads; " - "this is unsupported by GLib!"; -#endif - - RunState state; - state.delegate = delegate; - state.dispatcher = dispatcher; - state.should_quit = false; - state.run_depth = state_ ? state_->run_depth + 1 : 1; - state.has_work = false; - - RunState* previous_state = state_; - state_ = &state; - - // We really only do a single task for each iteration of the loop. If we - // have done something, assume there is likely something more to do. This - // will mean that we don't block on the message pump until there was nothing - // more to do. We also set this to true to make sure not to block on the - // first iteration of the loop, so RunUntilIdle() works correctly. - bool more_work_is_plausible = true; - - // We run our own loop instead of using g_main_loop_quit in one of the - // callbacks. This is so we only quit our own loops, and we don't quit - // nested loops run by others. TODO(deanm): Is this what we want? - for (;;) { - // Don't block if we think we have more work to do. - bool block = !more_work_is_plausible; - - more_work_is_plausible = g_main_context_iteration(context_, block); - if (state_->should_quit) - break; - - more_work_is_plausible |= state_->delegate->DoWork(); - if (state_->should_quit) - break; - - more_work_is_plausible |= - state_->delegate->DoDelayedWork(&delayed_work_time_); - if (state_->should_quit) - break; - - if (more_work_is_plausible) - continue; - - more_work_is_plausible = state_->delegate->DoIdleWork(); - if (state_->should_quit) - break; - } - - state_ = previous_state; -} - -// Return the timeout we want passed to poll. -int MessagePumpGlib::HandlePrepare() { - // We know we have work, but we haven't called HandleDispatch yet. Don't let - // the pump block so that we can do some processing. - if (state_ && // state_ may be null during tests. - state_->has_work) - return 0; - - // We don't think we have work to do, but make sure not to block - // longer than the next time we need to run delayed work. - return GetTimeIntervalMilliseconds(delayed_work_time_); -} - -bool MessagePumpGlib::HandleCheck() { - if (!state_) // state_ may be null during tests. - return false; - - // We usually have a single message on the wakeup pipe, since we are only - // signaled when the queue went from empty to non-empty, but there can be - // two messages if a task posted a task, hence we read at most two bytes. - // The glib poll will tell us whether there was data, so this read - // shouldn't block. - if (wakeup_gpollfd_->revents & G_IO_IN) { - char msg[2]; - const int num_bytes = HANDLE_EINTR(read(wakeup_pipe_read_, msg, 2)); - if (num_bytes < 1) { - NOTREACHED() << "Error reading from the wakeup pipe."; - } - DCHECK((num_bytes == 1 && msg[0] == '!') || - (num_bytes == 2 && msg[0] == '!' && msg[1] == '!')); - // Since we ate the message, we need to record that we have more work, - // because HandleCheck() may be called without HandleDispatch being called - // afterwards. - state_->has_work = true; - } - - if (state_->has_work) - return true; - - if (GetTimeIntervalMilliseconds(delayed_work_time_) == 0) { - // The timer has expired. That condition will stay true until we process - // that delayed work, so we don't need to record this differently. - return true; - } - - return false; -} - -void MessagePumpGlib::HandleDispatch() { - state_->has_work = false; - if (state_->delegate->DoWork()) { - // NOTE: on Windows at this point we would call ScheduleWork (see - // MessagePumpGlib::HandleWorkMessage in message_pump_win.cc). But here, - // instead of posting a message on the wakeup pipe, we can avoid the - // syscalls and just signal that we have more work. - state_->has_work = true; - } - - if (state_->should_quit) - return; - - state_->delegate->DoDelayedWork(&delayed_work_time_); -} - -void MessagePumpGlib::AddObserver(MessagePumpObserver* observer) { - observers_.AddObserver(observer); -} - -void MessagePumpGlib::RemoveObserver(MessagePumpObserver* observer) { - observers_.RemoveObserver(observer); -} - -void MessagePumpGlib::Run(Delegate* delegate) { - RunWithDispatcher(delegate, NULL); -} - -void MessagePumpGlib::Quit() { - if (state_) { - state_->should_quit = true; - } else { - NOTREACHED() << "Quit called outside Run!"; - } -} - -void MessagePumpGlib::ScheduleWork() { - // This can be called on any thread, so we don't want to touch any state - // variables as we would then need locks all over. This ensures that if - // we are sleeping in a poll that we will wake up. - char msg = '!'; - if (HANDLE_EINTR(write(wakeup_pipe_write_, &msg, 1)) != 1) { - NOTREACHED() << "Could not write to the UI message loop wakeup pipe!"; - } -} - -void MessagePumpGlib::ScheduleDelayedWork(const TimeTicks& delayed_work_time) { - // We need to wake up the loop in case the poll timeout needs to be - // adjusted. This will cause us to try to do work, but that's ok. - delayed_work_time_ = delayed_work_time; - ScheduleWork(); -} - -MessagePumpDispatcher* MessagePumpGlib::GetDispatcher() { - return state_ ? state_->dispatcher : NULL; -} - -} // namespace base diff --git a/base/message_loop/message_pump_glib.h b/base/message_loop/message_pump_glib.h deleted file mode 100644 index 33690d0858..0000000000 --- a/base/message_loop/message_pump_glib.h +++ /dev/null @@ -1,109 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef BASE_MESSAGE_LOOP_MESSAGE_PUMP_GLIB_H_ -#define BASE_MESSAGE_LOOP_MESSAGE_PUMP_GLIB_H_ - -#include "base/base_export.h" -#include "base/memory/scoped_ptr.h" -#include "base/message_loop/message_pump.h" -#include "base/observer_list.h" -#include "base/time/time.h" - -typedef struct _GMainContext GMainContext; -typedef struct _GPollFD GPollFD; -typedef struct _GSource GSource; - -namespace base { - -// MessagePumpObserver is notified prior to an event being dispatched. As -// Observers are notified of every change, they have to be FAST! The platform -// specific implementation of the class is in message_pump_gtk/message_pump_x. -class MessagePumpObserver; - -// MessagePumpDispatcher is used during a nested invocation of Run to dispatch -// events. If Run is invoked with a non-NULL MessagePumpDispatcher, MessageLoop -// does not dispatch events (or invoke gtk_main_do_event), rather every event is -// passed to Dispatcher's Dispatch method for dispatch. It is up to the -// Dispatcher to dispatch, or not, the event. The platform specific -// implementation of the class is in message_pump_gtk/message_pump_x. -class MessagePumpDispatcher; - -// This class implements a base MessagePump needed for TYPE_UI MessageLoops on -// platforms using GLib. -class BASE_EXPORT MessagePumpGlib : public MessagePump { - public: - MessagePumpGlib(); - virtual ~MessagePumpGlib(); - - // Like MessagePump::Run, but events are routed through dispatcher. - virtual void RunWithDispatcher(Delegate* delegate, - MessagePumpDispatcher* dispatcher); - - // Internal methods used for processing the pump callbacks. They are - // public for simplicity but should not be used directly. HandlePrepare - // is called during the prepare step of glib, and returns a timeout that - // will be passed to the poll. HandleCheck is called after the poll - // has completed, and returns whether or not HandleDispatch should be called. - // HandleDispatch is called if HandleCheck returned true. - int HandlePrepare(); - bool HandleCheck(); - void HandleDispatch(); - - // Adds an Observer, which will start receiving notifications immediately. - void AddObserver(MessagePumpObserver* observer); - - // Removes an Observer. It is safe to call this method while an Observer is - // receiving a notification callback. - void RemoveObserver(MessagePumpObserver* observer); - - // Overridden from MessagePump: - virtual void Run(Delegate* delegate) OVERRIDE; - virtual void Quit() OVERRIDE; - virtual void ScheduleWork() OVERRIDE; - virtual void ScheduleDelayedWork(const TimeTicks& delayed_work_time) OVERRIDE; - - protected: - // Returns the dispatcher for the current run state (|state_->dispatcher|). - MessagePumpDispatcher* GetDispatcher(); - - ObserverList& observers() { return observers_; } - - private: - // We may make recursive calls to Run, so we save state that needs to be - // separate between them in this structure type. - struct RunState; - - RunState* state_; - - // This is a GLib structure that we can add event sources to. We use the - // default GLib context, which is the one to which all GTK events are - // dispatched. - GMainContext* context_; - - // This is the time when we need to do delayed work. - TimeTicks delayed_work_time_; - - // The work source. It is shared by all calls to Run and destroyed when - // the message pump is destroyed. - GSource* work_source_; - - // We use a wakeup pipe to make sure we'll get out of the glib polling phase - // when another thread has scheduled us to do some work. There is a glib - // mechanism g_main_context_wakeup, but this won't guarantee that our event's - // Dispatch() will be called. - int wakeup_pipe_read_; - int wakeup_pipe_write_; - // Use a scoped_ptr to avoid needing the definition of GPollFD in the header. - scoped_ptr wakeup_gpollfd_; - - // List of observers. - ObserverList observers_; - - DISALLOW_COPY_AND_ASSIGN(MessagePumpGlib); -}; - -} // namespace base - -#endif // BASE_MESSAGE_LOOP_MESSAGE_PUMP_GLIB_H_ diff --git a/base/message_loop/message_pump_glib_unittest.cc b/base/message_loop/message_pump_glib_unittest.cc deleted file mode 100644 index 033e6cde92..0000000000 --- a/base/message_loop/message_pump_glib_unittest.cc +++ /dev/null @@ -1,580 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "base/message_loop/message_pump_glib.h" - -#include -#include - -#include -#include - -#include "base/bind.h" -#include "base/bind_helpers.h" -#include "base/callback.h" -#include "base/memory/ref_counted.h" -#include "base/message_loop/message_loop.h" -#include "base/run_loop.h" -#include "base/threading/thread.h" -#include "testing/gtest/include/gtest/gtest.h" - -#if defined(TOOLKIT_GTK) -#include -#endif - -namespace base { -namespace { - -// This class injects dummy "events" into the GLib loop. When "handled" these -// events can run tasks. This is intended to mock gtk events (the corresponding -// GLib source runs at the same priority). -class EventInjector { - public: - EventInjector() : processed_events_(0) { - source_ = static_cast(g_source_new(&SourceFuncs, sizeof(Source))); - source_->injector = this; - g_source_attach(source_, NULL); - g_source_set_can_recurse(source_, TRUE); - } - - ~EventInjector() { - g_source_destroy(source_); - g_source_unref(source_); - } - - int HandlePrepare() { - // If the queue is empty, block. - if (events_.empty()) - return -1; - TimeDelta delta = events_[0].time - Time::NowFromSystemTime(); - return std::max(0, static_cast(ceil(delta.InMillisecondsF()))); - } - - bool HandleCheck() { - if (events_.empty()) - return false; - return events_[0].time <= Time::NowFromSystemTime(); - } - - void HandleDispatch() { - if (events_.empty()) - return; - Event event = events_[0]; - events_.erase(events_.begin()); - ++processed_events_; - if (!event.callback.is_null()) - event.callback.Run(); - else if (!event.task.is_null()) - event.task.Run(); - } - - // Adds an event to the queue. When "handled", executes |callback|. - // delay_ms is relative to the last event if any, or to Now() otherwise. - void AddEvent(int delay_ms, const Closure& callback) { - AddEventHelper(delay_ms, callback, Closure()); - } - - void AddDummyEvent(int delay_ms) { - AddEventHelper(delay_ms, Closure(), Closure()); - } - - void AddEventAsTask(int delay_ms, const Closure& task) { - AddEventHelper(delay_ms, Closure(), task); - } - - void Reset() { - processed_events_ = 0; - events_.clear(); - } - - int processed_events() const { return processed_events_; } - - private: - struct Event { - Time time; - Closure callback; - Closure task; - }; - - struct Source : public GSource { - EventInjector* injector; - }; - - void AddEventHelper( - int delay_ms, const Closure& callback, const Closure& task) { - Time last_time; - if (!events_.empty()) - last_time = (events_.end()-1)->time; - else - last_time = Time::NowFromSystemTime(); - - Time future = last_time + TimeDelta::FromMilliseconds(delay_ms); - EventInjector::Event event = {future, callback, task}; - events_.push_back(event); - } - - static gboolean Prepare(GSource* source, gint* timeout_ms) { - *timeout_ms = static_cast(source)->injector->HandlePrepare(); - return FALSE; - } - - static gboolean Check(GSource* source) { - return static_cast(source)->injector->HandleCheck(); - } - - static gboolean Dispatch(GSource* source, - GSourceFunc unused_func, - gpointer unused_data) { - static_cast(source)->injector->HandleDispatch(); - return TRUE; - } - - Source* source_; - std::vector events_; - int processed_events_; - static GSourceFuncs SourceFuncs; - DISALLOW_COPY_AND_ASSIGN(EventInjector); -}; - -GSourceFuncs EventInjector::SourceFuncs = { - EventInjector::Prepare, - EventInjector::Check, - EventInjector::Dispatch, - NULL -}; - -void IncrementInt(int *value) { - ++*value; -} - -// Checks how many events have been processed by the injector. -void ExpectProcessedEvents(EventInjector* injector, int count) { - EXPECT_EQ(injector->processed_events(), count); -} - -// Posts a task on the current message loop. -void PostMessageLoopTask(const tracked_objects::Location& from_here, - const Closure& task) { - MessageLoop::current()->PostTask(from_here, task); -} - -// Test fixture. -class MessagePumpGLibTest : public testing::Test { - public: - MessagePumpGLibTest() : loop_(NULL), injector_(NULL) { } - - // Overridden from testing::Test: - virtual void SetUp() OVERRIDE { - loop_ = new MessageLoop(MessageLoop::TYPE_UI); - injector_ = new EventInjector(); - } - virtual void TearDown() OVERRIDE { - delete injector_; - injector_ = NULL; - delete loop_; - loop_ = NULL; - } - - MessageLoop* loop() const { return loop_; } - EventInjector* injector() const { return injector_; } - - private: - MessageLoop* loop_; - EventInjector* injector_; - DISALLOW_COPY_AND_ASSIGN(MessagePumpGLibTest); -}; - -} // namespace - -TEST_F(MessagePumpGLibTest, TestQuit) { - // Checks that Quit works and that the basic infrastructure is working. - - // Quit from a task - RunLoop().RunUntilIdle(); - EXPECT_EQ(0, injector()->processed_events()); - - injector()->Reset(); - // Quit from an event - injector()->AddEvent(0, MessageLoop::QuitWhenIdleClosure()); - loop()->Run(); - EXPECT_EQ(1, injector()->processed_events()); -} - -TEST_F(MessagePumpGLibTest, TestEventTaskInterleave) { - // Checks that tasks posted by events are executed before the next event if - // the posted task queue is empty. - // MessageLoop doesn't make strong guarantees that it is the case, but the - // current implementation ensures it and the tests below rely on it. - // If changes cause this test to fail, it is reasonable to change it, but - // TestWorkWhileWaitingForEvents and TestEventsWhileWaitingForWork have to be - // changed accordingly, otherwise they can become flaky. - injector()->AddEventAsTask(0, Bind(&DoNothing)); - Closure check_task = - Bind(&ExpectProcessedEvents, Unretained(injector()), 2); - Closure posted_task = - Bind(&PostMessageLoopTask, FROM_HERE, check_task); - injector()->AddEventAsTask(0, posted_task); - injector()->AddEventAsTask(0, Bind(&DoNothing)); - injector()->AddEvent(0, MessageLoop::QuitWhenIdleClosure()); - loop()->Run(); - EXPECT_EQ(4, injector()->processed_events()); - - injector()->Reset(); - injector()->AddEventAsTask(0, Bind(&DoNothing)); - check_task = - Bind(&ExpectProcessedEvents, Unretained(injector()), 2); - posted_task = Bind(&PostMessageLoopTask, FROM_HERE, check_task); - injector()->AddEventAsTask(0, posted_task); - injector()->AddEventAsTask(10, Bind(&DoNothing)); - injector()->AddEvent(0, MessageLoop::QuitWhenIdleClosure()); - loop()->Run(); - EXPECT_EQ(4, injector()->processed_events()); -} - -TEST_F(MessagePumpGLibTest, TestWorkWhileWaitingForEvents) { - int task_count = 0; - // Tests that we process tasks while waiting for new events. - // The event queue is empty at first. - for (int i = 0; i < 10; ++i) { - loop()->PostTask(FROM_HERE, Bind(&IncrementInt, &task_count)); - } - // After all the previous tasks have executed, enqueue an event that will - // quit. - loop()->PostTask( - FROM_HERE, - Bind(&EventInjector::AddEvent, Unretained(injector()), 0, - MessageLoop::QuitWhenIdleClosure())); - loop()->Run(); - ASSERT_EQ(10, task_count); - EXPECT_EQ(1, injector()->processed_events()); - - // Tests that we process delayed tasks while waiting for new events. - injector()->Reset(); - task_count = 0; - for (int i = 0; i < 10; ++i) { - loop()->PostDelayedTask( - FROM_HERE, - Bind(&IncrementInt, &task_count), - TimeDelta::FromMilliseconds(10*i)); - } - // After all the previous tasks have executed, enqueue an event that will - // quit. - // This relies on the fact that delayed tasks are executed in delay order. - // That is verified in message_loop_unittest.cc. - loop()->PostDelayedTask( - FROM_HERE, - Bind(&EventInjector::AddEvent, Unretained(injector()), 10, - MessageLoop::QuitWhenIdleClosure()), - TimeDelta::FromMilliseconds(150)); - loop()->Run(); - ASSERT_EQ(10, task_count); - EXPECT_EQ(1, injector()->processed_events()); -} - -TEST_F(MessagePumpGLibTest, TestEventsWhileWaitingForWork) { - // Tests that we process events while waiting for work. - // The event queue is empty at first. - for (int i = 0; i < 10; ++i) { - injector()->AddDummyEvent(0); - } - // After all the events have been processed, post a task that will check that - // the events have been processed (note: the task executes after the event - // that posted it has been handled, so we expect 11 at that point). - Closure check_task = - Bind(&ExpectProcessedEvents, Unretained(injector()), 11); - Closure posted_task = - Bind(&PostMessageLoopTask, FROM_HERE, check_task); - injector()->AddEventAsTask(10, posted_task); - - // And then quit (relies on the condition tested by TestEventTaskInterleave). - injector()->AddEvent(10, MessageLoop::QuitWhenIdleClosure()); - loop()->Run(); - - EXPECT_EQ(12, injector()->processed_events()); -} - -namespace { - -// This class is a helper for the concurrent events / posted tasks test below. -// It will quit the main loop once enough tasks and events have been processed, -// while making sure there is always work to do and events in the queue. -class ConcurrentHelper : public RefCounted { - public: - explicit ConcurrentHelper(EventInjector* injector) - : injector_(injector), - event_count_(kStartingEventCount), - task_count_(kStartingTaskCount) { - } - - void FromTask() { - if (task_count_ > 0) { - --task_count_; - } - if (task_count_ == 0 && event_count_ == 0) { - MessageLoop::current()->QuitWhenIdle(); - } else { - MessageLoop::current()->PostTask( - FROM_HERE, Bind(&ConcurrentHelper::FromTask, this)); - } - } - - void FromEvent() { - if (event_count_ > 0) { - --event_count_; - } - if (task_count_ == 0 && event_count_ == 0) { - MessageLoop::current()->QuitWhenIdle(); - } else { - injector_->AddEventAsTask( - 0, Bind(&ConcurrentHelper::FromEvent, this)); - } - } - - int event_count() const { return event_count_; } - int task_count() const { return task_count_; } - - private: - friend class RefCounted; - - ~ConcurrentHelper() {} - - static const int kStartingEventCount = 20; - static const int kStartingTaskCount = 20; - - EventInjector* injector_; - int event_count_; - int task_count_; -}; - -} // namespace - -TEST_F(MessagePumpGLibTest, TestConcurrentEventPostedTask) { - // Tests that posted tasks don't starve events, nor the opposite. - // We use the helper class above. We keep both event and posted task queues - // full, the helper verifies that both tasks and events get processed. - // If that is not the case, either event_count_ or task_count_ will not get - // to 0, and MessageLoop::QuitWhenIdle() will never be called. - scoped_refptr helper = new ConcurrentHelper(injector()); - - // Add 2 events to the queue to make sure it is always full (when we remove - // the event before processing it). - injector()->AddEventAsTask( - 0, Bind(&ConcurrentHelper::FromEvent, helper.get())); - injector()->AddEventAsTask( - 0, Bind(&ConcurrentHelper::FromEvent, helper.get())); - - // Similarly post 2 tasks. - loop()->PostTask( - FROM_HERE, Bind(&ConcurrentHelper::FromTask, helper.get())); - loop()->PostTask( - FROM_HERE, Bind(&ConcurrentHelper::FromTask, helper.get())); - - loop()->Run(); - EXPECT_EQ(0, helper->event_count()); - EXPECT_EQ(0, helper->task_count()); -} - -namespace { - -void AddEventsAndDrainGLib(EventInjector* injector) { - // Add a couple of dummy events - injector->AddDummyEvent(0); - injector->AddDummyEvent(0); - // Then add an event that will quit the main loop. - injector->AddEvent(0, MessageLoop::QuitWhenIdleClosure()); - - // Post a couple of dummy tasks - MessageLoop::current()->PostTask(FROM_HERE, Bind(&DoNothing)); - MessageLoop::current()->PostTask(FROM_HERE, Bind(&DoNothing)); - - // Drain the events - while (g_main_context_pending(NULL)) { - g_main_context_iteration(NULL, FALSE); - } -} - -} // namespace - -TEST_F(MessagePumpGLibTest, TestDrainingGLib) { - // Tests that draining events using GLib works. - loop()->PostTask( - FROM_HERE, - Bind(&AddEventsAndDrainGLib, Unretained(injector()))); - loop()->Run(); - - EXPECT_EQ(3, injector()->processed_events()); -} - - -namespace { - -#if defined(TOOLKIT_GTK) -void AddEventsAndDrainGtk(EventInjector* injector) { - // Add a couple of dummy events - injector->AddDummyEvent(0); - injector->AddDummyEvent(0); - // Then add an event that will quit the main loop. - injector->AddEvent(0, MessageLoop::QuitWhenIdleClosure()); - - // Post a couple of dummy tasks - MessageLoop::current()->PostTask(FROM_HERE, Bind(&DoNothing)); - MessageLoop::current()->PostTask(FROM_HERE, Bind(&DoNothing)); - - // Drain the events - while (gtk_events_pending()) { - gtk_main_iteration(); - } -} -#endif - -} // namespace - -#if defined(TOOLKIT_GTK) -TEST_F(MessagePumpGLibTest, TestDrainingGtk) { - // Tests that draining events using Gtk works. - loop()->PostTask( - FROM_HERE, - Bind(&AddEventsAndDrainGtk, Unretained(injector()))); - loop()->Run(); - - EXPECT_EQ(3, injector()->processed_events()); -} -#endif - -namespace { - -// Helper class that lets us run the GLib message loop. -class GLibLoopRunner : public RefCounted { - public: - GLibLoopRunner() : quit_(false) { } - - void RunGLib() { - while (!quit_) { - g_main_context_iteration(NULL, TRUE); - } - } - - void RunLoop() { -#if defined(TOOLKIT_GTK) - while (!quit_) { - gtk_main_iteration(); - } -#else - while (!quit_) { - g_main_context_iteration(NULL, TRUE); - } -#endif - } - - void Quit() { - quit_ = true; - } - - void Reset() { - quit_ = false; - } - - private: - friend class RefCounted; - - ~GLibLoopRunner() {} - - bool quit_; -}; - -void TestGLibLoopInternal(EventInjector* injector) { - // Allow tasks to be processed from 'native' event loops. - MessageLoop::current()->SetNestableTasksAllowed(true); - scoped_refptr runner = new GLibLoopRunner(); - - int task_count = 0; - // Add a couple of dummy events - injector->AddDummyEvent(0); - injector->AddDummyEvent(0); - // Post a couple of dummy tasks - MessageLoop::current()->PostTask( - FROM_HERE, Bind(&IncrementInt, &task_count)); - MessageLoop::current()->PostTask( - FROM_HERE, Bind(&IncrementInt, &task_count)); - // Delayed events - injector->AddDummyEvent(10); - injector->AddDummyEvent(10); - // Delayed work - MessageLoop::current()->PostDelayedTask( - FROM_HERE, - Bind(&IncrementInt, &task_count), - TimeDelta::FromMilliseconds(30)); - MessageLoop::current()->PostDelayedTask( - FROM_HERE, - Bind(&GLibLoopRunner::Quit, runner.get()), - TimeDelta::FromMilliseconds(40)); - - // Run a nested, straight GLib message loop. - runner->RunGLib(); - - ASSERT_EQ(3, task_count); - EXPECT_EQ(4, injector->processed_events()); - MessageLoop::current()->QuitWhenIdle(); -} - -void TestGtkLoopInternal(EventInjector* injector) { - // Allow tasks to be processed from 'native' event loops. - MessageLoop::current()->SetNestableTasksAllowed(true); - scoped_refptr runner = new GLibLoopRunner(); - - int task_count = 0; - // Add a couple of dummy events - injector->AddDummyEvent(0); - injector->AddDummyEvent(0); - // Post a couple of dummy tasks - MessageLoop::current()->PostTask( - FROM_HERE, Bind(&IncrementInt, &task_count)); - MessageLoop::current()->PostTask( - FROM_HERE, Bind(&IncrementInt, &task_count)); - // Delayed events - injector->AddDummyEvent(10); - injector->AddDummyEvent(10); - // Delayed work - MessageLoop::current()->PostDelayedTask( - FROM_HERE, - Bind(&IncrementInt, &task_count), - TimeDelta::FromMilliseconds(30)); - MessageLoop::current()->PostDelayedTask( - FROM_HERE, - Bind(&GLibLoopRunner::Quit, runner.get()), - TimeDelta::FromMilliseconds(40)); - - // Run a nested, straight Gtk message loop. - runner->RunLoop(); - - ASSERT_EQ(3, task_count); - EXPECT_EQ(4, injector->processed_events()); - MessageLoop::current()->QuitWhenIdle(); -} - -} // namespace - -TEST_F(MessagePumpGLibTest, TestGLibLoop) { - // Tests that events and posted tasks are correctly executed if the message - // loop is not run by MessageLoop::Run() but by a straight GLib loop. - // Note that in this case we don't make strong guarantees about niceness - // between events and posted tasks. - loop()->PostTask( - FROM_HERE, - Bind(&TestGLibLoopInternal, Unretained(injector()))); - loop()->Run(); -} - -TEST_F(MessagePumpGLibTest, TestGtkLoop) { - // Tests that events and posted tasks are correctly executed if the message - // loop is not run by MessageLoop::Run() but by a straight Gtk loop. - // Note that in this case we don't make strong guarantees about niceness - // between events and posted tasks. - loop()->PostTask( - FROM_HERE, - Bind(&TestGtkLoopInternal, Unretained(injector()))); - loop()->Run(); -} - -} // namespace base diff --git a/base/message_loop/message_pump_gtk.cc b/base/message_loop/message_pump_gtk.cc deleted file mode 100644 index ad6511318a..0000000000 --- a/base/message_loop/message_pump_gtk.cc +++ /dev/null @@ -1,114 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "base/message_loop/message_pump_gtk.h" - -#include -#include - -#include "base/debug/trace_event.h" -#include "base/profiler/scoped_profile.h" - -namespace base { - -namespace { - -const char* EventToTypeString(const GdkEvent* event) { - switch (event->type) { - case GDK_NOTHING: return "GDK_NOTHING"; - case GDK_DELETE: return "GDK_DELETE"; - case GDK_DESTROY: return "GDK_DESTROY"; - case GDK_EXPOSE: return "GDK_EXPOSE"; - case GDK_MOTION_NOTIFY: return "GDK_MOTION_NOTIFY"; - case GDK_BUTTON_PRESS: return "GDK_BUTTON_PRESS"; - case GDK_2BUTTON_PRESS: return "GDK_2BUTTON_PRESS"; - case GDK_3BUTTON_PRESS: return "GDK_3BUTTON_PRESS"; - case GDK_BUTTON_RELEASE: return "GDK_BUTTON_RELEASE"; - case GDK_KEY_PRESS: return "GDK_KEY_PRESS"; - case GDK_KEY_RELEASE: return "GDK_KEY_RELEASE"; - case GDK_ENTER_NOTIFY: return "GDK_ENTER_NOTIFY"; - case GDK_LEAVE_NOTIFY: return "GDK_LEAVE_NOTIFY"; - case GDK_FOCUS_CHANGE: return "GDK_FOCUS_CHANGE"; - case GDK_CONFIGURE: return "GDK_CONFIGURE"; - case GDK_MAP: return "GDK_MAP"; - case GDK_UNMAP: return "GDK_UNMAP"; - case GDK_PROPERTY_NOTIFY: return "GDK_PROPERTY_NOTIFY"; - case GDK_SELECTION_CLEAR: return "GDK_SELECTION_CLEAR"; - case GDK_SELECTION_REQUEST: return "GDK_SELECTION_REQUEST"; - case GDK_SELECTION_NOTIFY: return "GDK_SELECTION_NOTIFY"; - case GDK_PROXIMITY_IN: return "GDK_PROXIMITY_IN"; - case GDK_PROXIMITY_OUT: return "GDK_PROXIMITY_OUT"; - case GDK_DRAG_ENTER: return "GDK_DRAG_ENTER"; - case GDK_DRAG_LEAVE: return "GDK_DRAG_LEAVE"; - case GDK_DRAG_MOTION: return "GDK_DRAG_MOTION"; - case GDK_DRAG_STATUS: return "GDK_DRAG_STATUS"; - case GDK_DROP_START: return "GDK_DROP_START"; - case GDK_DROP_FINISHED: return "GDK_DROP_FINISHED"; - case GDK_CLIENT_EVENT: return "GDK_CLIENT_EVENT"; - case GDK_VISIBILITY_NOTIFY: return "GDK_VISIBILITY_NOTIFY"; - case GDK_NO_EXPOSE: return "GDK_NO_EXPOSE"; - case GDK_SCROLL: return "GDK_SCROLL"; - case GDK_WINDOW_STATE: return "GDK_WINDOW_STATE"; - case GDK_SETTING: return "GDK_SETTING"; - case GDK_OWNER_CHANGE: return "GDK_OWNER_CHANGE"; - case GDK_GRAB_BROKEN: return "GDK_GRAB_BROKEN"; - case GDK_DAMAGE: return "GDK_DAMAGE"; - default: - return "Unknown Gdk Event"; - } -} - -} // namespace - -MessagePumpGtk::MessagePumpGtk() : MessagePumpGlib() { - gdk_event_handler_set(&EventDispatcher, this, NULL); -} - -MessagePumpGtk::~MessagePumpGtk() { - gdk_event_handler_set(reinterpret_cast(gtk_main_do_event), - this, NULL); -} - -void MessagePumpGtk::DispatchEvents(GdkEvent* event) { - UNSHIPPED_TRACE_EVENT1("task", "MessagePumpGtk::DispatchEvents", - "type", EventToTypeString(event)); - - WillProcessEvent(event); - - MessagePumpDispatcher* dispatcher = GetDispatcher(); - if (!dispatcher) - gtk_main_do_event(event); - else if (!dispatcher->Dispatch(event)) - Quit(); - - DidProcessEvent(event); -} - -// static -Display* MessagePumpGtk::GetDefaultXDisplay() { - static GdkDisplay* display = gdk_display_get_default(); - if (!display) { - // GTK / GDK has not been initialized, which is a decision we wish to - // support, for example for the GPU process. - static Display* xdisplay = XOpenDisplay(NULL); - return xdisplay; - } - return GDK_DISPLAY_XDISPLAY(display); -} - -void MessagePumpGtk::WillProcessEvent(GdkEvent* event) { - FOR_EACH_OBSERVER(MessagePumpObserver, observers(), WillProcessEvent(event)); -} - -void MessagePumpGtk::DidProcessEvent(GdkEvent* event) { - FOR_EACH_OBSERVER(MessagePumpObserver, observers(), DidProcessEvent(event)); -} - -// static -void MessagePumpGtk::EventDispatcher(GdkEvent* event, gpointer data) { - MessagePumpGtk* message_pump = reinterpret_cast(data); - message_pump->DispatchEvents(event); -} - -} // namespace base diff --git a/base/message_loop/message_pump_gtk.h b/base/message_loop/message_pump_gtk.h deleted file mode 100644 index 947ab885af..0000000000 --- a/base/message_loop/message_pump_gtk.h +++ /dev/null @@ -1,74 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef BASE_MESSAGE_LOOP_MESSAGE_PUMP_GTK_H_ -#define BASE_MESSAGE_LOOP_MESSAGE_PUMP_GTK_H_ - -#include "base/message_loop/message_pump_glib.h" - -typedef union _GdkEvent GdkEvent; -typedef struct _XDisplay Display; - -namespace base { - -// The documentation for this class is in message_pump_glib.h -class MessagePumpObserver { - public: - // This method is called before processing a message. - virtual void WillProcessEvent(GdkEvent* event) = 0; - - // This method is called after processing a message. - virtual void DidProcessEvent(GdkEvent* event) = 0; - - protected: - virtual ~MessagePumpObserver() {} -}; - -// The documentation for this class is in message_pump_glib.h -// -// The nested loop is exited by either posting a quit, or returning false -// from Dispatch. -class MessagePumpDispatcher { - public: - // Dispatches the event. If true is returned processing continues as - // normal. If false is returned, the nested loop exits immediately. - virtual bool Dispatch(GdkEvent* event) = 0; - - protected: - virtual ~MessagePumpDispatcher() {} -}; - -// This class implements a message-pump for dispatching GTK events. -class BASE_EXPORT MessagePumpGtk : public MessagePumpGlib { - public: - MessagePumpGtk(); - virtual ~MessagePumpGtk(); - - // Dispatch an available GdkEvent. Essentially this allows a subclass to do - // some task before/after calling the default handler (EventDispatcher). - void DispatchEvents(GdkEvent* event); - - // Returns default X Display. - static Display* GetDefaultXDisplay(); - - private: - // Invoked from EventDispatcher. Notifies all observers we're about to - // process an event. - void WillProcessEvent(GdkEvent* event); - - // Invoked from EventDispatcher. Notifies all observers we processed an - // event. - void DidProcessEvent(GdkEvent* event); - - // Callback prior to gdk dispatching an event. - static void EventDispatcher(GdkEvent* event, void* data); - - DISALLOW_COPY_AND_ASSIGN(MessagePumpGtk); -}; - -typedef MessagePumpGtk MessagePumpForUI; - -} // namespace base - -#endif // BASE_MESSAGE_LOOP_MESSAGE_PUMP_GTK_H_ diff --git a/base/message_loop/message_pump_io_ios.cc b/base/message_loop/message_pump_io_ios.cc deleted file mode 100644 index cd5ffed4b9..0000000000 --- a/base/message_loop/message_pump_io_ios.cc +++ /dev/null @@ -1,209 +0,0 @@ -// Copyright 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "base/message_loop/message_pump_io_ios.h" - -namespace base { - -MessagePumpIOSForIO::FileDescriptorWatcher::FileDescriptorWatcher() - : is_persistent_(false), - fdref_(NULL), - callback_types_(0), - fd_source_(NULL), - watcher_(NULL) { -} - -MessagePumpIOSForIO::FileDescriptorWatcher::~FileDescriptorWatcher() { - StopWatchingFileDescriptor(); -} - -bool MessagePumpIOSForIO::FileDescriptorWatcher::StopWatchingFileDescriptor() { - if (fdref_ == NULL) - return true; - - CFFileDescriptorDisableCallBacks(fdref_, callback_types_); - if (pump_) - pump_->RemoveRunLoopSource(fd_source_); - fd_source_.reset(); - fdref_.reset(); - callback_types_ = 0; - pump_.reset(); - watcher_ = NULL; - return true; -} - -void MessagePumpIOSForIO::FileDescriptorWatcher::Init( - CFFileDescriptorRef fdref, - CFOptionFlags callback_types, - CFRunLoopSourceRef fd_source, - bool is_persistent) { - DCHECK(fdref); - DCHECK(!fdref_); - - is_persistent_ = is_persistent; - fdref_.reset(fdref); - callback_types_ = callback_types; - fd_source_.reset(fd_source); -} - -void MessagePumpIOSForIO::FileDescriptorWatcher::OnFileCanReadWithoutBlocking( - int fd, - MessagePumpIOSForIO* pump) { - DCHECK(callback_types_ & kCFFileDescriptorReadCallBack); - pump->WillProcessIOEvent(); - watcher_->OnFileCanReadWithoutBlocking(fd); - pump->DidProcessIOEvent(); -} - -void MessagePumpIOSForIO::FileDescriptorWatcher::OnFileCanWriteWithoutBlocking( - int fd, - MessagePumpIOSForIO* pump) { - DCHECK(callback_types_ & kCFFileDescriptorWriteCallBack); - pump->WillProcessIOEvent(); - watcher_->OnFileCanWriteWithoutBlocking(fd); - pump->DidProcessIOEvent(); -} - -MessagePumpIOSForIO::MessagePumpIOSForIO() : weak_factory_(this) { -} - -MessagePumpIOSForIO::~MessagePumpIOSForIO() { -} - -bool MessagePumpIOSForIO::WatchFileDescriptor( - int fd, - bool persistent, - int mode, - FileDescriptorWatcher *controller, - Watcher *delegate) { - DCHECK_GE(fd, 0); - DCHECK(controller); - DCHECK(delegate); - DCHECK(mode == WATCH_READ || mode == WATCH_WRITE || mode == WATCH_READ_WRITE); - - // WatchFileDescriptor should be called on the pump thread. It is not - // threadsafe, and your watcher may never be registered. - DCHECK(watch_file_descriptor_caller_checker_.CalledOnValidThread()); - - CFFileDescriptorContext source_context = {0}; - source_context.info = controller; - - CFOptionFlags callback_types = 0; - if (mode & WATCH_READ) { - callback_types |= kCFFileDescriptorReadCallBack; - } - if (mode & WATCH_WRITE) { - callback_types |= kCFFileDescriptorWriteCallBack; - } - - CFFileDescriptorRef fdref = controller->fdref_; - if (fdref == NULL) { - base::ScopedCFTypeRef scoped_fdref( - CFFileDescriptorCreate( - kCFAllocatorDefault, fd, false, HandleFdIOEvent, &source_context)); - if (scoped_fdref == NULL) { - NOTREACHED() << "CFFileDescriptorCreate failed"; - return false; - } - - CFFileDescriptorEnableCallBacks(scoped_fdref, callback_types); - - // TODO(wtc): what should the 'order' argument be? - base::ScopedCFTypeRef scoped_fd_source( - CFFileDescriptorCreateRunLoopSource( - kCFAllocatorDefault, scoped_fdref, 0)); - if (scoped_fd_source == NULL) { - NOTREACHED() << "CFFileDescriptorCreateRunLoopSource failed"; - return false; - } - CFRunLoopAddSource(run_loop(), scoped_fd_source, kCFRunLoopCommonModes); - - // Transfer ownership of scoped_fdref and fd_source to controller. - controller->Init(scoped_fdref.release(), callback_types, - scoped_fd_source.release(), persistent); - } else { - // It's illegal to use this function to listen on 2 separate fds with the - // same |controller|. - if (CFFileDescriptorGetNativeDescriptor(fdref) != fd) { - NOTREACHED() << "FDs don't match: " - << CFFileDescriptorGetNativeDescriptor(fdref) - << " != " << fd; - return false; - } - if (persistent != controller->is_persistent_) { - NOTREACHED() << "persistent doesn't match"; - return false; - } - - // Combine old/new event masks. - CFFileDescriptorDisableCallBacks(fdref, controller->callback_types_); - controller->callback_types_ |= callback_types; - CFFileDescriptorEnableCallBacks(fdref, controller->callback_types_); - } - - controller->set_watcher(delegate); - controller->set_pump(weak_factory_.GetWeakPtr()); - - return true; -} - -void MessagePumpIOSForIO::RemoveRunLoopSource(CFRunLoopSourceRef source) { - CFRunLoopRemoveSource(run_loop(), source, kCFRunLoopCommonModes); -} - -void MessagePumpIOSForIO::AddIOObserver(IOObserver *obs) { - io_observers_.AddObserver(obs); -} - -void MessagePumpIOSForIO::RemoveIOObserver(IOObserver *obs) { - io_observers_.RemoveObserver(obs); -} - -void MessagePumpIOSForIO::WillProcessIOEvent() { - FOR_EACH_OBSERVER(IOObserver, io_observers_, WillProcessIOEvent()); -} - -void MessagePumpIOSForIO::DidProcessIOEvent() { - FOR_EACH_OBSERVER(IOObserver, io_observers_, DidProcessIOEvent()); -} - -// static -void MessagePumpIOSForIO::HandleFdIOEvent(CFFileDescriptorRef fdref, - CFOptionFlags callback_types, - void* context) { - FileDescriptorWatcher* controller = - static_cast(context); - DCHECK_EQ(fdref, controller->fdref_); - - // Ensure that |fdref| will remain live for the duration of this function - // call even if |controller| is deleted or |StopWatchingFileDescriptor()| is - // called, either of which will cause |fdref| to be released. - ScopedCFTypeRef scoped_fdref( - fdref, base::scoped_policy::RETAIN); - - int fd = CFFileDescriptorGetNativeDescriptor(fdref); - MessagePumpIOSForIO* pump = controller->pump().get(); - DCHECK(pump); - if (callback_types & kCFFileDescriptorWriteCallBack) - controller->OnFileCanWriteWithoutBlocking(fd, pump); - - // Perform the read callback only if the file descriptor has not been - // invalidated in the write callback. As |FileDescriptorWatcher| invalidates - // its file descriptor on destruction, the file descriptor being valid also - // guarantees that |controller| has not been deleted. - if (callback_types & kCFFileDescriptorReadCallBack && - CFFileDescriptorIsValid(fdref)) { - DCHECK_EQ(fdref, controller->fdref_); - controller->OnFileCanReadWithoutBlocking(fd, pump); - } - - // Re-enable callbacks after the read/write if the file descriptor is still - // valid and the controller is persistent. - if (CFFileDescriptorIsValid(fdref) && controller->is_persistent_) { - DCHECK_EQ(fdref, controller->fdref_); - CFFileDescriptorEnableCallBacks(fdref, callback_types); - } -} - -} // namespace base diff --git a/base/message_loop/message_pump_io_ios.h b/base/message_loop/message_pump_io_ios.h deleted file mode 100644 index 18af4a8fe3..0000000000 --- a/base/message_loop/message_pump_io_ios.h +++ /dev/null @@ -1,144 +0,0 @@ -// Copyright 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef BASE_MESSAGE_LOOP_MESSAGE_PUMP_IO_IOS_H_ -#define BASE_MESSAGE_LOOP_MESSAGE_PUMP_IO_IOS_H_ - -#include "base/base_export.h" -#include "base/mac/scoped_cffiledescriptorref.h" -#include "base/mac/scoped_cftyperef.h" -#include "base/memory/ref_counted.h" -#include "base/memory/weak_ptr.h" -#include "base/message_loop/message_pump_mac.h" -#include "base/observer_list.h" -#include "base/threading/thread_checker.h" - -namespace base { - -// This file introduces a class to monitor sockets and issue callbacks when -// sockets are ready for I/O on iOS. -class BASE_EXPORT MessagePumpIOSForIO : public MessagePumpNSRunLoop { - public: - class IOObserver { - public: - IOObserver() {} - - // An IOObserver is an object that receives IO notifications from the - // MessagePump. - // - // NOTE: An IOObserver implementation should be extremely fast! - virtual void WillProcessIOEvent() = 0; - virtual void DidProcessIOEvent() = 0; - - protected: - virtual ~IOObserver() {} - }; - - // Used with WatchFileDescriptor to asynchronously monitor the I/O readiness - // of a file descriptor. - class Watcher { - public: - // Called from MessageLoop::Run when an FD can be read from/written to - // without blocking - virtual void OnFileCanReadWithoutBlocking(int fd) = 0; - virtual void OnFileCanWriteWithoutBlocking(int fd) = 0; - - protected: - virtual ~Watcher() {} - }; - - // Object returned by WatchFileDescriptor to manage further watching. - class FileDescriptorWatcher { - public: - FileDescriptorWatcher(); - ~FileDescriptorWatcher(); // Implicitly calls StopWatchingFileDescriptor. - - // NOTE: These methods aren't called StartWatching()/StopWatching() to - // avoid confusion with the win32 ObjectWatcher class. - - // Stop watching the FD, always safe to call. No-op if there's nothing - // to do. - bool StopWatchingFileDescriptor(); - - private: - friend class MessagePumpIOSForIO; - friend class MessagePumpIOSForIOTest; - - // Called by MessagePumpIOSForIO, ownership of |fdref| and |fd_source| - // is transferred to this object. - void Init(CFFileDescriptorRef fdref, - CFOptionFlags callback_types, - CFRunLoopSourceRef fd_source, - bool is_persistent); - - void set_pump(base::WeakPtr pump) { pump_ = pump; } - const base::WeakPtr& pump() const { return pump_; } - - void set_watcher(Watcher* watcher) { watcher_ = watcher; } - - void OnFileCanReadWithoutBlocking(int fd, MessagePumpIOSForIO* pump); - void OnFileCanWriteWithoutBlocking(int fd, MessagePumpIOSForIO* pump); - - bool is_persistent_; // false if this event is one-shot. - base::mac::ScopedCFFileDescriptorRef fdref_; - CFOptionFlags callback_types_; - base::ScopedCFTypeRef fd_source_; - base::WeakPtr pump_; - Watcher* watcher_; - - DISALLOW_COPY_AND_ASSIGN(FileDescriptorWatcher); - }; - - enum Mode { - WATCH_READ = 1 << 0, - WATCH_WRITE = 1 << 1, - WATCH_READ_WRITE = WATCH_READ | WATCH_WRITE - }; - - MessagePumpIOSForIO(); - virtual ~MessagePumpIOSForIO(); - - // Have the current thread's message loop watch for a a situation in which - // reading/writing to the FD can be performed without blocking. - // Callers must provide a preallocated FileDescriptorWatcher object which - // can later be used to manage the lifetime of this event. - // If a FileDescriptorWatcher is passed in which is already attached to - // an event, then the effect is cumulative i.e. after the call |controller| - // will watch both the previous event and the new one. - // If an error occurs while calling this method in a cumulative fashion, the - // event previously attached to |controller| is aborted. - // Returns true on success. - // Must be called on the same thread the message_pump is running on. - bool WatchFileDescriptor(int fd, - bool persistent, - int mode, - FileDescriptorWatcher *controller, - Watcher *delegate); - - void RemoveRunLoopSource(CFRunLoopSourceRef source); - - void AddIOObserver(IOObserver* obs); - void RemoveIOObserver(IOObserver* obs); - - private: - friend class MessagePumpIOSForIOTest; - - void WillProcessIOEvent(); - void DidProcessIOEvent(); - - static void HandleFdIOEvent(CFFileDescriptorRef fdref, - CFOptionFlags callback_types, - void* context); - - ObserverList io_observers_; - ThreadChecker watch_file_descriptor_caller_checker_; - - base::WeakPtrFactory weak_factory_; - - DISALLOW_COPY_AND_ASSIGN(MessagePumpIOSForIO); -}; - -} // namespace base - -#endif // BASE_MESSAGE_LOOP_MESSAGE_PUMP_IO_IOS_H_ diff --git a/base/message_loop/message_pump_io_ios_unittest.cc b/base/message_loop/message_pump_io_ios_unittest.cc deleted file mode 100644 index 9c7a8fbf65..0000000000 --- a/base/message_loop/message_pump_io_ios_unittest.cc +++ /dev/null @@ -1,188 +0,0 @@ -// Copyright 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "base/message_loop/message_pump_io_ios.h" - -#include - -#include "base/message_loop/message_loop.h" -#include "base/posix/eintr_wrapper.h" -#include "base/threading/thread.h" -#include "testing/gtest/include/gtest/gtest.h" - -namespace base { - -class MessagePumpIOSForIOTest : public testing::Test { - protected: - MessagePumpIOSForIOTest() - : ui_loop_(MessageLoop::TYPE_UI), - io_thread_("MessagePumpIOSForIOTestIOThread") {} - virtual ~MessagePumpIOSForIOTest() {} - - virtual void SetUp() OVERRIDE { - Thread::Options options(MessageLoop::TYPE_IO, 0); - ASSERT_TRUE(io_thread_.StartWithOptions(options)); - ASSERT_EQ(MessageLoop::TYPE_IO, io_thread_.message_loop()->type()); - int ret = pipe(pipefds_); - ASSERT_EQ(0, ret); - ret = pipe(alternate_pipefds_); - ASSERT_EQ(0, ret); - } - - virtual void TearDown() OVERRIDE { - if (HANDLE_EINTR(close(pipefds_[0])) < 0) - PLOG(ERROR) << "close"; - if (HANDLE_EINTR(close(pipefds_[1])) < 0) - PLOG(ERROR) << "close"; - } - - MessageLoop* ui_loop() { return &ui_loop_; } - MessageLoopForIO* io_loop() const { - return static_cast(io_thread_.message_loop()); - } - - void HandleFdIOEvent(MessageLoopForIO::FileDescriptorWatcher* watcher) { - MessagePumpIOSForIO::HandleFdIOEvent(watcher->fdref_, - kCFFileDescriptorReadCallBack | kCFFileDescriptorWriteCallBack, - watcher); - } - - int pipefds_[2]; - int alternate_pipefds_[2]; - - private: - MessageLoop ui_loop_; - Thread io_thread_; - - DISALLOW_COPY_AND_ASSIGN(MessagePumpIOSForIOTest); -}; - -namespace { - -// Concrete implementation of MessagePumpIOSForIO::Watcher that does -// nothing useful. -class StupidWatcher : public MessagePumpIOSForIO::Watcher { - public: - virtual ~StupidWatcher() {} - - // base:MessagePumpIOSForIO::Watcher interface - virtual void OnFileCanReadWithoutBlocking(int fd) OVERRIDE {} - virtual void OnFileCanWriteWithoutBlocking(int fd) OVERRIDE {} -}; - -#if GTEST_HAS_DEATH_TEST && !defined(NDEBUG) - -// Test to make sure that we catch calling WatchFileDescriptor off of the -// wrong thread. -TEST_F(MessagePumpIOSForIOTest, TestWatchingFromBadThread) { - MessagePumpIOSForIO::FileDescriptorWatcher watcher; - StupidWatcher delegate; - - ASSERT_DEBUG_DEATH(io_loop()->WatchFileDescriptor( - STDOUT_FILENO, false, MessageLoopForIO::WATCH_READ, &watcher, &delegate), - "Check failed: " - "watch_file_descriptor_caller_checker_.CalledOnValidThread()"); -} - -#endif // GTEST_HAS_DEATH_TEST && !defined(NDEBUG) - -class BaseWatcher : public MessagePumpIOSForIO::Watcher { - public: - BaseWatcher(MessagePumpIOSForIO::FileDescriptorWatcher* controller) - : controller_(controller) { - DCHECK(controller_); - } - virtual ~BaseWatcher() {} - - // MessagePumpIOSForIO::Watcher interface - virtual void OnFileCanReadWithoutBlocking(int /* fd */) OVERRIDE { - NOTREACHED(); - } - - virtual void OnFileCanWriteWithoutBlocking(int /* fd */) OVERRIDE { - NOTREACHED(); - } - - protected: - MessagePumpIOSForIO::FileDescriptorWatcher* controller_; -}; - -class DeleteWatcher : public BaseWatcher { - public: - explicit DeleteWatcher( - MessagePumpIOSForIO::FileDescriptorWatcher* controller) - : BaseWatcher(controller) {} - - virtual ~DeleteWatcher() { - DCHECK(!controller_); - } - - virtual void OnFileCanWriteWithoutBlocking(int /* fd */) OVERRIDE { - DCHECK(controller_); - delete controller_; - controller_ = NULL; - } -}; - -TEST_F(MessagePumpIOSForIOTest, DeleteWatcher) { - scoped_ptr pump(new MessagePumpIOSForIO); - MessagePumpIOSForIO::FileDescriptorWatcher* watcher = - new MessagePumpIOSForIO::FileDescriptorWatcher; - DeleteWatcher delegate(watcher); - pump->WatchFileDescriptor(pipefds_[1], - false, MessagePumpIOSForIO::WATCH_READ_WRITE, watcher, &delegate); - - // Spoof a callback. - HandleFdIOEvent(watcher); -} - -class StopWatcher : public BaseWatcher { - public: - StopWatcher(MessagePumpIOSForIO::FileDescriptorWatcher* controller, - MessagePumpIOSForIO* pump, - int fd_to_start_watching = -1) - : BaseWatcher(controller), - pump_(pump), - fd_to_start_watching_(fd_to_start_watching) {} - - virtual ~StopWatcher() {} - - virtual void OnFileCanWriteWithoutBlocking(int /* fd */) OVERRIDE { - controller_->StopWatchingFileDescriptor(); - if (fd_to_start_watching_ >= 0) { - pump_->WatchFileDescriptor(fd_to_start_watching_, - false, MessagePumpIOSForIO::WATCH_READ_WRITE, controller_, this); - } - } - - private: - MessagePumpIOSForIO* pump_; - int fd_to_start_watching_; -}; - -TEST_F(MessagePumpIOSForIOTest, StopWatcher) { - scoped_ptr pump(new MessagePumpIOSForIO); - MessagePumpIOSForIO::FileDescriptorWatcher watcher; - StopWatcher delegate(&watcher, pump.get()); - pump->WatchFileDescriptor(pipefds_[1], - false, MessagePumpIOSForIO::WATCH_READ_WRITE, &watcher, &delegate); - - // Spoof a callback. - HandleFdIOEvent(&watcher); -} - -TEST_F(MessagePumpIOSForIOTest, StopWatcherAndWatchSomethingElse) { - scoped_ptr pump(new MessagePumpIOSForIO); - MessagePumpIOSForIO::FileDescriptorWatcher watcher; - StopWatcher delegate(&watcher, pump.get(), alternate_pipefds_[1]); - pump->WatchFileDescriptor(pipefds_[1], - false, MessagePumpIOSForIO::WATCH_READ_WRITE, &watcher, &delegate); - - // Spoof a callback. - HandleFdIOEvent(&watcher); -} - -} // namespace - -} // namespace base diff --git a/base/message_loop/message_pump_libevent.cc b/base/message_loop/message_pump_libevent.cc deleted file mode 100644 index 6d862d1d26..0000000000 --- a/base/message_loop/message_pump_libevent.cc +++ /dev/null @@ -1,375 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "base/message_loop/message_pump_libevent.h" - -#include -#include -#include - -#include "base/auto_reset.h" -#include "base/compiler_specific.h" -#include "base/logging.h" -#include "base/memory/scoped_ptr.h" -#include "base/observer_list.h" -#include "base/posix/eintr_wrapper.h" -#include "base/time/time.h" -#include "third_party/libevent/event.h" - -#if defined(OS_MACOSX) -#include "base/mac/scoped_nsautorelease_pool.h" -#endif - -// Lifecycle of struct event -// Libevent uses two main data structures: -// struct event_base (of which there is one per message pump), and -// struct event (of which there is roughly one per socket). -// The socket's struct event is created in -// MessagePumpLibevent::WatchFileDescriptor(), -// is owned by the FileDescriptorWatcher, and is destroyed in -// StopWatchingFileDescriptor(). -// It is moved into and out of lists in struct event_base by -// the libevent functions event_add() and event_del(). -// -// TODO(dkegel): -// At the moment bad things happen if a FileDescriptorWatcher -// is active after its MessagePumpLibevent has been destroyed. -// See MessageLoopTest.FileDescriptorWatcherOutlivesMessageLoop -// Not clear yet whether that situation occurs in practice, -// but if it does, we need to fix it. - -namespace base { - -// Return 0 on success -// Too small a function to bother putting in a library? -static int SetNonBlocking(int fd) { - int flags = fcntl(fd, F_GETFL, 0); - if (flags == -1) - flags = 0; - return fcntl(fd, F_SETFL, flags | O_NONBLOCK); -} - -MessagePumpLibevent::FileDescriptorWatcher::FileDescriptorWatcher() - : event_(NULL), - pump_(NULL), - watcher_(NULL), - weak_factory_(this) { -} - -MessagePumpLibevent::FileDescriptorWatcher::~FileDescriptorWatcher() { - if (event_) { - StopWatchingFileDescriptor(); - } -} - -bool MessagePumpLibevent::FileDescriptorWatcher::StopWatchingFileDescriptor() { - event* e = ReleaseEvent(); - if (e == NULL) - return true; - - // event_del() is a no-op if the event isn't active. - int rv = event_del(e); - delete e; - pump_ = NULL; - watcher_ = NULL; - return (rv == 0); -} - -void MessagePumpLibevent::FileDescriptorWatcher::Init(event *e) { - DCHECK(e); - DCHECK(!event_); - - event_ = e; -} - -event *MessagePumpLibevent::FileDescriptorWatcher::ReleaseEvent() { - struct event *e = event_; - event_ = NULL; - return e; -} - -void MessagePumpLibevent::FileDescriptorWatcher::OnFileCanReadWithoutBlocking( - int fd, MessagePumpLibevent* pump) { - // Since OnFileCanWriteWithoutBlocking() gets called first, it can stop - // watching the file descriptor. - if (!watcher_) - return; - pump->WillProcessIOEvent(); - watcher_->OnFileCanReadWithoutBlocking(fd); - pump->DidProcessIOEvent(); -} - -void MessagePumpLibevent::FileDescriptorWatcher::OnFileCanWriteWithoutBlocking( - int fd, MessagePumpLibevent* pump) { - DCHECK(watcher_); - pump->WillProcessIOEvent(); - watcher_->OnFileCanWriteWithoutBlocking(fd); - pump->DidProcessIOEvent(); -} - -MessagePumpLibevent::MessagePumpLibevent() - : keep_running_(true), - in_run_(false), - processed_io_events_(false), - event_base_(event_base_new()), - wakeup_pipe_in_(-1), - wakeup_pipe_out_(-1) { - if (!Init()) - NOTREACHED(); -} - -MessagePumpLibevent::~MessagePumpLibevent() { - DCHECK(wakeup_event_); - DCHECK(event_base_); - event_del(wakeup_event_); - delete wakeup_event_; - if (wakeup_pipe_in_ >= 0) { - if (HANDLE_EINTR(close(wakeup_pipe_in_)) < 0) - DPLOG(ERROR) << "close"; - } - if (wakeup_pipe_out_ >= 0) { - if (HANDLE_EINTR(close(wakeup_pipe_out_)) < 0) - DPLOG(ERROR) << "close"; - } - event_base_free(event_base_); -} - -bool MessagePumpLibevent::WatchFileDescriptor(int fd, - bool persistent, - int mode, - FileDescriptorWatcher *controller, - Watcher *delegate) { - DCHECK_GE(fd, 0); - DCHECK(controller); - DCHECK(delegate); - DCHECK(mode == WATCH_READ || mode == WATCH_WRITE || mode == WATCH_READ_WRITE); - // WatchFileDescriptor should be called on the pump thread. It is not - // threadsafe, and your watcher may never be registered. - DCHECK(watch_file_descriptor_caller_checker_.CalledOnValidThread()); - - int event_mask = persistent ? EV_PERSIST : 0; - if (mode & WATCH_READ) { - event_mask |= EV_READ; - } - if (mode & WATCH_WRITE) { - event_mask |= EV_WRITE; - } - - scoped_ptr evt(controller->ReleaseEvent()); - if (evt.get() == NULL) { - // Ownership is transferred to the controller. - evt.reset(new event); - } else { - // Make sure we don't pick up any funky internal libevent masks. - int old_interest_mask = evt.get()->ev_events & - (EV_READ | EV_WRITE | EV_PERSIST); - - // Combine old/new event masks. - event_mask |= old_interest_mask; - - // Must disarm the event before we can reuse it. - event_del(evt.get()); - - // It's illegal to use this function to listen on 2 separate fds with the - // same |controller|. - if (EVENT_FD(evt.get()) != fd) { - NOTREACHED() << "FDs don't match" << EVENT_FD(evt.get()) << "!=" << fd; - return false; - } - } - - // Set current interest mask and message pump for this event. - event_set(evt.get(), fd, event_mask, OnLibeventNotification, controller); - - // Tell libevent which message pump this socket will belong to when we add it. - if (event_base_set(event_base_, evt.get())) { - return false; - } - - // Add this socket to the list of monitored sockets. - if (event_add(evt.get(), NULL)) { - return false; - } - - // Transfer ownership of evt to controller. - controller->Init(evt.release()); - - controller->set_watcher(delegate); - controller->set_pump(this); - - return true; -} - -void MessagePumpLibevent::AddIOObserver(IOObserver *obs) { - io_observers_.AddObserver(obs); -} - -void MessagePumpLibevent::RemoveIOObserver(IOObserver *obs) { - io_observers_.RemoveObserver(obs); -} - -// Tell libevent to break out of inner loop. -static void timer_callback(int fd, short events, void *context) -{ - event_base_loopbreak((struct event_base *)context); -} - -// Reentrant! -void MessagePumpLibevent::Run(Delegate* delegate) { - DCHECK(keep_running_) << "Quit must have been called outside of Run!"; - AutoReset auto_reset_in_run(&in_run_, true); - - // event_base_loopexit() + EVLOOP_ONCE is leaky, see http://crbug.com/25641. - // Instead, make our own timer and reuse it on each call to event_base_loop(). - scoped_ptr timer_event(new event); - - for (;;) { -#if defined(OS_MACOSX) - mac::ScopedNSAutoreleasePool autorelease_pool; -#endif - - bool did_work = delegate->DoWork(); - if (!keep_running_) - break; - - event_base_loop(event_base_, EVLOOP_NONBLOCK); - did_work |= processed_io_events_; - processed_io_events_ = false; - if (!keep_running_) - break; - - did_work |= delegate->DoDelayedWork(&delayed_work_time_); - if (!keep_running_) - break; - - if (did_work) - continue; - - did_work = delegate->DoIdleWork(); - if (!keep_running_) - break; - - if (did_work) - continue; - - // EVLOOP_ONCE tells libevent to only block once, - // but to service all pending events when it wakes up. - if (delayed_work_time_.is_null()) { - event_base_loop(event_base_, EVLOOP_ONCE); - } else { - TimeDelta delay = delayed_work_time_ - TimeTicks::Now(); - if (delay > TimeDelta()) { - struct timeval poll_tv; - poll_tv.tv_sec = delay.InSeconds(); - poll_tv.tv_usec = delay.InMicroseconds() % Time::kMicrosecondsPerSecond; - event_set(timer_event.get(), -1, 0, timer_callback, event_base_); - event_base_set(event_base_, timer_event.get()); - event_add(timer_event.get(), &poll_tv); - event_base_loop(event_base_, EVLOOP_ONCE); - event_del(timer_event.get()); - } else { - // It looks like delayed_work_time_ indicates a time in the past, so we - // need to call DoDelayedWork now. - delayed_work_time_ = TimeTicks(); - } - } - } - - keep_running_ = true; -} - -void MessagePumpLibevent::Quit() { - DCHECK(in_run_); - // Tell both libevent and Run that they should break out of their loops. - keep_running_ = false; - ScheduleWork(); -} - -void MessagePumpLibevent::ScheduleWork() { - // Tell libevent (in a threadsafe way) that it should break out of its loop. - char buf = 0; - int nwrite = HANDLE_EINTR(write(wakeup_pipe_in_, &buf, 1)); - DCHECK(nwrite == 1 || errno == EAGAIN) - << "[nwrite:" << nwrite << "] [errno:" << errno << "]"; -} - -void MessagePumpLibevent::ScheduleDelayedWork( - const TimeTicks& delayed_work_time) { - // We know that we can't be blocked on Wait right now since this method can - // only be called on the same thread as Run, so we only need to update our - // record of how long to sleep when we do sleep. - delayed_work_time_ = delayed_work_time; -} - -void MessagePumpLibevent::WillProcessIOEvent() { - FOR_EACH_OBSERVER(IOObserver, io_observers_, WillProcessIOEvent()); -} - -void MessagePumpLibevent::DidProcessIOEvent() { - FOR_EACH_OBSERVER(IOObserver, io_observers_, DidProcessIOEvent()); -} - -bool MessagePumpLibevent::Init() { - int fds[2]; - if (pipe(fds)) { - DLOG(ERROR) << "pipe() failed, errno: " << errno; - return false; - } - if (SetNonBlocking(fds[0])) { - DLOG(ERROR) << "SetNonBlocking for pipe fd[0] failed, errno: " << errno; - return false; - } - if (SetNonBlocking(fds[1])) { - DLOG(ERROR) << "SetNonBlocking for pipe fd[1] failed, errno: " << errno; - return false; - } - wakeup_pipe_out_ = fds[0]; - wakeup_pipe_in_ = fds[1]; - - wakeup_event_ = new event; - event_set(wakeup_event_, wakeup_pipe_out_, EV_READ | EV_PERSIST, - OnWakeup, this); - event_base_set(event_base_, wakeup_event_); - - if (event_add(wakeup_event_, 0)) - return false; - return true; -} - -// static -void MessagePumpLibevent::OnLibeventNotification(int fd, short flags, - void* context) { - WeakPtr controller = - static_cast(context)->weak_factory_.GetWeakPtr(); - DCHECK(controller.get()); - - MessagePumpLibevent* pump = controller->pump(); - pump->processed_io_events_ = true; - - if (flags & EV_WRITE) { - controller->OnFileCanWriteWithoutBlocking(fd, pump); - } - // Check |controller| in case it's been deleted in - // controller->OnFileCanWriteWithoutBlocking(). - if (controller.get() && flags & EV_READ) { - controller->OnFileCanReadWithoutBlocking(fd, pump); - } -} - -// Called if a byte is received on the wakeup pipe. -// static -void MessagePumpLibevent::OnWakeup(int socket, short flags, void* context) { - MessagePumpLibevent* that = static_cast(context); - DCHECK(that->wakeup_pipe_out_ == socket); - - // Remove and discard the wakeup byte. - char buf; - int nread = HANDLE_EINTR(read(socket, &buf, 1)); - DCHECK_EQ(nread, 1); - that->processed_io_events_ = true; - // Tell libevent to break out of inner loop. - event_base_loopbreak(that->event_base_); -} - -} // namespace base diff --git a/base/message_loop/message_pump_libevent.h b/base/message_loop/message_pump_libevent.h deleted file mode 100644 index f3a48a9f62..0000000000 --- a/base/message_loop/message_pump_libevent.h +++ /dev/null @@ -1,177 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef BASE_MESSAGE_LOOP_MESSAGE_PUMP_LIBEVENT_H_ -#define BASE_MESSAGE_LOOP_MESSAGE_PUMP_LIBEVENT_H_ - -#include "base/basictypes.h" -#include "base/compiler_specific.h" -#include "base/memory/weak_ptr.h" -#include "base/message_loop/message_pump.h" -#include "base/observer_list.h" -#include "base/threading/thread_checker.h" -#include "base/time/time.h" - -// Declare structs we need from libevent.h rather than including it -struct event_base; -struct event; - -namespace base { - -// Class to monitor sockets and issue callbacks when sockets are ready for I/O -// TODO(dkegel): add support for background file IO somehow -class BASE_EXPORT MessagePumpLibevent : public MessagePump { - public: - class IOObserver { - public: - IOObserver() {} - - // An IOObserver is an object that receives IO notifications from the - // MessagePump. - // - // NOTE: An IOObserver implementation should be extremely fast! - virtual void WillProcessIOEvent() = 0; - virtual void DidProcessIOEvent() = 0; - - protected: - virtual ~IOObserver() {} - }; - - // Used with WatchFileDescriptor to asynchronously monitor the I/O readiness - // of a file descriptor. - class Watcher { - public: - // Called from MessageLoop::Run when an FD can be read from/written to - // without blocking - virtual void OnFileCanReadWithoutBlocking(int fd) = 0; - virtual void OnFileCanWriteWithoutBlocking(int fd) = 0; - - protected: - virtual ~Watcher() {} - }; - - // Object returned by WatchFileDescriptor to manage further watching. - class FileDescriptorWatcher { - public: - FileDescriptorWatcher(); - ~FileDescriptorWatcher(); // Implicitly calls StopWatchingFileDescriptor. - - // NOTE: These methods aren't called StartWatching()/StopWatching() to - // avoid confusion with the win32 ObjectWatcher class. - - // Stop watching the FD, always safe to call. No-op if there's nothing - // to do. - bool StopWatchingFileDescriptor(); - - private: - friend class MessagePumpLibevent; - friend class MessagePumpLibeventTest; - - // Called by MessagePumpLibevent, ownership of |e| is transferred to this - // object. - void Init(event* e); - - // Used by MessagePumpLibevent to take ownership of event_. - event* ReleaseEvent(); - - void set_pump(MessagePumpLibevent* pump) { pump_ = pump; } - MessagePumpLibevent* pump() const { return pump_; } - - void set_watcher(Watcher* watcher) { watcher_ = watcher; } - - void OnFileCanReadWithoutBlocking(int fd, MessagePumpLibevent* pump); - void OnFileCanWriteWithoutBlocking(int fd, MessagePumpLibevent* pump); - - event* event_; - MessagePumpLibevent* pump_; - Watcher* watcher_; - WeakPtrFactory weak_factory_; - - DISALLOW_COPY_AND_ASSIGN(FileDescriptorWatcher); - }; - - enum Mode { - WATCH_READ = 1 << 0, - WATCH_WRITE = 1 << 1, - WATCH_READ_WRITE = WATCH_READ | WATCH_WRITE - }; - - MessagePumpLibevent(); - virtual ~MessagePumpLibevent(); - - // Have the current thread's message loop watch for a a situation in which - // reading/writing to the FD can be performed without blocking. - // Callers must provide a preallocated FileDescriptorWatcher object which - // can later be used to manage the lifetime of this event. - // If a FileDescriptorWatcher is passed in which is already attached to - // an event, then the effect is cumulative i.e. after the call |controller| - // will watch both the previous event and the new one. - // If an error occurs while calling this method in a cumulative fashion, the - // event previously attached to |controller| is aborted. - // Returns true on success. - // Must be called on the same thread the message_pump is running on. - // TODO(dkegel): switch to edge-triggered readiness notification - bool WatchFileDescriptor(int fd, - bool persistent, - int mode, - FileDescriptorWatcher *controller, - Watcher *delegate); - - void AddIOObserver(IOObserver* obs); - void RemoveIOObserver(IOObserver* obs); - - // MessagePump methods: - virtual void Run(Delegate* delegate) OVERRIDE; - virtual void Quit() OVERRIDE; - virtual void ScheduleWork() OVERRIDE; - virtual void ScheduleDelayedWork(const TimeTicks& delayed_work_time) OVERRIDE; - - private: - friend class MessagePumpLibeventTest; - - void WillProcessIOEvent(); - void DidProcessIOEvent(); - - // Risky part of constructor. Returns true on success. - bool Init(); - - // Called by libevent to tell us a registered FD can be read/written to. - static void OnLibeventNotification(int fd, short flags, - void* context); - - // Unix pipe used to implement ScheduleWork() - // ... callback; called by libevent inside Run() when pipe is ready to read - static void OnWakeup(int socket, short flags, void* context); - - // This flag is set to false when Run should return. - bool keep_running_; - - // This flag is set when inside Run. - bool in_run_; - - // This flag is set if libevent has processed I/O events. - bool processed_io_events_; - - // The time at which we should call DoDelayedWork. - TimeTicks delayed_work_time_; - - // Libevent dispatcher. Watches all sockets registered with it, and sends - // readiness callbacks when a socket is ready for I/O. - event_base* event_base_; - - // ... write end; ScheduleWork() writes a single byte to it - int wakeup_pipe_in_; - // ... read end; OnWakeup reads it and then breaks Run() out of its sleep - int wakeup_pipe_out_; - // ... libevent wrapper for read end - event* wakeup_event_; - - ObserverList io_observers_; - ThreadChecker watch_file_descriptor_caller_checker_; - DISALLOW_COPY_AND_ASSIGN(MessagePumpLibevent); -}; - -} // namespace base - -#endif // BASE_MESSAGE_LOOP_MESSAGE_PUMP_LIBEVENT_H_ diff --git a/base/message_loop/message_pump_libevent_unittest.cc b/base/message_loop/message_pump_libevent_unittest.cc deleted file mode 100644 index 52ca95bebf..0000000000 --- a/base/message_loop/message_pump_libevent_unittest.cc +++ /dev/null @@ -1,162 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "base/message_loop/message_pump_libevent.h" - -#include - -#include "base/message_loop/message_loop.h" -#include "base/posix/eintr_wrapper.h" -#include "base/threading/thread.h" -#include "testing/gtest/include/gtest/gtest.h" -#include "third_party/libevent/event.h" - -namespace base { - -class MessagePumpLibeventTest : public testing::Test { - protected: - MessagePumpLibeventTest() - : ui_loop_(MessageLoop::TYPE_UI), - io_thread_("MessagePumpLibeventTestIOThread") {} - virtual ~MessagePumpLibeventTest() {} - - virtual void SetUp() OVERRIDE { - Thread::Options options(MessageLoop::TYPE_IO, 0); - ASSERT_TRUE(io_thread_.StartWithOptions(options)); - ASSERT_EQ(MessageLoop::TYPE_IO, io_thread_.message_loop()->type()); - int ret = pipe(pipefds_); - ASSERT_EQ(0, ret); - } - - virtual void TearDown() OVERRIDE { - if (HANDLE_EINTR(close(pipefds_[0])) < 0) - PLOG(ERROR) << "close"; - if (HANDLE_EINTR(close(pipefds_[1])) < 0) - PLOG(ERROR) << "close"; - } - - MessageLoop* ui_loop() { return &ui_loop_; } - MessageLoopForIO* io_loop() const { - return static_cast(io_thread_.message_loop()); - } - - void OnLibeventNotification( - MessagePumpLibevent* pump, - MessagePumpLibevent::FileDescriptorWatcher* controller) { - pump->OnLibeventNotification(0, EV_WRITE | EV_READ, controller); - } - - int pipefds_[2]; - - private: - MessageLoop ui_loop_; - Thread io_thread_; -}; - -namespace { - -// Concrete implementation of MessagePumpLibevent::Watcher that does -// nothing useful. -class StupidWatcher : public MessagePumpLibevent::Watcher { - public: - virtual ~StupidWatcher() {} - - // base:MessagePumpLibevent::Watcher interface - virtual void OnFileCanReadWithoutBlocking(int fd) OVERRIDE {} - virtual void OnFileCanWriteWithoutBlocking(int fd) OVERRIDE {} -}; - -#if GTEST_HAS_DEATH_TEST && !defined(NDEBUG) - -// Test to make sure that we catch calling WatchFileDescriptor off of the -// wrong thread. -TEST_F(MessagePumpLibeventTest, TestWatchingFromBadThread) { - MessagePumpLibevent::FileDescriptorWatcher watcher; - StupidWatcher delegate; - - ASSERT_DEATH(io_loop()->WatchFileDescriptor( - STDOUT_FILENO, false, MessageLoopForIO::WATCH_READ, &watcher, &delegate), - "Check failed: " - "watch_file_descriptor_caller_checker_.CalledOnValidThread()"); -} - -#endif // GTEST_HAS_DEATH_TEST && !defined(NDEBUG) - -class BaseWatcher : public MessagePumpLibevent::Watcher { - public: - explicit BaseWatcher(MessagePumpLibevent::FileDescriptorWatcher* controller) - : controller_(controller) { - DCHECK(controller_); - } - virtual ~BaseWatcher() {} - - // base:MessagePumpLibevent::Watcher interface - virtual void OnFileCanReadWithoutBlocking(int /* fd */) OVERRIDE { - NOTREACHED(); - } - - virtual void OnFileCanWriteWithoutBlocking(int /* fd */) OVERRIDE { - NOTREACHED(); - } - - protected: - MessagePumpLibevent::FileDescriptorWatcher* controller_; -}; - -class DeleteWatcher : public BaseWatcher { - public: - explicit DeleteWatcher( - MessagePumpLibevent::FileDescriptorWatcher* controller) - : BaseWatcher(controller) {} - - virtual ~DeleteWatcher() { - DCHECK(!controller_); - } - - virtual void OnFileCanWriteWithoutBlocking(int /* fd */) OVERRIDE { - DCHECK(controller_); - delete controller_; - controller_ = NULL; - } -}; - -TEST_F(MessagePumpLibeventTest, DeleteWatcher) { - scoped_ptr pump(new MessagePumpLibevent); - MessagePumpLibevent::FileDescriptorWatcher* watcher = - new MessagePumpLibevent::FileDescriptorWatcher; - DeleteWatcher delegate(watcher); - pump->WatchFileDescriptor(pipefds_[1], - false, MessagePumpLibevent::WATCH_READ_WRITE, watcher, &delegate); - - // Spoof a libevent notification. - OnLibeventNotification(pump.get(), watcher); -} - -class StopWatcher : public BaseWatcher { - public: - explicit StopWatcher( - MessagePumpLibevent::FileDescriptorWatcher* controller) - : BaseWatcher(controller) {} - - virtual ~StopWatcher() {} - - virtual void OnFileCanWriteWithoutBlocking(int /* fd */) OVERRIDE { - controller_->StopWatchingFileDescriptor(); - } -}; - -TEST_F(MessagePumpLibeventTest, StopWatcher) { - scoped_ptr pump(new MessagePumpLibevent); - MessagePumpLibevent::FileDescriptorWatcher watcher; - StopWatcher delegate(&watcher); - pump->WatchFileDescriptor(pipefds_[1], - false, MessagePumpLibevent::WATCH_READ_WRITE, &watcher, &delegate); - - // Spoof a libevent notification. - OnLibeventNotification(pump.get(), &watcher); -} - -} // namespace - -} // namespace base diff --git a/base/message_loop/message_pump_mac.h b/base/message_loop/message_pump_mac.h deleted file mode 100644 index 748b26591f..0000000000 --- a/base/message_loop/message_pump_mac.h +++ /dev/null @@ -1,329 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -// The basis for all native run loops on the Mac is the CFRunLoop. It can be -// used directly, it can be used as the driving force behind the similar -// Foundation NSRunLoop, and it can be used to implement higher-level event -// loops such as the NSApplication event loop. -// -// This file introduces a basic CFRunLoop-based implementation of the -// MessagePump interface called CFRunLoopBase. CFRunLoopBase contains all -// of the machinery necessary to dispatch events to a delegate, but does not -// implement the specific run loop. Concrete subclasses must provide their -// own DoRun and Quit implementations. -// -// A concrete subclass that just runs a CFRunLoop loop is provided in -// MessagePumpCFRunLoop. For an NSRunLoop, the similar MessagePumpNSRunLoop -// is provided. -// -// For the application's event loop, an implementation based on AppKit's -// NSApplication event system is provided in MessagePumpNSApplication. -// -// Typically, MessagePumpNSApplication only makes sense on a Cocoa -// application's main thread. If a CFRunLoop-based message pump is needed on -// any other thread, one of the other concrete subclasses is preferrable. -// MessagePumpMac::Create is defined, which returns a new NSApplication-based -// or NSRunLoop-based MessagePump subclass depending on which thread it is -// called on. - -#ifndef BASE_MESSAGE_LOOP_MESSAGE_PUMP_MAC_H_ -#define BASE_MESSAGE_LOOP_MESSAGE_PUMP_MAC_H_ - -#include "base/message_loop/message_pump.h" - -#include "base/basictypes.h" - -#include - -#if !defined(__OBJC__) -class NSAutoreleasePool; -#else // !defined(__OBJC__) -#if defined(OS_IOS) -#import -#else -#import - -// Clients must subclass NSApplication and implement this protocol if they use -// MessagePumpMac. -@protocol CrAppProtocol -// Must return true if -[NSApplication sendEvent:] is currently on the stack. -// See the comment for |CreateAutoreleasePool()| in the cc file for why this is -// necessary. -- (BOOL)isHandlingSendEvent; -@end -#endif // !defined(OS_IOS) -#endif // !defined(__OBJC__) - -namespace base { - -class RunLoop; -class TimeTicks; - -class MessagePumpCFRunLoopBase : public MessagePump { - // Needs access to CreateAutoreleasePool. - friend class MessagePumpScopedAutoreleasePool; - public: - MessagePumpCFRunLoopBase(); - virtual ~MessagePumpCFRunLoopBase(); - - // Subclasses should implement the work they need to do in MessagePump::Run - // in the DoRun method. MessagePumpCFRunLoopBase::Run calls DoRun directly. - // This arrangement is used because MessagePumpCFRunLoopBase needs to set - // up and tear down things before and after the "meat" of DoRun. - virtual void Run(Delegate* delegate) OVERRIDE; - virtual void DoRun(Delegate* delegate) = 0; - - virtual void ScheduleWork() OVERRIDE; - virtual void ScheduleDelayedWork(const TimeTicks& delayed_work_time) OVERRIDE; - - protected: - // Accessors for private data members to be used by subclasses. - CFRunLoopRef run_loop() const { return run_loop_; } - int nesting_level() const { return nesting_level_; } - int run_nesting_level() const { return run_nesting_level_; } - - // Sets this pump's delegate. Signals the appropriate sources if - // |delegateless_work_| is true. |delegate| can be NULL. - void SetDelegate(Delegate* delegate); - - // Return an autorelease pool to wrap around any work being performed. - // In some cases, CreateAutoreleasePool may return nil intentionally to - // preventing an autorelease pool from being created, allowing any - // objects autoreleased by work to fall into the current autorelease pool. - virtual NSAutoreleasePool* CreateAutoreleasePool(); - - private: - // Timer callback scheduled by ScheduleDelayedWork. This does not do any - // work, but it signals work_source_ so that delayed work can be performed - // within the appropriate priority constraints. - static void RunDelayedWorkTimer(CFRunLoopTimerRef timer, void* info); - - // Perform highest-priority work. This is associated with work_source_ - // signalled by ScheduleWork or RunDelayedWorkTimer. The static method calls - // the instance method; the instance method returns true if it resignalled - // work_source_ to be called again from the loop. - static void RunWorkSource(void* info); - bool RunWork(); - - // Perform idle-priority work. This is normally called by PreWaitObserver, - // but is also associated with idle_work_source_. When this function - // actually does perform idle work, it will resignal that source. The - // static method calls the instance method; the instance method returns - // true if idle work was done. - static void RunIdleWorkSource(void* info); - bool RunIdleWork(); - - // Perform work that may have been deferred because it was not runnable - // within a nested run loop. This is associated with - // nesting_deferred_work_source_ and is signalled by - // MaybeScheduleNestingDeferredWork when returning from a nested loop, - // so that an outer loop will be able to perform the necessary tasks if it - // permits nestable tasks. - static void RunNestingDeferredWorkSource(void* info); - bool RunNestingDeferredWork(); - - // Schedules possible nesting-deferred work to be processed before the run - // loop goes to sleep, exits, or begins processing sources at the top of its - // loop. If this function detects that a nested loop had run since the - // previous attempt to schedule nesting-deferred work, it will schedule a - // call to RunNestingDeferredWorkSource. - void MaybeScheduleNestingDeferredWork(); - - // Observer callback responsible for performing idle-priority work, before - // the run loop goes to sleep. Associated with idle_work_observer_. - static void PreWaitObserver(CFRunLoopObserverRef observer, - CFRunLoopActivity activity, void* info); - - // Observer callback called before the run loop processes any sources. - // Associated with pre_source_observer_. - static void PreSourceObserver(CFRunLoopObserverRef observer, - CFRunLoopActivity activity, void* info); - - // Observer callback called when the run loop starts and stops, at the - // beginning and end of calls to CFRunLoopRun. This is used to maintain - // nesting_level_. Associated with enter_exit_observer_. - static void EnterExitObserver(CFRunLoopObserverRef observer, - CFRunLoopActivity activity, void* info); - - // Called by EnterExitObserver after performing maintenance on nesting_level_. - // This allows subclasses an opportunity to perform additional processing on - // the basis of run loops starting and stopping. - virtual void EnterExitRunLoop(CFRunLoopActivity activity); - - // The thread's run loop. - CFRunLoopRef run_loop_; - - // The timer, sources, and observers are described above alongside their - // callbacks. - CFRunLoopTimerRef delayed_work_timer_; - CFRunLoopSourceRef work_source_; - CFRunLoopSourceRef idle_work_source_; - CFRunLoopSourceRef nesting_deferred_work_source_; - CFRunLoopObserverRef pre_wait_observer_; - CFRunLoopObserverRef pre_source_observer_; - CFRunLoopObserverRef enter_exit_observer_; - - // (weak) Delegate passed as an argument to the innermost Run call. - Delegate* delegate_; - - // The time that delayed_work_timer_ is scheduled to fire. This is tracked - // independently of CFRunLoopTimerGetNextFireDate(delayed_work_timer_) - // to be able to reset the timer properly after waking from system sleep. - // See PowerStateNotification. - CFAbsoluteTime delayed_work_fire_time_; - - // The recursion depth of the currently-executing CFRunLoopRun loop on the - // run loop's thread. 0 if no run loops are running inside of whatever scope - // the object was created in. - int nesting_level_; - - // The recursion depth (calculated in the same way as nesting_level_) of the - // innermost executing CFRunLoopRun loop started by a call to Run. - int run_nesting_level_; - - // The deepest (numerically highest) recursion depth encountered since the - // most recent attempt to run nesting-deferred work. - int deepest_nesting_level_; - - // "Delegateless" work flags are set when work is ready to be performed but - // must wait until a delegate is available to process it. This can happen - // when a MessagePumpCFRunLoopBase is instantiated and work arrives without - // any call to Run on the stack. The Run method will check for delegateless - // work on entry and redispatch it as needed once a delegate is available. - bool delegateless_work_; - bool delegateless_idle_work_; - - DISALLOW_COPY_AND_ASSIGN(MessagePumpCFRunLoopBase); -}; - -class MessagePumpCFRunLoop : public MessagePumpCFRunLoopBase { - public: - MessagePumpCFRunLoop(); - virtual ~MessagePumpCFRunLoop(); - - virtual void DoRun(Delegate* delegate) OVERRIDE; - virtual void Quit() OVERRIDE; - - private: - virtual void EnterExitRunLoop(CFRunLoopActivity activity) OVERRIDE; - - // True if Quit is called to stop the innermost MessagePump - // (innermost_quittable_) but some other CFRunLoopRun loop (nesting_level_) - // is running inside the MessagePump's innermost Run call. - bool quit_pending_; - - DISALLOW_COPY_AND_ASSIGN(MessagePumpCFRunLoop); -}; - -class MessagePumpNSRunLoop : public MessagePumpCFRunLoopBase { - public: - BASE_EXPORT MessagePumpNSRunLoop(); - virtual ~MessagePumpNSRunLoop(); - - virtual void DoRun(Delegate* delegate) OVERRIDE; - virtual void Quit() OVERRIDE; - - private: - // A source that doesn't do anything but provide something signalable - // attached to the run loop. This source will be signalled when Quit - // is called, to cause the loop to wake up so that it can stop. - CFRunLoopSourceRef quit_source_; - - // False after Quit is called. - bool keep_running_; - - DISALLOW_COPY_AND_ASSIGN(MessagePumpNSRunLoop); -}; - -#if defined(OS_IOS) -// This is a fake message pump. It attaches sources to the main thread's -// CFRunLoop, so PostTask() will work, but it is unable to drive the loop -// directly, so calling Run() or Quit() are errors. -class MessagePumpUIApplication : public MessagePumpCFRunLoopBase { - public: - MessagePumpUIApplication(); - virtual ~MessagePumpUIApplication(); - virtual void DoRun(Delegate* delegate) OVERRIDE; - virtual void Quit() OVERRIDE; - - // This message pump can not spin the main message loop directly. Instead, - // call |Attach()| to set up a delegate. It is an error to call |Run()|. - virtual void Attach(Delegate* delegate); - - private: - RunLoop* run_loop_; - - DISALLOW_COPY_AND_ASSIGN(MessagePumpUIApplication); -}; - -#else - -class MessagePumpNSApplication : public MessagePumpCFRunLoopBase { - public: - MessagePumpNSApplication(); - virtual ~MessagePumpNSApplication(); - - virtual void DoRun(Delegate* delegate) OVERRIDE; - virtual void Quit() OVERRIDE; - - private: - // False after Quit is called. - bool keep_running_; - - // True if DoRun is managing its own run loop as opposed to letting - // -[NSApplication run] handle it. The outermost run loop in the application - // is managed by -[NSApplication run], inner run loops are handled by a loop - // in DoRun. - bool running_own_loop_; - - DISALLOW_COPY_AND_ASSIGN(MessagePumpNSApplication); -}; - -class MessagePumpCrApplication : public MessagePumpNSApplication { - public: - MessagePumpCrApplication(); - virtual ~MessagePumpCrApplication(); - - protected: - // Returns nil if NSApp is currently in the middle of calling - // -sendEvent. Requires NSApp implementing CrAppProtocol. - virtual NSAutoreleasePool* CreateAutoreleasePool() OVERRIDE; - - private: - DISALLOW_COPY_AND_ASSIGN(MessagePumpCrApplication); -}; -#endif // !defined(OS_IOS) - -class MessagePumpMac { - public: - // If not on the main thread, returns a new instance of - // MessagePumpNSRunLoop. - // - // On the main thread, if NSApp exists and conforms to - // CrAppProtocol, creates an instances of MessagePumpCrApplication. - // - // Otherwise creates an instance of MessagePumpNSApplication using a - // default NSApplication. - static MessagePump* Create(); - -#if !defined(OS_IOS) - // If a pump is created before the required CrAppProtocol is - // created, the wrong MessagePump subclass could be used. - // UsingCrApp() returns false if the message pump was created before - // NSApp was initialized, or if NSApp does not implement - // CrAppProtocol. NSApp must be initialized before calling. - BASE_EXPORT static bool UsingCrApp(); - - // Wrapper to query -[NSApp isHandlingSendEvent] from C++ code. - // Requires NSApp to implement CrAppProtocol. - BASE_EXPORT static bool IsHandlingSendEvent(); -#endif // !defined(OS_IOS) - - private: - DISALLOW_IMPLICIT_CONSTRUCTORS(MessagePumpMac); -}; - -} // namespace base - -#endif // BASE_MESSAGE_LOOP_MESSAGE_PUMP_MAC_H_ diff --git a/base/message_loop/message_pump_mac.mm b/base/message_loop/message_pump_mac.mm deleted file mode 100644 index f885fbf5f6..0000000000 --- a/base/message_loop/message_pump_mac.mm +++ /dev/null @@ -1,704 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#import "base/message_loop/message_pump_mac.h" - -#import - -#include - -#include "base/logging.h" -#include "base/run_loop.h" -#include "base/time/time.h" - -#if !defined(OS_IOS) -#import -#endif // !defined(OS_IOS) - -namespace { - -void NoOp(void* info) { -} - -const CFTimeInterval kCFTimeIntervalMax = - std::numeric_limits::max(); - -#if !defined(OS_IOS) -// Set to true if MessagePumpMac::Create() is called before NSApp is -// initialized. Only accessed from the main thread. -bool g_not_using_cr_app = false; -#endif - -} // namespace - -namespace base { - -// A scoper for autorelease pools created from message pump run loops. -// Avoids dirtying up the ScopedNSAutoreleasePool interface for the rare -// case where an autorelease pool needs to be passed in. -class MessagePumpScopedAutoreleasePool { - public: - explicit MessagePumpScopedAutoreleasePool(MessagePumpCFRunLoopBase* pump) : - pool_(pump->CreateAutoreleasePool()) { - } - ~MessagePumpScopedAutoreleasePool() { - [pool_ drain]; - } - - private: - NSAutoreleasePool* pool_; - DISALLOW_COPY_AND_ASSIGN(MessagePumpScopedAutoreleasePool); -}; - -// Must be called on the run loop thread. -MessagePumpCFRunLoopBase::MessagePumpCFRunLoopBase() - : delegate_(NULL), - delayed_work_fire_time_(kCFTimeIntervalMax), - nesting_level_(0), - run_nesting_level_(0), - deepest_nesting_level_(0), - delegateless_work_(false), - delegateless_idle_work_(false) { - run_loop_ = CFRunLoopGetCurrent(); - CFRetain(run_loop_); - - // Set a repeating timer with a preposterous firing time and interval. The - // timer will effectively never fire as-is. The firing time will be adjusted - // as needed when ScheduleDelayedWork is called. - CFRunLoopTimerContext timer_context = CFRunLoopTimerContext(); - timer_context.info = this; - delayed_work_timer_ = CFRunLoopTimerCreate(NULL, // allocator - kCFTimeIntervalMax, // fire time - kCFTimeIntervalMax, // interval - 0, // flags - 0, // priority - RunDelayedWorkTimer, - &timer_context); - CFRunLoopAddTimer(run_loop_, delayed_work_timer_, kCFRunLoopCommonModes); - - CFRunLoopSourceContext source_context = CFRunLoopSourceContext(); - source_context.info = this; - source_context.perform = RunWorkSource; - work_source_ = CFRunLoopSourceCreate(NULL, // allocator - 1, // priority - &source_context); - CFRunLoopAddSource(run_loop_, work_source_, kCFRunLoopCommonModes); - - source_context.perform = RunIdleWorkSource; - idle_work_source_ = CFRunLoopSourceCreate(NULL, // allocator - 2, // priority - &source_context); - CFRunLoopAddSource(run_loop_, idle_work_source_, kCFRunLoopCommonModes); - - source_context.perform = RunNestingDeferredWorkSource; - nesting_deferred_work_source_ = CFRunLoopSourceCreate(NULL, // allocator - 0, // priority - &source_context); - CFRunLoopAddSource(run_loop_, nesting_deferred_work_source_, - kCFRunLoopCommonModes); - - CFRunLoopObserverContext observer_context = CFRunLoopObserverContext(); - observer_context.info = this; - pre_wait_observer_ = CFRunLoopObserverCreate(NULL, // allocator - kCFRunLoopBeforeWaiting, - true, // repeat - 0, // priority - PreWaitObserver, - &observer_context); - CFRunLoopAddObserver(run_loop_, pre_wait_observer_, kCFRunLoopCommonModes); - - pre_source_observer_ = CFRunLoopObserverCreate(NULL, // allocator - kCFRunLoopBeforeSources, - true, // repeat - 0, // priority - PreSourceObserver, - &observer_context); - CFRunLoopAddObserver(run_loop_, pre_source_observer_, kCFRunLoopCommonModes); - - enter_exit_observer_ = CFRunLoopObserverCreate(NULL, // allocator - kCFRunLoopEntry | - kCFRunLoopExit, - true, // repeat - 0, // priority - EnterExitObserver, - &observer_context); - CFRunLoopAddObserver(run_loop_, enter_exit_observer_, kCFRunLoopCommonModes); -} - -// Ideally called on the run loop thread. If other run loops were running -// lower on the run loop thread's stack when this object was created, the -// same number of run loops must be running when this object is destroyed. -MessagePumpCFRunLoopBase::~MessagePumpCFRunLoopBase() { - CFRunLoopRemoveObserver(run_loop_, enter_exit_observer_, - kCFRunLoopCommonModes); - CFRelease(enter_exit_observer_); - - CFRunLoopRemoveObserver(run_loop_, pre_source_observer_, - kCFRunLoopCommonModes); - CFRelease(pre_source_observer_); - - CFRunLoopRemoveObserver(run_loop_, pre_wait_observer_, - kCFRunLoopCommonModes); - CFRelease(pre_wait_observer_); - - CFRunLoopRemoveSource(run_loop_, nesting_deferred_work_source_, - kCFRunLoopCommonModes); - CFRelease(nesting_deferred_work_source_); - - CFRunLoopRemoveSource(run_loop_, idle_work_source_, kCFRunLoopCommonModes); - CFRelease(idle_work_source_); - - CFRunLoopRemoveSource(run_loop_, work_source_, kCFRunLoopCommonModes); - CFRelease(work_source_); - - CFRunLoopRemoveTimer(run_loop_, delayed_work_timer_, kCFRunLoopCommonModes); - CFRelease(delayed_work_timer_); - - CFRelease(run_loop_); -} - -// Must be called on the run loop thread. -void MessagePumpCFRunLoopBase::Run(Delegate* delegate) { - // nesting_level_ will be incremented in EnterExitRunLoop, so set - // run_nesting_level_ accordingly. - int last_run_nesting_level = run_nesting_level_; - run_nesting_level_ = nesting_level_ + 1; - - Delegate* last_delegate = delegate_; - SetDelegate(delegate); - - DoRun(delegate); - - // Restore the previous state of the object. - SetDelegate(last_delegate); - run_nesting_level_ = last_run_nesting_level; -} - -void MessagePumpCFRunLoopBase::SetDelegate(Delegate* delegate) { - delegate_ = delegate; - - if (delegate) { - // If any work showed up but could not be dispatched for want of a - // delegate, set it up for dispatch again now that a delegate is - // available. - if (delegateless_work_) { - CFRunLoopSourceSignal(work_source_); - delegateless_work_ = false; - } - if (delegateless_idle_work_) { - CFRunLoopSourceSignal(idle_work_source_); - delegateless_idle_work_ = false; - } - } -} - -// May be called on any thread. -void MessagePumpCFRunLoopBase::ScheduleWork() { - CFRunLoopSourceSignal(work_source_); - CFRunLoopWakeUp(run_loop_); -} - -// Must be called on the run loop thread. -void MessagePumpCFRunLoopBase::ScheduleDelayedWork( - const TimeTicks& delayed_work_time) { - TimeDelta delta = delayed_work_time - TimeTicks::Now(); - delayed_work_fire_time_ = CFAbsoluteTimeGetCurrent() + delta.InSecondsF(); - CFRunLoopTimerSetNextFireDate(delayed_work_timer_, delayed_work_fire_time_); -} - -// Called from the run loop. -// static -void MessagePumpCFRunLoopBase::RunDelayedWorkTimer(CFRunLoopTimerRef timer, - void* info) { - MessagePumpCFRunLoopBase* self = static_cast(info); - - // The timer won't fire again until it's reset. - self->delayed_work_fire_time_ = kCFTimeIntervalMax; - - // CFRunLoopTimers fire outside of the priority scheme for CFRunLoopSources. - // In order to establish the proper priority in which work and delayed work - // are processed one for one, the timer used to schedule delayed work must - // signal a CFRunLoopSource used to dispatch both work and delayed work. - CFRunLoopSourceSignal(self->work_source_); -} - -// Called from the run loop. -// static -void MessagePumpCFRunLoopBase::RunWorkSource(void* info) { - MessagePumpCFRunLoopBase* self = static_cast(info); - self->RunWork(); -} - -// Called by MessagePumpCFRunLoopBase::RunWorkSource. -bool MessagePumpCFRunLoopBase::RunWork() { - if (!delegate_) { - // This point can be reached with a NULL delegate_ if Run is not on the - // stack but foreign code is spinning the CFRunLoop. Arrange to come back - // here when a delegate is available. - delegateless_work_ = true; - return false; - } - - // The NSApplication-based run loop only drains the autorelease pool at each - // UI event (NSEvent). The autorelease pool is not drained for each - // CFRunLoopSource target that's run. Use a local pool for any autoreleased - // objects if the app is not currently handling a UI event to ensure they're - // released promptly even in the absence of UI events. - MessagePumpScopedAutoreleasePool autorelease_pool(this); - - // Call DoWork and DoDelayedWork once, and if something was done, arrange to - // come back here again as long as the loop is still running. - bool did_work = delegate_->DoWork(); - bool resignal_work_source = did_work; - - TimeTicks next_time; - delegate_->DoDelayedWork(&next_time); - if (!did_work) { - // Determine whether there's more delayed work, and if so, if it needs to - // be done at some point in the future or if it's already time to do it. - // Only do these checks if did_work is false. If did_work is true, this - // function, and therefore any additional delayed work, will get another - // chance to run before the loop goes to sleep. - bool more_delayed_work = !next_time.is_null(); - if (more_delayed_work) { - TimeDelta delay = next_time - TimeTicks::Now(); - if (delay > TimeDelta()) { - // There's more delayed work to be done in the future. - ScheduleDelayedWork(next_time); - } else { - // There's more delayed work to be done, and its time is in the past. - // Arrange to come back here directly as long as the loop is still - // running. - resignal_work_source = true; - } - } - } - - if (resignal_work_source) { - CFRunLoopSourceSignal(work_source_); - } - - return resignal_work_source; -} - -// Called from the run loop. -// static -void MessagePumpCFRunLoopBase::RunIdleWorkSource(void* info) { - MessagePumpCFRunLoopBase* self = static_cast(info); - self->RunIdleWork(); -} - -// Called by MessagePumpCFRunLoopBase::RunIdleWorkSource. -bool MessagePumpCFRunLoopBase::RunIdleWork() { - if (!delegate_) { - // This point can be reached with a NULL delegate_ if Run is not on the - // stack but foreign code is spinning the CFRunLoop. Arrange to come back - // here when a delegate is available. - delegateless_idle_work_ = true; - return false; - } - - // The NSApplication-based run loop only drains the autorelease pool at each - // UI event (NSEvent). The autorelease pool is not drained for each - // CFRunLoopSource target that's run. Use a local pool for any autoreleased - // objects if the app is not currently handling a UI event to ensure they're - // released promptly even in the absence of UI events. - MessagePumpScopedAutoreleasePool autorelease_pool(this); - - // Call DoIdleWork once, and if something was done, arrange to come back here - // again as long as the loop is still running. - bool did_work = delegate_->DoIdleWork(); - if (did_work) { - CFRunLoopSourceSignal(idle_work_source_); - } - - return did_work; -} - -// Called from the run loop. -// static -void MessagePumpCFRunLoopBase::RunNestingDeferredWorkSource(void* info) { - MessagePumpCFRunLoopBase* self = static_cast(info); - self->RunNestingDeferredWork(); -} - -// Called by MessagePumpCFRunLoopBase::RunNestingDeferredWorkSource. -bool MessagePumpCFRunLoopBase::RunNestingDeferredWork() { - if (!delegate_) { - // This point can be reached with a NULL delegate_ if Run is not on the - // stack but foreign code is spinning the CFRunLoop. There's no sense in - // attempting to do any work or signalling the work sources because - // without a delegate, work is not possible. - return false; - } - - // Immediately try work in priority order. - if (!RunWork()) { - if (!RunIdleWork()) { - return false; - } - } else { - // Work was done. Arrange for the loop to try non-nestable idle work on - // a subsequent pass. - CFRunLoopSourceSignal(idle_work_source_); - } - - return true; -} - -// Called before the run loop goes to sleep or exits, or processes sources. -void MessagePumpCFRunLoopBase::MaybeScheduleNestingDeferredWork() { - // deepest_nesting_level_ is set as run loops are entered. If the deepest - // level encountered is deeper than the current level, a nested loop - // (relative to the current level) ran since the last time nesting-deferred - // work was scheduled. When that situation is encountered, schedule - // nesting-deferred work in case any work was deferred because nested work - // was disallowed. - if (deepest_nesting_level_ > nesting_level_) { - deepest_nesting_level_ = nesting_level_; - CFRunLoopSourceSignal(nesting_deferred_work_source_); - } -} - -// Called from the run loop. -// static -void MessagePumpCFRunLoopBase::PreWaitObserver(CFRunLoopObserverRef observer, - CFRunLoopActivity activity, - void* info) { - MessagePumpCFRunLoopBase* self = static_cast(info); - - // Attempt to do some idle work before going to sleep. - self->RunIdleWork(); - - // The run loop is about to go to sleep. If any of the work done since it - // started or woke up resulted in a nested run loop running, - // nesting-deferred work may have accumulated. Schedule it for processing - // if appropriate. - self->MaybeScheduleNestingDeferredWork(); -} - -// Called from the run loop. -// static -void MessagePumpCFRunLoopBase::PreSourceObserver(CFRunLoopObserverRef observer, - CFRunLoopActivity activity, - void* info) { - MessagePumpCFRunLoopBase* self = static_cast(info); - - // The run loop has reached the top of the loop and is about to begin - // processing sources. If the last iteration of the loop at this nesting - // level did not sleep or exit, nesting-deferred work may have accumulated - // if a nested loop ran. Schedule nesting-deferred work for processing if - // appropriate. - self->MaybeScheduleNestingDeferredWork(); -} - -// Called from the run loop. -// static -void MessagePumpCFRunLoopBase::EnterExitObserver(CFRunLoopObserverRef observer, - CFRunLoopActivity activity, - void* info) { - MessagePumpCFRunLoopBase* self = static_cast(info); - - switch (activity) { - case kCFRunLoopEntry: - ++self->nesting_level_; - if (self->nesting_level_ > self->deepest_nesting_level_) { - self->deepest_nesting_level_ = self->nesting_level_; - } - break; - - case kCFRunLoopExit: - // Not all run loops go to sleep. If a run loop is stopped before it - // goes to sleep due to a CFRunLoopStop call, or if the timeout passed - // to CFRunLoopRunInMode expires, the run loop may proceed directly from - // handling sources to exiting without any sleep. This most commonly - // occurs when CFRunLoopRunInMode is passed a timeout of 0, causing it - // to make a single pass through the loop and exit without sleep. Some - // native loops use CFRunLoop in this way. Because PreWaitObserver will - // not be called in these case, MaybeScheduleNestingDeferredWork needs - // to be called here, as the run loop exits. - // - // MaybeScheduleNestingDeferredWork consults self->nesting_level_ - // to determine whether to schedule nesting-deferred work. It expects - // the nesting level to be set to the depth of the loop that is going - // to sleep or exiting. It must be called before decrementing the - // value so that the value still corresponds to the level of the exiting - // loop. - self->MaybeScheduleNestingDeferredWork(); - --self->nesting_level_; - break; - - default: - break; - } - - self->EnterExitRunLoop(activity); -} - -// Called by MessagePumpCFRunLoopBase::EnterExitRunLoop. The default -// implementation is a no-op. -void MessagePumpCFRunLoopBase::EnterExitRunLoop(CFRunLoopActivity activity) { -} - -// Base version returns a standard NSAutoreleasePool. -NSAutoreleasePool* MessagePumpCFRunLoopBase::CreateAutoreleasePool() { - return [[NSAutoreleasePool alloc] init]; -} - -MessagePumpCFRunLoop::MessagePumpCFRunLoop() - : quit_pending_(false) { -} - -MessagePumpCFRunLoop::~MessagePumpCFRunLoop() {} - -// Called by MessagePumpCFRunLoopBase::DoRun. If other CFRunLoopRun loops were -// running lower on the run loop thread's stack when this object was created, -// the same number of CFRunLoopRun loops must be running for the outermost call -// to Run. Run/DoRun are reentrant after that point. -void MessagePumpCFRunLoop::DoRun(Delegate* delegate) { - // This is completely identical to calling CFRunLoopRun(), except autorelease - // pool management is introduced. - int result; - do { - MessagePumpScopedAutoreleasePool autorelease_pool(this); - result = CFRunLoopRunInMode(kCFRunLoopDefaultMode, - kCFTimeIntervalMax, - false); - } while (result != kCFRunLoopRunStopped && result != kCFRunLoopRunFinished); -} - -// Must be called on the run loop thread. -void MessagePumpCFRunLoop::Quit() { - // Stop the innermost run loop managed by this MessagePumpCFRunLoop object. - if (nesting_level() == run_nesting_level()) { - // This object is running the innermost loop, just stop it. - CFRunLoopStop(run_loop()); - } else { - // There's another loop running inside the loop managed by this object. - // In other words, someone else called CFRunLoopRunInMode on the same - // thread, deeper on the stack than the deepest Run call. Don't preempt - // other run loops, just mark this object to quit the innermost Run as - // soon as the other inner loops not managed by Run are done. - quit_pending_ = true; - } -} - -// Called by MessagePumpCFRunLoopBase::EnterExitObserver. -void MessagePumpCFRunLoop::EnterExitRunLoop(CFRunLoopActivity activity) { - if (activity == kCFRunLoopExit && - nesting_level() == run_nesting_level() && - quit_pending_) { - // Quit was called while loops other than those managed by this object - // were running further inside a run loop managed by this object. Now - // that all unmanaged inner run loops are gone, stop the loop running - // just inside Run. - CFRunLoopStop(run_loop()); - quit_pending_ = false; - } -} - -MessagePumpNSRunLoop::MessagePumpNSRunLoop() - : keep_running_(true) { - CFRunLoopSourceContext source_context = CFRunLoopSourceContext(); - source_context.perform = NoOp; - quit_source_ = CFRunLoopSourceCreate(NULL, // allocator - 0, // priority - &source_context); - CFRunLoopAddSource(run_loop(), quit_source_, kCFRunLoopCommonModes); -} - -MessagePumpNSRunLoop::~MessagePumpNSRunLoop() { - CFRunLoopRemoveSource(run_loop(), quit_source_, kCFRunLoopCommonModes); - CFRelease(quit_source_); -} - -void MessagePumpNSRunLoop::DoRun(Delegate* delegate) { - while (keep_running_) { - // NSRunLoop manages autorelease pools itself. - [[NSRunLoop currentRunLoop] runMode:NSDefaultRunLoopMode - beforeDate:[NSDate distantFuture]]; - } - - keep_running_ = true; -} - -void MessagePumpNSRunLoop::Quit() { - keep_running_ = false; - CFRunLoopSourceSignal(quit_source_); - CFRunLoopWakeUp(run_loop()); -} - -#if defined(OS_IOS) -MessagePumpUIApplication::MessagePumpUIApplication() - : run_loop_(NULL) { -} - -MessagePumpUIApplication::~MessagePumpUIApplication() {} - -void MessagePumpUIApplication::DoRun(Delegate* delegate) { - NOTREACHED(); -} - -void MessagePumpUIApplication::Quit() { - NOTREACHED(); -} - -void MessagePumpUIApplication::Attach(Delegate* delegate) { - DCHECK(!run_loop_); - run_loop_ = new RunLoop(); - CHECK(run_loop_->BeforeRun()); - SetDelegate(delegate); -} - -#else - -MessagePumpNSApplication::MessagePumpNSApplication() - : keep_running_(true), - running_own_loop_(false) { -} - -MessagePumpNSApplication::~MessagePumpNSApplication() {} - -void MessagePumpNSApplication::DoRun(Delegate* delegate) { - bool last_running_own_loop_ = running_own_loop_; - - // NSApp must be initialized by calling: - // [{some class which implements CrAppProtocol} sharedApplication] - // Most likely candidates are CrApplication or BrowserCrApplication. - // These can be initialized from C++ code by calling - // RegisterCrApp() or RegisterBrowserCrApp(). - CHECK(NSApp); - - if (![NSApp isRunning]) { - running_own_loop_ = false; - // NSApplication manages autorelease pools itself when run this way. - [NSApp run]; - } else { - running_own_loop_ = true; - NSDate* distant_future = [NSDate distantFuture]; - while (keep_running_) { - MessagePumpScopedAutoreleasePool autorelease_pool(this); - NSEvent* event = [NSApp nextEventMatchingMask:NSAnyEventMask - untilDate:distant_future - inMode:NSDefaultRunLoopMode - dequeue:YES]; - if (event) { - [NSApp sendEvent:event]; - } - } - keep_running_ = true; - } - - running_own_loop_ = last_running_own_loop_; -} - -void MessagePumpNSApplication::Quit() { - if (!running_own_loop_) { - [[NSApplication sharedApplication] stop:nil]; - } else { - keep_running_ = false; - } - - // Send a fake event to wake the loop up. - [NSApp postEvent:[NSEvent otherEventWithType:NSApplicationDefined - location:NSZeroPoint - modifierFlags:0 - timestamp:0 - windowNumber:0 - context:NULL - subtype:0 - data1:0 - data2:0] - atStart:NO]; -} - -MessagePumpCrApplication::MessagePumpCrApplication() { -} - -MessagePumpCrApplication::~MessagePumpCrApplication() { -} - -// Prevents an autorelease pool from being created if the app is in the midst of -// handling a UI event because various parts of AppKit depend on objects that -// are created while handling a UI event to be autoreleased in the event loop. -// An example of this is NSWindowController. When a window with a window -// controller is closed it goes through a stack like this: -// (Several stack frames elided for clarity) -// -// #0 [NSWindowController autorelease] -// #1 DoAClose -// #2 MessagePumpCFRunLoopBase::DoWork() -// #3 [NSRunLoop run] -// #4 [NSButton performClick:] -// #5 [NSWindow sendEvent:] -// #6 [NSApp sendEvent:] -// #7 [NSApp run] -// -// -performClick: spins a nested run loop. If the pool created in DoWork was a -// standard NSAutoreleasePool, it would release the objects that were -// autoreleased into it once DoWork released it. This would cause the window -// controller, which autoreleased itself in frame #0, to release itself, and -// possibly free itself. Unfortunately this window controller controls the -// window in frame #5. When the stack is unwound to frame #5, the window would -// no longer exists and crashes may occur. Apple gets around this by never -// releasing the pool it creates in frame #4, and letting frame #7 clean it up -// when it cleans up the pool that wraps frame #7. When an autorelease pool is -// released it releases all other pools that were created after it on the -// autorelease pool stack. -// -// CrApplication is responsible for setting handlingSendEvent to true just -// before it sends the event through the event handling mechanism, and -// returning it to its previous value once the event has been sent. -NSAutoreleasePool* MessagePumpCrApplication::CreateAutoreleasePool() { - if (MessagePumpMac::IsHandlingSendEvent()) - return nil; - return MessagePumpNSApplication::CreateAutoreleasePool(); -} - -// static -bool MessagePumpMac::UsingCrApp() { - DCHECK([NSThread isMainThread]); - - // If NSApp is still not initialized, then the subclass used cannot - // be determined. - DCHECK(NSApp); - - // The pump was created using MessagePumpNSApplication. - if (g_not_using_cr_app) - return false; - - return [NSApp conformsToProtocol:@protocol(CrAppProtocol)]; -} - -// static -bool MessagePumpMac::IsHandlingSendEvent() { - DCHECK([NSApp conformsToProtocol:@protocol(CrAppProtocol)]); - NSObject* app = static_cast*>(NSApp); - return [app isHandlingSendEvent]; -} -#endif // !defined(OS_IOS) - -// static -MessagePump* MessagePumpMac::Create() { - if ([NSThread isMainThread]) { -#if defined(OS_IOS) - return new MessagePumpUIApplication; -#else - if ([NSApp conformsToProtocol:@protocol(CrAppProtocol)]) - return new MessagePumpCrApplication; - - // The main-thread MessagePump implementations REQUIRE an NSApp. - // Executables which have specific requirements for their - // NSApplication subclass should initialize appropriately before - // creating an event loop. - [NSApplication sharedApplication]; - g_not_using_cr_app = true; - return new MessagePumpNSApplication; -#endif - } - - return new MessagePumpNSRunLoop; -} - -} // namespace base diff --git a/base/message_loop/message_pump_observer.h b/base/message_loop/message_pump_observer.h deleted file mode 100644 index cb46fa35b8..0000000000 --- a/base/message_loop/message_pump_observer.h +++ /dev/null @@ -1,47 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef BASE_MESSAGE_LOOP_MESSAGE_PUMP_OBSERVER_H -#define BASE_MESSAGE_LOOP_MESSAGE_PUMP_OBSERVER_H - -#include "base/base_export.h" -#include "base/event_types.h" - -namespace base { - -enum EventStatus { - EVENT_CONTINUE, // The event should be dispatched as normal. -#if defined(USE_X11) - EVENT_HANDLED // The event should not be processed any farther. -#endif -}; - -// A MessagePumpObserver is an object that receives global -// notifications from the UI MessageLoop with MessagePumpWin or -// MessagePumpAuraX11. -// -// NOTE: An Observer implementation should be extremely fast! -// -// For use with MessagePumpAuraX11, please see message_pump_glib.h for more -// info about how this is invoked in this environment. -class BASE_EXPORT MessagePumpObserver { - public: - // This method is called before processing a NativeEvent. If the - // method returns EVENT_HANDLED, it indicates the event has already - // been handled, so the event is not processed any farther. If the - // method returns EVENT_CONTINUE, the event dispatching proceeds as - // normal. - virtual EventStatus WillProcessEvent(const NativeEvent& event) = 0; - - // This method is called after processing a message. This method - // will not be called if WillProcessEvent returns EVENT_HANDLED. - virtual void DidProcessEvent(const NativeEvent& event) = 0; - - protected: - virtual ~MessagePumpObserver() {} -}; - -} // namespace base - -#endif // BASE_MESSAGE_LOOP_MESSAGE_PUMP_OBSERVER_H diff --git a/base/message_loop/message_pump_ozone.cc b/base/message_loop/message_pump_ozone.cc deleted file mode 100644 index f7bff6d3ac..0000000000 --- a/base/message_loop/message_pump_ozone.cc +++ /dev/null @@ -1,61 +0,0 @@ -// Copyright (c) 2013 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "base/message_loop/message_pump_ozone.h" - -#include "base/logging.h" -#include "base/message_loop/message_loop.h" - -namespace base { - -MessagePumpOzone::MessagePumpOzone() - : MessagePumpLibevent() { -} - -MessagePumpOzone::~MessagePumpOzone() { -} - -void MessagePumpOzone::AddObserver(MessagePumpObserver* /* observer */) { - NOTIMPLEMENTED(); -} - -void MessagePumpOzone::RemoveObserver(MessagePumpObserver* /* observer */) { - NOTIMPLEMENTED(); -} - -// static -MessagePumpOzone* MessagePumpOzone::Current() { - MessageLoopForUI* loop = MessageLoopForUI::current(); - return static_cast(loop->pump_ui()); -} - -void MessagePumpOzone::AddDispatcherForRootWindow( - MessagePumpDispatcher* dispatcher) { - // Only one root window is supported. - DCHECK(dispatcher_.size() == 0); - dispatcher_.insert(dispatcher_.begin(),dispatcher); -} - -void MessagePumpOzone::RemoveDispatcherForRootWindow( - MessagePumpDispatcher* dispatcher) { - DCHECK(dispatcher_.size() == 1); - dispatcher_.pop_back(); -} - -bool MessagePumpOzone::Dispatch(const NativeEvent& dev) { - if (dispatcher_.size() > 0) - return dispatcher_[0]->Dispatch(dev); - else - return true; -} - -// This code assumes that the caller tracks the lifetime of the |dispatcher|. -void MessagePumpOzone::RunWithDispatcher( - Delegate* delegate, MessagePumpDispatcher* dispatcher) { - dispatcher_.push_back(dispatcher); - Run(delegate); - dispatcher_.pop_back(); -} - -} // namespace base diff --git a/base/message_loop/message_pump_ozone.h b/base/message_loop/message_pump_ozone.h deleted file mode 100644 index edcdf2e3a8..0000000000 --- a/base/message_loop/message_pump_ozone.h +++ /dev/null @@ -1,52 +0,0 @@ -// Copyright (c) 2013 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef BASE_MESSAGE_LOOP_MESSAGE_PUMP_OZONE_H_ -#define BASE_MESSAGE_LOOP_MESSAGE_PUMP_OZONE_H_ - -#include "base/memory/scoped_ptr.h" -#include "base/memory/scoped_vector.h" -#include "base/message_loop/message_pump_dispatcher.h" -#include "base/message_loop/message_pump_libevent.h" -#include "base/message_loop/message_pump_observer.h" -#include "base/observer_list.h" - -namespace base { - -// This class implements a message-pump for processing events from input devices -// Refer to MessagePump for further documentation. -class BASE_EXPORT MessagePumpOzone : public MessagePumpLibevent, - public MessagePumpDispatcher { - public: - MessagePumpOzone(); - virtual ~MessagePumpOzone(); - - // Returns the UI message pump. - static MessagePumpOzone* Current(); - - // Add/Remove the root window dispatcher. - void AddDispatcherForRootWindow(MessagePumpDispatcher* dispatcher); - void RemoveDispatcherForRootWindow(MessagePumpDispatcher* dispatcher); - - void RunWithDispatcher(Delegate* delegate, MessagePumpDispatcher* dispatcher); - - // Add / remove an Observer, which will start receiving notifications - // immediately. - void AddObserver(MessagePumpObserver* observer); - void RemoveObserver(MessagePumpObserver* observer); - - // Overridden from MessagePumpDispatcher. - virtual bool Dispatch(const NativeEvent& event) OVERRIDE; - - private: - std::vector dispatcher_; - - DISALLOW_COPY_AND_ASSIGN(MessagePumpOzone); -}; - -typedef MessagePumpOzone MessagePumpForUI; - -} // namespace base - -#endif // BASE_MESSAGE_LOOP_MESSAGE_PUMP_OZONE_H_ diff --git a/base/message_loop/message_pump_win.cc b/base/message_loop/message_pump_win.cc deleted file mode 100644 index 589d077541..0000000000 --- a/base/message_loop/message_pump_win.cc +++ /dev/null @@ -1,686 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "base/message_loop/message_pump_win.h" - -#include - -#include "base/debug/trace_event.h" -#include "base/message_loop/message_loop.h" -#include "base/metrics/histogram.h" -#include "base/process/memory.h" -#include "base/strings/stringprintf.h" -#include "base/win/wrapped_window_proc.h" - -namespace base { - -namespace { - -enum MessageLoopProblems { - MESSAGE_POST_ERROR, - COMPLETION_POST_ERROR, - SET_TIMER_ERROR, - MESSAGE_LOOP_PROBLEM_MAX, -}; - -} // namespace - -static const wchar_t kWndClassFormat[] = L"Chrome_MessagePumpWindow_%p"; - -// Message sent to get an additional time slice for pumping (processing) another -// task (a series of such messages creates a continuous task pump). -static const int kMsgHaveWork = WM_USER + 1; - -//----------------------------------------------------------------------------- -// MessagePumpWin public: - -void MessagePumpWin::AddObserver(MessagePumpObserver* observer) { - observers_.AddObserver(observer); -} - -void MessagePumpWin::RemoveObserver(MessagePumpObserver* observer) { - observers_.RemoveObserver(observer); -} - -void MessagePumpWin::WillProcessMessage(const MSG& msg) { - FOR_EACH_OBSERVER(MessagePumpObserver, observers_, WillProcessEvent(msg)); -} - -void MessagePumpWin::DidProcessMessage(const MSG& msg) { - FOR_EACH_OBSERVER(MessagePumpObserver, observers_, DidProcessEvent(msg)); -} - -void MessagePumpWin::RunWithDispatcher( - Delegate* delegate, MessagePumpDispatcher* dispatcher) { - RunState s; - s.delegate = delegate; - s.dispatcher = dispatcher; - s.should_quit = false; - s.run_depth = state_ ? state_->run_depth + 1 : 1; - - RunState* previous_state = state_; - state_ = &s; - - DoRunLoop(); - - state_ = previous_state; -} - -void MessagePumpWin::Quit() { - DCHECK(state_); - state_->should_quit = true; -} - -//----------------------------------------------------------------------------- -// MessagePumpWin protected: - -int MessagePumpWin::GetCurrentDelay() const { - if (delayed_work_time_.is_null()) - return -1; - - // Be careful here. TimeDelta has a precision of microseconds, but we want a - // value in milliseconds. If there are 5.5ms left, should the delay be 5 or - // 6? It should be 6 to avoid executing delayed work too early. - double timeout = - ceil((delayed_work_time_ - TimeTicks::Now()).InMillisecondsF()); - - // If this value is negative, then we need to run delayed work soon. - int delay = static_cast(timeout); - if (delay < 0) - delay = 0; - - return delay; -} - -//----------------------------------------------------------------------------- -// MessagePumpForUI public: - -MessagePumpForUI::MessagePumpForUI() - : atom_(0), - message_filter_(new MessageFilter) { - InitMessageWnd(); -} - -MessagePumpForUI::~MessagePumpForUI() { - DestroyWindow(message_hwnd_); - UnregisterClass(MAKEINTATOM(atom_), - GetModuleFromAddress(&WndProcThunk)); -} - -void MessagePumpForUI::ScheduleWork() { - if (InterlockedExchange(&have_work_, 1)) - return; // Someone else continued the pumping. - - // Make sure the MessagePump does some work for us. - BOOL ret = PostMessage(message_hwnd_, kMsgHaveWork, - reinterpret_cast(this), 0); - if (ret) - return; // There was room in the Window Message queue. - - // We have failed to insert a have-work message, so there is a chance that we - // will starve tasks/timers while sitting in a nested message loop. Nested - // loops only look at Windows Message queues, and don't look at *our* task - // queues, etc., so we might not get a time slice in such. :-( - // We could abort here, but the fear is that this failure mode is plausibly - // common (queue is full, of about 2000 messages), so we'll do a near-graceful - // recovery. Nested loops are pretty transient (we think), so this will - // probably be recoverable. - InterlockedExchange(&have_work_, 0); // Clarify that we didn't really insert. - UMA_HISTOGRAM_ENUMERATION("Chrome.MessageLoopProblem", MESSAGE_POST_ERROR, - MESSAGE_LOOP_PROBLEM_MAX); -} - -void MessagePumpForUI::ScheduleDelayedWork(const TimeTicks& delayed_work_time) { - // - // We would *like* to provide high resolution timers. Windows timers using - // SetTimer() have a 10ms granularity. We have to use WM_TIMER as a wakeup - // mechanism because the application can enter modal windows loops where it - // is not running our MessageLoop; the only way to have our timers fire in - // these cases is to post messages there. - // - // To provide sub-10ms timers, we process timers directly from our run loop. - // For the common case, timers will be processed there as the run loop does - // its normal work. However, we *also* set the system timer so that WM_TIMER - // events fire. This mops up the case of timers not being able to work in - // modal message loops. It is possible for the SetTimer to pop and have no - // pending timers, because they could have already been processed by the - // run loop itself. - // - // We use a single SetTimer corresponding to the timer that will expire - // soonest. As new timers are created and destroyed, we update SetTimer. - // Getting a spurrious SetTimer event firing is benign, as we'll just be - // processing an empty timer queue. - // - delayed_work_time_ = delayed_work_time; - - int delay_msec = GetCurrentDelay(); - DCHECK_GE(delay_msec, 0); - if (delay_msec < USER_TIMER_MINIMUM) - delay_msec = USER_TIMER_MINIMUM; - - // Create a WM_TIMER event that will wake us up to check for any pending - // timers (in case we are running within a nested, external sub-pump). - BOOL ret = SetTimer(message_hwnd_, reinterpret_cast(this), - delay_msec, NULL); - if (ret) - return; - // If we can't set timers, we are in big trouble... but cross our fingers for - // now. - // TODO(jar): If we don't see this error, use a CHECK() here instead. - UMA_HISTOGRAM_ENUMERATION("Chrome.MessageLoopProblem", SET_TIMER_ERROR, - MESSAGE_LOOP_PROBLEM_MAX); -} - -void MessagePumpForUI::PumpOutPendingPaintMessages() { - // If we are being called outside of the context of Run, then don't try to do - // any work. - if (!state_) - return; - - // Create a mini-message-pump to force immediate processing of only Windows - // WM_PAINT messages. Don't provide an infinite loop, but do enough peeking - // to get the job done. Actual common max is 4 peeks, but we'll be a little - // safe here. - const int kMaxPeekCount = 20; - int peek_count; - for (peek_count = 0; peek_count < kMaxPeekCount; ++peek_count) { - MSG msg; - if (!PeekMessage(&msg, NULL, 0, 0, PM_REMOVE | PM_QS_PAINT)) - break; - ProcessMessageHelper(msg); - if (state_->should_quit) // Handle WM_QUIT. - break; - } - // Histogram what was really being used, to help to adjust kMaxPeekCount. - DHISTOGRAM_COUNTS("Loop.PumpOutPendingPaintMessages Peeks", peek_count); -} - -//----------------------------------------------------------------------------- -// MessagePumpForUI private: - -// static -LRESULT CALLBACK MessagePumpForUI::WndProcThunk( - HWND hwnd, UINT message, WPARAM wparam, LPARAM lparam) { - switch (message) { - case kMsgHaveWork: - reinterpret_cast(wparam)->HandleWorkMessage(); - break; - case WM_TIMER: - reinterpret_cast(wparam)->HandleTimerMessage(); - break; - } - return DefWindowProc(hwnd, message, wparam, lparam); -} - -void MessagePumpForUI::DoRunLoop() { - // IF this was just a simple PeekMessage() loop (servicing all possible work - // queues), then Windows would try to achieve the following order according - // to MSDN documentation about PeekMessage with no filter): - // * Sent messages - // * Posted messages - // * Sent messages (again) - // * WM_PAINT messages - // * WM_TIMER messages - // - // Summary: none of the above classes is starved, and sent messages has twice - // the chance of being processed (i.e., reduced service time). - - for (;;) { - // If we do any work, we may create more messages etc., and more work may - // possibly be waiting in another task group. When we (for example) - // ProcessNextWindowsMessage(), there is a good chance there are still more - // messages waiting. On the other hand, when any of these methods return - // having done no work, then it is pretty unlikely that calling them again - // quickly will find any work to do. Finally, if they all say they had no - // work, then it is a good time to consider sleeping (waiting) for more - // work. - - bool more_work_is_plausible = ProcessNextWindowsMessage(); - if (state_->should_quit) - break; - - more_work_is_plausible |= state_->delegate->DoWork(); - if (state_->should_quit) - break; - - more_work_is_plausible |= - state_->delegate->DoDelayedWork(&delayed_work_time_); - // If we did not process any delayed work, then we can assume that our - // existing WM_TIMER if any will fire when delayed work should run. We - // don't want to disturb that timer if it is already in flight. However, - // if we did do all remaining delayed work, then lets kill the WM_TIMER. - if (more_work_is_plausible && delayed_work_time_.is_null()) - KillTimer(message_hwnd_, reinterpret_cast(this)); - if (state_->should_quit) - break; - - if (more_work_is_plausible) - continue; - - more_work_is_plausible = state_->delegate->DoIdleWork(); - if (state_->should_quit) - break; - - if (more_work_is_plausible) - continue; - - WaitForWork(); // Wait (sleep) until we have work to do again. - } -} - -void MessagePumpForUI::InitMessageWnd() { - // Generate a unique window class name. - string16 class_name = StringPrintf(kWndClassFormat, this); - - HINSTANCE instance = GetModuleFromAddress(&WndProcThunk); - WNDCLASSEX wc = {0}; - wc.cbSize = sizeof(wc); - wc.lpfnWndProc = base::win::WrappedWindowProc; - wc.hInstance = instance; - wc.lpszClassName = class_name.c_str(); - atom_ = RegisterClassEx(&wc); - DCHECK(atom_); - - message_hwnd_ = CreateWindow(MAKEINTATOM(atom_), 0, 0, 0, 0, 0, 0, - HWND_MESSAGE, 0, instance, 0); - DCHECK(message_hwnd_); -} - -void MessagePumpForUI::WaitForWork() { - // Wait until a message is available, up to the time needed by the timer - // manager to fire the next set of timers. - int delay = GetCurrentDelay(); - if (delay < 0) // Negative value means no timers waiting. - delay = INFINITE; - - DWORD result; - result = MsgWaitForMultipleObjectsEx(0, NULL, delay, QS_ALLINPUT, - MWMO_INPUTAVAILABLE); - - if (WAIT_OBJECT_0 == result) { - // A WM_* message is available. - // If a parent child relationship exists between windows across threads - // then their thread inputs are implicitly attached. - // This causes the MsgWaitForMultipleObjectsEx API to return indicating - // that messages are ready for processing (Specifically, mouse messages - // intended for the child window may appear if the child window has - // capture). - // The subsequent PeekMessages call may fail to return any messages thus - // causing us to enter a tight loop at times. - // The WaitMessage call below is a workaround to give the child window - // some time to process its input messages. - MSG msg = {0}; - DWORD queue_status = GetQueueStatus(QS_MOUSE); - if (HIWORD(queue_status) & QS_MOUSE && - !PeekMessage(&msg, NULL, WM_MOUSEFIRST, WM_MOUSELAST, PM_NOREMOVE)) { - WaitMessage(); - } - return; - } - - DCHECK_NE(WAIT_FAILED, result) << GetLastError(); -} - -void MessagePumpForUI::HandleWorkMessage() { - // If we are being called outside of the context of Run, then don't try to do - // any work. This could correspond to a MessageBox call or something of that - // sort. - if (!state_) { - // Since we handled a kMsgHaveWork message, we must still update this flag. - InterlockedExchange(&have_work_, 0); - return; - } - - // Let whatever would have run had we not been putting messages in the queue - // run now. This is an attempt to make our dummy message not starve other - // messages that may be in the Windows message queue. - ProcessPumpReplacementMessage(); - - // Now give the delegate a chance to do some work. He'll let us know if he - // needs to do more work. - if (state_->delegate->DoWork()) - ScheduleWork(); -} - -void MessagePumpForUI::HandleTimerMessage() { - KillTimer(message_hwnd_, reinterpret_cast(this)); - - // If we are being called outside of the context of Run, then don't do - // anything. This could correspond to a MessageBox call or something of - // that sort. - if (!state_) - return; - - state_->delegate->DoDelayedWork(&delayed_work_time_); - if (!delayed_work_time_.is_null()) { - // A bit gratuitous to set delayed_work_time_ again, but oh well. - ScheduleDelayedWork(delayed_work_time_); - } -} - -bool MessagePumpForUI::ProcessNextWindowsMessage() { - // If there are sent messages in the queue then PeekMessage internally - // dispatches the message and returns false. We return true in this - // case to ensure that the message loop peeks again instead of calling - // MsgWaitForMultipleObjectsEx again. - bool sent_messages_in_queue = false; - DWORD queue_status = GetQueueStatus(QS_SENDMESSAGE); - if (HIWORD(queue_status) & QS_SENDMESSAGE) - sent_messages_in_queue = true; - - MSG msg; - if (message_filter_->DoPeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) - return ProcessMessageHelper(msg); - - return sent_messages_in_queue; -} - -bool MessagePumpForUI::ProcessMessageHelper(const MSG& msg) { - TRACE_EVENT1("base", "MessagePumpForUI::ProcessMessageHelper", - "message", msg.message); - if (WM_QUIT == msg.message) { - // Repost the QUIT message so that it will be retrieved by the primary - // GetMessage() loop. - state_->should_quit = true; - PostQuitMessage(static_cast(msg.wParam)); - return false; - } - - // While running our main message pump, we discard kMsgHaveWork messages. - if (msg.message == kMsgHaveWork && msg.hwnd == message_hwnd_) - return ProcessPumpReplacementMessage(); - - if (CallMsgFilter(const_cast(&msg), kMessageFilterCode)) - return true; - - WillProcessMessage(msg); - - if (!message_filter_->ProcessMessage(msg)) { - if (state_->dispatcher) { - if (!state_->dispatcher->Dispatch(msg)) - state_->should_quit = true; - } else { - TranslateMessage(&msg); - DispatchMessage(&msg); - } - } - - DidProcessMessage(msg); - return true; -} - -bool MessagePumpForUI::ProcessPumpReplacementMessage() { - // When we encounter a kMsgHaveWork message, this method is called to peek - // and process a replacement message, such as a WM_PAINT or WM_TIMER. The - // goal is to make the kMsgHaveWork as non-intrusive as possible, even though - // a continuous stream of such messages are posted. This method carefully - // peeks a message while there is no chance for a kMsgHaveWork to be pending, - // then resets the have_work_ flag (allowing a replacement kMsgHaveWork to - // possibly be posted), and finally dispatches that peeked replacement. Note - // that the re-post of kMsgHaveWork may be asynchronous to this thread!! - - bool have_message = false; - MSG msg; - // We should not process all window messages if we are in the context of an - // OS modal loop, i.e. in the context of a windows API call like MessageBox. - // This is to ensure that these messages are peeked out by the OS modal loop. - if (MessageLoop::current()->os_modal_loop()) { - // We only peek out WM_PAINT and WM_TIMER here for reasons mentioned above. - have_message = PeekMessage(&msg, NULL, WM_PAINT, WM_PAINT, PM_REMOVE) || - PeekMessage(&msg, NULL, WM_TIMER, WM_TIMER, PM_REMOVE); - } else { - have_message = !!message_filter_->DoPeekMessage(&msg, NULL, 0, 0, - PM_REMOVE); - } - - DCHECK(!have_message || kMsgHaveWork != msg.message || - msg.hwnd != message_hwnd_); - - // Since we discarded a kMsgHaveWork message, we must update the flag. - int old_have_work = InterlockedExchange(&have_work_, 0); - DCHECK(old_have_work); - - // We don't need a special time slice if we didn't have_message to process. - if (!have_message) - return false; - - // Guarantee we'll get another time slice in the case where we go into native - // windows code. This ScheduleWork() may hurt performance a tiny bit when - // tasks appear very infrequently, but when the event queue is busy, the - // kMsgHaveWork events get (percentage wise) rarer and rarer. - ScheduleWork(); - return ProcessMessageHelper(msg); -} - -void MessagePumpForUI::SetMessageFilter( - scoped_ptr message_filter) { - message_filter_ = message_filter.Pass(); -} - -//----------------------------------------------------------------------------- -// MessagePumpForIO public: - -MessagePumpForIO::MessagePumpForIO() { - port_.Set(CreateIoCompletionPort(INVALID_HANDLE_VALUE, NULL, NULL, 1)); - DCHECK(port_.IsValid()); -} - -void MessagePumpForIO::ScheduleWork() { - if (InterlockedExchange(&have_work_, 1)) - return; // Someone else continued the pumping. - - // Make sure the MessagePump does some work for us. - BOOL ret = PostQueuedCompletionStatus(port_, 0, - reinterpret_cast(this), - reinterpret_cast(this)); - if (ret) - return; // Post worked perfectly. - - // See comment in MessagePumpForUI::ScheduleWork() for this error recovery. - InterlockedExchange(&have_work_, 0); // Clarify that we didn't succeed. - UMA_HISTOGRAM_ENUMERATION("Chrome.MessageLoopProblem", COMPLETION_POST_ERROR, - MESSAGE_LOOP_PROBLEM_MAX); -} - -void MessagePumpForIO::ScheduleDelayedWork(const TimeTicks& delayed_work_time) { - // We know that we can't be blocked right now since this method can only be - // called on the same thread as Run, so we only need to update our record of - // how long to sleep when we do sleep. - delayed_work_time_ = delayed_work_time; -} - -void MessagePumpForIO::RegisterIOHandler(HANDLE file_handle, - IOHandler* handler) { - ULONG_PTR key = HandlerToKey(handler, true); - HANDLE port = CreateIoCompletionPort(file_handle, port_, key, 1); - DPCHECK(port); -} - -bool MessagePumpForIO::RegisterJobObject(HANDLE job_handle, - IOHandler* handler) { - // Job object notifications use the OVERLAPPED pointer to carry the message - // data. Mark the completion key correspondingly, so we will not try to - // convert OVERLAPPED* to IOContext*. - ULONG_PTR key = HandlerToKey(handler, false); - JOBOBJECT_ASSOCIATE_COMPLETION_PORT info; - info.CompletionKey = reinterpret_cast(key); - info.CompletionPort = port_; - return SetInformationJobObject(job_handle, - JobObjectAssociateCompletionPortInformation, - &info, - sizeof(info)) != FALSE; -} - -//----------------------------------------------------------------------------- -// MessagePumpForIO private: - -void MessagePumpForIO::DoRunLoop() { - for (;;) { - // If we do any work, we may create more messages etc., and more work may - // possibly be waiting in another task group. When we (for example) - // WaitForIOCompletion(), there is a good chance there are still more - // messages waiting. On the other hand, when any of these methods return - // having done no work, then it is pretty unlikely that calling them - // again quickly will find any work to do. Finally, if they all say they - // had no work, then it is a good time to consider sleeping (waiting) for - // more work. - - bool more_work_is_plausible = state_->delegate->DoWork(); - if (state_->should_quit) - break; - - more_work_is_plausible |= WaitForIOCompletion(0, NULL); - if (state_->should_quit) - break; - - more_work_is_plausible |= - state_->delegate->DoDelayedWork(&delayed_work_time_); - if (state_->should_quit) - break; - - if (more_work_is_plausible) - continue; - - more_work_is_plausible = state_->delegate->DoIdleWork(); - if (state_->should_quit) - break; - - if (more_work_is_plausible) - continue; - - WaitForWork(); // Wait (sleep) until we have work to do again. - } -} - -// Wait until IO completes, up to the time needed by the timer manager to fire -// the next set of timers. -void MessagePumpForIO::WaitForWork() { - // We do not support nested IO message loops. This is to avoid messy - // recursion problems. - DCHECK_EQ(1, state_->run_depth) << "Cannot nest an IO message loop!"; - - int timeout = GetCurrentDelay(); - if (timeout < 0) // Negative value means no timers waiting. - timeout = INFINITE; - - WaitForIOCompletion(timeout, NULL); -} - -bool MessagePumpForIO::WaitForIOCompletion(DWORD timeout, IOHandler* filter) { - IOItem item; - if (completed_io_.empty() || !MatchCompletedIOItem(filter, &item)) { - // We have to ask the system for another IO completion. - if (!GetIOItem(timeout, &item)) - return false; - - if (ProcessInternalIOItem(item)) - return true; - } - - // If |item.has_valid_io_context| is false then |item.context| does not point - // to a context structure, and so should not be dereferenced, although it may - // still hold valid non-pointer data. - if (!item.has_valid_io_context || item.context->handler) { - if (filter && item.handler != filter) { - // Save this item for later - completed_io_.push_back(item); - } else { - DCHECK(!item.has_valid_io_context || - (item.context->handler == item.handler)); - WillProcessIOEvent(); - item.handler->OnIOCompleted(item.context, item.bytes_transfered, - item.error); - DidProcessIOEvent(); - } - } else { - // The handler must be gone by now, just cleanup the mess. - delete item.context; - } - return true; -} - -// Asks the OS for another IO completion result. -bool MessagePumpForIO::GetIOItem(DWORD timeout, IOItem* item) { - memset(item, 0, sizeof(*item)); - ULONG_PTR key = NULL; - OVERLAPPED* overlapped = NULL; - if (!GetQueuedCompletionStatus(port_.Get(), &item->bytes_transfered, &key, - &overlapped, timeout)) { - if (!overlapped) - return false; // Nothing in the queue. - item->error = GetLastError(); - item->bytes_transfered = 0; - } - - item->handler = KeyToHandler(key, &item->has_valid_io_context); - item->context = reinterpret_cast(overlapped); - return true; -} - -bool MessagePumpForIO::ProcessInternalIOItem(const IOItem& item) { - if (this == reinterpret_cast(item.context) && - this == reinterpret_cast(item.handler)) { - // This is our internal completion. - DCHECK(!item.bytes_transfered); - InterlockedExchange(&have_work_, 0); - return true; - } - return false; -} - -// Returns a completion item that was previously received. -bool MessagePumpForIO::MatchCompletedIOItem(IOHandler* filter, IOItem* item) { - DCHECK(!completed_io_.empty()); - for (std::list::iterator it = completed_io_.begin(); - it != completed_io_.end(); ++it) { - if (!filter || it->handler == filter) { - *item = *it; - completed_io_.erase(it); - return true; - } - } - return false; -} - -void MessagePumpForIO::AddIOObserver(IOObserver *obs) { - io_observers_.AddObserver(obs); -} - -void MessagePumpForIO::RemoveIOObserver(IOObserver *obs) { - io_observers_.RemoveObserver(obs); -} - -void MessagePumpForIO::WillProcessIOEvent() { - FOR_EACH_OBSERVER(IOObserver, io_observers_, WillProcessIOEvent()); -} - -void MessagePumpForIO::DidProcessIOEvent() { - FOR_EACH_OBSERVER(IOObserver, io_observers_, DidProcessIOEvent()); -} - -// static -ULONG_PTR MessagePumpForIO::HandlerToKey(IOHandler* handler, - bool has_valid_io_context) { - ULONG_PTR key = reinterpret_cast(handler); - - // |IOHandler| is at least pointer-size aligned, so the lowest two bits are - // always cleared. We use the lowest bit to distinguish completion keys with - // and without the associated |IOContext|. - DCHECK((key & 1) == 0); - - // Mark the completion key as context-less. - if (!has_valid_io_context) - key = key | 1; - return key; -} - -// static -MessagePumpForIO::IOHandler* MessagePumpForIO::KeyToHandler( - ULONG_PTR key, - bool* has_valid_io_context) { - *has_valid_io_context = ((key & 1) == 0); - return reinterpret_cast(key & ~static_cast(1)); -} - -} // namespace base diff --git a/base/message_loop/message_pump_win.h b/base/message_loop/message_pump_win.h deleted file mode 100644 index 2d833540e0..0000000000 --- a/base/message_loop/message_pump_win.h +++ /dev/null @@ -1,396 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef BASE_MESSAGE_LOOP_MESSAGE_PUMP_WIN_H_ -#define BASE_MESSAGE_LOOP_MESSAGE_PUMP_WIN_H_ - -#include - -#include - -#include "base/base_export.h" -#include "base/basictypes.h" -#include "base/memory/scoped_ptr.h" -#include "base/message_loop/message_pump.h" -#include "base/message_loop/message_pump_dispatcher.h" -#include "base/message_loop/message_pump_observer.h" -#include "base/observer_list.h" -#include "base/time/time.h" -#include "base/win/scoped_handle.h" - -namespace base { - -// MessagePumpWin serves as the base for specialized versions of the MessagePump -// for Windows. It provides basic functionality like handling of observers and -// controlling the lifetime of the message pump. -class BASE_EXPORT MessagePumpWin : public MessagePump { - public: - MessagePumpWin() : have_work_(0), state_(NULL) {} - virtual ~MessagePumpWin() {} - - // Add an Observer, which will start receiving notifications immediately. - void AddObserver(MessagePumpObserver* observer); - - // Remove an Observer. It is safe to call this method while an Observer is - // receiving a notification callback. - void RemoveObserver(MessagePumpObserver* observer); - - // Give a chance to code processing additional messages to notify the - // message loop observers that another message has been processed. - void WillProcessMessage(const MSG& msg); - void DidProcessMessage(const MSG& msg); - - // Like MessagePump::Run, but MSG objects are routed through dispatcher. - void RunWithDispatcher(Delegate* delegate, MessagePumpDispatcher* dispatcher); - - // MessagePump methods: - virtual void Run(Delegate* delegate) { RunWithDispatcher(delegate, NULL); } - virtual void Quit(); - - protected: - struct RunState { - Delegate* delegate; - MessagePumpDispatcher* dispatcher; - - // Used to flag that the current Run() invocation should return ASAP. - bool should_quit; - - // Used to count how many Run() invocations are on the stack. - int run_depth; - }; - - virtual void DoRunLoop() = 0; - int GetCurrentDelay() const; - - ObserverList observers_; - - // The time at which delayed work should run. - TimeTicks delayed_work_time_; - - // A boolean value used to indicate if there is a kMsgDoWork message pending - // in the Windows Message queue. There is at most one such message, and it - // can drive execution of tasks when a native message pump is running. - LONG have_work_; - - // State for the current invocation of Run. - RunState* state_; -}; - -//----------------------------------------------------------------------------- -// MessagePumpForUI extends MessagePumpWin with methods that are particular to a -// MessageLoop instantiated with TYPE_UI. -// -// MessagePumpForUI implements a "traditional" Windows message pump. It contains -// a nearly infinite loop that peeks out messages, and then dispatches them. -// Intermixed with those peeks are callouts to DoWork for pending tasks, and -// DoDelayedWork for pending timers. When there are no events to be serviced, -// this pump goes into a wait state. In most cases, this message pump handles -// all processing. -// -// However, when a task, or windows event, invokes on the stack a native dialog -// box or such, that window typically provides a bare bones (native?) message -// pump. That bare-bones message pump generally supports little more than a -// peek of the Windows message queue, followed by a dispatch of the peeked -// message. MessageLoop extends that bare-bones message pump to also service -// Tasks, at the cost of some complexity. -// -// The basic structure of the extension (refered to as a sub-pump) is that a -// special message, kMsgHaveWork, is repeatedly injected into the Windows -// Message queue. Each time the kMsgHaveWork message is peeked, checks are -// made for an extended set of events, including the availability of Tasks to -// run. -// -// After running a task, the special message kMsgHaveWork is again posted to -// the Windows Message queue, ensuring a future time slice for processing a -// future event. To prevent flooding the Windows Message queue, care is taken -// to be sure that at most one kMsgHaveWork message is EVER pending in the -// Window's Message queue. -// -// There are a few additional complexities in this system where, when there are -// no Tasks to run, this otherwise infinite stream of messages which drives the -// sub-pump is halted. The pump is automatically re-started when Tasks are -// queued. -// -// A second complexity is that the presence of this stream of posted tasks may -// prevent a bare-bones message pump from ever peeking a WM_PAINT or WM_TIMER. -// Such paint and timer events always give priority to a posted message, such as -// kMsgHaveWork messages. As a result, care is taken to do some peeking in -// between the posting of each kMsgHaveWork message (i.e., after kMsgHaveWork -// is peeked, and before a replacement kMsgHaveWork is posted). -// -// NOTE: Although it may seem odd that messages are used to start and stop this -// flow (as opposed to signaling objects, etc.), it should be understood that -// the native message pump will *only* respond to messages. As a result, it is -// an excellent choice. It is also helpful that the starter messages that are -// placed in the queue when new task arrive also awakens DoRunLoop. -// -class BASE_EXPORT MessagePumpForUI : public MessagePumpWin { - public: - // A MessageFilter implements the common Peek/Translate/Dispatch code to deal - // with windows messages. - // This abstraction is used to inject TSF message peeking. See - // TextServicesMessageFilter. - class BASE_EXPORT MessageFilter { - public: - virtual ~MessageFilter() {} - // Implements the functionality exposed by the OS through PeekMessage. - virtual BOOL DoPeekMessage(MSG* msg, - HWND window_handle, - UINT msg_filter_min, - UINT msg_filter_max, - UINT remove_msg) { - return PeekMessage(msg, window_handle, msg_filter_min, msg_filter_max, - remove_msg); - } - // Returns true if |message| was consumed by the filter and no extra - // processing is required. If this method returns false, it is the - // responsibility of the caller to ensure that normal processing takes - // place. - // The priority to consume messages is the following: - // - Native Windows' message filter (CallMsgFilter). - // - MessageFilter::ProcessMessage. - // - MessagePumpDispatcher. - // - TranslateMessage / DispatchMessage. - virtual bool ProcessMessage(const MSG& msg) { return false;} - }; - // The application-defined code passed to the hook procedure. - static const int kMessageFilterCode = 0x5001; - - MessagePumpForUI(); - virtual ~MessagePumpForUI(); - - // Sets a new MessageFilter. MessagePumpForUI takes ownership of - // |message_filter|. When SetMessageFilter is called, old MessageFilter is - // deleted. - void SetMessageFilter(scoped_ptr message_filter); - - // MessagePump methods: - virtual void ScheduleWork(); - virtual void ScheduleDelayedWork(const TimeTicks& delayed_work_time); - - // Applications can call this to encourage us to process all pending WM_PAINT - // messages. This method will process all paint messages the Windows Message - // queue can provide, up to some fixed number (to avoid any infinite loops). - void PumpOutPendingPaintMessages(); - - private: - static LRESULT CALLBACK WndProcThunk(HWND window_handle, - UINT message, - WPARAM wparam, - LPARAM lparam); - virtual void DoRunLoop(); - void InitMessageWnd(); - void WaitForWork(); - void HandleWorkMessage(); - void HandleTimerMessage(); - bool ProcessNextWindowsMessage(); - bool ProcessMessageHelper(const MSG& msg); - bool ProcessPumpReplacementMessage(); - - // Atom representing the registered window class. - ATOM atom_; - - // A hidden message-only window. - HWND message_hwnd_; - - scoped_ptr message_filter_; -}; - -//----------------------------------------------------------------------------- -// MessagePumpForIO extends MessagePumpWin with methods that are particular to a -// MessageLoop instantiated with TYPE_IO. This version of MessagePump does not -// deal with Windows mesagges, and instead has a Run loop based on Completion -// Ports so it is better suited for IO operations. -// -class BASE_EXPORT MessagePumpForIO : public MessagePumpWin { - public: - struct IOContext; - - // Clients interested in receiving OS notifications when asynchronous IO - // operations complete should implement this interface and register themselves - // with the message pump. - // - // Typical use #1: - // // Use only when there are no user's buffers involved on the actual IO, - // // so that all the cleanup can be done by the message pump. - // class MyFile : public IOHandler { - // MyFile() { - // ... - // context_ = new IOContext; - // context_->handler = this; - // message_pump->RegisterIOHandler(file_, this); - // } - // ~MyFile() { - // if (pending_) { - // // By setting the handler to NULL, we're asking for this context - // // to be deleted when received, without calling back to us. - // context_->handler = NULL; - // } else { - // delete context_; - // } - // } - // virtual void OnIOCompleted(IOContext* context, DWORD bytes_transfered, - // DWORD error) { - // pending_ = false; - // } - // void DoSomeIo() { - // ... - // // The only buffer required for this operation is the overlapped - // // structure. - // ConnectNamedPipe(file_, &context_->overlapped); - // pending_ = true; - // } - // bool pending_; - // IOContext* context_; - // HANDLE file_; - // }; - // - // Typical use #2: - // class MyFile : public IOHandler { - // MyFile() { - // ... - // message_pump->RegisterIOHandler(file_, this); - // } - // // Plus some code to make sure that this destructor is not called - // // while there are pending IO operations. - // ~MyFile() { - // } - // virtual void OnIOCompleted(IOContext* context, DWORD bytes_transfered, - // DWORD error) { - // ... - // delete context; - // } - // void DoSomeIo() { - // ... - // IOContext* context = new IOContext; - // // This is not used for anything. It just prevents the context from - // // being considered "abandoned". - // context->handler = this; - // ReadFile(file_, buffer, num_bytes, &read, &context->overlapped); - // } - // HANDLE file_; - // }; - // - // Typical use #3: - // Same as the previous example, except that in order to deal with the - // requirement stated for the destructor, the class calls WaitForIOCompletion - // from the destructor to block until all IO finishes. - // ~MyFile() { - // while(pending_) - // message_pump->WaitForIOCompletion(INFINITE, this); - // } - // - class IOHandler { - public: - virtual ~IOHandler() {} - // This will be called once the pending IO operation associated with - // |context| completes. |error| is the Win32 error code of the IO operation - // (ERROR_SUCCESS if there was no error). |bytes_transfered| will be zero - // on error. - virtual void OnIOCompleted(IOContext* context, DWORD bytes_transfered, - DWORD error) = 0; - }; - - // An IOObserver is an object that receives IO notifications from the - // MessagePump. - // - // NOTE: An IOObserver implementation should be extremely fast! - class IOObserver { - public: - IOObserver() {} - - virtual void WillProcessIOEvent() = 0; - virtual void DidProcessIOEvent() = 0; - - protected: - virtual ~IOObserver() {} - }; - - // The extended context that should be used as the base structure on every - // overlapped IO operation. |handler| must be set to the registered IOHandler - // for the given file when the operation is started, and it can be set to NULL - // before the operation completes to indicate that the handler should not be - // called anymore, and instead, the IOContext should be deleted when the OS - // notifies the completion of this operation. Please remember that any buffers - // involved with an IO operation should be around until the callback is - // received, so this technique can only be used for IO that do not involve - // additional buffers (other than the overlapped structure itself). - struct IOContext { - OVERLAPPED overlapped; - IOHandler* handler; - }; - - MessagePumpForIO(); - virtual ~MessagePumpForIO() {} - - // MessagePump methods: - virtual void ScheduleWork(); - virtual void ScheduleDelayedWork(const TimeTicks& delayed_work_time); - - // Register the handler to be used when asynchronous IO for the given file - // completes. The registration persists as long as |file_handle| is valid, so - // |handler| must be valid as long as there is pending IO for the given file. - void RegisterIOHandler(HANDLE file_handle, IOHandler* handler); - - // Register the handler to be used to process job events. The registration - // persists as long as the job object is live, so |handler| must be valid - // until the job object is destroyed. Returns true if the registration - // succeeded, and false otherwise. - bool RegisterJobObject(HANDLE job_handle, IOHandler* handler); - - // Waits for the next IO completion that should be processed by |filter|, for - // up to |timeout| milliseconds. Return true if any IO operation completed, - // regardless of the involved handler, and false if the timeout expired. If - // the completion port received any message and the involved IO handler - // matches |filter|, the callback is called before returning from this code; - // if the handler is not the one that we are looking for, the callback will - // be postponed for another time, so reentrancy problems can be avoided. - // External use of this method should be reserved for the rare case when the - // caller is willing to allow pausing regular task dispatching on this thread. - bool WaitForIOCompletion(DWORD timeout, IOHandler* filter); - - void AddIOObserver(IOObserver* obs); - void RemoveIOObserver(IOObserver* obs); - - private: - struct IOItem { - IOHandler* handler; - IOContext* context; - DWORD bytes_transfered; - DWORD error; - - // In some cases |context| can be a non-pointer value casted to a pointer. - // |has_valid_io_context| is true if |context| is a valid IOContext - // pointer, and false otherwise. - bool has_valid_io_context; - }; - - virtual void DoRunLoop(); - void WaitForWork(); - bool MatchCompletedIOItem(IOHandler* filter, IOItem* item); - bool GetIOItem(DWORD timeout, IOItem* item); - bool ProcessInternalIOItem(const IOItem& item); - void WillProcessIOEvent(); - void DidProcessIOEvent(); - - // Converts an IOHandler pointer to a completion port key. - // |has_valid_io_context| specifies whether completion packets posted to - // |handler| will have valid OVERLAPPED pointers. - static ULONG_PTR HandlerToKey(IOHandler* handler, bool has_valid_io_context); - - // Converts a completion port key to an IOHandler pointer. - static IOHandler* KeyToHandler(ULONG_PTR key, bool* has_valid_io_context); - - // The completion port associated with this thread. - win::ScopedHandle port_; - // This list will be empty almost always. It stores IO completions that have - // not been delivered yet because somebody was doing cleanup. - std::list completed_io_; - - ObserverList io_observers_; -}; - -} // namespace base - -#endif // BASE_MESSAGE_LOOP_MESSAGE_PUMP_WIN_H_ diff --git a/base/metrics/OWNERS b/base/metrics/OWNERS deleted file mode 100644 index 17a19451a2..0000000000 --- a/base/metrics/OWNERS +++ /dev/null @@ -1,8 +0,0 @@ -# Primary OWNER -jar@chromium.org - -# Secondary OWNER; can review simpler changes -isherman@chromium.org - -# Note that all members of the parent file base/OWNERS can also stamp trivial -# changes, but will probably defer to Jim for meatier changes. diff --git a/base/metrics/bucket_ranges.cc b/base/metrics/bucket_ranges.cc deleted file mode 100644 index 949c813e46..0000000000 --- a/base/metrics/bucket_ranges.cc +++ /dev/null @@ -1,139 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "base/metrics/bucket_ranges.h" - -#include - -#include "base/logging.h" - -namespace base { - -// Static table of checksums for all possible 8 bit bytes. -const uint32 kCrcTable[256] = { 0x0, 0x77073096L, 0xee0e612cL, -0x990951baL, 0x76dc419L, 0x706af48fL, 0xe963a535L, 0x9e6495a3L, 0xedb8832L, -0x79dcb8a4L, 0xe0d5e91eL, 0x97d2d988L, 0x9b64c2bL, 0x7eb17cbdL, 0xe7b82d07L, -0x90bf1d91L, 0x1db71064L, 0x6ab020f2L, 0xf3b97148L, 0x84be41deL, 0x1adad47dL, -0x6ddde4ebL, 0xf4d4b551L, 0x83d385c7L, 0x136c9856L, 0x646ba8c0L, 0xfd62f97aL, -0x8a65c9ecL, 0x14015c4fL, 0x63066cd9L, 0xfa0f3d63L, 0x8d080df5L, 0x3b6e20c8L, -0x4c69105eL, 0xd56041e4L, 0xa2677172L, 0x3c03e4d1L, 0x4b04d447L, 0xd20d85fdL, -0xa50ab56bL, 0x35b5a8faL, 0x42b2986cL, 0xdbbbc9d6L, 0xacbcf940L, 0x32d86ce3L, -0x45df5c75L, 0xdcd60dcfL, 0xabd13d59L, 0x26d930acL, 0x51de003aL, 0xc8d75180L, -0xbfd06116L, 0x21b4f4b5L, 0x56b3c423L, 0xcfba9599L, 0xb8bda50fL, 0x2802b89eL, -0x5f058808L, 0xc60cd9b2L, 0xb10be924L, 0x2f6f7c87L, 0x58684c11L, 0xc1611dabL, -0xb6662d3dL, 0x76dc4190L, 0x1db7106L, 0x98d220bcL, 0xefd5102aL, 0x71b18589L, -0x6b6b51fL, 0x9fbfe4a5L, 0xe8b8d433L, 0x7807c9a2L, 0xf00f934L, 0x9609a88eL, -0xe10e9818L, 0x7f6a0dbbL, 0x86d3d2dL, 0x91646c97L, 0xe6635c01L, 0x6b6b51f4L, -0x1c6c6162L, 0x856530d8L, 0xf262004eL, 0x6c0695edL, 0x1b01a57bL, 0x8208f4c1L, -0xf50fc457L, 0x65b0d9c6L, 0x12b7e950L, 0x8bbeb8eaL, 0xfcb9887cL, 0x62dd1ddfL, -0x15da2d49L, 0x8cd37cf3L, 0xfbd44c65L, 0x4db26158L, 0x3ab551ceL, 0xa3bc0074L, -0xd4bb30e2L, 0x4adfa541L, 0x3dd895d7L, 0xa4d1c46dL, 0xd3d6f4fbL, 0x4369e96aL, -0x346ed9fcL, 0xad678846L, 0xda60b8d0L, 0x44042d73L, 0x33031de5L, 0xaa0a4c5fL, -0xdd0d7cc9L, 0x5005713cL, 0x270241aaL, 0xbe0b1010L, 0xc90c2086L, 0x5768b525L, -0x206f85b3L, 0xb966d409L, 0xce61e49fL, 0x5edef90eL, 0x29d9c998L, 0xb0d09822L, -0xc7d7a8b4L, 0x59b33d17L, 0x2eb40d81L, 0xb7bd5c3bL, 0xc0ba6cadL, 0xedb88320L, -0x9abfb3b6L, 0x3b6e20cL, 0x74b1d29aL, 0xead54739L, 0x9dd277afL, 0x4db2615L, -0x73dc1683L, 0xe3630b12L, 0x94643b84L, 0xd6d6a3eL, 0x7a6a5aa8L, 0xe40ecf0bL, -0x9309ff9dL, 0xa00ae27L, 0x7d079eb1L, 0xf00f9344L, 0x8708a3d2L, 0x1e01f268L, -0x6906c2feL, 0xf762575dL, 0x806567cbL, 0x196c3671L, 0x6e6b06e7L, 0xfed41b76L, -0x89d32be0L, 0x10da7a5aL, 0x67dd4accL, 0xf9b9df6fL, 0x8ebeeff9L, 0x17b7be43L, -0x60b08ed5L, 0xd6d6a3e8L, 0xa1d1937eL, 0x38d8c2c4L, 0x4fdff252L, 0xd1bb67f1L, -0xa6bc5767L, 0x3fb506ddL, 0x48b2364bL, 0xd80d2bdaL, 0xaf0a1b4cL, 0x36034af6L, -0x41047a60L, 0xdf60efc3L, 0xa867df55L, 0x316e8eefL, 0x4669be79L, 0xcb61b38cL, -0xbc66831aL, 0x256fd2a0L, 0x5268e236L, 0xcc0c7795L, 0xbb0b4703L, 0x220216b9L, -0x5505262fL, 0xc5ba3bbeL, 0xb2bd0b28L, 0x2bb45a92L, 0x5cb36a04L, 0xc2d7ffa7L, -0xb5d0cf31L, 0x2cd99e8bL, 0x5bdeae1dL, 0x9b64c2b0L, 0xec63f226L, 0x756aa39cL, -0x26d930aL, 0x9c0906a9L, 0xeb0e363fL, 0x72076785L, 0x5005713L, 0x95bf4a82L, -0xe2b87a14L, 0x7bb12baeL, 0xcb61b38L, 0x92d28e9bL, 0xe5d5be0dL, 0x7cdcefb7L, -0xbdbdf21L, 0x86d3d2d4L, 0xf1d4e242L, 0x68ddb3f8L, 0x1fda836eL, 0x81be16cdL, -0xf6b9265bL, 0x6fb077e1L, 0x18b74777L, 0x88085ae6L, 0xff0f6a70L, 0x66063bcaL, -0x11010b5cL, 0x8f659effL, 0xf862ae69L, 0x616bffd3L, 0x166ccf45L, 0xa00ae278L, -0xd70dd2eeL, 0x4e048354L, 0x3903b3c2L, 0xa7672661L, 0xd06016f7L, 0x4969474dL, -0x3e6e77dbL, 0xaed16a4aL, 0xd9d65adcL, 0x40df0b66L, 0x37d83bf0L, 0xa9bcae53L, -0xdebb9ec5L, 0x47b2cf7fL, 0x30b5ffe9L, 0xbdbdf21cL, 0xcabac28aL, 0x53b39330L, -0x24b4a3a6L, 0xbad03605L, 0xcdd70693L, 0x54de5729L, 0x23d967bfL, 0xb3667a2eL, -0xc4614ab8L, 0x5d681b02L, 0x2a6f2b94L, 0xb40bbe37L, 0xc30c8ea1L, 0x5a05df1bL, -0x2d02ef8dL, -}; - -// We generate the CRC-32 using the low order bits to select whether to XOR in -// the reversed polynomial 0xedb88320L. This is nice and simple, and allows us -// to keep the quotient in a uint32. Since we're not concerned about the nature -// of corruptions (i.e., we don't care about bit sequencing, since we are -// handling memory changes, which are more grotesque) so we don't bother to -// get the CRC correct for big-endian vs little-ending calculations. All we -// need is a nice hash, that tends to depend on all the bits of the sample, with -// very little chance of changes in one place impacting changes in another -// place. -static uint32 Crc32(uint32 sum, HistogramBase::Sample value) { - // TODO(jar): Switch to false and watch stats. - const bool kUseRealCrc = true; - - if (kUseRealCrc) { - union { - HistogramBase::Sample range; - unsigned char bytes[sizeof(HistogramBase::Sample)]; - } converter; - converter.range = value; - for (size_t i = 0; i < sizeof(converter); ++i) - sum = kCrcTable[(sum & 0xff) ^ converter.bytes[i]] ^ (sum >> 8); - } else { - // Use hash techniques provided in ReallyFastHash, except we don't care - // about "avalanching" (which would worsten the hash, and add collisions), - // and we don't care about edge cases since we have an even number of bytes. - union { - HistogramBase::Sample range; - uint16 ints[sizeof(HistogramBase::Sample) / 2]; - } converter; - DCHECK_EQ(sizeof(HistogramBase::Sample), sizeof(converter)); - converter.range = value; - sum += converter.ints[0]; - sum = (sum << 16) ^ sum ^ (static_cast(converter.ints[1]) << 11); - sum += sum >> 11; - } - return sum; -} - -BucketRanges::BucketRanges(size_t num_ranges) - : ranges_(num_ranges, 0), - checksum_(0) {} - -BucketRanges::~BucketRanges() {} - -void BucketRanges::set_range(size_t i, HistogramBase::Sample value) { - DCHECK_LT(i, ranges_.size()); - CHECK_GE(value, 0); - ranges_[i] = value; -} - -uint32 BucketRanges::CalculateChecksum() const { - // Seed checksum. - uint32 checksum = static_cast(ranges_.size()); - - for (size_t index = 0; index < ranges_.size(); ++index) - checksum = Crc32(checksum, ranges_[index]); - return checksum; -} - -bool BucketRanges::HasValidChecksum() const { - return CalculateChecksum() == checksum_; -} - -void BucketRanges::ResetChecksum() { - checksum_ = CalculateChecksum(); -} - -bool BucketRanges::Equals(const BucketRanges* other) const { - if (checksum_ != other->checksum_) - return false; - if (ranges_.size() != other->ranges_.size()) - return false; - for (size_t index = 0; index < ranges_.size(); ++index) { - if (ranges_[index] != other->ranges_[index]) - return false; - } - return true; -} - -} // namespace base diff --git a/base/metrics/bucket_ranges.h b/base/metrics/bucket_ranges.h deleted file mode 100644 index fe1152f5db..0000000000 --- a/base/metrics/bucket_ranges.h +++ /dev/null @@ -1,79 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. -// -// BucketRanges stores the vector of ranges that delimit what samples are -// tallied in the corresponding buckets of a histogram. Histograms that have -// same ranges for all their corresponding buckets should share the same -// BucketRanges object. -// -// E.g. A 5 buckets LinearHistogram with 1 as minimal value and 4 as maximal -// value will need a BucketRanges with 6 ranges: -// 0, 1, 2, 3, 4, INT_MAX -// -// TODO(kaiwang): Currently we keep all negative values in 0~1 bucket. Consider -// changing 0 to INT_MIN. - -#ifndef BASE_METRICS_BUCKET_RANGES_H_ -#define BASE_METRICS_BUCKET_RANGES_H_ - -#include - -#include "base/base_export.h" -#include "base/basictypes.h" -#include "base/gtest_prod_util.h" -#include "base/metrics/histogram_base.h" - -namespace base { - -class BASE_EXPORT BucketRanges { - public: - typedef std::vector Ranges; - - explicit BucketRanges(size_t num_ranges); - ~BucketRanges(); - - size_t size() const { return ranges_.size(); } - HistogramBase::Sample range(size_t i) const { return ranges_[i]; } - void set_range(size_t i, HistogramBase::Sample value); - uint32 checksum() const { return checksum_; } - void set_checksum(uint32 checksum) { checksum_ = checksum; } - - // A bucket is defined by a consecutive pair of entries in |ranges|, so there - // is one fewer bucket than there are ranges. For example, if |ranges| is - // [0, 1, 3, 7, INT_MAX], then the buckets in this histogram are - // [0, 1), [1, 3), [3, 7), and [7, INT_MAX). - size_t bucket_count() const { return ranges_.size() - 1; } - - // Checksum methods to verify whether the ranges are corrupted (e.g. bad - // memory access). - uint32 CalculateChecksum() const; - bool HasValidChecksum() const; - void ResetChecksum(); - - // Return true iff |other| object has same ranges_ as |this| object's ranges_. - bool Equals(const BucketRanges* other) const; - - private: - // A monotonically increasing list of values which determine which bucket to - // put a sample into. For each index, show the smallest sample that can be - // added to the corresponding bucket. - Ranges ranges_; - - // Checksum for the conntents of ranges_. Used to detect random over-writes - // of our data, and to quickly see if some other BucketRanges instance is - // possibly Equal() to this instance. - // TODO(kaiwang): Consider change this to uint64. Because we see a lot of - // noise on UMA dashboard. - uint32 checksum_; - - DISALLOW_COPY_AND_ASSIGN(BucketRanges); -}; - -////////////////////////////////////////////////////////////////////////////// -// Expose only for test. -BASE_EXPORT_PRIVATE extern const uint32 kCrcTable[256]; - -} // namespace base - -#endif // BASE_METRICS_BUCKET_RANGES_H_ diff --git a/base/metrics/bucket_ranges_unittest.cc b/base/metrics/bucket_ranges_unittest.cc deleted file mode 100644 index fc0699c733..0000000000 --- a/base/metrics/bucket_ranges_unittest.cc +++ /dev/null @@ -1,92 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "base/metrics/bucket_ranges.h" - -#include "testing/gtest/include/gtest/gtest.h" - -namespace base { -namespace { - -TEST(BucketRangesTest, NormalSetup) { - BucketRanges ranges(5); - ASSERT_EQ(5u, ranges.size()); - ASSERT_EQ(4u, ranges.bucket_count()); - - for (int i = 0; i < 5; ++i) { - EXPECT_EQ(0, ranges.range(i)); - } - EXPECT_EQ(0u, ranges.checksum()); - - ranges.set_range(3, 100); - EXPECT_EQ(100, ranges.range(3)); -} - -TEST(BucketRangesTest, Equals) { - // Compare empty ranges. - BucketRanges ranges1(3); - BucketRanges ranges2(3); - BucketRanges ranges3(5); - - EXPECT_TRUE(ranges1.Equals(&ranges2)); - EXPECT_FALSE(ranges1.Equals(&ranges3)); - EXPECT_FALSE(ranges2.Equals(&ranges3)); - - // Compare full filled ranges. - ranges1.set_range(0, 0); - ranges1.set_range(1, 1); - ranges1.set_range(2, 2); - ranges1.set_checksum(100); - ranges2.set_range(0, 0); - ranges2.set_range(1, 1); - ranges2.set_range(2, 2); - ranges2.set_checksum(100); - - EXPECT_TRUE(ranges1.Equals(&ranges2)); - - // Checksum does not match. - ranges1.set_checksum(99); - EXPECT_FALSE(ranges1.Equals(&ranges2)); - ranges1.set_checksum(100); - - // Range does not match. - ranges1.set_range(1, 3); - EXPECT_FALSE(ranges1.Equals(&ranges2)); -} - -TEST(BucketRangesTest, Checksum) { - BucketRanges ranges(3); - ranges.set_range(0, 0); - ranges.set_range(1, 1); - ranges.set_range(2, 2); - - ranges.ResetChecksum(); - EXPECT_EQ(289217253u, ranges.checksum()); - - ranges.set_range(2, 3); - EXPECT_FALSE(ranges.HasValidChecksum()); - - ranges.ResetChecksum(); - EXPECT_EQ(2843835776u, ranges.checksum()); - EXPECT_TRUE(ranges.HasValidChecksum()); -} - -// Table was generated similarly to sample code for CRC-32 given on: -// http://www.w3.org/TR/PNG/#D-CRCAppendix. -TEST(BucketRangesTest, Crc32TableTest) { - for (int i = 0; i < 256; ++i) { - uint32 checksum = i; - for (int j = 0; j < 8; ++j) { - const uint32 kReversedPolynomial = 0xedb88320L; - if (checksum & 1) - checksum = kReversedPolynomial ^ (checksum >> 1); - else - checksum >>= 1; - } - EXPECT_EQ(kCrcTable[i], checksum); - } -} - -} // namespace -} // namespace base diff --git a/base/metrics/field_trial.cc b/base/metrics/field_trial.cc deleted file mode 100644 index 4456a79716..0000000000 --- a/base/metrics/field_trial.cc +++ /dev/null @@ -1,505 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "base/metrics/field_trial.h" - -#include "base/build_time.h" -#include "base/logging.h" -#include "base/rand_util.h" -#include "base/sha1.h" -#include "base/strings/string_util.h" -#include "base/strings/stringprintf.h" -#include "base/strings/utf_string_conversions.h" -#include "base/sys_byteorder.h" - -namespace base { - -namespace { - -// Created a time value based on |year|, |month| and |day_of_month| parameters. -Time CreateTimeFromParams(int year, int month, int day_of_month) { - DCHECK_GT(year, 1970); - DCHECK_GT(month, 0); - DCHECK_LT(month, 13); - DCHECK_GT(day_of_month, 0); - DCHECK_LT(day_of_month, 32); - - Time::Exploded exploded; - exploded.year = year; - exploded.month = month; - exploded.day_of_week = 0; // Should be unused. - exploded.day_of_month = day_of_month; - exploded.hour = 0; - exploded.minute = 0; - exploded.second = 0; - exploded.millisecond = 0; - - return Time::FromLocalExploded(exploded); -} - -} // namespace - -static const char kHistogramFieldTrialSeparator('_'); - -// statics -const int FieldTrial::kNotFinalized = -1; -const int FieldTrial::kDefaultGroupNumber = 0; -bool FieldTrial::enable_benchmarking_ = false; - -const char FieldTrialList::kPersistentStringSeparator('/'); -int FieldTrialList::kNoExpirationYear = 0; - -//------------------------------------------------------------------------------ -// FieldTrial methods and members. - -FieldTrial::FieldTrial(const std::string& trial_name, - const Probability total_probability, - const std::string& default_group_name, - double entropy_value) - : trial_name_(trial_name), - divisor_(total_probability), - default_group_name_(default_group_name), - random_(static_cast(divisor_ * entropy_value)), - accumulated_group_probability_(0), - next_group_number_(kDefaultGroupNumber + 1), - group_(kNotFinalized), - enable_field_trial_(true), - forced_(false), - group_reported_(false) { - DCHECK_GT(total_probability, 0); - DCHECK(!trial_name_.empty()); - DCHECK(!default_group_name_.empty()); -} - -FieldTrial::EntropyProvider::~EntropyProvider() { -} - -void FieldTrial::Disable() { - DCHECK(!group_reported_); - enable_field_trial_ = false; - - // In case we are disabled after initialization, we need to switch - // the trial to the default group. - if (group_ != kNotFinalized) { - // Only reset when not already the default group, because in case we were - // forced to the default group, the group number may not be - // kDefaultGroupNumber, so we should keep it as is. - if (group_name_ != default_group_name_) - SetGroupChoice(default_group_name_, kDefaultGroupNumber); - } -} - -int FieldTrial::AppendGroup(const std::string& name, - Probability group_probability) { - // When the group choice was previously forced, we only need to return the - // the id of the chosen group, and anything can be returned for the others. - if (forced_) { - DCHECK(!group_name_.empty()); - if (name == group_name_) { - // Note that while |group_| may be equal to |kDefaultGroupNumber| on the - // forced trial, it will not have the same value as the default group - // number returned from the non-forced |FactoryGetFieldTrial()| call, - // which takes care to ensure that this does not happen. - return group_; - } - DCHECK_NE(next_group_number_, group_); - // We still return different numbers each time, in case some caller need - // them to be different. - return next_group_number_++; - } - - DCHECK_LE(group_probability, divisor_); - DCHECK_GE(group_probability, 0); - - if (enable_benchmarking_ || !enable_field_trial_) - group_probability = 0; - - accumulated_group_probability_ += group_probability; - - DCHECK_LE(accumulated_group_probability_, divisor_); - if (group_ == kNotFinalized && accumulated_group_probability_ > random_) { - // This is the group that crossed the random line, so we do the assignment. - SetGroupChoice(name, next_group_number_); - } - return next_group_number_++; -} - -int FieldTrial::group() { - FinalizeGroupChoice(); - FieldTrialList::NotifyFieldTrialGroupSelection(this); - return group_; -} - -const std::string& FieldTrial::group_name() { - // Call |group()| to ensure group gets assigned and observers are notified. - group(); - DCHECK(!group_name_.empty()); - return group_name_; -} - -// static -std::string FieldTrial::MakeName(const std::string& name_prefix, - const std::string& trial_name) { - std::string big_string(name_prefix); - big_string.append(1, kHistogramFieldTrialSeparator); - return big_string.append(FieldTrialList::FindFullName(trial_name)); -} - -// static -void FieldTrial::EnableBenchmarking() { - DCHECK_EQ(0u, FieldTrialList::GetFieldTrialCount()); - enable_benchmarking_ = true; -} - -void FieldTrial::SetForced() { - // We might have been forced before (e.g., by CreateFieldTrial) and it's - // first come first served, e.g., command line switch has precedence. - if (forced_) - return; - - // And we must finalize the group choice before we mark ourselves as forced. - FinalizeGroupChoice(); - forced_ = true; -} - -FieldTrial::~FieldTrial() {} - -void FieldTrial::SetGroupChoice(const std::string& group_name, int number) { - group_ = number; - if (group_name.empty()) - StringAppendF(&group_name_, "%d", group_); - else - group_name_ = group_name; - DVLOG(1) << "Field trial: " << trial_name_ << " Group choice:" << group_name_; -} - -void FieldTrial::FinalizeGroupChoice() { - if (group_ != kNotFinalized) - return; - accumulated_group_probability_ = divisor_; - // Here it's OK to use |kDefaultGroupNumber| since we can't be forced and not - // finalized. - DCHECK(!forced_); - SetGroupChoice(default_group_name_, kDefaultGroupNumber); -} - -bool FieldTrial::GetActiveGroup(ActiveGroup* active_group) const { - if (!group_reported_ || !enable_field_trial_) - return false; - DCHECK_NE(group_, kNotFinalized); - active_group->trial_name = trial_name_; - active_group->group_name = group_name_; - return true; -} - -//------------------------------------------------------------------------------ -// FieldTrialList methods and members. - -// static -FieldTrialList* FieldTrialList::global_ = NULL; - -// static -bool FieldTrialList::used_without_global_ = false; - -FieldTrialList::Observer::~Observer() { -} - -FieldTrialList::FieldTrialList( - const FieldTrial::EntropyProvider* entropy_provider) - : entropy_provider_(entropy_provider), - observer_list_(new ObserverListThreadSafe( - ObserverListBase::NOTIFY_EXISTING_ONLY)) { - DCHECK(!global_); - DCHECK(!used_without_global_); - global_ = this; - - Time two_years_from_build_time = GetBuildTime() + TimeDelta::FromDays(730); - Time::Exploded exploded; - two_years_from_build_time.LocalExplode(&exploded); - kNoExpirationYear = exploded.year; -} - -FieldTrialList::~FieldTrialList() { - AutoLock auto_lock(lock_); - while (!registered_.empty()) { - RegistrationList::iterator it = registered_.begin(); - it->second->Release(); - registered_.erase(it->first); - } - DCHECK_EQ(this, global_); - global_ = NULL; -} - -// static -FieldTrial* FieldTrialList::FactoryGetFieldTrial( - const std::string& trial_name, - FieldTrial::Probability total_probability, - const std::string& default_group_name, - const int year, - const int month, - const int day_of_month, - FieldTrial::RandomizationType randomization_type, - int* default_group_number) { - return FactoryGetFieldTrialWithRandomizationSeed( - trial_name, total_probability, default_group_name, - year, month, day_of_month, randomization_type, 0, default_group_number); -} - -// static -FieldTrial* FieldTrialList::FactoryGetFieldTrialWithRandomizationSeed( - const std::string& trial_name, - FieldTrial::Probability total_probability, - const std::string& default_group_name, - const int year, - const int month, - const int day_of_month, - FieldTrial::RandomizationType randomization_type, - uint32 randomization_seed, - int* default_group_number) { - if (default_group_number) - *default_group_number = FieldTrial::kDefaultGroupNumber; - // Check if the field trial has already been created in some other way. - FieldTrial* existing_trial = Find(trial_name); - if (existing_trial) { - CHECK(existing_trial->forced_); - // If the default group name differs between the existing forced trial - // and this trial, then use a different value for the default group number. - if (default_group_number && - default_group_name != existing_trial->default_group_name()) { - // If the new default group number corresponds to the group that was - // chosen for the forced trial (which has been finalized when it was - // forced), then set the default group number to that. - if (default_group_name == existing_trial->group_name_internal()) { - *default_group_number = existing_trial->group_; - } else { - // Otherwise, use |kNonConflictingGroupNumber| (-2) for the default - // group number, so that it does not conflict with the |AppendGroup()| - // result for the chosen group. - const int kNonConflictingGroupNumber = -2; - COMPILE_ASSERT( - kNonConflictingGroupNumber != FieldTrial::kDefaultGroupNumber, - conflicting_default_group_number); - COMPILE_ASSERT( - kNonConflictingGroupNumber != FieldTrial::kNotFinalized, - conflicting_default_group_number); - *default_group_number = kNonConflictingGroupNumber; - } - } - return existing_trial; - } - - double entropy_value; - if (randomization_type == FieldTrial::ONE_TIME_RANDOMIZED) { - entropy_value = GetEntropyProviderForOneTimeRandomization()-> - GetEntropyForTrial(trial_name, randomization_seed); - } else { - DCHECK_EQ(FieldTrial::SESSION_RANDOMIZED, randomization_type); - DCHECK_EQ(0U, randomization_seed); - entropy_value = RandDouble(); - } - - FieldTrial* field_trial = new FieldTrial(trial_name, total_probability, - default_group_name, entropy_value); - if (GetBuildTime() > CreateTimeFromParams(year, month, day_of_month)) - field_trial->Disable(); - FieldTrialList::Register(field_trial); - return field_trial; -} - -// static -FieldTrial* FieldTrialList::Find(const std::string& name) { - if (!global_) - return NULL; - AutoLock auto_lock(global_->lock_); - return global_->PreLockedFind(name); -} - -// static -int FieldTrialList::FindValue(const std::string& name) { - FieldTrial* field_trial = Find(name); - if (field_trial) - return field_trial->group(); - return FieldTrial::kNotFinalized; -} - -// static -std::string FieldTrialList::FindFullName(const std::string& name) { - FieldTrial* field_trial = Find(name); - if (field_trial) - return field_trial->group_name(); - return std::string(); -} - -// static -bool FieldTrialList::TrialExists(const std::string& name) { - return Find(name) != NULL; -} - -// static -void FieldTrialList::StatesToString(std::string* output) { - FieldTrial::ActiveGroups active_groups; - GetActiveFieldTrialGroups(&active_groups); - for (FieldTrial::ActiveGroups::const_iterator it = active_groups.begin(); - it != active_groups.end(); ++it) { - DCHECK_EQ(std::string::npos, - it->trial_name.find(kPersistentStringSeparator)); - DCHECK_EQ(std::string::npos, - it->group_name.find(kPersistentStringSeparator)); - output->append(it->trial_name); - output->append(1, kPersistentStringSeparator); - output->append(it->group_name); - output->append(1, kPersistentStringSeparator); - } -} - -// static -void FieldTrialList::GetActiveFieldTrialGroups( - FieldTrial::ActiveGroups* active_groups) { - DCHECK(active_groups->empty()); - if (!global_) - return; - AutoLock auto_lock(global_->lock_); - - for (RegistrationList::iterator it = global_->registered_.begin(); - it != global_->registered_.end(); ++it) { - FieldTrial::ActiveGroup active_group; - if (it->second->GetActiveGroup(&active_group)) - active_groups->push_back(active_group); - } -} - -// static -bool FieldTrialList::CreateTrialsFromString(const std::string& trials_string, - FieldTrialActivationMode mode) { - DCHECK(global_); - if (trials_string.empty() || !global_) - return true; - - size_t next_item = 0; - while (next_item < trials_string.length()) { - size_t name_end = trials_string.find(kPersistentStringSeparator, next_item); - if (name_end == trials_string.npos || next_item == name_end) - return false; - size_t group_name_end = trials_string.find(kPersistentStringSeparator, - name_end + 1); - if (group_name_end == trials_string.npos || name_end + 1 == group_name_end) - return false; - std::string name(trials_string, next_item, name_end - next_item); - std::string group_name(trials_string, name_end + 1, - group_name_end - name_end - 1); - next_item = group_name_end + 1; - - FieldTrial* trial = CreateFieldTrial(name, group_name); - if (!trial) - return false; - if (mode == ACTIVATE_TRIALS) { - // Call |group()| to mark the trial as "used" and notify observers, if - // any. This is useful to ensure that field trials created in child - // processes are properly reported in crash reports. - trial->group(); - } - } - return true; -} - -// static -FieldTrial* FieldTrialList::CreateFieldTrial( - const std::string& name, - const std::string& group_name) { - DCHECK(global_); - DCHECK_GE(name.size(), 0u); - DCHECK_GE(group_name.size(), 0u); - if (name.empty() || group_name.empty() || !global_) - return NULL; - - FieldTrial* field_trial = FieldTrialList::Find(name); - if (field_trial) { - // In single process mode, or when we force them from the command line, - // we may have already created the field trial. - if (field_trial->group_name_internal() != group_name) - return NULL; - return field_trial; - } - const int kTotalProbability = 100; - field_trial = new FieldTrial(name, kTotalProbability, group_name, 0); - // Force the trial, which will also finalize the group choice. - field_trial->SetForced(); - FieldTrialList::Register(field_trial); - return field_trial; -} - -// static -void FieldTrialList::AddObserver(Observer* observer) { - if (!global_) - return; - global_->observer_list_->AddObserver(observer); -} - -// static -void FieldTrialList::RemoveObserver(Observer* observer) { - if (!global_) - return; - global_->observer_list_->RemoveObserver(observer); -} - -// static -void FieldTrialList::NotifyFieldTrialGroupSelection(FieldTrial* field_trial) { - if (!global_) - return; - - { - AutoLock auto_lock(global_->lock_); - if (field_trial->group_reported_) - return; - field_trial->group_reported_ = true; - } - - if (!field_trial->enable_field_trial_) - return; - - global_->observer_list_->Notify( - &FieldTrialList::Observer::OnFieldTrialGroupFinalized, - field_trial->trial_name(), - field_trial->group_name_internal()); -} - -// static -size_t FieldTrialList::GetFieldTrialCount() { - if (!global_) - return 0; - AutoLock auto_lock(global_->lock_); - return global_->registered_.size(); -} - -// static -const FieldTrial::EntropyProvider* - FieldTrialList::GetEntropyProviderForOneTimeRandomization() { - if (!global_) { - used_without_global_ = true; - return NULL; - } - - return global_->entropy_provider_.get(); -} - -FieldTrial* FieldTrialList::PreLockedFind(const std::string& name) { - RegistrationList::iterator it = registered_.find(name); - if (registered_.end() == it) - return NULL; - return it->second; -} - -// static -void FieldTrialList::Register(FieldTrial* trial) { - if (!global_) { - used_without_global_ = true; - return; - } - AutoLock auto_lock(global_->lock_); - DCHECK(!global_->PreLockedFind(trial->trial_name())); - trial->AddRef(); - global_->registered_[trial->trial_name()] = trial; -} - -} // namespace base diff --git a/base/metrics/field_trial.h b/base/metrics/field_trial.h deleted file mode 100644 index 08a8406353..0000000000 --- a/base/metrics/field_trial.h +++ /dev/null @@ -1,486 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -// FieldTrial is a class for handling details of statistical experiments -// performed by actual users in the field (i.e., in a shipped or beta product). -// All code is called exclusively on the UI thread currently. -// -// The simplest example is an experiment to see whether one of two options -// produces "better" results across our user population. In that scenario, UMA -// data is uploaded to aggregate the test results, and this FieldTrial class -// manages the state of each such experiment (state == which option was -// pseudo-randomly selected). -// -// States are typically generated randomly, either based on a one time -// randomization (which will yield the same results, in terms of selecting -// the client for a field trial or not, for every run of the program on a -// given machine), or by a session randomization (generated each time the -// application starts up, but held constant during the duration of the -// process). - -//------------------------------------------------------------------------------ -// Example: Suppose we have an experiment involving memory, such as determining -// the impact of some pruning algorithm. -// We assume that we already have a histogram of memory usage, such as: - -// HISTOGRAM_COUNTS("Memory.RendererTotal", count); - -// Somewhere in main thread initialization code, we'd probably define an -// instance of a FieldTrial, with code such as: - -// // FieldTrials are reference counted, and persist automagically until -// // process teardown, courtesy of their automatic registration in -// // FieldTrialList. -// // Note: This field trial will run in Chrome instances compiled through -// // 8 July, 2015, and after that all instances will be in "StandardMem". -// scoped_refptr trial( -// base::FieldTrialList::FactoryGetFieldTrial( -// "MemoryExperiment", 1000, "StandardMem", 2015, 7, 8, -// base::FieldTrial::ONE_TIME_RANDOMIZED, NULL)); -// -// const int high_mem_group = -// trial->AppendGroup("HighMem", 20); // 2% in HighMem group. -// const int low_mem_group = -// trial->AppendGroup("LowMem", 20); // 2% in LowMem group. -// // Take action depending of which group we randomly land in. -// if (trial->group() == high_mem_group) -// SetPruningAlgorithm(kType1); // Sample setting of browser state. -// else if (trial->group() == low_mem_group) -// SetPruningAlgorithm(kType2); // Sample alternate setting. - -// We then, in addition to our original histogram, output histograms which have -// slightly different names depending on what group the trial instance happened -// to randomly be assigned: - -// HISTOGRAM_COUNTS("Memory.RendererTotal", count); // The original histogram. -// static const bool memory_renderer_total_trial_exists = -// FieldTrialList::TrialExists("MemoryExperiment"); -// if (memory_renderer_total_trial_exists) { -// HISTOGRAM_COUNTS(FieldTrial::MakeName("Memory.RendererTotal", -// "MemoryExperiment"), count); -// } - -// The above code will create four distinct histograms, with each run of the -// application being assigned to of of the three groups, and for each group, the -// correspondingly named histogram will be populated: - -// Memory.RendererTotal // 100% of users still fill this histogram. -// Memory.RendererTotal_HighMem // 2% of users will fill this histogram. -// Memory.RendererTotal_LowMem // 2% of users will fill this histogram. -// Memory.RendererTotal_StandardMem // 96% of users will fill this histogram. - -//------------------------------------------------------------------------------ - -#ifndef BASE_METRICS_FIELD_TRIAL_H_ -#define BASE_METRICS_FIELD_TRIAL_H_ - -#include -#include -#include - -#include "base/base_export.h" -#include "base/gtest_prod_util.h" -#include "base/memory/ref_counted.h" -#include "base/observer_list_threadsafe.h" -#include "base/synchronization/lock.h" -#include "base/time/time.h" - -namespace base { - -class FieldTrialList; - -class BASE_EXPORT FieldTrial : public RefCounted { - public: - typedef int Probability; // Probability type for being selected in a trial. - - // Specifies the persistence of the field trial group choice. - enum RandomizationType { - // One time randomized trials will persist the group choice between - // restarts, which is recommended for most trials, especially those that - // change user visible behavior. - ONE_TIME_RANDOMIZED, - // Session randomized trials will roll the dice to select a group on every - // process restart. - SESSION_RANDOMIZED, - }; - - // EntropyProvider is an interface for providing entropy for one-time - // randomized (persistent) field trials. - class BASE_EXPORT EntropyProvider { - public: - virtual ~EntropyProvider(); - - // Returns a double in the range of [0, 1) to be used for the dice roll for - // the specified field trial. If |randomization_seed| is not 0, it will be - // used in preference to |trial_name| for generating the entropy by entropy - // providers that support it. A given instance should always return the same - // value given the same input |trial_name| and |randomization_seed| values. - virtual double GetEntropyForTrial(const std::string& trial_name, - uint32 randomization_seed) const = 0; - }; - - // A pair representing a Field Trial and its selected group. - struct ActiveGroup { - std::string trial_name; - std::string group_name; - }; - - typedef std::vector ActiveGroups; - - // A return value to indicate that a given instance has not yet had a group - // assignment (and hence is not yet participating in the trial). - static const int kNotFinalized; - - // Disables this trial, meaning it always determines the default group - // has been selected. May be called immediately after construction, or - // at any time after initialization (should not be interleaved with - // AppendGroup calls). Once disabled, there is no way to re-enable a - // trial. - // TODO(mad): http://code.google.com/p/chromium/issues/detail?id=121446 - // This doesn't properly reset to Default when a group was forced. - void Disable(); - - // Establish the name and probability of the next group in this trial. - // Sometimes, based on construction randomization, this call may cause the - // provided group to be *THE* group selected for use in this instance. - // The return value is the group number of the new group. - int AppendGroup(const std::string& name, Probability group_probability); - - // Return the name of the FieldTrial (excluding the group name). - const std::string& trial_name() const { return trial_name_; } - - // Return the randomly selected group number that was assigned, and notify - // any/all observers that this finalized group number has presumably been used - // (queried), and will never change. Note that this will force an instance to - // participate, and make it illegal to attempt to probabilistically add any - // other groups to the trial. - int group(); - - // If the group's name is empty, a string version containing the group number - // is used as the group name. This causes a winner to be chosen if none was. - const std::string& group_name(); - - // Helper function for the most common use: as an argument to specify the - // name of a HISTOGRAM. Use the original histogram name as the name_prefix. - static std::string MakeName(const std::string& name_prefix, - const std::string& trial_name); - - // Enable benchmarking sets field trials to a common setting. - static void EnableBenchmarking(); - - // Set the field trial as forced, meaning that it was setup earlier than - // the hard coded registration of the field trial to override it. - // This allows the code that was hard coded to register the field trial to - // still succeed even though the field trial has already been registered. - // This must be called after appending all the groups, since we will make - // the group choice here. Note that this is a NOOP for already forced trials. - // And, as the rest of the FieldTrial code, this is not thread safe and must - // be done from the UI thread. - void SetForced(); - - private: - // Allow tests to access our innards for testing purposes. - FRIEND_TEST_ALL_PREFIXES(FieldTrialTest, Registration); - FRIEND_TEST_ALL_PREFIXES(FieldTrialTest, AbsoluteProbabilities); - FRIEND_TEST_ALL_PREFIXES(FieldTrialTest, RemainingProbability); - FRIEND_TEST_ALL_PREFIXES(FieldTrialTest, FiftyFiftyProbability); - FRIEND_TEST_ALL_PREFIXES(FieldTrialTest, MiddleProbabilities); - FRIEND_TEST_ALL_PREFIXES(FieldTrialTest, OneWinner); - FRIEND_TEST_ALL_PREFIXES(FieldTrialTest, DisableProbability); - FRIEND_TEST_ALL_PREFIXES(FieldTrialTest, ActiveGroups); - FRIEND_TEST_ALL_PREFIXES(FieldTrialTest, ActiveGroupsNotFinalized); - FRIEND_TEST_ALL_PREFIXES(FieldTrialTest, Save); - FRIEND_TEST_ALL_PREFIXES(FieldTrialTest, DuplicateRestore); - FRIEND_TEST_ALL_PREFIXES(FieldTrialTest, MakeName); - FRIEND_TEST_ALL_PREFIXES(FieldTrialTest, HashClientId); - FRIEND_TEST_ALL_PREFIXES(FieldTrialTest, HashClientIdIsUniform); - FRIEND_TEST_ALL_PREFIXES(FieldTrialTest, NameGroupIds); - FRIEND_TEST_ALL_PREFIXES(FieldTrialTest, SetForcedTurnFeatureOff); - FRIEND_TEST_ALL_PREFIXES(FieldTrialTest, SetForcedTurnFeatureOn); - FRIEND_TEST_ALL_PREFIXES(FieldTrialTest, SetForcedChangeDefault_Default); - FRIEND_TEST_ALL_PREFIXES(FieldTrialTest, SetForcedChangeDefault_NonDefault); - - friend class base::FieldTrialList; - - friend class RefCounted; - - // This is the group number of the 'default' group when a choice wasn't forced - // by a call to FieldTrialList::CreateFieldTrial. It is kept private so that - // consumers don't use it by mistake in cases where the group was forced. - static const int kDefaultGroupNumber; - - // Creates a field trial with the specified parameters. Group assignment will - // be done based on |entropy_value|, which must have a range of [0, 1). - FieldTrial(const std::string& name, - Probability total_probability, - const std::string& default_group_name, - double entropy_value); - virtual ~FieldTrial(); - - // Return the default group name of the FieldTrial. - std::string default_group_name() const { return default_group_name_; } - - // Sets the chosen group name and number. - void SetGroupChoice(const std::string& group_name, int number); - - // Ensures that a group is chosen, if it hasn't yet been. The field trial - // might yet be disabled, so this call will *not* notify observers of the - // status. - void FinalizeGroupChoice(); - - // Returns the trial name and selected group name for this field trial via - // the output parameter |active_group|, but only if the group has already - // been chosen and has been externally observed via |group()| and the trial - // has not been disabled. In that case, true is returned and |active_group| - // is filled in; otherwise, the result is false and |active_group| is left - // untouched. - bool GetActiveGroup(ActiveGroup* active_group) const; - - // Returns the group_name. A winner need not have been chosen. - std::string group_name_internal() const { return group_name_; } - - // The name of the field trial, as can be found via the FieldTrialList. - const std::string trial_name_; - - // The maximum sum of all probabilities supplied, which corresponds to 100%. - // This is the scaling factor used to adjust supplied probabilities. - const Probability divisor_; - - // The name of the default group. - const std::string default_group_name_; - - // The randomly selected probability that is used to select a group (or have - // the instance not participate). It is the product of divisor_ and a random - // number between [0, 1). - Probability random_; - - // Sum of the probabilities of all appended groups. - Probability accumulated_group_probability_; - - int next_group_number_; - - // The pseudo-randomly assigned group number. - // This is kNotFinalized if no group has been assigned. - int group_; - - // A textual name for the randomly selected group. Valid after |group()| - // has been called. - std::string group_name_; - - // When enable_field_trial_ is false, field trial reverts to the 'default' - // group. - bool enable_field_trial_; - - // When forced_ is true, we return the chosen group from AppendGroup when - // appropriate. - bool forced_; - - // Specifies whether the group choice has been reported to observers. - bool group_reported_; - - // When benchmarking is enabled, field trials all revert to the 'default' - // group. - static bool enable_benchmarking_; - - DISALLOW_COPY_AND_ASSIGN(FieldTrial); -}; - -//------------------------------------------------------------------------------ -// Class with a list of all active field trials. A trial is active if it has -// been registered, which includes evaluating its state based on its probaility. -// Only one instance of this class exists. -class BASE_EXPORT FieldTrialList { - public: - // Specifies whether field trials should be activated (marked as "used"), when - // created using |CreateTrialsFromString()|. - enum FieldTrialActivationMode { - DONT_ACTIVATE_TRIALS, - ACTIVATE_TRIALS, - }; - - // Define a separator character to use when creating a persistent form of an - // instance. This is intended for use as a command line argument, passed to a - // second process to mimic our state (i.e., provide the same group name). - static const char kPersistentStringSeparator; // Currently a slash. - - // Year that is guaranteed to not be expired when instantiating a field trial - // via |FactoryGetFieldTrial()|. Set to two years from the build date. - static int kNoExpirationYear; - - // Observer is notified when a FieldTrial's group is selected. - class BASE_EXPORT Observer { - public: - // Notify observers when FieldTrials's group is selected. - virtual void OnFieldTrialGroupFinalized(const std::string& trial_name, - const std::string& group_name) = 0; - - protected: - virtual ~Observer(); - }; - - // This singleton holds the global list of registered FieldTrials. - // - // To support one-time randomized field trials, specify a non-NULL - // |entropy_provider| which should be a source of uniformly distributed - // entropy values. Takes ownership of |entropy_provider|. If one time - // randomization is not desired, pass in NULL for |entropy_provider|. - explicit FieldTrialList(const FieldTrial::EntropyProvider* entropy_provider); - - // Destructor Release()'s references to all registered FieldTrial instances. - ~FieldTrialList(); - - // Get a FieldTrial instance from the factory. - // - // |name| is used to register the instance with the FieldTrialList class, - // and can be used to find the trial (only one trial can be present for each - // name). |default_group_name| is the name of the default group which will - // be chosen if none of the subsequent appended groups get to be chosen. - // |default_group_number| can receive the group number of the default group as - // AppendGroup returns the number of the subsequence groups. |trial_name| and - // |default_group_name| may not be empty but |default_group_number| can be - // NULL if the value is not needed. - // - // Group probabilities that are later supplied must sum to less than or equal - // to the |total_probability|. Arguments |year|, |month| and |day_of_month| - // specify the expiration time. If the build time is after the expiration time - // then the field trial reverts to the 'default' group. - // - // Use this static method to get a startup-randomized FieldTrial or a - // previously created forced FieldTrial. - static FieldTrial* FactoryGetFieldTrial( - const std::string& trial_name, - FieldTrial::Probability total_probability, - const std::string& default_group_name, - const int year, - const int month, - const int day_of_month, - FieldTrial::RandomizationType randomization_type, - int* default_group_number); - - // Same as FactoryGetFieldTrial(), but allows specifying a custom seed to be - // used on one-time randomized field trials (instead of a hash of the trial - // name, which is used otherwise or if |randomization_seed| has value 0). The - // |randomization_seed| value (other than 0) should never be the same for two - // trials, else this would result in correlated group assignments. - // Note: Using a custom randomization seed is only supported by the - // PermutedEntropyProvider (which is used when UMA is not enabled). - static FieldTrial* FactoryGetFieldTrialWithRandomizationSeed( - const std::string& trial_name, - FieldTrial::Probability total_probability, - const std::string& default_group_name, - const int year, - const int month, - const int day_of_month, - FieldTrial::RandomizationType randomization_type, - uint32 randomization_seed, - int* default_group_number); - - // The Find() method can be used to test to see if a named Trial was already - // registered, or to retrieve a pointer to it from the global map. - static FieldTrial* Find(const std::string& name); - - // Returns the group number chosen for the named trial, or - // FieldTrial::kNotFinalized if the trial does not exist. - static int FindValue(const std::string& name); - - // Returns the group name chosen for the named trial, or the - // empty string if the trial does not exist. - static std::string FindFullName(const std::string& name); - - // Returns true if the named trial has been registered. - static bool TrialExists(const std::string& name); - - // Creates a persistent representation of active FieldTrial instances for - // resurrection in another process. This allows randomization to be done in - // one process, and secondary processes can be synchronized on the result. - // The resulting string contains the name and group name pairs of all - // registered FieldTrials for which the group has been chosen and externally - // observed (via |group()|) and which have not been disabled, with "/" used - // to separate all names and to terminate the string. This string is parsed - // by |CreateTrialsFromString()|. - static void StatesToString(std::string* output); - - // Fills in the supplied vector |active_groups| (which must be empty when - // called) with a snapshot of all registered FieldTrials for which the group - // has been chosen and externally observed (via |group()|) and which have - // not been disabled. - static void GetActiveFieldTrialGroups( - FieldTrial::ActiveGroups* active_groups); - - // Use a state string (re: StatesToString()) to augment the current list of - // field trials to include the supplied trials, and using a 100% probability - // for each trial, force them to have the same group string. This is commonly - // used in a non-browser process, to carry randomly selected state in a - // browser process into this non-browser process, but could also be invoked - // through a command line argument to the browser process. The created field - // trials are marked as "used" for the purposes of active trial reporting if - // |mode| is ACTIVATE_TRIALS. - static bool CreateTrialsFromString(const std::string& prior_trials, - FieldTrialActivationMode mode); - - // Create a FieldTrial with the given |name| and using 100% probability for - // the FieldTrial, force FieldTrial to have the same group string as - // |group_name|. This is commonly used in a non-browser process, to carry - // randomly selected state in a browser process into this non-browser process. - // It returns NULL if there is a FieldTrial that is already registered with - // the same |name| but has different finalized group string (|group_name|). - static FieldTrial* CreateFieldTrial(const std::string& name, - const std::string& group_name); - - // Add an observer to be notified when a field trial is irrevocably committed - // to being part of some specific field_group (and hence the group_name is - // also finalized for that field_trial). - static void AddObserver(Observer* observer); - - // Remove an observer. - static void RemoveObserver(Observer* observer); - - // Notify all observers that a group has been finalized for |field_trial|. - static void NotifyFieldTrialGroupSelection(FieldTrial* field_trial); - - // Return the number of active field trials. - static size_t GetFieldTrialCount(); - - private: - // A map from FieldTrial names to the actual instances. - typedef std::map RegistrationList; - - // If one-time randomization is enabled, returns a weak pointer to the - // corresponding EntropyProvider. Otherwise, returns NULL. - static const FieldTrial::EntropyProvider* - GetEntropyProviderForOneTimeRandomization(); - - // Helper function should be called only while holding lock_. - FieldTrial* PreLockedFind(const std::string& name); - - // Register() stores a pointer to the given trial in a global map. - // This method also AddRef's the indicated trial. - // This should always be called after creating a new FieldTrial instance. - static void Register(FieldTrial* trial); - - static FieldTrialList* global_; // The singleton of this class. - - // This will tell us if there is an attempt to register a field - // trial or check if one-time randomization is enabled without - // creating the FieldTrialList. This is not an error, unless a - // FieldTrialList is created after that. - static bool used_without_global_; - - // Lock for access to registered_. - base::Lock lock_; - RegistrationList registered_; - - // Entropy provider to be used for one-time randomized field trials. If NULL, - // one-time randomization is not supported. - scoped_ptr entropy_provider_; - - // List of observers to be notified when a group is selected for a FieldTrial. - scoped_refptr > observer_list_; - - DISALLOW_COPY_AND_ASSIGN(FieldTrialList); -}; - -} // namespace base - -#endif // BASE_METRICS_FIELD_TRIAL_H_ diff --git a/base/metrics/field_trial_unittest.cc b/base/metrics/field_trial_unittest.cc deleted file mode 100644 index 21be9910b8..0000000000 --- a/base/metrics/field_trial_unittest.cc +++ /dev/null @@ -1,859 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "base/metrics/field_trial.h" - -#include "base/message_loop/message_loop.h" -#include "base/rand_util.h" -#include "base/run_loop.h" -#include "base/strings/string_number_conversions.h" -#include "base/strings/stringprintf.h" -#include "testing/gtest/include/gtest/gtest.h" - -namespace base { - -namespace { - -// Default group name used by several tests. -const char kDefaultGroupName[] = "DefaultGroup"; - -// Call FieldTrialList::FactoryGetFieldTrial() with a future expiry date. -scoped_refptr CreateFieldTrial( - const std::string& trial_name, - int total_probability, - const std::string& default_group_name, - int* default_group_number) { - return FieldTrialList::FactoryGetFieldTrial( - trial_name, total_probability, default_group_name, - base::FieldTrialList::kNoExpirationYear, 1, 1, - base::FieldTrial::SESSION_RANDOMIZED, default_group_number); -} - -int GetLastYear() { - Time last_year_time = Time::NowFromSystemTime() - TimeDelta::FromDays(365); - Time::Exploded exploded; - last_year_time.LocalExplode(&exploded); - return exploded.year; -} - -// FieldTrialList::Observer implementation for testing. -class TestFieldTrialObserver : public FieldTrialList::Observer { - public: - TestFieldTrialObserver() { - FieldTrialList::AddObserver(this); - } - - virtual ~TestFieldTrialObserver() { - FieldTrialList::RemoveObserver(this); - } - - virtual void OnFieldTrialGroupFinalized(const std::string& trial, - const std::string& group) OVERRIDE { - trial_name_ = trial; - group_name_ = group; - } - - const std::string& trial_name() const { return trial_name_; } - const std::string& group_name() const { return group_name_; } - - private: - std::string trial_name_; - std::string group_name_; - - DISALLOW_COPY_AND_ASSIGN(TestFieldTrialObserver); -}; - -} // namespace - -class FieldTrialTest : public testing::Test { - public: - FieldTrialTest() : trial_list_(NULL) {} - - private: - MessageLoop message_loop_; - FieldTrialList trial_list_; -}; - -// Test registration, and also check that destructors are called for trials -// (and that Valgrind doesn't catch us leaking). -TEST_F(FieldTrialTest, Registration) { - const char* name1 = "name 1 test"; - const char* name2 = "name 2 test"; - EXPECT_FALSE(FieldTrialList::Find(name1)); - EXPECT_FALSE(FieldTrialList::Find(name2)); - - FieldTrial* trial1 = CreateFieldTrial(name1, 10, "default name 1 test", NULL); - EXPECT_EQ(FieldTrial::kNotFinalized, trial1->group_); - EXPECT_EQ(name1, trial1->trial_name()); - EXPECT_EQ("", trial1->group_name_internal()); - - trial1->AppendGroup(std::string(), 7); - - EXPECT_EQ(trial1, FieldTrialList::Find(name1)); - EXPECT_FALSE(FieldTrialList::Find(name2)); - - FieldTrial* trial2 = CreateFieldTrial(name2, 10, "default name 2 test", NULL); - EXPECT_EQ(FieldTrial::kNotFinalized, trial2->group_); - EXPECT_EQ(name2, trial2->trial_name()); - EXPECT_EQ("", trial2->group_name_internal()); - - trial2->AppendGroup("a first group", 7); - - EXPECT_EQ(trial1, FieldTrialList::Find(name1)); - EXPECT_EQ(trial2, FieldTrialList::Find(name2)); - // Note: FieldTrialList should delete the objects at shutdown. -} - -TEST_F(FieldTrialTest, AbsoluteProbabilities) { - char always_true[] = " always true"; - char default_always_true[] = " default always true"; - char always_false[] = " always false"; - char default_always_false[] = " default always false"; - for (int i = 1; i < 250; ++i) { - // Try lots of names, by changing the first character of the name. - always_true[0] = i; - default_always_true[0] = i; - always_false[0] = i; - default_always_false[0] = i; - - FieldTrial* trial_true = - CreateFieldTrial(always_true, 10, default_always_true, NULL); - const std::string winner = "TheWinner"; - int winner_group = trial_true->AppendGroup(winner, 10); - - EXPECT_EQ(winner_group, trial_true->group()); - EXPECT_EQ(winner, trial_true->group_name()); - - FieldTrial* trial_false = - CreateFieldTrial(always_false, 10, default_always_false, NULL); - int loser_group = trial_false->AppendGroup("ALoser", 0); - - EXPECT_NE(loser_group, trial_false->group()); - } -} - -TEST_F(FieldTrialTest, RemainingProbability) { - // First create a test that hasn't had a winner yet. - const std::string winner = "Winner"; - const std::string loser = "Loser"; - scoped_refptr trial; - int counter = 0; - int default_group_number = -1; - do { - std::string name = StringPrintf("trial%d", ++counter); - trial = CreateFieldTrial(name, 10, winner, &default_group_number); - trial->AppendGroup(loser, 5); // 50% chance of not being chosen. - // If a group is not assigned, group_ will be kNotFinalized. - } while (trial->group_ != FieldTrial::kNotFinalized); - - // And that 'default' group (winner) should always win. - EXPECT_EQ(default_group_number, trial->group()); - - // And that winner should ALWAYS win. - EXPECT_EQ(winner, trial->group_name()); -} - -TEST_F(FieldTrialTest, FiftyFiftyProbability) { - // Check that even with small divisors, we have the proper probabilities, and - // all outcomes are possible. Since this is a 50-50 test, it should get both - // outcomes in a few tries, but we'll try no more than 100 times (and be flaky - // with probability around 1 in 2^99). - bool first_winner = false; - bool second_winner = false; - int counter = 0; - do { - std::string name = base::StringPrintf("FiftyFifty%d", ++counter); - std::string default_group_name = base::StringPrintf("Default FiftyFifty%d", - ++counter); - FieldTrial* trial = CreateFieldTrial(name, 2, default_group_name, NULL); - trial->AppendGroup("first", 1); // 50% chance of being chosen. - // If group_ is kNotFinalized, then a group assignement hasn't been done. - if (trial->group_ != FieldTrial::kNotFinalized) { - first_winner = true; - continue; - } - trial->AppendGroup("second", 1); // Always chosen at this point. - EXPECT_NE(FieldTrial::kNotFinalized, trial->group()); - second_winner = true; - } while ((!second_winner || !first_winner) && counter < 100); - EXPECT_TRUE(second_winner); - EXPECT_TRUE(first_winner); -} - -TEST_F(FieldTrialTest, MiddleProbabilities) { - char name[] = " same name"; - char default_group_name[] = " default same name"; - bool false_event_seen = false; - bool true_event_seen = false; - for (int i = 1; i < 250; ++i) { - name[0] = i; - default_group_name[0] = i; - FieldTrial* trial = CreateFieldTrial(name, 10, default_group_name, NULL); - int might_win = trial->AppendGroup("MightWin", 5); - - if (trial->group() == might_win) { - true_event_seen = true; - } else { - false_event_seen = true; - } - if (false_event_seen && true_event_seen) - return; // Successful test!!! - } - // Very surprising to get here. Probability should be around 1 in 2 ** 250. - // One of the following will fail. - EXPECT_TRUE(false_event_seen); - EXPECT_TRUE(true_event_seen); -} - -TEST_F(FieldTrialTest, OneWinner) { - char name[] = "Some name"; - char default_group_name[] = "Default some name"; - int group_count(10); - - int default_group_number = -1; - FieldTrial* trial = - CreateFieldTrial(name, group_count, default_group_name, NULL); - int winner_index(-2); - std::string winner_name; - - for (int i = 1; i <= group_count; ++i) { - int might_win = trial->AppendGroup(std::string(), 1); - - // Because we keep appending groups, we want to see if the last group that - // was added has been assigned or not. - if (trial->group_ == might_win) { - EXPECT_EQ(-2, winner_index); - winner_index = might_win; - StringAppendF(&winner_name, "%d", might_win); - EXPECT_EQ(winner_name, trial->group_name()); - } - } - EXPECT_GE(winner_index, 0); - // Since all groups cover the total probability, we should not have - // chosen the default group. - EXPECT_NE(trial->group(), default_group_number); - EXPECT_EQ(trial->group(), winner_index); - EXPECT_EQ(trial->group_name(), winner_name); -} - -TEST_F(FieldTrialTest, DisableProbability) { - const std::string default_group_name = "Default group"; - const std::string loser = "Loser"; - const std::string name = "Trial"; - - // Create a field trail that has expired. - int default_group_number = -1; - FieldTrial* trial = FieldTrialList::FactoryGetFieldTrial( - name, 1000000000, default_group_name, GetLastYear(), 1, 1, - FieldTrial::SESSION_RANDOMIZED, - &default_group_number); - trial->AppendGroup(loser, 999999999); // 99.9999999% chance of being chosen. - - // Because trial has expired, we should always be in the default group. - EXPECT_EQ(default_group_number, trial->group()); - - // And that default_group_name should ALWAYS win. - EXPECT_EQ(default_group_name, trial->group_name()); -} - -TEST_F(FieldTrialTest, ActiveGroups) { - std::string no_group("No Group"); - FieldTrial* trial = CreateFieldTrial(no_group, 10, "Default", NULL); - - // There is no winner yet, so no NameGroupId should be returned. - FieldTrial::ActiveGroup active_group; - EXPECT_FALSE(trial->GetActiveGroup(&active_group)); - - // Create a single winning group. - std::string one_winner("One Winner"); - trial = CreateFieldTrial(one_winner, 10, "Default", NULL); - std::string winner("Winner"); - trial->AppendGroup(winner, 10); - EXPECT_FALSE(trial->GetActiveGroup(&active_group)); - // Finalize the group selection by accessing the selected group. - trial->group(); - EXPECT_TRUE(trial->GetActiveGroup(&active_group)); - EXPECT_EQ(one_winner, active_group.trial_name); - EXPECT_EQ(winner, active_group.group_name); - - std::string multi_group("MultiGroup"); - FieldTrial* multi_group_trial = - CreateFieldTrial(multi_group, 9, "Default", NULL); - - multi_group_trial->AppendGroup("Me", 3); - multi_group_trial->AppendGroup("You", 3); - multi_group_trial->AppendGroup("Them", 3); - EXPECT_FALSE(multi_group_trial->GetActiveGroup(&active_group)); - // Finalize the group selection by accessing the selected group. - multi_group_trial->group(); - EXPECT_TRUE(multi_group_trial->GetActiveGroup(&active_group)); - EXPECT_EQ(multi_group, active_group.trial_name); - EXPECT_EQ(multi_group_trial->group_name(), active_group.group_name); - - // Now check if the list is built properly... - FieldTrial::ActiveGroups active_groups; - FieldTrialList::GetActiveFieldTrialGroups(&active_groups); - EXPECT_EQ(2U, active_groups.size()); - for (size_t i = 0; i < active_groups.size(); ++i) { - // Order is not guaranteed, so check all values. - EXPECT_NE(no_group, active_groups[i].trial_name); - EXPECT_TRUE(one_winner != active_groups[i].trial_name || - winner == active_groups[i].group_name); - EXPECT_TRUE(multi_group != active_groups[i].trial_name || - multi_group_trial->group_name() == active_groups[i].group_name); - } -} - -TEST_F(FieldTrialTest, ActiveGroupsNotFinalized) { - const char kTrialName[] = "TestTrial"; - const char kSecondaryGroupName[] = "SecondaryGroup"; - - int default_group = -1; - FieldTrial* trial = - CreateFieldTrial(kTrialName, 100, kDefaultGroupName, &default_group); - const int secondary_group = trial->AppendGroup(kSecondaryGroupName, 50); - - // Before |group()| is called, |GetActiveGroup()| should return false. - FieldTrial::ActiveGroup active_group; - EXPECT_FALSE(trial->GetActiveGroup(&active_group)); - - // |GetActiveFieldTrialGroups()| should also not include the trial. - FieldTrial::ActiveGroups active_groups; - FieldTrialList::GetActiveFieldTrialGroups(&active_groups); - EXPECT_TRUE(active_groups.empty()); - - // After |group()| has been called, both APIs should succeed. - const int chosen_group = trial->group(); - EXPECT_TRUE(chosen_group == default_group || chosen_group == secondary_group); - - EXPECT_TRUE(trial->GetActiveGroup(&active_group)); - EXPECT_EQ(kTrialName, active_group.trial_name); - if (chosen_group == default_group) - EXPECT_EQ(kDefaultGroupName, active_group.group_name); - else - EXPECT_EQ(kSecondaryGroupName, active_group.group_name); - - FieldTrialList::GetActiveFieldTrialGroups(&active_groups); - ASSERT_EQ(1U, active_groups.size()); - EXPECT_EQ(kTrialName, active_groups[0].trial_name); - EXPECT_EQ(active_group.group_name, active_groups[0].group_name); -} - -TEST_F(FieldTrialTest, Save) { - std::string save_string; - - FieldTrial* trial = - CreateFieldTrial("Some name", 10, "Default some name", NULL); - // There is no winner yet, so no textual group name is associated with trial. - // In this case, the trial should not be included. - EXPECT_EQ("", trial->group_name_internal()); - FieldTrialList::StatesToString(&save_string); - EXPECT_EQ("", save_string); - save_string.clear(); - - // Create a winning group. - trial->AppendGroup("Winner", 10); - // Finalize the group selection by accessing the selected group. - trial->group(); - FieldTrialList::StatesToString(&save_string); - EXPECT_EQ("Some name/Winner/", save_string); - save_string.clear(); - - // Create a second trial and winning group. - FieldTrial* trial2 = CreateFieldTrial("xxx", 10, "Default xxx", NULL); - trial2->AppendGroup("yyyy", 10); - // Finalize the group selection by accessing the selected group. - trial2->group(); - - FieldTrialList::StatesToString(&save_string); - // We assume names are alphabetized... though this is not critical. - EXPECT_EQ("Some name/Winner/xxx/yyyy/", save_string); - save_string.clear(); - - // Create a third trial with only the default group. - FieldTrial* trial3 = CreateFieldTrial("zzz", 10, "default", NULL); - // Finalize the group selection by accessing the selected group. - trial3->group(); - - FieldTrialList::StatesToString(&save_string); - EXPECT_EQ("Some name/Winner/xxx/yyyy/zzz/default/", save_string); -} - -TEST_F(FieldTrialTest, Restore) { - ASSERT_FALSE(FieldTrialList::TrialExists("Some_name")); - ASSERT_FALSE(FieldTrialList::TrialExists("xxx")); - - FieldTrialList::CreateTrialsFromString("Some_name/Winner/xxx/yyyy/", - FieldTrialList::DONT_ACTIVATE_TRIALS); - - FieldTrial* trial = FieldTrialList::Find("Some_name"); - ASSERT_NE(static_cast(NULL), trial); - EXPECT_EQ("Winner", trial->group_name()); - EXPECT_EQ("Some_name", trial->trial_name()); - - trial = FieldTrialList::Find("xxx"); - ASSERT_NE(static_cast(NULL), trial); - EXPECT_EQ("yyyy", trial->group_name()); - EXPECT_EQ("xxx", trial->trial_name()); -} - -TEST_F(FieldTrialTest, BogusRestore) { - EXPECT_FALSE(FieldTrialList::CreateTrialsFromString( - "MissingSlash", FieldTrialList::DONT_ACTIVATE_TRIALS)); - EXPECT_FALSE(FieldTrialList::CreateTrialsFromString( - "MissingGroupName/", FieldTrialList::DONT_ACTIVATE_TRIALS)); - EXPECT_FALSE(FieldTrialList::CreateTrialsFromString( - "MissingFinalSlash/gname", FieldTrialList::DONT_ACTIVATE_TRIALS)); - EXPECT_FALSE(FieldTrialList::CreateTrialsFromString( - "noname, only group/", FieldTrialList::DONT_ACTIVATE_TRIALS)); -} - -TEST_F(FieldTrialTest, DuplicateRestore) { - FieldTrial* trial = CreateFieldTrial("Some name", 10, "Default", NULL); - trial->AppendGroup("Winner", 10); - // Finalize the group selection by accessing the selected group. - trial->group(); - std::string save_string; - FieldTrialList::StatesToString(&save_string); - EXPECT_EQ("Some name/Winner/", save_string); - - // It is OK if we redundantly specify a winner. - EXPECT_TRUE(FieldTrialList::CreateTrialsFromString( - save_string, FieldTrialList::DONT_ACTIVATE_TRIALS)); - - // But it is an error to try to change to a different winner. - EXPECT_FALSE(FieldTrialList::CreateTrialsFromString( - "Some name/Loser/", FieldTrialList::DONT_ACTIVATE_TRIALS)); -} - -TEST_F(FieldTrialTest, CreateTrialsFromStringActive) { - ASSERT_FALSE(FieldTrialList::TrialExists("Abc")); - ASSERT_FALSE(FieldTrialList::TrialExists("Xyz")); - ASSERT_TRUE(FieldTrialList::CreateTrialsFromString( - "Abc/def/Xyz/zyx/", FieldTrialList::ACTIVATE_TRIALS)); - - FieldTrial::ActiveGroups active_groups; - FieldTrialList::GetActiveFieldTrialGroups(&active_groups); - ASSERT_EQ(2U, active_groups.size()); - EXPECT_EQ("Abc", active_groups[0].trial_name); - EXPECT_EQ("def", active_groups[0].group_name); - EXPECT_EQ("Xyz", active_groups[1].trial_name); - EXPECT_EQ("zyx", active_groups[1].group_name); -} - -TEST_F(FieldTrialTest, CreateTrialsFromStringNotActive) { - ASSERT_FALSE(FieldTrialList::TrialExists("Abc")); - ASSERT_FALSE(FieldTrialList::TrialExists("Xyz")); - ASSERT_TRUE(FieldTrialList::CreateTrialsFromString( - "Abc/def/Xyz/zyx/", FieldTrialList::DONT_ACTIVATE_TRIALS)); - - FieldTrial::ActiveGroups active_groups; - FieldTrialList::GetActiveFieldTrialGroups(&active_groups); - ASSERT_TRUE(active_groups.empty()); - - // Check that the values still get returned and querying them activates them. - EXPECT_EQ("def", FieldTrialList::FindFullName("Abc")); - EXPECT_EQ("zyx", FieldTrialList::FindFullName("Xyz")); - - FieldTrialList::GetActiveFieldTrialGroups(&active_groups); - ASSERT_EQ(2U, active_groups.size()); - EXPECT_EQ("Abc", active_groups[0].trial_name); - EXPECT_EQ("def", active_groups[0].group_name); - EXPECT_EQ("Xyz", active_groups[1].trial_name); - EXPECT_EQ("zyx", active_groups[1].group_name); -} - -TEST_F(FieldTrialTest, CreateTrialsFromStringActiveObserver) { - ASSERT_FALSE(FieldTrialList::TrialExists("Abc")); - - TestFieldTrialObserver observer; - ASSERT_TRUE(FieldTrialList::CreateTrialsFromString( - "Abc/def/", FieldTrialList::ACTIVATE_TRIALS)); - - RunLoop().RunUntilIdle(); - EXPECT_EQ("Abc", observer.trial_name()); - EXPECT_EQ("def", observer.group_name()); -} - -TEST_F(FieldTrialTest, CreateTrialsFromStringNotActiveObserver) { - ASSERT_FALSE(FieldTrialList::TrialExists("Abc")); - - TestFieldTrialObserver observer; - ASSERT_TRUE(FieldTrialList::CreateTrialsFromString( - "Abc/def/", FieldTrialList::DONT_ACTIVATE_TRIALS)); - RunLoop().RunUntilIdle(); - // Observer shouldn't be notified. - EXPECT_TRUE(observer.trial_name().empty()); - - // Check that the values still get returned and querying them activates them. - EXPECT_EQ("def", FieldTrialList::FindFullName("Abc")); - - RunLoop().RunUntilIdle(); - EXPECT_EQ("Abc", observer.trial_name()); - EXPECT_EQ("def", observer.group_name()); -} - -TEST_F(FieldTrialTest, CreateFieldTrial) { - ASSERT_FALSE(FieldTrialList::TrialExists("Some_name")); - - FieldTrialList::CreateFieldTrial("Some_name", "Winner"); - - FieldTrial* trial = FieldTrialList::Find("Some_name"); - ASSERT_NE(static_cast(NULL), trial); - EXPECT_EQ("Winner", trial->group_name()); - EXPECT_EQ("Some_name", trial->trial_name()); -} - -TEST_F(FieldTrialTest, CreateFieldTrialIsNotActive) { - const char kTrialName[] = "CreateFieldTrialIsActiveTrial"; - const char kWinnerGroup[] = "Winner"; - ASSERT_FALSE(FieldTrialList::TrialExists(kTrialName)); - FieldTrialList::CreateFieldTrial(kTrialName, kWinnerGroup); - - FieldTrial::ActiveGroups active_groups; - FieldTrialList::GetActiveFieldTrialGroups(&active_groups); - EXPECT_TRUE(active_groups.empty()); -} - -TEST_F(FieldTrialTest, DuplicateFieldTrial) { - FieldTrial* trial = CreateFieldTrial("Some_name", 10, "Default", NULL); - trial->AppendGroup("Winner", 10); - - // It is OK if we redundantly specify a winner. - FieldTrial* trial1 = FieldTrialList::CreateFieldTrial("Some_name", "Winner"); - EXPECT_TRUE(trial1 != NULL); - - // But it is an error to try to change to a different winner. - FieldTrial* trial2 = FieldTrialList::CreateFieldTrial("Some_name", "Loser"); - EXPECT_TRUE(trial2 == NULL); -} - -TEST_F(FieldTrialTest, MakeName) { - FieldTrial* trial = CreateFieldTrial("Field Trial", 10, "Winner", NULL); - trial->group(); - EXPECT_EQ("Histogram_Winner", - FieldTrial::MakeName("Histogram", "Field Trial")); -} - -TEST_F(FieldTrialTest, DisableImmediately) { - int default_group_number = -1; - FieldTrial* trial = - CreateFieldTrial("trial", 100, "default", &default_group_number); - trial->Disable(); - ASSERT_EQ("default", trial->group_name()); - ASSERT_EQ(default_group_number, trial->group()); -} - -TEST_F(FieldTrialTest, DisableAfterInitialization) { - FieldTrial* trial = CreateFieldTrial("trial", 100, "default", NULL); - trial->AppendGroup("non_default", 100); - trial->Disable(); - ASSERT_EQ("default", trial->group_name()); -} - -TEST_F(FieldTrialTest, ForcedFieldTrials) { - // Validate we keep the forced choice. - FieldTrial* forced_trial = FieldTrialList::CreateFieldTrial("Use the", - "Force"); - EXPECT_STREQ("Force", forced_trial->group_name().c_str()); - - int default_group_number = -1; - FieldTrial* factory_trial = - CreateFieldTrial("Use the", 1000, "default", &default_group_number); - EXPECT_EQ(factory_trial, forced_trial); - - int chosen_group = factory_trial->AppendGroup("Force", 100); - EXPECT_EQ(chosen_group, factory_trial->group()); - int not_chosen_group = factory_trial->AppendGroup("Dark Side", 100); - EXPECT_NE(chosen_group, not_chosen_group); - - // Since we didn't force the default group, we should not be returned the - // chosen group as the default group. - EXPECT_NE(default_group_number, chosen_group); - int new_group = factory_trial->AppendGroup("Duck Tape", 800); - EXPECT_NE(chosen_group, new_group); - // The new group should not be the default group either. - EXPECT_NE(default_group_number, new_group); -} - -TEST_F(FieldTrialTest, ForcedFieldTrialsDefaultGroup) { - // Forcing the default should use the proper group ID. - FieldTrial* forced_trial = FieldTrialList::CreateFieldTrial("Trial Name", - "Default"); - int default_group_number = -1; - FieldTrial* factory_trial = - CreateFieldTrial("Trial Name", 1000, "Default", &default_group_number); - EXPECT_EQ(forced_trial, factory_trial); - - int other_group = factory_trial->AppendGroup("Not Default", 100); - EXPECT_STREQ("Default", factory_trial->group_name().c_str()); - EXPECT_EQ(default_group_number, factory_trial->group()); - EXPECT_NE(other_group, factory_trial->group()); - - int new_other_group = factory_trial->AppendGroup("Not Default Either", 800); - EXPECT_NE(new_other_group, factory_trial->group()); -} - -TEST_F(FieldTrialTest, SetForced) { - // Start by setting a trial for which we ensure a winner... - int default_group_number = -1; - FieldTrial* forced_trial = - CreateFieldTrial("Use the", 1, "default", &default_group_number); - EXPECT_EQ(forced_trial, forced_trial); - - int forced_group = forced_trial->AppendGroup("Force", 1); - EXPECT_EQ(forced_group, forced_trial->group()); - - // Now force it. - forced_trial->SetForced(); - - // Now try to set it up differently as a hard coded registration would. - FieldTrial* hard_coded_trial = - CreateFieldTrial("Use the", 1, "default", &default_group_number); - EXPECT_EQ(hard_coded_trial, forced_trial); - - int would_lose_group = hard_coded_trial->AppendGroup("Force", 0); - EXPECT_EQ(forced_group, hard_coded_trial->group()); - EXPECT_EQ(forced_group, would_lose_group); - - // Same thing if we would have done it to win again. - FieldTrial* other_hard_coded_trial = - CreateFieldTrial("Use the", 1, "default", &default_group_number); - EXPECT_EQ(other_hard_coded_trial, forced_trial); - - int would_win_group = other_hard_coded_trial->AppendGroup("Force", 1); - EXPECT_EQ(forced_group, other_hard_coded_trial->group()); - EXPECT_EQ(forced_group, would_win_group); -} - -TEST_F(FieldTrialTest, SetForcedDefaultOnly) { - const char kTrialName[] = "SetForcedDefaultOnly"; - ASSERT_FALSE(FieldTrialList::TrialExists(kTrialName)); - - int default_group = -1; - FieldTrial* trial = - CreateFieldTrial(kTrialName, 100, kDefaultGroupName, &default_group); - trial->SetForced(); - - trial = CreateFieldTrial(kTrialName, 100, kDefaultGroupName, NULL); - EXPECT_EQ(default_group, trial->group()); - EXPECT_EQ(kDefaultGroupName, trial->group_name()); -} - -TEST_F(FieldTrialTest, SetForcedDefaultWithExtraGroup) { - const char kTrialName[] = "SetForcedDefaultWithExtraGroup"; - ASSERT_FALSE(FieldTrialList::TrialExists(kTrialName)); - - int default_group = -1; - FieldTrial* trial = - CreateFieldTrial(kTrialName, 100, kDefaultGroupName, &default_group); - trial->SetForced(); - - trial = CreateFieldTrial(kTrialName, 100, kDefaultGroupName, NULL); - const int extra_group = trial->AppendGroup("Extra", 100); - EXPECT_EQ(default_group, trial->group()); - EXPECT_NE(extra_group, trial->group()); - EXPECT_EQ(kDefaultGroupName, trial->group_name()); -} - -TEST_F(FieldTrialTest, SetForcedTurnFeatureOn) { - const char kTrialName[] = "SetForcedTurnFeatureOn"; - const char kExtraGroupName[] = "Extra"; - ASSERT_FALSE(FieldTrialList::TrialExists(kTrialName)); - - // Simulate a server-side (forced) config that turns the feature on when the - // original hard-coded config had it disabled. - FieldTrial* forced_trial = - CreateFieldTrial(kTrialName, 100, kDefaultGroupName, NULL); - forced_trial->AppendGroup(kExtraGroupName, 100); - forced_trial->SetForced(); - - int default_group = -1; - FieldTrial* client_trial = - CreateFieldTrial(kTrialName, 100, kDefaultGroupName, &default_group); - const int extra_group = client_trial->AppendGroup(kExtraGroupName, 0); - EXPECT_NE(default_group, extra_group); - - EXPECT_FALSE(client_trial->group_reported_); - EXPECT_EQ(extra_group, client_trial->group()); - EXPECT_TRUE(client_trial->group_reported_); - EXPECT_EQ(kExtraGroupName, client_trial->group_name()); -} - -TEST_F(FieldTrialTest, SetForcedTurnFeatureOff) { - const char kTrialName[] = "SetForcedTurnFeatureOff"; - const char kExtraGroupName[] = "Extra"; - ASSERT_FALSE(FieldTrialList::TrialExists(kTrialName)); - - // Simulate a server-side (forced) config that turns the feature off when the - // original hard-coded config had it enabled. - FieldTrial* forced_trial = - CreateFieldTrial(kTrialName, 100, kDefaultGroupName, NULL); - forced_trial->AppendGroup(kExtraGroupName, 0); - forced_trial->SetForced(); - - int default_group = -1; - FieldTrial* client_trial = - CreateFieldTrial(kTrialName, 100, kDefaultGroupName, &default_group); - const int extra_group = client_trial->AppendGroup(kExtraGroupName, 100); - EXPECT_NE(default_group, extra_group); - - EXPECT_FALSE(client_trial->group_reported_); - EXPECT_EQ(default_group, client_trial->group()); - EXPECT_TRUE(client_trial->group_reported_); - EXPECT_EQ(kDefaultGroupName, client_trial->group_name()); -} - -TEST_F(FieldTrialTest, SetForcedChangeDefault_Default) { - const char kTrialName[] = "SetForcedDefaultGroupChange"; - const char kGroupAName[] = "A"; - const char kGroupBName[] = "B"; - ASSERT_FALSE(FieldTrialList::TrialExists(kTrialName)); - - // Simulate a server-side (forced) config that switches which group is default - // and ensures that the non-forced code receives the correct group numbers. - FieldTrial* forced_trial = - CreateFieldTrial(kTrialName, 100, kGroupAName, NULL); - forced_trial->AppendGroup(kGroupBName, 100); - forced_trial->SetForced(); - - int default_group = -1; - FieldTrial* client_trial = - CreateFieldTrial(kTrialName, 100, kGroupBName, &default_group); - const int extra_group = client_trial->AppendGroup(kGroupAName, 50); - EXPECT_NE(default_group, extra_group); - - EXPECT_FALSE(client_trial->group_reported_); - EXPECT_EQ(default_group, client_trial->group()); - EXPECT_TRUE(client_trial->group_reported_); - EXPECT_EQ(kGroupBName, client_trial->group_name()); -} - -TEST_F(FieldTrialTest, SetForcedChangeDefault_NonDefault) { - const char kTrialName[] = "SetForcedDefaultGroupChange"; - const char kGroupAName[] = "A"; - const char kGroupBName[] = "B"; - ASSERT_FALSE(FieldTrialList::TrialExists(kTrialName)); - - // Simulate a server-side (forced) config that switches which group is default - // and ensures that the non-forced code receives the correct group numbers. - FieldTrial* forced_trial = - CreateFieldTrial(kTrialName, 100, kGroupAName, NULL); - forced_trial->AppendGroup(kGroupBName, 0); - forced_trial->SetForced(); - - int default_group = -1; - FieldTrial* client_trial = - CreateFieldTrial(kTrialName, 100, kGroupBName, &default_group); - const int extra_group = client_trial->AppendGroup(kGroupAName, 50); - EXPECT_NE(default_group, extra_group); - - EXPECT_FALSE(client_trial->group_reported_); - EXPECT_EQ(extra_group, client_trial->group()); - EXPECT_TRUE(client_trial->group_reported_); - EXPECT_EQ(kGroupAName, client_trial->group_name()); -} - -TEST_F(FieldTrialTest, Observe) { - const char kTrialName[] = "TrialToObserve1"; - const char kSecondaryGroupName[] = "SecondaryGroup"; - - TestFieldTrialObserver observer; - int default_group = -1; - FieldTrial* trial = - CreateFieldTrial(kTrialName, 100, kDefaultGroupName, &default_group); - const int secondary_group = trial->AppendGroup(kSecondaryGroupName, 50); - const int chosen_group = trial->group(); - EXPECT_TRUE(chosen_group == default_group || chosen_group == secondary_group); - - RunLoop().RunUntilIdle(); - EXPECT_EQ(kTrialName, observer.trial_name()); - if (chosen_group == default_group) - EXPECT_EQ(kDefaultGroupName, observer.group_name()); - else - EXPECT_EQ(kSecondaryGroupName, observer.group_name()); -} - -TEST_F(FieldTrialTest, ObserveDisabled) { - const char kTrialName[] = "TrialToObserve2"; - - TestFieldTrialObserver observer; - int default_group = -1; - FieldTrial* trial = - CreateFieldTrial(kTrialName, 100, kDefaultGroupName, &default_group); - trial->AppendGroup("A", 25); - trial->AppendGroup("B", 25); - trial->AppendGroup("C", 25); - trial->Disable(); - - // Observer shouldn't be notified of a disabled trial. - RunLoop().RunUntilIdle(); - EXPECT_TRUE(observer.trial_name().empty()); - EXPECT_TRUE(observer.group_name().empty()); - - // Observer shouldn't be notified even after a |group()| call. - EXPECT_EQ(default_group, trial->group()); - RunLoop().RunUntilIdle(); - EXPECT_TRUE(observer.trial_name().empty()); - EXPECT_TRUE(observer.group_name().empty()); -} - -TEST_F(FieldTrialTest, ObserveForcedDisabled) { - const char kTrialName[] = "TrialToObserve3"; - - TestFieldTrialObserver observer; - int default_group = -1; - FieldTrial* trial = - CreateFieldTrial(kTrialName, 100, kDefaultGroupName, &default_group); - trial->AppendGroup("A", 25); - trial->AppendGroup("B", 25); - trial->AppendGroup("C", 25); - trial->SetForced(); - trial->Disable(); - - // Observer shouldn't be notified of a disabled trial, even when forced. - RunLoop().RunUntilIdle(); - EXPECT_TRUE(observer.trial_name().empty()); - EXPECT_TRUE(observer.group_name().empty()); - - // Observer shouldn't be notified even after a |group()| call. - EXPECT_EQ(default_group, trial->group()); - RunLoop().RunUntilIdle(); - EXPECT_TRUE(observer.trial_name().empty()); - EXPECT_TRUE(observer.group_name().empty()); -} - -TEST_F(FieldTrialTest, DisabledTrialNotActive) { - const char kTrialName[] = "DisabledTrial"; - ASSERT_FALSE(FieldTrialList::TrialExists(kTrialName)); - - FieldTrial* trial = - CreateFieldTrial(kTrialName, 100, kDefaultGroupName, NULL); - trial->AppendGroup("X", 50); - trial->Disable(); - - // Ensure the trial is not listed as active. - FieldTrial::ActiveGroups active_groups; - FieldTrialList::GetActiveFieldTrialGroups(&active_groups); - EXPECT_TRUE(active_groups.empty()); - - // Ensure the trial is not listed in the |StatesToString()| result. - std::string states; - FieldTrialList::StatesToString(&states); - EXPECT_TRUE(states.empty()); -} - -TEST_F(FieldTrialTest, ExpirationYearNotExpired) { - const char kTrialName[] = "NotExpired"; - const char kGroupName[] = "Group2"; - const int kProbability = 100; - ASSERT_FALSE(FieldTrialList::TrialExists(kTrialName)); - - FieldTrial* trial = - CreateFieldTrial(kTrialName, kProbability, kDefaultGroupName, NULL); - trial->AppendGroup(kGroupName, kProbability); - EXPECT_EQ(kGroupName, trial->group_name()); -} - -} // namespace base diff --git a/base/metrics/histogram.cc b/base/metrics/histogram.cc deleted file mode 100644 index fbe66d05d2..0000000000 --- a/base/metrics/histogram.cc +++ /dev/null @@ -1,834 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -// Histogram is an object that aggregates statistics, and can summarize them in -// various forms, including ASCII graphical, HTML, and numerically (as a -// vector of numbers corresponding to each of the aggregating buckets). -// See header file for details and examples. - -#include "base/metrics/histogram.h" - -#include - -#include -#include - -#include "base/compiler_specific.h" -#include "base/debug/alias.h" -#include "base/logging.h" -#include "base/metrics/sample_vector.h" -#include "base/metrics/statistics_recorder.h" -#include "base/pickle.h" -#include "base/strings/string_util.h" -#include "base/strings/stringprintf.h" -#include "base/synchronization/lock.h" -#include "base/values.h" - -using std::string; -using std::vector; - -namespace base { - -namespace { - -bool ReadHistogramArguments(PickleIterator* iter, - string* histogram_name, - int* flags, - int* declared_min, - int* declared_max, - uint64* bucket_count, - uint32* range_checksum) { - if (!iter->ReadString(histogram_name) || - !iter->ReadInt(flags) || - !iter->ReadInt(declared_min) || - !iter->ReadInt(declared_max) || - !iter->ReadUInt64(bucket_count) || - !iter->ReadUInt32(range_checksum)) { - DLOG(ERROR) << "Pickle error decoding Histogram: " << *histogram_name; - return false; - } - - // Since these fields may have come from an untrusted renderer, do additional - // checks above and beyond those in Histogram::Initialize() - if (*declared_max <= 0 || - *declared_min <= 0 || - *declared_max < *declared_min || - INT_MAX / sizeof(HistogramBase::Count) <= *bucket_count || - *bucket_count < 2) { - DLOG(ERROR) << "Values error decoding Histogram: " << histogram_name; - return false; - } - - // We use the arguments to find or create the local version of the histogram - // in this process, so we need to clear the IPC flag. - DCHECK(*flags & HistogramBase::kIPCSerializationSourceFlag); - *flags &= ~HistogramBase::kIPCSerializationSourceFlag; - - return true; -} - -bool ValidateRangeChecksum(const HistogramBase& histogram, - uint32 range_checksum) { - const Histogram& casted_histogram = - static_cast(histogram); - - return casted_histogram.bucket_ranges()->checksum() == range_checksum; -} - -} // namespace - -typedef HistogramBase::Count Count; -typedef HistogramBase::Sample Sample; - -// static -const size_t Histogram::kBucketCount_MAX = 16384u; - -HistogramBase* Histogram::FactoryGet(const string& name, - Sample minimum, - Sample maximum, - size_t bucket_count, - int32 flags) { - bool valid_arguments = - InspectConstructionArguments(name, &minimum, &maximum, &bucket_count); - DCHECK(valid_arguments); - - HistogramBase* histogram = StatisticsRecorder::FindHistogram(name); - if (!histogram) { - // To avoid racy destruction at shutdown, the following will be leaked. - BucketRanges* ranges = new BucketRanges(bucket_count + 1); - InitializeBucketRanges(minimum, maximum, ranges); - const BucketRanges* registered_ranges = - StatisticsRecorder::RegisterOrDeleteDuplicateRanges(ranges); - - Histogram* tentative_histogram = - new Histogram(name, minimum, maximum, registered_ranges); - - tentative_histogram->SetFlags(flags); - histogram = - StatisticsRecorder::RegisterOrDeleteDuplicate(tentative_histogram); - } - - DCHECK_EQ(HISTOGRAM, histogram->GetHistogramType()); - CHECK(histogram->HasConstructionArguments(minimum, maximum, bucket_count)); - return histogram; -} - -HistogramBase* Histogram::FactoryTimeGet(const string& name, - TimeDelta minimum, - TimeDelta maximum, - size_t bucket_count, - int32 flags) { - return FactoryGet(name, minimum.InMilliseconds(), maximum.InMilliseconds(), - bucket_count, flags); -} - -TimeTicks Histogram::DebugNow() { -#ifndef NDEBUG - return TimeTicks::Now(); -#else - return TimeTicks(); -#endif -} - -// Calculate what range of values are held in each bucket. -// We have to be careful that we don't pick a ratio between starting points in -// consecutive buckets that is sooo small, that the integer bounds are the same -// (effectively making one bucket get no values). We need to avoid: -// ranges(i) == ranges(i + 1) -// To avoid that, we just do a fine-grained bucket width as far as we need to -// until we get a ratio that moves us along at least 2 units at a time. From -// that bucket onward we do use the exponential growth of buckets. -// -// static -void Histogram::InitializeBucketRanges(Sample minimum, - Sample maximum, - BucketRanges* ranges) { - double log_max = log(static_cast(maximum)); - double log_ratio; - double log_next; - size_t bucket_index = 1; - Sample current = minimum; - ranges->set_range(bucket_index, current); - size_t bucket_count = ranges->bucket_count(); - while (bucket_count > ++bucket_index) { - double log_current; - log_current = log(static_cast(current)); - // Calculate the count'th root of the range. - log_ratio = (log_max - log_current) / (bucket_count - bucket_index); - // See where the next bucket would start. - log_next = log_current + log_ratio; - Sample next; - next = static_cast(floor(exp(log_next) + 0.5)); - if (next > current) - current = next; - else - ++current; // Just do a narrow bucket, and keep trying. - ranges->set_range(bucket_index, current); - } - ranges->set_range(ranges->bucket_count(), HistogramBase::kSampleType_MAX); - ranges->ResetChecksum(); -} - -// static -const int Histogram::kCommonRaceBasedCountMismatch = 5; - -int Histogram::FindCorruption(const HistogramSamples& samples) const { - int inconsistencies = NO_INCONSISTENCIES; - Sample previous_range = -1; // Bottom range is always 0. - for (size_t index = 0; index < bucket_count(); ++index) { - int new_range = ranges(index); - if (previous_range >= new_range) - inconsistencies |= BUCKET_ORDER_ERROR; - previous_range = new_range; - } - - if (!bucket_ranges()->HasValidChecksum()) - inconsistencies |= RANGE_CHECKSUM_ERROR; - - int64 delta64 = samples.redundant_count() - samples.TotalCount(); - if (delta64 != 0) { - int delta = static_cast(delta64); - if (delta != delta64) - delta = INT_MAX; // Flag all giant errors as INT_MAX. - if (delta > 0) { - UMA_HISTOGRAM_COUNTS("Histogram.InconsistentCountHigh", delta); - if (delta > kCommonRaceBasedCountMismatch) - inconsistencies |= COUNT_HIGH_ERROR; - } else { - DCHECK_GT(0, delta); - UMA_HISTOGRAM_COUNTS("Histogram.InconsistentCountLow", -delta); - if (-delta > kCommonRaceBasedCountMismatch) - inconsistencies |= COUNT_LOW_ERROR; - } - } - return inconsistencies; -} - -Sample Histogram::ranges(size_t i) const { - return bucket_ranges_->range(i); -} - -size_t Histogram::bucket_count() const { - return bucket_ranges_->bucket_count(); -} - -// static -bool Histogram::InspectConstructionArguments(const string& name, - Sample* minimum, - Sample* maximum, - size_t* bucket_count) { - // Defensive code for backward compatibility. - if (*minimum < 1) { - DVLOG(1) << "Histogram: " << name << " has bad minimum: " << *minimum; - *minimum = 1; - } - if (*maximum >= kSampleType_MAX) { - DVLOG(1) << "Histogram: " << name << " has bad maximum: " << *maximum; - *maximum = kSampleType_MAX - 1; - } - if (*bucket_count >= kBucketCount_MAX) { - DVLOG(1) << "Histogram: " << name << " has bad bucket_count: " - << *bucket_count; - *bucket_count = kBucketCount_MAX - 1; - } - - if (*minimum >= *maximum) - return false; - if (*bucket_count < 3) - return false; - if (*bucket_count > static_cast(*maximum - *minimum + 2)) - return false; - return true; -} - -HistogramType Histogram::GetHistogramType() const { - return HISTOGRAM; -} - -bool Histogram::HasConstructionArguments(Sample expected_minimum, - Sample expected_maximum, - size_t expected_bucket_count) const { - return ((expected_minimum == declared_min_) && - (expected_maximum == declared_max_) && - (expected_bucket_count == bucket_count())); -} - -void Histogram::Add(int value) { - DCHECK_EQ(0, ranges(0)); - DCHECK_EQ(kSampleType_MAX, ranges(bucket_count())); - - if (value > kSampleType_MAX - 1) - value = kSampleType_MAX - 1; - if (value < 0) - value = 0; - samples_->Accumulate(value, 1); -} - -scoped_ptr Histogram::SnapshotSamples() const { - return SnapshotSampleVector().PassAs(); -} - -void Histogram::AddSamples(const HistogramSamples& samples) { - samples_->Add(samples); -} - -bool Histogram::AddSamplesFromPickle(PickleIterator* iter) { - return samples_->AddFromPickle(iter); -} - -// The following methods provide a graphical histogram display. -void Histogram::WriteHTMLGraph(string* output) const { - // TBD(jar) Write a nice HTML bar chart, with divs an mouse-overs etc. - output->append("
");
-  WriteAsciiImpl(true, "
", output); - output->append("
"); -} - -void Histogram::WriteAscii(string* output) const { - WriteAsciiImpl(true, "\n", output); -} - -bool Histogram::SerializeInfoImpl(Pickle* pickle) const { - DCHECK(bucket_ranges()->HasValidChecksum()); - return pickle->WriteString(histogram_name()) && - pickle->WriteInt(flags()) && - pickle->WriteInt(declared_min()) && - pickle->WriteInt(declared_max()) && - pickle->WriteUInt64(bucket_count()) && - pickle->WriteUInt32(bucket_ranges()->checksum()); -} - -Histogram::Histogram(const string& name, - Sample minimum, - Sample maximum, - const BucketRanges* ranges) - : HistogramBase(name), - bucket_ranges_(ranges), - declared_min_(minimum), - declared_max_(maximum) { - if (ranges) - samples_.reset(new SampleVector(ranges)); -} - -Histogram::~Histogram() { -} - -bool Histogram::PrintEmptyBucket(size_t index) const { - return true; -} - -// Use the actual bucket widths (like a linear histogram) until the widths get -// over some transition value, and then use that transition width. Exponentials -// get so big so fast (and we don't expect to see a lot of entries in the large -// buckets), so we need this to make it possible to see what is going on and -// not have 0-graphical-height buckets. -double Histogram::GetBucketSize(Count current, size_t i) const { - DCHECK_GT(ranges(i + 1), ranges(i)); - static const double kTransitionWidth = 5; - double denominator = ranges(i + 1) - ranges(i); - if (denominator > kTransitionWidth) - denominator = kTransitionWidth; // Stop trying to normalize. - return current/denominator; -} - -const string Histogram::GetAsciiBucketRange(size_t i) const { - return GetSimpleAsciiBucketRange(ranges(i)); -} - -//------------------------------------------------------------------------------ -// Private methods - -// static -HistogramBase* Histogram::DeserializeInfoImpl(PickleIterator* iter) { - string histogram_name; - int flags; - int declared_min; - int declared_max; - uint64 bucket_count; - uint32 range_checksum; - - if (!ReadHistogramArguments(iter, &histogram_name, &flags, &declared_min, - &declared_max, &bucket_count, &range_checksum)) { - return NULL; - } - - // Find or create the local version of the histogram in this process. - HistogramBase* histogram = Histogram::FactoryGet( - histogram_name, declared_min, declared_max, bucket_count, flags); - - if (!ValidateRangeChecksum(*histogram, range_checksum)) { - // The serialized histogram might be corrupted. - return NULL; - } - return histogram; -} - -scoped_ptr Histogram::SnapshotSampleVector() const { - scoped_ptr samples(new SampleVector(bucket_ranges())); - samples->Add(*samples_); - return samples.Pass(); -} - -void Histogram::WriteAsciiImpl(bool graph_it, - const string& newline, - string* output) const { - // Get local (stack) copies of all effectively volatile class data so that we - // are consistent across our output activities. - scoped_ptr snapshot = SnapshotSampleVector(); - Count sample_count = snapshot->TotalCount(); - - WriteAsciiHeader(*snapshot, sample_count, output); - output->append(newline); - - // Prepare to normalize graphical rendering of bucket contents. - double max_size = 0; - if (graph_it) - max_size = GetPeakBucketSize(*snapshot); - - // Calculate space needed to print bucket range numbers. Leave room to print - // nearly the largest bucket range without sliding over the histogram. - size_t largest_non_empty_bucket = bucket_count() - 1; - while (0 == snapshot->GetCountAtIndex(largest_non_empty_bucket)) { - if (0 == largest_non_empty_bucket) - break; // All buckets are empty. - --largest_non_empty_bucket; - } - - // Calculate largest print width needed for any of our bucket range displays. - size_t print_width = 1; - for (size_t i = 0; i < bucket_count(); ++i) { - if (snapshot->GetCountAtIndex(i)) { - size_t width = GetAsciiBucketRange(i).size() + 1; - if (width > print_width) - print_width = width; - } - } - - int64 remaining = sample_count; - int64 past = 0; - // Output the actual histogram graph. - for (size_t i = 0; i < bucket_count(); ++i) { - Count current = snapshot->GetCountAtIndex(i); - if (!current && !PrintEmptyBucket(i)) - continue; - remaining -= current; - string range = GetAsciiBucketRange(i); - output->append(range); - for (size_t j = 0; range.size() + j < print_width + 1; ++j) - output->push_back(' '); - if (0 == current && i < bucket_count() - 1 && - 0 == snapshot->GetCountAtIndex(i + 1)) { - while (i < bucket_count() - 1 && - 0 == snapshot->GetCountAtIndex(i + 1)) { - ++i; - } - output->append("... "); - output->append(newline); - continue; // No reason to plot emptiness. - } - double current_size = GetBucketSize(current, i); - if (graph_it) - WriteAsciiBucketGraph(current_size, max_size, output); - WriteAsciiBucketContext(past, current, remaining, i, output); - output->append(newline); - past += current; - } - DCHECK_EQ(sample_count, past); -} - -double Histogram::GetPeakBucketSize(const SampleVector& samples) const { - double max = 0; - for (size_t i = 0; i < bucket_count() ; ++i) { - double current_size = GetBucketSize(samples.GetCountAtIndex(i), i); - if (current_size > max) - max = current_size; - } - return max; -} - -void Histogram::WriteAsciiHeader(const SampleVector& samples, - Count sample_count, - string* output) const { - StringAppendF(output, - "Histogram: %s recorded %d samples", - histogram_name().c_str(), - sample_count); - if (0 == sample_count) { - DCHECK_EQ(samples.sum(), 0); - } else { - double average = static_cast(samples.sum()) / sample_count; - - StringAppendF(output, ", average = %.1f", average); - } - if (flags() & ~kHexRangePrintingFlag) - StringAppendF(output, " (flags = 0x%x)", flags() & ~kHexRangePrintingFlag); -} - -void Histogram::WriteAsciiBucketContext(const int64 past, - const Count current, - const int64 remaining, - const size_t i, - string* output) const { - double scaled_sum = (past + current + remaining) / 100.0; - WriteAsciiBucketValue(current, scaled_sum, output); - if (0 < i) { - double percentage = past / scaled_sum; - StringAppendF(output, " {%3.1f%%}", percentage); - } -} - -void Histogram::GetParameters(DictionaryValue* params) const { - params->SetString("type", HistogramTypeToString(GetHistogramType())); - params->SetInteger("min", declared_min()); - params->SetInteger("max", declared_max()); - params->SetInteger("bucket_count", static_cast(bucket_count())); -} - -void Histogram::GetCountAndBucketData(Count* count, - int64* sum, - ListValue* buckets) const { - scoped_ptr snapshot = SnapshotSampleVector(); - *count = snapshot->TotalCount(); - *sum = snapshot->sum(); - size_t index = 0; - for (size_t i = 0; i < bucket_count(); ++i) { - Sample count = snapshot->GetCountAtIndex(i); - if (count > 0) { - scoped_ptr bucket_value(new DictionaryValue()); - bucket_value->SetInteger("low", ranges(i)); - if (i != bucket_count() - 1) - bucket_value->SetInteger("high", ranges(i + 1)); - bucket_value->SetInteger("count", count); - buckets->Set(index, bucket_value.release()); - ++index; - } - } -} - -//------------------------------------------------------------------------------ -// LinearHistogram: This histogram uses a traditional set of evenly spaced -// buckets. -//------------------------------------------------------------------------------ - -LinearHistogram::~LinearHistogram() {} - -HistogramBase* LinearHistogram::FactoryGet(const string& name, - Sample minimum, - Sample maximum, - size_t bucket_count, - int32 flags) { - return FactoryGetWithRangeDescription( - name, minimum, maximum, bucket_count, flags, NULL); -} - -HistogramBase* LinearHistogram::FactoryTimeGet(const string& name, - TimeDelta minimum, - TimeDelta maximum, - size_t bucket_count, - int32 flags) { - return FactoryGet(name, minimum.InMilliseconds(), maximum.InMilliseconds(), - bucket_count, flags); -} - -HistogramBase* LinearHistogram::FactoryGetWithRangeDescription( - const std::string& name, - Sample minimum, - Sample maximum, - size_t bucket_count, - int32 flags, - const DescriptionPair descriptions[]) { - bool valid_arguments = Histogram::InspectConstructionArguments( - name, &minimum, &maximum, &bucket_count); - DCHECK(valid_arguments); - - HistogramBase* histogram = StatisticsRecorder::FindHistogram(name); - if (!histogram) { - // To avoid racy destruction at shutdown, the following will be leaked. - BucketRanges* ranges = new BucketRanges(bucket_count + 1); - InitializeBucketRanges(minimum, maximum, ranges); - const BucketRanges* registered_ranges = - StatisticsRecorder::RegisterOrDeleteDuplicateRanges(ranges); - - LinearHistogram* tentative_histogram = - new LinearHistogram(name, minimum, maximum, registered_ranges); - - // Set range descriptions. - if (descriptions) { - for (int i = 0; descriptions[i].description; ++i) { - tentative_histogram->bucket_description_[descriptions[i].sample] = - descriptions[i].description; - } - } - - tentative_histogram->SetFlags(flags); - histogram = - StatisticsRecorder::RegisterOrDeleteDuplicate(tentative_histogram); - } - - DCHECK_EQ(LINEAR_HISTOGRAM, histogram->GetHistogramType()); - CHECK(histogram->HasConstructionArguments(minimum, maximum, bucket_count)); - return histogram; -} - -HistogramType LinearHistogram::GetHistogramType() const { - return LINEAR_HISTOGRAM; -} - -LinearHistogram::LinearHistogram(const string& name, - Sample minimum, - Sample maximum, - const BucketRanges* ranges) - : Histogram(name, minimum, maximum, ranges) { -} - -double LinearHistogram::GetBucketSize(Count current, size_t i) const { - DCHECK_GT(ranges(i + 1), ranges(i)); - // Adjacent buckets with different widths would have "surprisingly" many (few) - // samples in a histogram if we didn't normalize this way. - double denominator = ranges(i + 1) - ranges(i); - return current/denominator; -} - -const string LinearHistogram::GetAsciiBucketRange(size_t i) const { - int range = ranges(i); - BucketDescriptionMap::const_iterator it = bucket_description_.find(range); - if (it == bucket_description_.end()) - return Histogram::GetAsciiBucketRange(i); - return it->second; -} - -bool LinearHistogram::PrintEmptyBucket(size_t index) const { - return bucket_description_.find(ranges(index)) == bucket_description_.end(); -} - -// static -void LinearHistogram::InitializeBucketRanges(Sample minimum, - Sample maximum, - BucketRanges* ranges) { - double min = minimum; - double max = maximum; - size_t bucket_count = ranges->bucket_count(); - for (size_t i = 1; i < bucket_count; ++i) { - double linear_range = - (min * (bucket_count - 1 - i) + max * (i - 1)) / (bucket_count - 2); - ranges->set_range(i, static_cast(linear_range + 0.5)); - } - ranges->set_range(ranges->bucket_count(), HistogramBase::kSampleType_MAX); - ranges->ResetChecksum(); -} - -// static -HistogramBase* LinearHistogram::DeserializeInfoImpl(PickleIterator* iter) { - string histogram_name; - int flags; - int declared_min; - int declared_max; - uint64 bucket_count; - uint32 range_checksum; - - if (!ReadHistogramArguments(iter, &histogram_name, &flags, &declared_min, - &declared_max, &bucket_count, &range_checksum)) { - return NULL; - } - - HistogramBase* histogram = LinearHistogram::FactoryGet( - histogram_name, declared_min, declared_max, bucket_count, flags); - if (!ValidateRangeChecksum(*histogram, range_checksum)) { - // The serialized histogram might be corrupted. - return NULL; - } - return histogram; -} - -//------------------------------------------------------------------------------ -// This section provides implementation for BooleanHistogram. -//------------------------------------------------------------------------------ - -HistogramBase* BooleanHistogram::FactoryGet(const string& name, int32 flags) { - HistogramBase* histogram = StatisticsRecorder::FindHistogram(name); - if (!histogram) { - // To avoid racy destruction at shutdown, the following will be leaked. - BucketRanges* ranges = new BucketRanges(4); - LinearHistogram::InitializeBucketRanges(1, 2, ranges); - const BucketRanges* registered_ranges = - StatisticsRecorder::RegisterOrDeleteDuplicateRanges(ranges); - - BooleanHistogram* tentative_histogram = - new BooleanHistogram(name, registered_ranges); - - tentative_histogram->SetFlags(flags); - histogram = - StatisticsRecorder::RegisterOrDeleteDuplicate(tentative_histogram); - } - - DCHECK_EQ(BOOLEAN_HISTOGRAM, histogram->GetHistogramType()); - return histogram; -} - -HistogramType BooleanHistogram::GetHistogramType() const { - return BOOLEAN_HISTOGRAM; -} - -BooleanHistogram::BooleanHistogram(const string& name, - const BucketRanges* ranges) - : LinearHistogram(name, 1, 2, ranges) {} - -HistogramBase* BooleanHistogram::DeserializeInfoImpl(PickleIterator* iter) { - string histogram_name; - int flags; - int declared_min; - int declared_max; - uint64 bucket_count; - uint32 range_checksum; - - if (!ReadHistogramArguments(iter, &histogram_name, &flags, &declared_min, - &declared_max, &bucket_count, &range_checksum)) { - return NULL; - } - - HistogramBase* histogram = BooleanHistogram::FactoryGet( - histogram_name, flags); - if (!ValidateRangeChecksum(*histogram, range_checksum)) { - // The serialized histogram might be corrupted. - return NULL; - } - return histogram; -} - -//------------------------------------------------------------------------------ -// CustomHistogram: -//------------------------------------------------------------------------------ - -HistogramBase* CustomHistogram::FactoryGet(const string& name, - const vector& custom_ranges, - int32 flags) { - CHECK(ValidateCustomRanges(custom_ranges)); - - HistogramBase* histogram = StatisticsRecorder::FindHistogram(name); - if (!histogram) { - BucketRanges* ranges = CreateBucketRangesFromCustomRanges(custom_ranges); - const BucketRanges* registered_ranges = - StatisticsRecorder::RegisterOrDeleteDuplicateRanges(ranges); - - // To avoid racy destruction at shutdown, the following will be leaked. - CustomHistogram* tentative_histogram = - new CustomHistogram(name, registered_ranges); - - tentative_histogram->SetFlags(flags); - - histogram = - StatisticsRecorder::RegisterOrDeleteDuplicate(tentative_histogram); - } - - DCHECK_EQ(histogram->GetHistogramType(), CUSTOM_HISTOGRAM); - return histogram; -} - -HistogramType CustomHistogram::GetHistogramType() const { - return CUSTOM_HISTOGRAM; -} - -// static -vector CustomHistogram::ArrayToCustomRanges( - const Sample* values, size_t num_values) { - vector all_values; - for (size_t i = 0; i < num_values; ++i) { - Sample value = values[i]; - all_values.push_back(value); - - // Ensure that a guard bucket is added. If we end up with duplicate - // values, FactoryGet will take care of removing them. - all_values.push_back(value + 1); - } - return all_values; -} - -CustomHistogram::CustomHistogram(const string& name, - const BucketRanges* ranges) - : Histogram(name, - ranges->range(1), - ranges->range(ranges->bucket_count() - 1), - ranges) {} - -bool CustomHistogram::SerializeInfoImpl(Pickle* pickle) const { - if (!Histogram::SerializeInfoImpl(pickle)) - return false; - - // Serialize ranges. First and last ranges are alwasy 0 and INT_MAX, so don't - // write them. - for (size_t i = 1; i < bucket_ranges()->bucket_count(); ++i) { - if (!pickle->WriteInt(bucket_ranges()->range(i))) - return false; - } - return true; -} - -double CustomHistogram::GetBucketSize(Count current, size_t i) const { - return 1; -} - -// static -HistogramBase* CustomHistogram::DeserializeInfoImpl(PickleIterator* iter) { - string histogram_name; - int flags; - int declared_min; - int declared_max; - uint64 bucket_count; - uint32 range_checksum; - - if (!ReadHistogramArguments(iter, &histogram_name, &flags, &declared_min, - &declared_max, &bucket_count, &range_checksum)) { - return NULL; - } - - // First and last ranges are not serialized. - vector sample_ranges(bucket_count - 1); - - for (size_t i = 0; i < sample_ranges.size(); ++i) { - if (!iter->ReadInt(&sample_ranges[i])) - return NULL; - } - - HistogramBase* histogram = CustomHistogram::FactoryGet( - histogram_name, sample_ranges, flags); - if (!ValidateRangeChecksum(*histogram, range_checksum)) { - // The serialized histogram might be corrupted. - return NULL; - } - return histogram; -} - -// static -bool CustomHistogram::ValidateCustomRanges( - const vector& custom_ranges) { - bool has_valid_range = false; - for (size_t i = 0; i < custom_ranges.size(); i++) { - Sample sample = custom_ranges[i]; - if (sample < 0 || sample > HistogramBase::kSampleType_MAX - 1) - return false; - if (sample != 0) - has_valid_range = true; - } - return has_valid_range; -} - -// static -BucketRanges* CustomHistogram::CreateBucketRangesFromCustomRanges( - const vector& custom_ranges) { - // Remove the duplicates in the custom ranges array. - vector ranges = custom_ranges; - ranges.push_back(0); // Ensure we have a zero value. - ranges.push_back(HistogramBase::kSampleType_MAX); - std::sort(ranges.begin(), ranges.end()); - ranges.erase(std::unique(ranges.begin(), ranges.end()), ranges.end()); - - BucketRanges* bucket_ranges = new BucketRanges(ranges.size()); - for (size_t i = 0; i < ranges.size(); i++) { - bucket_ranges->set_range(i, ranges[i]); - } - bucket_ranges->ResetChecksum(); - return bucket_ranges; -} - -} // namespace base diff --git a/base/metrics/histogram.h b/base/metrics/histogram.h deleted file mode 100644 index d82f90aabd..0000000000 --- a/base/metrics/histogram.h +++ /dev/null @@ -1,675 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -// Histogram is an object that aggregates statistics, and can summarize them in -// various forms, including ASCII graphical, HTML, and numerically (as a -// vector of numbers corresponding to each of the aggregating buckets). - -// It supports calls to accumulate either time intervals (which are processed -// as integral number of milliseconds), or arbitrary integral units. - -// For Histogram(exponential histogram), LinearHistogram and CustomHistogram, -// the minimum for a declared range is 1 (instead of 0), while the maximum is -// (HistogramBase::kSampleType_MAX - 1). Currently you can declare histograms -// with ranges exceeding those limits (e.g. 0 as minimal or -// HistogramBase::kSampleType_MAX as maximal), but those excesses will be -// silently clamped to those limits (for backwards compatibility with existing -// code). Best practice is to not exceed the limits. - -// Each use of a histogram with the same name will reference the same underlying -// data, so it is safe to record to the same histogram from multiple locations -// in the code. It is a runtime error if all uses of the same histogram do not -// agree exactly in type, bucket size and range. - -// For Histogram and LinearHistogram, the maximum for a declared range should -// always be larger (not equal) than minmal range. Zero and -// HistogramBase::kSampleType_MAX are implicitly added as first and last ranges, -// so the smallest legal bucket_count is 3. However CustomHistogram can have -// bucket count as 2 (when you give a custom ranges vector containing only 1 -// range). -// For these 3 kinds of histograms, the max bucket count is always -// (Histogram::kBucketCount_MAX - 1). - -// The buckets layout of class Histogram is exponential. For example, buckets -// might contain (sequentially) the count of values in the following intervals: -// [0,1), [1,2), [2,4), [4,8), [8,16), [16,32), [32,64), [64,infinity) -// That bucket allocation would actually result from construction of a histogram -// for values between 1 and 64, with 8 buckets, such as: -// Histogram count("some name", 1, 64, 8); -// Note that the underflow bucket [0,1) and the overflow bucket [64,infinity) -// are also counted by the constructor in the user supplied "bucket_count" -// argument. -// The above example has an exponential ratio of 2 (doubling the bucket width -// in each consecutive bucket. The Histogram class automatically calculates -// the smallest ratio that it can use to construct the number of buckets -// selected in the constructor. An another example, if you had 50 buckets, -// and millisecond time values from 1 to 10000, then the ratio between -// consecutive bucket widths will be approximately somewhere around the 50th -// root of 10000. This approach provides very fine grain (narrow) buckets -// at the low end of the histogram scale, but allows the histogram to cover a -// gigantic range with the addition of very few buckets. - -// Usually we use macros to define and use a histogram. These macros use a -// pattern involving a function static variable, that is a pointer to a -// histogram. This static is explicitly initialized on any thread -// that detects a uninitialized (NULL) pointer. The potentially racy -// initialization is not a problem as it is always set to point to the same -// value (i.e., the FactoryGet always returns the same value). FactoryGet -// is also completely thread safe, which results in a completely thread safe, -// and relatively fast, set of counters. To avoid races at shutdown, the static -// pointer is NOT deleted, and we leak the histograms at process termination. - -#ifndef BASE_METRICS_HISTOGRAM_H_ -#define BASE_METRICS_HISTOGRAM_H_ - -#include -#include -#include - -#include "base/atomicops.h" -#include "base/base_export.h" -#include "base/basictypes.h" -#include "base/compiler_specific.h" -#include "base/gtest_prod_util.h" -#include "base/logging.h" -#include "base/memory/scoped_ptr.h" -#include "base/metrics/bucket_ranges.h" -#include "base/metrics/histogram_base.h" -#include "base/metrics/histogram_samples.h" -#include "base/time/time.h" - -class Pickle; -class PickleIterator; - -namespace base { - -class Lock; -//------------------------------------------------------------------------------ -// Histograms are often put in areas where they are called many many times, and -// performance is critical. As a result, they are designed to have a very low -// recurring cost of executing (adding additional samples). Toward that end, -// the macros declare a static pointer to the histogram in question, and only -// take a "slow path" to construct (or find) the histogram on the first run -// through the macro. We leak the histograms at shutdown time so that we don't -// have to validate using the pointers at any time during the running of the -// process. - -// The following code is generally what a thread-safe static pointer -// initializaion looks like for a histogram (after a macro is expanded). This -// sample is an expansion (with comments) of the code for -// HISTOGRAM_CUSTOM_COUNTS(). - -/* - do { - // The pointer's presence indicates the initialization is complete. - // Initialization is idempotent, so it can safely be atomically repeated. - static base::subtle::AtomicWord atomic_histogram_pointer = 0; - - // Acquire_Load() ensures that we acquire visibility to the pointed-to data - // in the histogrom. - base::Histogram* histogram_pointer(reinterpret_cast( - base::subtle::Acquire_Load(&atomic_histogram_pointer))); - - if (!histogram_pointer) { - // This is the slow path, which will construct OR find the matching - // histogram. FactoryGet includes locks on a global histogram name map - // and is completely thread safe. - histogram_pointer = base::Histogram::FactoryGet( - name, min, max, bucket_count, base::HistogramBase::kNoFlags); - - // Use Release_Store to ensure that the histogram data is made available - // globally before we make the pointer visible. - // Several threads may perform this store, but the same value will be - // stored in all cases (for a given named/spec'ed histogram). - // We could do this without any barrier, since FactoryGet entered and - // exited a lock after construction, but this barrier makes things clear. - base::subtle::Release_Store(&atomic_histogram_pointer, - reinterpret_cast(histogram_pointer)); - } - - // Ensure calling contract is upheld, and the name does NOT vary. - DCHECK(histogram_pointer->histogram_name() == constant_histogram_name); - - histogram_pointer->Add(sample); - } while (0); -*/ - -// The above pattern is repeated in several macros. The only elements that -// vary are the invocation of the Add(sample) vs AddTime(sample), and the choice -// of which FactoryGet method to use. The different FactoryGet methods have -// various argument lists, so the function with its argument list is provided as -// a macro argument here. The name is only used in a DCHECK, to assure that -// callers don't try to vary the name of the histogram (which would tend to be -// ignored by the one-time initialization of the histogtram_pointer). -#define STATIC_HISTOGRAM_POINTER_BLOCK(constant_histogram_name, \ - histogram_add_method_invocation, \ - histogram_factory_get_invocation) \ - do { \ - static base::subtle::AtomicWord atomic_histogram_pointer = 0; \ - base::HistogramBase* histogram_pointer( \ - reinterpret_cast( \ - base::subtle::Acquire_Load(&atomic_histogram_pointer))); \ - if (!histogram_pointer) { \ - histogram_pointer = histogram_factory_get_invocation; \ - base::subtle::Release_Store(&atomic_histogram_pointer, \ - reinterpret_cast(histogram_pointer)); \ - } \ - DCHECK_EQ(histogram_pointer->histogram_name(), \ - std::string(constant_histogram_name)); \ - histogram_pointer->histogram_add_method_invocation; \ - } while (0) - - -//------------------------------------------------------------------------------ -// Provide easy general purpose histogram in a macro, just like stats counters. -// The first four macros use 50 buckets. - -#define HISTOGRAM_TIMES(name, sample) HISTOGRAM_CUSTOM_TIMES( \ - name, sample, base::TimeDelta::FromMilliseconds(1), \ - base::TimeDelta::FromSeconds(10), 50) - -// For folks that need real specific times, use this to select a precise range -// of times you want plotted, and the number of buckets you want used. -#define HISTOGRAM_CUSTOM_TIMES(name, sample, min, max, bucket_count) \ - STATIC_HISTOGRAM_POINTER_BLOCK(name, AddTime(sample), \ - base::Histogram::FactoryTimeGet(name, min, max, bucket_count, \ - base::HistogramBase::kNoFlags)) - -#define HISTOGRAM_COUNTS(name, sample) HISTOGRAM_CUSTOM_COUNTS( \ - name, sample, 1, 1000000, 50) - -#define HISTOGRAM_COUNTS_100(name, sample) HISTOGRAM_CUSTOM_COUNTS( \ - name, sample, 1, 100, 50) - -#define HISTOGRAM_COUNTS_10000(name, sample) HISTOGRAM_CUSTOM_COUNTS( \ - name, sample, 1, 10000, 50) - -#define HISTOGRAM_CUSTOM_COUNTS(name, sample, min, max, bucket_count) \ - STATIC_HISTOGRAM_POINTER_BLOCK(name, Add(sample), \ - base::Histogram::FactoryGet(name, min, max, bucket_count, \ - base::HistogramBase::kNoFlags)) - -#define HISTOGRAM_PERCENTAGE(name, under_one_hundred) \ - HISTOGRAM_ENUMERATION(name, under_one_hundred, 101) - -#define HISTOGRAM_BOOLEAN(name, sample) \ - STATIC_HISTOGRAM_POINTER_BLOCK(name, AddBoolean(sample), \ - base::BooleanHistogram::FactoryGet(name, base::Histogram::kNoFlags)) - -// Support histograming of an enumerated value. The samples should always be -// strictly less than |boundary_value| -- this prevents you from running into -// problems down the line if you add additional buckets to the histogram. Note -// also that, despite explicitly setting the minimum bucket value to |1| below, -// it is fine for enumerated histograms to be 0-indexed -- this is because -// enumerated histograms should never have underflow. -#define HISTOGRAM_ENUMERATION(name, sample, boundary_value) \ - STATIC_HISTOGRAM_POINTER_BLOCK(name, Add(sample), \ - base::LinearHistogram::FactoryGet(name, 1, boundary_value, \ - boundary_value + 1, base::HistogramBase::kNoFlags)) - -// Support histograming of an enumerated value. Samples should be one of the -// std::vector list provided via |custom_ranges|. See comments above -// CustomRanges::FactoryGet about the requirement of |custom_ranges|. -// You can use the helper function CustomHistogram::ArrayToCustomRanges to -// transform a C-style array of valid sample values to a std::vector. -#define HISTOGRAM_CUSTOM_ENUMERATION(name, sample, custom_ranges) \ - STATIC_HISTOGRAM_POINTER_BLOCK(name, Add(sample), \ - base::CustomHistogram::FactoryGet(name, custom_ranges, \ - base::HistogramBase::kNoFlags)) - -#define HISTOGRAM_MEMORY_KB(name, sample) HISTOGRAM_CUSTOM_COUNTS( \ - name, sample, 1000, 500000, 50) - -//------------------------------------------------------------------------------ -// Define Debug vs non-debug flavors of macros. -#ifndef NDEBUG - -#define DHISTOGRAM_TIMES(name, sample) HISTOGRAM_TIMES(name, sample) -#define DHISTOGRAM_COUNTS(name, sample) HISTOGRAM_COUNTS(name, sample) -#define DHISTOGRAM_PERCENTAGE(name, under_one_hundred) HISTOGRAM_PERCENTAGE(\ - name, under_one_hundred) -#define DHISTOGRAM_CUSTOM_TIMES(name, sample, min, max, bucket_count) \ - HISTOGRAM_CUSTOM_TIMES(name, sample, min, max, bucket_count) -#define DHISTOGRAM_CLIPPED_TIMES(name, sample, min, max, bucket_count) \ - HISTOGRAM_CLIPPED_TIMES(name, sample, min, max, bucket_count) -#define DHISTOGRAM_CUSTOM_COUNTS(name, sample, min, max, bucket_count) \ - HISTOGRAM_CUSTOM_COUNTS(name, sample, min, max, bucket_count) -#define DHISTOGRAM_ENUMERATION(name, sample, boundary_value) \ - HISTOGRAM_ENUMERATION(name, sample, boundary_value) -#define DHISTOGRAM_CUSTOM_ENUMERATION(name, sample, custom_ranges) \ - HISTOGRAM_CUSTOM_ENUMERATION(name, sample, custom_ranges) - -#else // NDEBUG -// Keep a mention of passed variables to avoid unused variable warnings in -// release build if these variables are only used in macros. -#define DISCARD_2_ARGUMENTS(a, b) \ - while (0) { \ - static_cast(a); \ - static_cast(b); \ - } -#define DISCARD_3_ARGUMENTS(a, b, c) \ - while (0) { \ - static_cast(a); \ - static_cast(b); \ - static_cast(c); \ - } -#define DISCARD_5_ARGUMENTS(a, b, c, d ,e) \ - while (0) { \ - static_cast(a); \ - static_cast(b); \ - static_cast(c); \ - static_cast(d); \ - static_cast(e); \ - } -#define DHISTOGRAM_TIMES(name, sample) \ - DISCARD_2_ARGUMENTS(name, sample) - -#define DHISTOGRAM_COUNTS(name, sample) \ - DISCARD_2_ARGUMENTS(name, sample) - -#define DHISTOGRAM_PERCENTAGE(name, under_one_hundred) \ - DISCARD_2_ARGUMENTS(name, under_one_hundred) - -#define DHISTOGRAM_CUSTOM_TIMES(name, sample, min, max, bucket_count) \ - DISCARD_5_ARGUMENTS(name, sample, min, max, bucket_count) - -#define DHISTOGRAM_CLIPPED_TIMES(name, sample, min, max, bucket_count) \ - DISCARD_5_ARGUMENTS(name, sample, min, max, bucket_count) - -#define DHISTOGRAM_CUSTOM_COUNTS(name, sample, min, max, bucket_count) \ - DISCARD_5_ARGUMENTS(name, sample, min, max, bucket_count) - -#define DHISTOGRAM_ENUMERATION(name, sample, boundary_value) \ - DISCARD_3_ARGUMENTS(name, sample, boundary_value) - -#define DHISTOGRAM_CUSTOM_ENUMERATION(name, sample, custom_ranges) \ - DISCARD_3_ARGUMENTS(name, sample, custom_ranges) - -#endif // NDEBUG - -//------------------------------------------------------------------------------ -// The following macros provide typical usage scenarios for callers that wish -// to record histogram data, and have the data submitted/uploaded via UMA. -// Not all systems support such UMA, but if they do, the following macros -// should work with the service. - -#define UMA_HISTOGRAM_TIMES(name, sample) UMA_HISTOGRAM_CUSTOM_TIMES( \ - name, sample, base::TimeDelta::FromMilliseconds(1), \ - base::TimeDelta::FromSeconds(10), 50) - -#define UMA_HISTOGRAM_MEDIUM_TIMES(name, sample) UMA_HISTOGRAM_CUSTOM_TIMES( \ - name, sample, base::TimeDelta::FromMilliseconds(10), \ - base::TimeDelta::FromMinutes(3), 50) - -// Use this macro when times can routinely be much longer than 10 seconds. -#define UMA_HISTOGRAM_LONG_TIMES(name, sample) UMA_HISTOGRAM_CUSTOM_TIMES( \ - name, sample, base::TimeDelta::FromMilliseconds(1), \ - base::TimeDelta::FromHours(1), 50) - -#define UMA_HISTOGRAM_CUSTOM_TIMES(name, sample, min, max, bucket_count) \ - STATIC_HISTOGRAM_POINTER_BLOCK(name, AddTime(sample), \ - base::Histogram::FactoryTimeGet(name, min, max, bucket_count, \ - base::HistogramBase::kUmaTargetedHistogramFlag)) - -#define UMA_HISTOGRAM_COUNTS(name, sample) UMA_HISTOGRAM_CUSTOM_COUNTS( \ - name, sample, 1, 1000000, 50) - -#define UMA_HISTOGRAM_COUNTS_100(name, sample) UMA_HISTOGRAM_CUSTOM_COUNTS( \ - name, sample, 1, 100, 50) - -#define UMA_HISTOGRAM_COUNTS_10000(name, sample) UMA_HISTOGRAM_CUSTOM_COUNTS( \ - name, sample, 1, 10000, 50) - -#define UMA_HISTOGRAM_CUSTOM_COUNTS(name, sample, min, max, bucket_count) \ - STATIC_HISTOGRAM_POINTER_BLOCK(name, Add(sample), \ - base::Histogram::FactoryGet(name, min, max, bucket_count, \ - base::HistogramBase::kUmaTargetedHistogramFlag)) - -#define UMA_HISTOGRAM_MEMORY_KB(name, sample) UMA_HISTOGRAM_CUSTOM_COUNTS( \ - name, sample, 1000, 500000, 50) - -#define UMA_HISTOGRAM_MEMORY_MB(name, sample) UMA_HISTOGRAM_CUSTOM_COUNTS( \ - name, sample, 1, 1000, 50) - -#define UMA_HISTOGRAM_PERCENTAGE(name, under_one_hundred) \ - UMA_HISTOGRAM_ENUMERATION(name, under_one_hundred, 101) - -#define UMA_HISTOGRAM_BOOLEAN(name, sample) \ - STATIC_HISTOGRAM_POINTER_BLOCK(name, AddBoolean(sample), \ - base::BooleanHistogram::FactoryGet(name, \ - base::HistogramBase::kUmaTargetedHistogramFlag)) - -// The samples should always be strictly less than |boundary_value|. For more -// details, see the comment for the |HISTOGRAM_ENUMERATION| macro, above. -#define UMA_HISTOGRAM_ENUMERATION(name, sample, boundary_value) \ - STATIC_HISTOGRAM_POINTER_BLOCK(name, Add(sample), \ - base::LinearHistogram::FactoryGet(name, 1, boundary_value, \ - boundary_value + 1, base::HistogramBase::kUmaTargetedHistogramFlag)) - -#define UMA_HISTOGRAM_CUSTOM_ENUMERATION(name, sample, custom_ranges) \ - STATIC_HISTOGRAM_POINTER_BLOCK(name, Add(sample), \ - base::CustomHistogram::FactoryGet(name, custom_ranges, \ - base::HistogramBase::kUmaTargetedHistogramFlag)) - -//------------------------------------------------------------------------------ - -class BucketRanges; -class SampleVector; - -class BooleanHistogram; -class CustomHistogram; -class Histogram; -class LinearHistogram; - -class BASE_EXPORT Histogram : public HistogramBase { - public: - // Initialize maximum number of buckets in histograms as 16,384. - static const size_t kBucketCount_MAX; - - typedef std::vector Counts; - - //---------------------------------------------------------------------------- - // For a valid histogram, input should follow these restrictions: - // minimum > 0 (if a minimum below 1 is specified, it will implicitly be - // normalized up to 1) - // maximum > minimum - // buckets > 2 [minimum buckets needed: underflow, overflow and the range] - // Additionally, - // buckets <= (maximum - minimum + 2) - this is to ensure that we don't have - // more buckets than the range of numbers; having more buckets than 1 per - // value in the range would be nonsensical. - static HistogramBase* FactoryGet(const std::string& name, - Sample minimum, - Sample maximum, - size_t bucket_count, - int32 flags); - static HistogramBase* FactoryTimeGet(const std::string& name, - base::TimeDelta minimum, - base::TimeDelta maximum, - size_t bucket_count, - int32 flags); - - // Time call for use with DHISTOGRAM*. - // Returns TimeTicks::Now() in debug and TimeTicks() in release build. - static TimeTicks DebugNow(); - - static void InitializeBucketRanges(Sample minimum, - Sample maximum, - BucketRanges* ranges); - - // This constant if for FindCorruption. Since snapshots of histograms are - // taken asynchronously relative to sampling, and our counting code currently - // does not prevent race conditions, it is pretty likely that we'll catch a - // redundant count that doesn't match the sample count. We allow for a - // certain amount of slop before flagging this as an inconsistency. Even with - // an inconsistency, we'll snapshot it again (for UMA in about a half hour), - // so we'll eventually get the data, if it was not the result of a corruption. - static const int kCommonRaceBasedCountMismatch; - - // Check to see if bucket ranges, counts and tallies in the snapshot are - // consistent with the bucket ranges and checksums in our histogram. This can - // produce a false-alarm if a race occurred in the reading of the data during - // a SnapShot process, but should otherwise be false at all times (unless we - // have memory over-writes, or DRAM failures). - virtual int FindCorruption(const HistogramSamples& samples) const OVERRIDE; - - //---------------------------------------------------------------------------- - // Accessors for factory constuction, serialization and testing. - //---------------------------------------------------------------------------- - Sample declared_min() const { return declared_min_; } - Sample declared_max() const { return declared_max_; } - virtual Sample ranges(size_t i) const; - virtual size_t bucket_count() const; - const BucketRanges* bucket_ranges() const { return bucket_ranges_; } - - // This function validates histogram construction arguments. It returns false - // if some of the arguments are totally bad. - // Note. Currently it allow some bad input, e.g. 0 as minimum, but silently - // converts it to good input: 1. - // TODO(kaiwang): Be more restrict and return false for any bad input, and - // make this a readonly validating function. - static bool InspectConstructionArguments(const std::string& name, - Sample* minimum, - Sample* maximum, - size_t* bucket_count); - - // HistogramBase implementation: - virtual HistogramType GetHistogramType() const OVERRIDE; - virtual bool HasConstructionArguments( - Sample expected_minimum, - Sample expected_maximum, - size_t expected_bucket_count) const OVERRIDE; - virtual void Add(Sample value) OVERRIDE; - virtual scoped_ptr SnapshotSamples() const OVERRIDE; - virtual void AddSamples(const HistogramSamples& samples) OVERRIDE; - virtual bool AddSamplesFromPickle(PickleIterator* iter) OVERRIDE; - virtual void WriteHTMLGraph(std::string* output) const OVERRIDE; - virtual void WriteAscii(std::string* output) const OVERRIDE; - - protected: - // |ranges| should contain the underflow and overflow buckets. See top - // comments for example. - Histogram(const std::string& name, - Sample minimum, - Sample maximum, - const BucketRanges* ranges); - - virtual ~Histogram(); - - // HistogramBase implementation: - virtual bool SerializeInfoImpl(Pickle* pickle) const OVERRIDE; - - // Method to override to skip the display of the i'th bucket if it's empty. - virtual bool PrintEmptyBucket(size_t index) const; - - // Get normalized size, relative to the ranges(i). - virtual double GetBucketSize(Count current, size_t i) const; - - // Return a string description of what goes in a given bucket. - // Most commonly this is the numeric value, but in derived classes it may - // be a name (or string description) given to the bucket. - virtual const std::string GetAsciiBucketRange(size_t it) const; - - private: - // Allow tests to corrupt our innards for testing purposes. - FRIEND_TEST_ALL_PREFIXES(HistogramTest, BoundsTest); - FRIEND_TEST_ALL_PREFIXES(HistogramTest, BucketPlacementTest); - FRIEND_TEST_ALL_PREFIXES(HistogramTest, CorruptBucketBounds); - FRIEND_TEST_ALL_PREFIXES(HistogramTest, CorruptSampleCounts); - FRIEND_TEST_ALL_PREFIXES(HistogramTest, NameMatchTest); - - friend class StatisticsRecorder; // To allow it to delete duplicates. - friend class StatisticsRecorderTest; - - friend BASE_EXPORT_PRIVATE HistogramBase* DeserializeHistogramInfo( - PickleIterator* iter); - static HistogramBase* DeserializeInfoImpl(PickleIterator* iter); - - // Implementation of SnapshotSamples function. - scoped_ptr SnapshotSampleVector() const; - - //---------------------------------------------------------------------------- - // Helpers for emitting Ascii graphic. Each method appends data to output. - - void WriteAsciiImpl(bool graph_it, - const std::string& newline, - std::string* output) const; - - // Find out how large (graphically) the largest bucket will appear to be. - double GetPeakBucketSize(const SampleVector& samples) const; - - // Write a common header message describing this histogram. - void WriteAsciiHeader(const SampleVector& samples, - Count sample_count, - std::string* output) const; - - // Write information about previous, current, and next buckets. - // Information such as cumulative percentage, etc. - void WriteAsciiBucketContext(const int64 past, const Count current, - const int64 remaining, const size_t i, - std::string* output) const; - - // WriteJSON calls these. - virtual void GetParameters(DictionaryValue* params) const OVERRIDE; - - virtual void GetCountAndBucketData(Count* count, - int64* sum, - ListValue* buckets) const OVERRIDE; - - // Does not own this object. Should get from StatisticsRecorder. - const BucketRanges* bucket_ranges_; - - Sample declared_min_; // Less than this goes into the first bucket. - Sample declared_max_; // Over this goes into the last bucket. - - // Finally, provide the state that changes with the addition of each new - // sample. - scoped_ptr samples_; - - DISALLOW_COPY_AND_ASSIGN(Histogram); -}; - -//------------------------------------------------------------------------------ - -// LinearHistogram is a more traditional histogram, with evenly spaced -// buckets. -class BASE_EXPORT LinearHistogram : public Histogram { - public: - virtual ~LinearHistogram(); - - /* minimum should start from 1. 0 is as minimum is invalid. 0 is an implicit - default underflow bucket. */ - static HistogramBase* FactoryGet(const std::string& name, - Sample minimum, - Sample maximum, - size_t bucket_count, - int32 flags); - static HistogramBase* FactoryTimeGet(const std::string& name, - TimeDelta minimum, - TimeDelta maximum, - size_t bucket_count, - int32 flags); - - struct DescriptionPair { - Sample sample; - const char* description; // Null means end of a list of pairs. - }; - - // Create a LinearHistogram and store a list of number/text values for use in - // writing the histogram graph. - // |descriptions| can be NULL, which means no special descriptions to set. If - // it's not NULL, the last element in the array must has a NULL in its - // "description" field. - static HistogramBase* FactoryGetWithRangeDescription( - const std::string& name, - Sample minimum, - Sample maximum, - size_t bucket_count, - int32 flags, - const DescriptionPair descriptions[]); - - static void InitializeBucketRanges(Sample minimum, - Sample maximum, - BucketRanges* ranges); - - // Overridden from Histogram: - virtual HistogramType GetHistogramType() const OVERRIDE; - - protected: - LinearHistogram(const std::string& name, - Sample minimum, - Sample maximum, - const BucketRanges* ranges); - - virtual double GetBucketSize(Count current, size_t i) const OVERRIDE; - - // If we have a description for a bucket, then return that. Otherwise - // let parent class provide a (numeric) description. - virtual const std::string GetAsciiBucketRange(size_t i) const OVERRIDE; - - // Skip printing of name for numeric range if we have a name (and if this is - // an empty bucket). - virtual bool PrintEmptyBucket(size_t index) const OVERRIDE; - - private: - friend BASE_EXPORT_PRIVATE HistogramBase* DeserializeHistogramInfo( - PickleIterator* iter); - static HistogramBase* DeserializeInfoImpl(PickleIterator* iter); - - // For some ranges, we store a printable description of a bucket range. - // If there is no desciption, then GetAsciiBucketRange() uses parent class - // to provide a description. - typedef std::map BucketDescriptionMap; - BucketDescriptionMap bucket_description_; - - DISALLOW_COPY_AND_ASSIGN(LinearHistogram); -}; - -//------------------------------------------------------------------------------ - -// BooleanHistogram is a histogram for booleans. -class BASE_EXPORT BooleanHistogram : public LinearHistogram { - public: - static HistogramBase* FactoryGet(const std::string& name, int32 flags); - - virtual HistogramType GetHistogramType() const OVERRIDE; - - private: - BooleanHistogram(const std::string& name, const BucketRanges* ranges); - - friend BASE_EXPORT_PRIVATE HistogramBase* DeserializeHistogramInfo( - PickleIterator* iter); - static HistogramBase* DeserializeInfoImpl(PickleIterator* iter); - - DISALLOW_COPY_AND_ASSIGN(BooleanHistogram); -}; - -//------------------------------------------------------------------------------ - -// CustomHistogram is a histogram for a set of custom integers. -class BASE_EXPORT CustomHistogram : public Histogram { - public: - // |custom_ranges| contains a vector of limits on ranges. Each limit should be - // > 0 and < kSampleType_MAX. (Currently 0 is still accepted for backward - // compatibility). The limits can be unordered or contain duplication, but - // client should not depend on this. - static HistogramBase* FactoryGet(const std::string& name, - const std::vector& custom_ranges, - int32 flags); - - // Overridden from Histogram: - virtual HistogramType GetHistogramType() const OVERRIDE; - - // Helper method for transforming an array of valid enumeration values - // to the std::vector expected by HISTOGRAM_CUSTOM_ENUMERATION. - // This function ensures that a guard bucket exists right after any - // valid sample value (unless the next higher sample is also a valid value), - // so that invalid samples never fall into the same bucket as valid samples. - // TODO(kaiwang): Change name to ArrayToCustomEnumRanges. - static std::vector ArrayToCustomRanges(const Sample* values, - size_t num_values); - protected: - CustomHistogram(const std::string& name, - const BucketRanges* ranges); - - // HistogramBase implementation: - virtual bool SerializeInfoImpl(Pickle* pickle) const OVERRIDE; - - virtual double GetBucketSize(Count current, size_t i) const OVERRIDE; - - private: - friend BASE_EXPORT_PRIVATE HistogramBase* DeserializeHistogramInfo( - PickleIterator* iter); - static HistogramBase* DeserializeInfoImpl(PickleIterator* iter); - - static bool ValidateCustomRanges(const std::vector& custom_ranges); - static BucketRanges* CreateBucketRangesFromCustomRanges( - const std::vector& custom_ranges); - - DISALLOW_COPY_AND_ASSIGN(CustomHistogram); -}; - -} // namespace base - -#endif // BASE_METRICS_HISTOGRAM_H_ diff --git a/base/metrics/histogram_base.cc b/base/metrics/histogram_base.cc deleted file mode 100644 index 5b46d2990c..0000000000 --- a/base/metrics/histogram_base.cc +++ /dev/null @@ -1,161 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "base/metrics/histogram_base.h" - -#include - -#include "base/json/json_string_value_serializer.h" -#include "base/logging.h" -#include "base/memory/scoped_ptr.h" -#include "base/metrics/histogram.h" -#include "base/metrics/histogram_samples.h" -#include "base/metrics/sparse_histogram.h" -#include "base/pickle.h" -#include "base/process/process_handle.h" -#include "base/strings/stringprintf.h" -#include "base/values.h" - -namespace base { - -std::string HistogramTypeToString(HistogramType type) { - switch(type) { - case HISTOGRAM: - return "HISTOGRAM"; - case LINEAR_HISTOGRAM: - return "LINEAR_HISTOGRAM"; - case BOOLEAN_HISTOGRAM: - return "BOOLEAN_HISTOGRAM"; - case CUSTOM_HISTOGRAM: - return "CUSTOM_HISTOGRAM"; - case SPARSE_HISTOGRAM: - return "SPARSE_HISTOGRAM"; - default: - NOTREACHED(); - } - return "UNKNOWN"; -} - -HistogramBase* DeserializeHistogramInfo(PickleIterator* iter) { - int type; - if (!iter->ReadInt(&type)) - return NULL; - - switch (type) { - case HISTOGRAM: - return Histogram::DeserializeInfoImpl(iter); - case LINEAR_HISTOGRAM: - return LinearHistogram::DeserializeInfoImpl(iter); - case BOOLEAN_HISTOGRAM: - return BooleanHistogram::DeserializeInfoImpl(iter); - case CUSTOM_HISTOGRAM: - return CustomHistogram::DeserializeInfoImpl(iter); - case SPARSE_HISTOGRAM: - return SparseHistogram::DeserializeInfoImpl(iter); - default: - return NULL; - } -} - -void DeserializeHistogramAndAddSamples(PickleIterator* iter) { - HistogramBase* histogram = DeserializeHistogramInfo(iter); - if (!histogram) - return; - - if (histogram->flags() & base::HistogramBase::kIPCSerializationSourceFlag) { - DVLOG(1) << "Single process mode, histogram observed and not copied: " - << histogram->histogram_name(); - return; - } - histogram->AddSamplesFromPickle(iter); -} - - -const HistogramBase::Sample HistogramBase::kSampleType_MAX = INT_MAX; - -HistogramBase::HistogramBase(const std::string& name) - : histogram_name_(name), - flags_(kNoFlags) {} - -HistogramBase::~HistogramBase() {} - -void HistogramBase::SetFlags(int32 flags) { - flags_ |= flags; -} - -void HistogramBase::ClearFlags(int32 flags) { - flags_ &= ~flags; -} - -void HistogramBase::AddTime(const TimeDelta& time) { - Add(static_cast(time.InMilliseconds())); -} - -void HistogramBase::AddBoolean(bool value) { - Add(value ? 1 : 0); -} - -bool HistogramBase::SerializeInfo(Pickle* pickle) const { - if (!pickle->WriteInt(GetHistogramType())) - return false; - return SerializeInfoImpl(pickle); -} - -int HistogramBase::FindCorruption(const HistogramSamples& samples) const { - // Not supported by default. - return NO_INCONSISTENCIES; -} - -void HistogramBase::WriteJSON(std::string* output) const { - Count count; - int64 sum; - scoped_ptr buckets(new ListValue()); - GetCountAndBucketData(&count, &sum, buckets.get()); - scoped_ptr parameters(new DictionaryValue()); - GetParameters(parameters.get()); - - JSONStringValueSerializer serializer(output); - DictionaryValue root; - root.SetString("name", histogram_name()); - root.SetInteger("count", count); - root.SetDouble("sum", sum); - root.SetInteger("flags", flags()); - root.Set("params", parameters.release()); - root.Set("buckets", buckets.release()); - root.SetInteger("pid", GetCurrentProcId()); - serializer.Serialize(root); -} - -void HistogramBase::WriteAsciiBucketGraph(double current_size, - double max_size, - std::string* output) const { - const int k_line_length = 72; // Maximal horizontal width of graph. - int x_count = static_cast(k_line_length * (current_size / max_size) - + 0.5); - int x_remainder = k_line_length - x_count; - - while (0 < x_count--) - output->append("-"); - output->append("O"); - while (0 < x_remainder--) - output->append(" "); -} - -const std::string HistogramBase::GetSimpleAsciiBucketRange( - Sample sample) const { - std::string result; - if (kHexRangePrintingFlag & flags()) - StringAppendF(&result, "%#x", sample); - else - StringAppendF(&result, "%d", sample); - return result; -} - -void HistogramBase::WriteAsciiBucketValue(Count current, - double scaled_sum, - std::string* output) const { - StringAppendF(output, " (%d = %3.1f%%)", current, current/scaled_sum); -} - -} // namespace base diff --git a/base/metrics/histogram_base.h b/base/metrics/histogram_base.h deleted file mode 100644 index f5448e78ca..0000000000 --- a/base/metrics/histogram_base.h +++ /dev/null @@ -1,171 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef BASE_METRICS_HISTOGRAM_BASE_H_ -#define BASE_METRICS_HISTOGRAM_BASE_H_ - -#include - -#include "base/base_export.h" -#include "base/basictypes.h" -#include "base/memory/scoped_ptr.h" -#include "base/time/time.h" - -class Pickle; -class PickleIterator; - -namespace base { - -class DictionaryValue; -class HistogramBase; -class HistogramSamples; -class ListValue; - -//////////////////////////////////////////////////////////////////////////////// -// These enums are used to facilitate deserialization of histograms from other -// processes into the browser. If you create another class that inherits from -// HistogramBase, add new histogram types and names below. - -enum BASE_EXPORT HistogramType { - HISTOGRAM, - LINEAR_HISTOGRAM, - BOOLEAN_HISTOGRAM, - CUSTOM_HISTOGRAM, - SPARSE_HISTOGRAM, -}; - -std::string HistogramTypeToString(HistogramType type); - -// Create or find existing histogram that matches the pickled info. -// Returns NULL if the pickled data has problems. -BASE_EXPORT_PRIVATE HistogramBase* DeserializeHistogramInfo( - PickleIterator* iter); - -// Create or find existing histogram and add the samples from pickle. -// Silently returns when seeing any data problem in the pickle. -BASE_EXPORT void DeserializeHistogramAndAddSamples(PickleIterator* iter); - -//////////////////////////////////////////////////////////////////////////////// - -class BASE_EXPORT HistogramBase { - public: - typedef int Sample; // Used for samples. - typedef int Count; // Used to count samples. - - static const Sample kSampleType_MAX; // INT_MAX - - enum Flags { - kNoFlags = 0, - kUmaTargetedHistogramFlag = 0x1, // Histogram should be UMA uploaded. - - // Indicate that the histogram was pickled to be sent across an IPC Channel. - // If we observe this flag on a histogram being aggregated into after IPC, - // then we are running in a single process mode, and the aggregation should - // not take place (as we would be aggregating back into the source - // histogram!). - kIPCSerializationSourceFlag = 0x10, - - // Only for Histogram and its sub classes: fancy bucket-naming support. - kHexRangePrintingFlag = 0x8000, - }; - - // Histogram data inconsistency types. - enum Inconsistency { - NO_INCONSISTENCIES = 0x0, - RANGE_CHECKSUM_ERROR = 0x1, - BUCKET_ORDER_ERROR = 0x2, - COUNT_HIGH_ERROR = 0x4, - COUNT_LOW_ERROR = 0x8, - - NEVER_EXCEEDED_VALUE = 0x10 - }; - - explicit HistogramBase(const std::string& name); - virtual ~HistogramBase(); - - std::string histogram_name() const { return histogram_name_; } - - // Operations with Flags enum. - int32 flags() const { return flags_; } - void SetFlags(int32 flags); - void ClearFlags(int32 flags); - - virtual HistogramType GetHistogramType() const = 0; - - // Whether the histogram has construction arguments as parameters specified. - // For histograms that don't have the concept of minimum, maximum or - // bucket_count, this function always returns false. - virtual bool HasConstructionArguments(Sample expected_minimum, - Sample expected_maximum, - size_t expected_bucket_count) const = 0; - - virtual void Add(Sample value) = 0; - - // 2 convenient functions that call Add(Sample). - void AddTime(const TimeDelta& time); - void AddBoolean(bool value); - - virtual void AddSamples(const HistogramSamples& samples) = 0; - virtual bool AddSamplesFromPickle(PickleIterator* iter) = 0; - - // Serialize the histogram info into |pickle|. - // Note: This only serializes the construction arguments of the histogram, but - // does not serialize the samples. - bool SerializeInfo(Pickle* pickle) const; - - // Try to find out data corruption from histogram and the samples. - // The returned value is a combination of Inconsistency enum. - virtual int FindCorruption(const HistogramSamples& samples) const; - - // Snapshot the current complete set of sample data. - // Override with atomic/locked snapshot if needed. - virtual scoped_ptr SnapshotSamples() const = 0; - - // The following methods provide graphical histogram displays. - virtual void WriteHTMLGraph(std::string* output) const = 0; - virtual void WriteAscii(std::string* output) const = 0; - - // Produce a JSON representation of the histogram. This is implemented with - // the help of GetParameters and GetCountAndBucketData; overwrite them to - // customize the output. - void WriteJSON(std::string* output) const; - -protected: - // Subclasses should implement this function to make SerializeInfo work. - virtual bool SerializeInfoImpl(Pickle* pickle) const = 0; - - // Writes information about the construction parameters in |params|. - virtual void GetParameters(DictionaryValue* params) const = 0; - - // Writes information about the current (non-empty) buckets and their sample - // counts to |buckets|, the total sample count to |count| and the total sum - // to |sum|. - virtual void GetCountAndBucketData(Count* count, - int64* sum, - ListValue* buckets) const = 0; - - //// Produce actual graph (set of blank vs non blank char's) for a bucket. - void WriteAsciiBucketGraph(double current_size, - double max_size, - std::string* output) const; - - // Return a string description of what goes in a given bucket. - const std::string GetSimpleAsciiBucketRange(Sample sample) const; - - // Write textual description of the bucket contents (relative to histogram). - // Output is the count in the buckets, as well as the percentage. - void WriteAsciiBucketValue(Count current, - double scaled_sum, - std::string* output) const; - - private: - const std::string histogram_name_; - int32 flags_; - - DISALLOW_COPY_AND_ASSIGN(HistogramBase); -}; - -} // namespace base - -#endif // BASE_METRICS_HISTOGRAM_BASE_H_ diff --git a/base/metrics/histogram_base_unittest.cc b/base/metrics/histogram_base_unittest.cc deleted file mode 100644 index 0e19d56f4c..0000000000 --- a/base/metrics/histogram_base_unittest.cc +++ /dev/null @@ -1,191 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include - -#include "base/metrics/histogram.h" -#include "base/metrics/histogram_base.h" -#include "base/metrics/sparse_histogram.h" -#include "base/metrics/statistics_recorder.h" -#include "base/pickle.h" -#include "testing/gtest/include/gtest/gtest.h" - -namespace base { - -class HistogramBaseTest : public testing::Test { - protected: - HistogramBaseTest() { - // Each test will have a clean state (no Histogram / BucketRanges - // registered). - statistics_recorder_ = NULL; - ResetStatisticsRecorder(); - } - - virtual ~HistogramBaseTest() { - delete statistics_recorder_; - } - - void ResetStatisticsRecorder() { - delete statistics_recorder_; - statistics_recorder_ = new StatisticsRecorder(); - } - - private: - StatisticsRecorder* statistics_recorder_; -}; - -TEST_F(HistogramBaseTest, DeserializeHistogram) { - HistogramBase* histogram = Histogram::FactoryGet( - "TestHistogram", 1, 1000, 10, - (HistogramBase::kUmaTargetedHistogramFlag | - HistogramBase::kIPCSerializationSourceFlag)); - - Pickle pickle; - ASSERT_TRUE(histogram->SerializeInfo(&pickle)); - - PickleIterator iter(pickle); - HistogramBase* deserialized = DeserializeHistogramInfo(&iter); - EXPECT_EQ(histogram, deserialized); - - ResetStatisticsRecorder(); - - PickleIterator iter2(pickle); - deserialized = DeserializeHistogramInfo(&iter2); - EXPECT_TRUE(deserialized); - EXPECT_NE(histogram, deserialized); - EXPECT_EQ("TestHistogram", deserialized->histogram_name()); - EXPECT_TRUE(deserialized->HasConstructionArguments(1, 1000, 10)); - - // kIPCSerializationSourceFlag will be cleared. - EXPECT_EQ(HistogramBase::kUmaTargetedHistogramFlag, deserialized->flags()); -} - -TEST_F(HistogramBaseTest, DeserializeHistogramAndAddSamples) { - HistogramBase* histogram = Histogram::FactoryGet( - "TestHistogram", 1, 1000, 10, HistogramBase::kIPCSerializationSourceFlag); - histogram->Add(1); - histogram->Add(10); - histogram->Add(100); - histogram->Add(1000); - - Pickle pickle; - ASSERT_TRUE(histogram->SerializeInfo(&pickle)); - histogram->SnapshotSamples()->Serialize(&pickle); - - PickleIterator iter(pickle); - DeserializeHistogramAndAddSamples(&iter); - - // The histogram has kIPCSerializationSourceFlag. So samples will be ignored. - scoped_ptr snapshot(histogram->SnapshotSamples()); - EXPECT_EQ(1, snapshot->GetCount(1)); - EXPECT_EQ(1, snapshot->GetCount(10)); - EXPECT_EQ(1, snapshot->GetCount(100)); - EXPECT_EQ(1, snapshot->GetCount(1000)); - - // Clear kIPCSerializationSourceFlag to emulate multi-process usage. - histogram->ClearFlags(HistogramBase::kIPCSerializationSourceFlag); - PickleIterator iter2(pickle); - DeserializeHistogramAndAddSamples(&iter2); - - scoped_ptr snapshot2(histogram->SnapshotSamples()); - EXPECT_EQ(2, snapshot2->GetCount(1)); - EXPECT_EQ(2, snapshot2->GetCount(10)); - EXPECT_EQ(2, snapshot2->GetCount(100)); - EXPECT_EQ(2, snapshot2->GetCount(1000)); -} - -TEST_F(HistogramBaseTest, DeserializeLinearHistogram) { - HistogramBase* histogram = LinearHistogram::FactoryGet( - "TestHistogram", 1, 1000, 10, - HistogramBase::kIPCSerializationSourceFlag); - - Pickle pickle; - ASSERT_TRUE(histogram->SerializeInfo(&pickle)); - - PickleIterator iter(pickle); - HistogramBase* deserialized = DeserializeHistogramInfo(&iter); - EXPECT_EQ(histogram, deserialized); - - ResetStatisticsRecorder(); - - PickleIterator iter2(pickle); - deserialized = DeserializeHistogramInfo(&iter2); - EXPECT_TRUE(deserialized); - EXPECT_NE(histogram, deserialized); - EXPECT_EQ("TestHistogram", deserialized->histogram_name()); - EXPECT_TRUE(deserialized->HasConstructionArguments(1, 1000, 10)); - EXPECT_EQ(0, deserialized->flags()); -} - -TEST_F(HistogramBaseTest, DeserializeBooleanHistogram) { - HistogramBase* histogram = BooleanHistogram::FactoryGet( - "TestHistogram", HistogramBase::kIPCSerializationSourceFlag); - - Pickle pickle; - ASSERT_TRUE(histogram->SerializeInfo(&pickle)); - - PickleIterator iter(pickle); - HistogramBase* deserialized = DeserializeHistogramInfo(&iter); - EXPECT_EQ(histogram, deserialized); - - ResetStatisticsRecorder(); - - PickleIterator iter2(pickle); - deserialized = DeserializeHistogramInfo(&iter2); - EXPECT_TRUE(deserialized); - EXPECT_NE(histogram, deserialized); - EXPECT_EQ("TestHistogram", deserialized->histogram_name()); - EXPECT_TRUE(deserialized->HasConstructionArguments(1, 2, 3)); - EXPECT_EQ(0, deserialized->flags()); -} - -TEST_F(HistogramBaseTest, DeserializeCustomHistogram) { - std::vector ranges; - ranges.push_back(13); - ranges.push_back(5); - ranges.push_back(9); - - HistogramBase* histogram = CustomHistogram::FactoryGet( - "TestHistogram", ranges, HistogramBase::kIPCSerializationSourceFlag); - - Pickle pickle; - ASSERT_TRUE(histogram->SerializeInfo(&pickle)); - - PickleIterator iter(pickle); - HistogramBase* deserialized = DeserializeHistogramInfo(&iter); - EXPECT_EQ(histogram, deserialized); - - ResetStatisticsRecorder(); - - PickleIterator iter2(pickle); - deserialized = DeserializeHistogramInfo(&iter2); - EXPECT_TRUE(deserialized); - EXPECT_NE(histogram, deserialized); - EXPECT_EQ("TestHistogram", deserialized->histogram_name()); - EXPECT_TRUE(deserialized->HasConstructionArguments(5, 13, 4)); - EXPECT_EQ(0, deserialized->flags()); -} - -TEST_F(HistogramBaseTest, DeserializeSparseHistogram) { - HistogramBase* histogram = SparseHistogram::FactoryGet( - "TestHistogram", HistogramBase::kIPCSerializationSourceFlag); - - Pickle pickle; - ASSERT_TRUE(histogram->SerializeInfo(&pickle)); - - PickleIterator iter(pickle); - HistogramBase* deserialized = DeserializeHistogramInfo(&iter); - EXPECT_EQ(histogram, deserialized); - - ResetStatisticsRecorder(); - - PickleIterator iter2(pickle); - deserialized = DeserializeHistogramInfo(&iter2); - EXPECT_TRUE(deserialized); - EXPECT_NE(histogram, deserialized); - EXPECT_EQ("TestHistogram", deserialized->histogram_name()); - EXPECT_EQ(0, deserialized->flags()); -} - -} // namespace base diff --git a/base/metrics/histogram_flattener.h b/base/metrics/histogram_flattener.h deleted file mode 100644 index ca05a4f421..0000000000 --- a/base/metrics/histogram_flattener.h +++ /dev/null @@ -1,51 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef BASE_METRICS_HISTOGRAM_FLATTENER_H_ -#define BASE_METRICS_HISTOGRAM_FLATTENER_H_ - -#include -#include - -#include "base/basictypes.h" -#include "base/metrics/histogram.h" - -namespace base { - -class HistogramSamples; - -// HistogramFlattener is an interface used by HistogramSnapshotManager, which -// handles the logistics of gathering up available histograms for recording. -// The implementors handle the exact lower level recording mechanism, or -// error report mechanism. -class BASE_EXPORT HistogramFlattener { - public: - virtual void RecordDelta(const HistogramBase& histogram, - const HistogramSamples& snapshot) = 0; - - // Will be called each time a type of Inconsistency is seen on a histogram, - // during inspections done internally in HistogramSnapshotManager class. - virtual void InconsistencyDetected(HistogramBase::Inconsistency problem) = 0; - - // Will be called when a type of Inconsistency is seen for the first time on - // a histogram. - virtual void UniqueInconsistencyDetected( - HistogramBase::Inconsistency problem) = 0; - - // Will be called when the total logged sample count of a histogram - // differs from the sum of logged sample count in all the buckets. The - // argument |amount| is the non-zero discrepancy. - virtual void InconsistencyDetectedInLoggedCount(int amount) = 0; - - protected: - HistogramFlattener() {} - virtual ~HistogramFlattener() {} - - private: - DISALLOW_COPY_AND_ASSIGN(HistogramFlattener); -}; - -} // namespace base - -#endif // BASE_METRICS_HISTOGRAM_FLATTENER_H_ diff --git a/base/metrics/histogram_samples.cc b/base/metrics/histogram_samples.cc deleted file mode 100644 index 0e0eeb4dd3..0000000000 --- a/base/metrics/histogram_samples.cc +++ /dev/null @@ -1,126 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "base/metrics/histogram_samples.h" - -#include "base/compiler_specific.h" -#include "base/pickle.h" - -namespace base { - -namespace { - -class SampleCountPickleIterator : public SampleCountIterator { - public: - explicit SampleCountPickleIterator(PickleIterator* iter); - - virtual bool Done() const OVERRIDE; - virtual void Next() OVERRIDE; - virtual void Get(HistogramBase::Sample* min, - HistogramBase::Sample* max, - HistogramBase::Count* count) const OVERRIDE; - private: - PickleIterator* const iter_; - - HistogramBase::Sample min_; - HistogramBase::Sample max_; - HistogramBase::Count count_; - bool is_done_; -}; - -SampleCountPickleIterator::SampleCountPickleIterator(PickleIterator* iter) - : iter_(iter), - is_done_(false) { - Next(); -} - -bool SampleCountPickleIterator::Done() const { - return is_done_; -} - -void SampleCountPickleIterator::Next() { - DCHECK(!Done()); - if (!iter_->ReadInt(&min_) || - !iter_->ReadInt(&max_) || - !iter_->ReadInt(&count_)) - is_done_ = true; -} - -void SampleCountPickleIterator::Get(HistogramBase::Sample* min, - HistogramBase::Sample* max, - HistogramBase::Count* count) const { - DCHECK(!Done()); - *min = min_; - *max = max_; - *count = count_; -} - -} // namespace - -HistogramSamples::HistogramSamples() : sum_(0), redundant_count_(0) {} - -HistogramSamples::~HistogramSamples() {} - -void HistogramSamples::Add(const HistogramSamples& other) { - sum_ += other.sum(); - redundant_count_ += other.redundant_count(); - bool success = AddSubtractImpl(other.Iterator().get(), ADD); - DCHECK(success); -} - -bool HistogramSamples::AddFromPickle(PickleIterator* iter) { - int64 sum; - HistogramBase::Count redundant_count; - - if (!iter->ReadInt64(&sum) || !iter->ReadInt(&redundant_count)) - return false; - sum_ += sum; - redundant_count_ += redundant_count; - - SampleCountPickleIterator pickle_iter(iter); - return AddSubtractImpl(&pickle_iter, ADD); -} - -void HistogramSamples::Subtract(const HistogramSamples& other) { - sum_ -= other.sum(); - redundant_count_ -= other.redundant_count(); - bool success = AddSubtractImpl(other.Iterator().get(), SUBTRACT); - DCHECK(success); -} - -bool HistogramSamples::Serialize(Pickle* pickle) const { - if (!pickle->WriteInt64(sum_) || !pickle->WriteInt(redundant_count_)) - return false; - - HistogramBase::Sample min; - HistogramBase::Sample max; - HistogramBase::Count count; - for (scoped_ptr it = Iterator(); - !it->Done(); - it->Next()) { - it->Get(&min, &max, &count); - if (!pickle->WriteInt(min) || - !pickle->WriteInt(max) || - !pickle->WriteInt(count)) - return false; - } - return true; -} - -void HistogramSamples::IncreaseSum(int64 diff) { - sum_ += diff; -} - -void HistogramSamples::IncreaseRedundantCount(HistogramBase::Count diff) { - redundant_count_ += diff; -} - -SampleCountIterator::~SampleCountIterator() {} - -bool SampleCountIterator::GetBucketIndex(size_t* index) const { - DCHECK(!Done()); - return false; -} - -} // namespace base diff --git a/base/metrics/histogram_samples.h b/base/metrics/histogram_samples.h deleted file mode 100644 index c55b58442c..0000000000 --- a/base/metrics/histogram_samples.h +++ /dev/null @@ -1,87 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef BASE_METRICS_HISTOGRAM_SAMPLES_H_ -#define BASE_METRICS_HISTOGRAM_SAMPLES_H_ - -#include "base/basictypes.h" -#include "base/metrics/histogram_base.h" -#include "base/memory/scoped_ptr.h" - -class Pickle; -class PickleIterator; - -namespace base { - -class SampleCountIterator; - -// HistogramSamples is a container storing all samples of a histogram. -class BASE_EXPORT HistogramSamples { - public: - HistogramSamples(); - virtual ~HistogramSamples(); - - virtual void Accumulate(HistogramBase::Sample value, - HistogramBase::Count count) = 0; - virtual HistogramBase::Count GetCount(HistogramBase::Sample value) const = 0; - virtual HistogramBase::Count TotalCount() const = 0; - - virtual void Add(const HistogramSamples& other); - - // Add from serialized samples. - virtual bool AddFromPickle(PickleIterator* iter); - - virtual void Subtract(const HistogramSamples& other); - - virtual scoped_ptr Iterator() const = 0; - virtual bool Serialize(Pickle* pickle) const; - - // Accessor fuctions. - int64 sum() const { return sum_; } - HistogramBase::Count redundant_count() const { return redundant_count_; } - - protected: - // Based on |op| type, add or subtract sample counts data from the iterator. - enum Operator { ADD, SUBTRACT }; - virtual bool AddSubtractImpl(SampleCountIterator* iter, Operator op) = 0; - - void IncreaseSum(int64 diff); - void IncreaseRedundantCount(HistogramBase::Count diff); - - private: - int64 sum_; - - // |redundant_count_| helps identify memory corruption. It redundantly stores - // the total number of samples accumulated in the histogram. We can compare - // this count to the sum of the counts (TotalCount() function), and detect - // problems. Note, depending on the implementation of different histogram - // types, there might be races during histogram accumulation and snapshotting - // that we choose to accept. In this case, the tallies might mismatch even - // when no memory corruption has happened. - HistogramBase::Count redundant_count_; -}; - -class BASE_EXPORT SampleCountIterator { - public: - virtual ~SampleCountIterator(); - - virtual bool Done() const = 0; - virtual void Next() = 0; - - // Get the sample and count at current position. - // |min| |max| and |count| can be NULL if the value is not of interest. - // Requires: !Done(); - virtual void Get(HistogramBase::Sample* min, - HistogramBase::Sample* max, - HistogramBase::Count* count) const = 0; - - // Get the index of current histogram bucket. - // For histograms that don't use predefined buckets, it returns false. - // Requires: !Done(); - virtual bool GetBucketIndex(size_t* index) const; -}; - -} // namespace base - -#endif // BASE_METRICS_HISTOGRAM_SAMPLES_H_ diff --git a/base/metrics/histogram_snapshot_manager.cc b/base/metrics/histogram_snapshot_manager.cc deleted file mode 100644 index 2301819ad3..0000000000 --- a/base/metrics/histogram_snapshot_manager.cc +++ /dev/null @@ -1,117 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "base/metrics/histogram_snapshot_manager.h" - -#include "base/memory/scoped_ptr.h" -#include "base/metrics/histogram_flattener.h" -#include "base/metrics/histogram_samples.h" -#include "base/metrics/statistics_recorder.h" -#include "base/stl_util.h" - -using std::map; -using std::string; - -namespace base { - -HistogramSnapshotManager::HistogramSnapshotManager( - HistogramFlattener* histogram_flattener) - : histogram_flattener_(histogram_flattener) { - DCHECK(histogram_flattener_); -} - -HistogramSnapshotManager::~HistogramSnapshotManager() { - STLDeleteValues(&logged_samples_); -} - -void HistogramSnapshotManager::PrepareDeltas(HistogramBase::Flags flag_to_set, - bool record_only_uma) { - StatisticsRecorder::Histograms histograms; - StatisticsRecorder::GetHistograms(&histograms); - for (StatisticsRecorder::Histograms::const_iterator it = histograms.begin(); - histograms.end() != it; - ++it) { - (*it)->SetFlags(flag_to_set); - if (record_only_uma && - 0 == ((*it)->flags() & Histogram::kUmaTargetedHistogramFlag)) - continue; - PrepareDelta(**it); - } -} - -void HistogramSnapshotManager::PrepareDelta(const HistogramBase& histogram) { - DCHECK(histogram_flattener_); - - // Get up-to-date snapshot of sample stats. - scoped_ptr snapshot(histogram.SnapshotSamples()); - const std::string& histogram_name = histogram.histogram_name(); - - int corruption = histogram.FindCorruption(*snapshot); - - // Crash if we detect that our histograms have been overwritten. This may be - // a fair distance from the memory smasher, but we hope to correlate these - // crashes with other events, such as plugins, or usage patterns, etc. - if (HistogramBase::BUCKET_ORDER_ERROR & corruption) { - // The checksum should have caught this, so crash separately if it didn't. - CHECK_NE(0, HistogramBase::RANGE_CHECKSUM_ERROR & corruption); - CHECK(false); // Crash for the bucket order corruption. - } - // Checksum corruption might not have caused order corruption. - CHECK_EQ(0, HistogramBase::RANGE_CHECKSUM_ERROR & corruption); - - // Note, at this point corruption can only be COUNT_HIGH_ERROR or - // COUNT_LOW_ERROR and they never arise together, so we don't need to extract - // bits from corruption. - if (corruption) { - DLOG(ERROR) << "Histogram: " << histogram_name - << " has data corruption: " << corruption; - histogram_flattener_->InconsistencyDetected( - static_cast(corruption)); - // Don't record corrupt data to metrics services. - int old_corruption = inconsistencies_[histogram_name]; - if (old_corruption == (corruption | old_corruption)) - return; // We've already seen this corruption for this histogram. - inconsistencies_[histogram_name] |= corruption; - histogram_flattener_->UniqueInconsistencyDetected( - static_cast(corruption)); - return; - } - - HistogramSamples* to_log; - map::iterator it = - logged_samples_.find(histogram_name); - if (it == logged_samples_.end()) { - to_log = snapshot.release(); - - // This histogram has not been logged before, add a new entry. - logged_samples_[histogram_name] = to_log; - } else { - HistogramSamples* already_logged = it->second; - InspectLoggedSamplesInconsistency(*snapshot, already_logged); - snapshot->Subtract(*already_logged); - already_logged->Add(*snapshot); - to_log = snapshot.get(); - } - - if (to_log->redundant_count() > 0) - histogram_flattener_->RecordDelta(histogram, *to_log); -} - -void HistogramSnapshotManager::InspectLoggedSamplesInconsistency( - const HistogramSamples& new_snapshot, - HistogramSamples* logged_samples) { - HistogramBase::Count discrepancy = - logged_samples->TotalCount() - logged_samples->redundant_count(); - if (!discrepancy) - return; - - histogram_flattener_->InconsistencyDetectedInLoggedCount(discrepancy); - if (discrepancy > Histogram::kCommonRaceBasedCountMismatch) { - // Fix logged_samples. - logged_samples->Subtract(*logged_samples); - logged_samples->Add(new_snapshot); - } -} - -} // namespace base diff --git a/base/metrics/histogram_snapshot_manager.h b/base/metrics/histogram_snapshot_manager.h deleted file mode 100644 index 3c7050859e..0000000000 --- a/base/metrics/histogram_snapshot_manager.h +++ /dev/null @@ -1,61 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef BASE_METRICS_HISTOGRAM_SNAPSHOT_MANAGER_H_ -#define BASE_METRICS_HISTOGRAM_SNAPSHOT_MANAGER_H_ - -#include -#include - -#include "base/basictypes.h" -#include "base/metrics/histogram_base.h" - -namespace base { - -class HistogramSamples; -class HistogramFlattener; - -// HistogramSnapshotManager handles the logistics of gathering up available -// histograms for recording either to disk or for transmission (such as from -// renderer to browser, or from browser to UMA upload). Since histograms can sit -// in memory for an extended period of time, and are vulnerable to memory -// corruption, this class also validates as much rendundancy as it can before -// calling for the marginal change (a.k.a., delta) in a histogram to be -// recorded. -class BASE_EXPORT HistogramSnapshotManager { - public: - explicit HistogramSnapshotManager(HistogramFlattener* histogram_flattener); - virtual ~HistogramSnapshotManager(); - - // Snapshot all histograms, and ask |histogram_flattener_| to record the - // delta. The arguments allow selecting only a subset of histograms for - // recording, or to set a flag in each recorded histogram. - void PrepareDeltas(HistogramBase::Flags flags_to_set, bool record_only_uma); - - private: - // Snapshot this histogram, and record the delta. - void PrepareDelta(const HistogramBase& histogram); - - // Try to detect and fix count inconsistency of logged samples. - void InspectLoggedSamplesInconsistency( - const HistogramSamples& new_snapshot, - HistogramSamples* logged_samples); - - // For histograms, track what we've already recorded (as a sample for - // each histogram) so that we can record only the delta with the next log. - std::map logged_samples_; - - // List of histograms found to be corrupt, and their problems. - std::map inconsistencies_; - - // |histogram_flattener_| handles the logistics of recording the histogram - // deltas. - HistogramFlattener* histogram_flattener_; // Weak. - - DISALLOW_COPY_AND_ASSIGN(HistogramSnapshotManager); -}; - -} // namespace base - -#endif // BASE_METRICS_HISTOGRAM_SNAPSHOT_MANAGER_H_ diff --git a/base/metrics/histogram_unittest.cc b/base/metrics/histogram_unittest.cc deleted file mode 100644 index e7a01aa5af..0000000000 --- a/base/metrics/histogram_unittest.cc +++ /dev/null @@ -1,493 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -// Test of Histogram class - -#include -#include -#include - -#include "base/logging.h" -#include "base/memory/scoped_ptr.h" -#include "base/metrics/bucket_ranges.h" -#include "base/metrics/histogram.h" -#include "base/metrics/sample_vector.h" -#include "base/metrics/statistics_recorder.h" -#include "base/pickle.h" -#include "base/time/time.h" -#include "testing/gtest/include/gtest/gtest.h" - -using std::vector; - -namespace base { - -class HistogramTest : public testing::Test { - protected: - virtual void SetUp() { - // Each test will have a clean state (no Histogram / BucketRanges - // registered). - InitializeStatisticsRecorder(); - } - - virtual void TearDown() { - UninitializeStatisticsRecorder(); - } - - void InitializeStatisticsRecorder() { - statistics_recorder_ = new StatisticsRecorder(); - } - - void UninitializeStatisticsRecorder() { - delete statistics_recorder_; - statistics_recorder_ = NULL; - } - - StatisticsRecorder* statistics_recorder_; -}; - -// Check for basic syntax and use. -TEST_F(HistogramTest, BasicTest) { - // Try basic construction - HistogramBase* histogram = Histogram::FactoryGet( - "TestHistogram", 1, 1000, 10, HistogramBase::kNoFlags); - EXPECT_TRUE(histogram); - - HistogramBase* linear_histogram = LinearHistogram::FactoryGet( - "TestLinearHistogram", 1, 1000, 10, HistogramBase::kNoFlags); - EXPECT_TRUE(linear_histogram); - - vector custom_ranges; - custom_ranges.push_back(1); - custom_ranges.push_back(5); - HistogramBase* custom_histogram = CustomHistogram::FactoryGet( - "TestCustomHistogram", custom_ranges, HistogramBase::kNoFlags); - EXPECT_TRUE(custom_histogram); - - // Use standard macros (but with fixed samples) - HISTOGRAM_TIMES("Test2Histogram", TimeDelta::FromDays(1)); - HISTOGRAM_COUNTS("Test3Histogram", 30); - - DHISTOGRAM_TIMES("Test4Histogram", TimeDelta::FromDays(1)); - DHISTOGRAM_COUNTS("Test5Histogram", 30); - - HISTOGRAM_ENUMERATION("Test6Histogram", 129, 130); -} - -// Check that the macro correctly matches histograms by name and records their -// data together. -TEST_F(HistogramTest, NameMatchTest) { - HISTOGRAM_PERCENTAGE("DuplicatedHistogram", 10); - HISTOGRAM_PERCENTAGE("DuplicatedHistogram", 10); - HistogramBase* histogram = LinearHistogram::FactoryGet( - "DuplicatedHistogram", 1, 101, 102, HistogramBase::kNoFlags); - - scoped_ptr samples = histogram->SnapshotSamples(); - EXPECT_EQ(2, samples->TotalCount()); - EXPECT_EQ(2, samples->GetCount(10)); -} - -TEST_F(HistogramTest, ExponentialRangesTest) { - // Check that we got a nice exponential when there was enough rooom. - BucketRanges ranges(9); - Histogram::InitializeBucketRanges(1, 64, &ranges); - EXPECT_EQ(0, ranges.range(0)); - int power_of_2 = 1; - for (int i = 1; i < 8; i++) { - EXPECT_EQ(power_of_2, ranges.range(i)); - power_of_2 *= 2; - } - EXPECT_EQ(HistogramBase::kSampleType_MAX, ranges.range(8)); - - // Check the corresponding Histogram will use the correct ranges. - Histogram* histogram = static_cast( - Histogram::FactoryGet("Histogram", 1, 64, 8, HistogramBase::kNoFlags)); - EXPECT_TRUE(ranges.Equals(histogram->bucket_ranges())); - - // When bucket count is limited, exponential ranges will partially look like - // linear. - BucketRanges ranges2(16); - Histogram::InitializeBucketRanges(1, 32, &ranges2); - - EXPECT_EQ(0, ranges2.range(0)); - EXPECT_EQ(1, ranges2.range(1)); - EXPECT_EQ(2, ranges2.range(2)); - EXPECT_EQ(3, ranges2.range(3)); - EXPECT_EQ(4, ranges2.range(4)); - EXPECT_EQ(5, ranges2.range(5)); - EXPECT_EQ(6, ranges2.range(6)); - EXPECT_EQ(7, ranges2.range(7)); - EXPECT_EQ(9, ranges2.range(8)); - EXPECT_EQ(11, ranges2.range(9)); - EXPECT_EQ(14, ranges2.range(10)); - EXPECT_EQ(17, ranges2.range(11)); - EXPECT_EQ(21, ranges2.range(12)); - EXPECT_EQ(26, ranges2.range(13)); - EXPECT_EQ(32, ranges2.range(14)); - EXPECT_EQ(HistogramBase::kSampleType_MAX, ranges2.range(15)); - - // Check the corresponding Histogram will use the correct ranges. - Histogram* histogram2 = static_cast( - Histogram::FactoryGet("Histogram2", 1, 32, 15, HistogramBase::kNoFlags)); - EXPECT_TRUE(ranges2.Equals(histogram2->bucket_ranges())); -} - -TEST_F(HistogramTest, LinearRangesTest) { - BucketRanges ranges(9); - LinearHistogram::InitializeBucketRanges(1, 7, &ranges); - // Gets a nice linear set of bucket ranges. - for (int i = 0; i < 8; i++) - EXPECT_EQ(i, ranges.range(i)); - EXPECT_EQ(HistogramBase::kSampleType_MAX, ranges.range(8)); - - // The correspoding LinearHistogram should use the correct ranges. - Histogram* histogram = static_cast( - LinearHistogram::FactoryGet("Linear", 1, 7, 8, HistogramBase::kNoFlags)); - EXPECT_TRUE(ranges.Equals(histogram->bucket_ranges())); - - // Linear ranges are not divisible. - BucketRanges ranges2(6); - LinearHistogram::InitializeBucketRanges(1, 6, &ranges2); - EXPECT_EQ(0, ranges2.range(0)); - EXPECT_EQ(1, ranges2.range(1)); - EXPECT_EQ(3, ranges2.range(2)); - EXPECT_EQ(4, ranges2.range(3)); - EXPECT_EQ(6, ranges2.range(4)); - EXPECT_EQ(HistogramBase::kSampleType_MAX, ranges2.range(5)); - // The correspoding LinearHistogram should use the correct ranges. - Histogram* histogram2 = static_cast( - LinearHistogram::FactoryGet("Linear2", 1, 6, 5, HistogramBase::kNoFlags)); - EXPECT_TRUE(ranges2.Equals(histogram2->bucket_ranges())); -} - -TEST_F(HistogramTest, ArrayToCustomRangesTest) { - const HistogramBase::Sample ranges[3] = {5, 10, 20}; - vector ranges_vec = - CustomHistogram::ArrayToCustomRanges(ranges, 3); - ASSERT_EQ(6u, ranges_vec.size()); - EXPECT_EQ(5, ranges_vec[0]); - EXPECT_EQ(6, ranges_vec[1]); - EXPECT_EQ(10, ranges_vec[2]); - EXPECT_EQ(11, ranges_vec[3]); - EXPECT_EQ(20, ranges_vec[4]); - EXPECT_EQ(21, ranges_vec[5]); -} - -TEST_F(HistogramTest, CustomHistogramTest) { - // A well prepared custom ranges. - vector custom_ranges; - custom_ranges.push_back(1); - custom_ranges.push_back(2); - - Histogram* histogram = static_cast( - CustomHistogram::FactoryGet("TestCustomHistogram1", custom_ranges, - HistogramBase::kNoFlags)); - const BucketRanges* ranges = histogram->bucket_ranges(); - ASSERT_EQ(4u, ranges->size()); - EXPECT_EQ(0, ranges->range(0)); // Auto added. - EXPECT_EQ(1, ranges->range(1)); - EXPECT_EQ(2, ranges->range(2)); - EXPECT_EQ(HistogramBase::kSampleType_MAX, ranges->range(3)); // Auto added. - - // A unordered custom ranges. - custom_ranges.clear(); - custom_ranges.push_back(2); - custom_ranges.push_back(1); - histogram = static_cast( - CustomHistogram::FactoryGet("TestCustomHistogram2", custom_ranges, - HistogramBase::kNoFlags)); - ranges = histogram->bucket_ranges(); - ASSERT_EQ(4u, ranges->size()); - EXPECT_EQ(0, ranges->range(0)); - EXPECT_EQ(1, ranges->range(1)); - EXPECT_EQ(2, ranges->range(2)); - EXPECT_EQ(HistogramBase::kSampleType_MAX, ranges->range(3)); - - // A custom ranges with duplicated values. - custom_ranges.clear(); - custom_ranges.push_back(4); - custom_ranges.push_back(1); - custom_ranges.push_back(4); - histogram = static_cast( - CustomHistogram::FactoryGet("TestCustomHistogram3", custom_ranges, - HistogramBase::kNoFlags)); - ranges = histogram->bucket_ranges(); - ASSERT_EQ(4u, ranges->size()); - EXPECT_EQ(0, ranges->range(0)); - EXPECT_EQ(1, ranges->range(1)); - EXPECT_EQ(4, ranges->range(2)); - EXPECT_EQ(HistogramBase::kSampleType_MAX, ranges->range(3)); -} - -TEST_F(HistogramTest, CustomHistogramWithOnly2Buckets) { - // This test exploits the fact that the CustomHistogram can have 2 buckets, - // while the base class Histogram is *supposed* to have at least 3 buckets. - // We should probably change the restriction on the base class (or not inherit - // the base class!). - - vector custom_ranges; - custom_ranges.push_back(4); - - Histogram* histogram = static_cast( - CustomHistogram::FactoryGet("2BucketsCustomHistogram", custom_ranges, - HistogramBase::kNoFlags)); - const BucketRanges* ranges = histogram->bucket_ranges(); - ASSERT_EQ(3u, ranges->size()); - EXPECT_EQ(0, ranges->range(0)); - EXPECT_EQ(4, ranges->range(1)); - EXPECT_EQ(HistogramBase::kSampleType_MAX, ranges->range(2)); -} - -// Make sure histogram handles out-of-bounds data gracefully. -TEST_F(HistogramTest, BoundsTest) { - const size_t kBucketCount = 50; - Histogram* histogram = static_cast( - Histogram::FactoryGet("Bounded", 10, 100, kBucketCount, - HistogramBase::kNoFlags)); - - // Put two samples "out of bounds" above and below. - histogram->Add(5); - histogram->Add(-50); - - histogram->Add(100); - histogram->Add(10000); - - // Verify they landed in the underflow, and overflow buckets. - scoped_ptr samples = histogram->SnapshotSampleVector(); - EXPECT_EQ(2, samples->GetCountAtIndex(0)); - EXPECT_EQ(0, samples->GetCountAtIndex(1)); - size_t array_size = histogram->bucket_count(); - EXPECT_EQ(kBucketCount, array_size); - EXPECT_EQ(0, samples->GetCountAtIndex(array_size - 2)); - EXPECT_EQ(2, samples->GetCountAtIndex(array_size - 1)); - - vector custom_ranges; - custom_ranges.push_back(10); - custom_ranges.push_back(50); - custom_ranges.push_back(100); - Histogram* test_custom_histogram = static_cast( - CustomHistogram::FactoryGet("TestCustomRangeBoundedHistogram", - custom_ranges, HistogramBase::kNoFlags)); - - // Put two samples "out of bounds" above and below. - test_custom_histogram->Add(5); - test_custom_histogram->Add(-50); - test_custom_histogram->Add(100); - test_custom_histogram->Add(1000); - test_custom_histogram->Add(INT_MAX); - - // Verify they landed in the underflow, and overflow buckets. - scoped_ptr custom_samples = - test_custom_histogram->SnapshotSampleVector(); - EXPECT_EQ(2, custom_samples->GetCountAtIndex(0)); - EXPECT_EQ(0, custom_samples->GetCountAtIndex(1)); - size_t bucket_count = test_custom_histogram->bucket_count(); - EXPECT_EQ(0, custom_samples->GetCountAtIndex(bucket_count - 2)); - EXPECT_EQ(3, custom_samples->GetCountAtIndex(bucket_count - 1)); -} - -// Check to be sure samples land as expected is "correct" buckets. -TEST_F(HistogramTest, BucketPlacementTest) { - Histogram* histogram = static_cast( - Histogram::FactoryGet("Histogram", 1, 64, 8, HistogramBase::kNoFlags)); - - // Add i+1 samples to the i'th bucket. - histogram->Add(0); - int power_of_2 = 1; - for (int i = 1; i < 8; i++) { - for (int j = 0; j <= i; j++) - histogram->Add(power_of_2); - power_of_2 *= 2; - } - - // Check to see that the bucket counts reflect our additions. - scoped_ptr samples = histogram->SnapshotSampleVector(); - for (int i = 0; i < 8; i++) - EXPECT_EQ(i + 1, samples->GetCountAtIndex(i)); -} - -TEST_F(HistogramTest, CorruptSampleCounts) { - Histogram* histogram = static_cast( - Histogram::FactoryGet("Histogram", 1, 64, 8, HistogramBase::kNoFlags)); - - // Add some samples. - histogram->Add(20); - histogram->Add(40); - - scoped_ptr snapshot = histogram->SnapshotSampleVector(); - EXPECT_EQ(HistogramBase::NO_INCONSISTENCIES, - histogram->FindCorruption(*snapshot)); - EXPECT_EQ(2, snapshot->redundant_count()); - EXPECT_EQ(2, snapshot->TotalCount()); - - snapshot->counts_[3] += 100; // Sample count won't match redundant count. - EXPECT_EQ(HistogramBase::COUNT_LOW_ERROR, - histogram->FindCorruption(*snapshot)); - snapshot->counts_[2] -= 200; - EXPECT_EQ(HistogramBase::COUNT_HIGH_ERROR, - histogram->FindCorruption(*snapshot)); - - // But we can't spot a corruption if it is compensated for. - snapshot->counts_[1] += 100; - EXPECT_EQ(HistogramBase::NO_INCONSISTENCIES, - histogram->FindCorruption(*snapshot)); -} - -TEST_F(HistogramTest, CorruptBucketBounds) { - Histogram* histogram = static_cast( - Histogram::FactoryGet("Histogram", 1, 64, 8, HistogramBase::kNoFlags)); - - scoped_ptr snapshot = histogram->SnapshotSampleVector(); - EXPECT_EQ(HistogramBase::NO_INCONSISTENCIES, - histogram->FindCorruption(*snapshot)); - - BucketRanges* bucket_ranges = - const_cast(histogram->bucket_ranges()); - HistogramBase::Sample tmp = bucket_ranges->range(1); - bucket_ranges->set_range(1, bucket_ranges->range(2)); - bucket_ranges->set_range(2, tmp); - EXPECT_EQ( - HistogramBase::BUCKET_ORDER_ERROR | HistogramBase::RANGE_CHECKSUM_ERROR, - histogram->FindCorruption(*snapshot)); - - bucket_ranges->set_range(2, bucket_ranges->range(1)); - bucket_ranges->set_range(1, tmp); - EXPECT_EQ(0, histogram->FindCorruption(*snapshot)); - - // Show that two simple changes don't offset each other - bucket_ranges->set_range(3, bucket_ranges->range(3) + 1); - EXPECT_EQ(HistogramBase::RANGE_CHECKSUM_ERROR, - histogram->FindCorruption(*snapshot)); - - bucket_ranges->set_range(4, bucket_ranges->range(4) - 1); - EXPECT_EQ(HistogramBase::RANGE_CHECKSUM_ERROR, - histogram->FindCorruption(*snapshot)); - - // Repair histogram so that destructor won't DCHECK(). - bucket_ranges->set_range(3, bucket_ranges->range(3) - 1); - bucket_ranges->set_range(4, bucket_ranges->range(4) + 1); -} - -TEST_F(HistogramTest, HistogramSerializeInfo) { - Histogram* histogram = static_cast( - Histogram::FactoryGet("Histogram", 1, 64, 8, - HistogramBase::kIPCSerializationSourceFlag)); - Pickle pickle; - histogram->SerializeInfo(&pickle); - - PickleIterator iter(pickle); - - int type; - EXPECT_TRUE(iter.ReadInt(&type)); - EXPECT_EQ(HISTOGRAM, type); - - std::string name; - EXPECT_TRUE(iter.ReadString(&name)); - EXPECT_EQ("Histogram", name); - - int flag; - EXPECT_TRUE(iter.ReadInt(&flag)); - EXPECT_EQ(HistogramBase::kIPCSerializationSourceFlag, flag); - - int min; - EXPECT_TRUE(iter.ReadInt(&min)); - EXPECT_EQ(1, min); - - int max; - EXPECT_TRUE(iter.ReadInt(&max)); - EXPECT_EQ(64, max); - - int64 bucket_count; - EXPECT_TRUE(iter.ReadInt64(&bucket_count)); - EXPECT_EQ(8, bucket_count); - - uint32 checksum; - EXPECT_TRUE(iter.ReadUInt32(&checksum)); - EXPECT_EQ(histogram->bucket_ranges()->checksum(), checksum); - - // No more data in the pickle. - EXPECT_FALSE(iter.SkipBytes(1)); -} - -TEST_F(HistogramTest, CustomHistogramSerializeInfo) { - vector custom_ranges; - custom_ranges.push_back(10); - custom_ranges.push_back(100); - - HistogramBase* custom_histogram = CustomHistogram::FactoryGet( - "TestCustomRangeBoundedHistogram", - custom_ranges, - HistogramBase::kNoFlags); - Pickle pickle; - custom_histogram->SerializeInfo(&pickle); - - // Validate the pickle. - PickleIterator iter(pickle); - - int i; - std::string s; - int64 bucket_count; - uint32 ui32; - EXPECT_TRUE(iter.ReadInt(&i) && iter.ReadString(&s) && iter.ReadInt(&i) && - iter.ReadInt(&i) && iter.ReadInt(&i) && - iter.ReadInt64(&bucket_count) && iter.ReadUInt32(&ui32)); - EXPECT_EQ(3, bucket_count); - - int range; - EXPECT_TRUE(iter.ReadInt(&range)); - EXPECT_EQ(10, range); - EXPECT_TRUE(iter.ReadInt(&range)); - EXPECT_EQ(100, range); - - // No more data in the pickle. - EXPECT_FALSE(iter.SkipBytes(1)); -} - -#if GTEST_HAS_DEATH_TEST -// For Histogram, LinearHistogram and CustomHistogram, the minimum for a -// declared range is 1, while the maximum is (HistogramBase::kSampleType_MAX - -// 1). But we accept ranges exceeding those limits, and silently clamped to -// those limits. This is for backwards compatibility. -TEST(HistogramDeathTest, BadRangesTest) { - HistogramBase* histogram = Histogram::FactoryGet( - "BadRanges", 0, HistogramBase::kSampleType_MAX, 8, - HistogramBase::kNoFlags); - EXPECT_TRUE( - histogram->HasConstructionArguments( - 1, HistogramBase::kSampleType_MAX - 1, 8)); - - HistogramBase* linear_histogram = LinearHistogram::FactoryGet( - "BadRangesLinear", 0, HistogramBase::kSampleType_MAX, 8, - HistogramBase::kNoFlags); - EXPECT_TRUE( - linear_histogram->HasConstructionArguments( - 1, HistogramBase::kSampleType_MAX - 1, 8)); - - vector custom_ranges; - custom_ranges.push_back(0); - custom_ranges.push_back(5); - Histogram* custom_histogram = static_cast( - CustomHistogram::FactoryGet( - "BadRangesCustom", custom_ranges, HistogramBase::kNoFlags)); - const BucketRanges* ranges = custom_histogram->bucket_ranges(); - ASSERT_EQ(3u, ranges->size()); - EXPECT_EQ(0, ranges->range(0)); - EXPECT_EQ(5, ranges->range(1)); - EXPECT_EQ(HistogramBase::kSampleType_MAX, ranges->range(2)); - - // CustomHistogram does not accepts kSampleType_MAX as range. - custom_ranges.push_back(HistogramBase::kSampleType_MAX); - EXPECT_DEATH(CustomHistogram::FactoryGet("BadRangesCustom2", custom_ranges, - HistogramBase::kNoFlags), - ""); - - // CustomHistogram needs at least 1 valid range. - custom_ranges.clear(); - custom_ranges.push_back(0); - EXPECT_DEATH(CustomHistogram::FactoryGet("BadRangesCustom3", custom_ranges, - HistogramBase::kNoFlags), - ""); -} -#endif - -} // namespace base diff --git a/base/metrics/sample_map.cc b/base/metrics/sample_map.cc deleted file mode 100644 index 42468cb57f..0000000000 --- a/base/metrics/sample_map.cc +++ /dev/null @@ -1,86 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "base/metrics/sample_map.h" - -#include "base/logging.h" - -using std::map; - -namespace base { - -typedef HistogramBase::Count Count; -typedef HistogramBase::Sample Sample; - -SampleMap::SampleMap() {} - -SampleMap::~SampleMap() {} - -void SampleMap::Accumulate(Sample value, Count count) { - sample_counts_[value] += count; - IncreaseSum(count * value); - IncreaseRedundantCount(count); -} - -Count SampleMap::GetCount(Sample value) const { - map::const_iterator it = sample_counts_.find(value); - if (it == sample_counts_.end()) - return 0; - return it->second; -} - -Count SampleMap::TotalCount() const { - Count count = 0; - for (map::const_iterator it = sample_counts_.begin(); - it != sample_counts_.end(); - ++it) { - count += it->second; - } - return count; -} - -scoped_ptr SampleMap::Iterator() const { - return scoped_ptr(new SampleMapIterator(sample_counts_)); -} - -bool SampleMap::AddSubtractImpl(SampleCountIterator* iter, - HistogramSamples::Operator op) { - Sample min; - Sample max; - Count count; - for (; !iter->Done(); iter->Next()) { - iter->Get(&min, &max, &count); - if (min + 1 != max) - return false; // SparseHistogram only supports bucket with size 1. - sample_counts_[min] += (op == HistogramSamples::ADD) ? count : -count; - } - return true; -} - -SampleMapIterator::SampleMapIterator(const SampleToCountMap& sample_counts) - : iter_(sample_counts.begin()), - end_(sample_counts.end()) {} - -SampleMapIterator::~SampleMapIterator() {} - -bool SampleMapIterator::Done() const { - return iter_ == end_; -} - -void SampleMapIterator::Next() { - DCHECK(!Done()); - iter_++; -} - -void SampleMapIterator::Get(Sample* min, Sample* max, Count* count) const { - DCHECK(!Done()); - if (min != NULL) - *min = iter_->first; - if (max != NULL) - *max = iter_->first + 1; - if (count != NULL) - *count = iter_->second; -} - -} // namespace base diff --git a/base/metrics/sample_map.h b/base/metrics/sample_map.h deleted file mode 100644 index cdd1138547..0000000000 --- a/base/metrics/sample_map.h +++ /dev/null @@ -1,65 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -// SampleMap implements HistogramSamples interface. It is used by the -// SparseHistogram class to store samples. - -#ifndef BASE_METRICS_SAMPLE_MAP_H_ -#define BASE_METRICS_SAMPLE_MAP_H_ - -#include - -#include "base/compiler_specific.h" -#include "base/memory/scoped_ptr.h" -#include "base/metrics/histogram_base.h" -#include "base/metrics/histogram_samples.h" - -namespace base { - -class BASE_EXPORT_PRIVATE SampleMap : public HistogramSamples { - public: - SampleMap(); - virtual ~SampleMap(); - - // HistogramSamples implementation: - virtual void Accumulate(HistogramBase::Sample value, - HistogramBase::Count count) OVERRIDE; - virtual HistogramBase::Count GetCount( - HistogramBase::Sample value) const OVERRIDE; - virtual HistogramBase::Count TotalCount() const OVERRIDE; - virtual scoped_ptr Iterator() const OVERRIDE; - - protected: - virtual bool AddSubtractImpl( - SampleCountIterator* iter, - HistogramSamples::Operator op) OVERRIDE; // |op| is ADD or SUBTRACT. - - private: - std::map sample_counts_; - - DISALLOW_COPY_AND_ASSIGN(SampleMap); -}; - -class BASE_EXPORT_PRIVATE SampleMapIterator : public SampleCountIterator { - public: - typedef std::map - SampleToCountMap; - - explicit SampleMapIterator(const SampleToCountMap& sample_counts); - virtual ~SampleMapIterator(); - - // SampleCountIterator implementation: - virtual bool Done() const OVERRIDE; - virtual void Next() OVERRIDE; - virtual void Get(HistogramBase::Sample* min, - HistogramBase::Sample* max, - HistogramBase::Count* count) const OVERRIDE; - private: - SampleToCountMap::const_iterator iter_; - const SampleToCountMap::const_iterator end_; -}; - -} // namespace base - -#endif // BASE_METRICS_SAMPLE_MAP_H_ diff --git a/base/metrics/sample_map_unittest.cc b/base/metrics/sample_map_unittest.cc deleted file mode 100644 index 1a53ee7f54..0000000000 --- a/base/metrics/sample_map_unittest.cc +++ /dev/null @@ -1,123 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "base/memory/scoped_ptr.h" -#include "base/metrics/sample_map.h" -#include "testing/gtest/include/gtest/gtest.h" - -namespace base { -namespace { - -TEST(SampleMapTest, AccumulateTest) { - SampleMap samples; - - samples.Accumulate(1, 100); - samples.Accumulate(2, 200); - samples.Accumulate(1, -200); - EXPECT_EQ(-100, samples.GetCount(1)); - EXPECT_EQ(200, samples.GetCount(2)); - - EXPECT_EQ(300, samples.sum()); - EXPECT_EQ(100, samples.TotalCount()); - EXPECT_EQ(samples.redundant_count(), samples.TotalCount()); -} - -TEST(SampleMapTest, AddSubtractTest) { - SampleMap samples1; - SampleMap samples2; - - samples1.Accumulate(1, 100); - samples1.Accumulate(2, 100); - samples1.Accumulate(3, 100); - - samples2.Accumulate(1, 200); - samples2.Accumulate(2, 200); - samples2.Accumulate(4, 200); - - samples1.Add(samples2); - EXPECT_EQ(300, samples1.GetCount(1)); - EXPECT_EQ(300, samples1.GetCount(2)); - EXPECT_EQ(100, samples1.GetCount(3)); - EXPECT_EQ(200, samples1.GetCount(4)); - EXPECT_EQ(2000, samples1.sum()); - EXPECT_EQ(900, samples1.TotalCount()); - EXPECT_EQ(samples1.redundant_count(), samples1.TotalCount()); - - samples1.Subtract(samples2); - EXPECT_EQ(100, samples1.GetCount(1)); - EXPECT_EQ(100, samples1.GetCount(2)); - EXPECT_EQ(100, samples1.GetCount(3)); - EXPECT_EQ(0, samples1.GetCount(4)); - EXPECT_EQ(600, samples1.sum()); - EXPECT_EQ(300, samples1.TotalCount()); - EXPECT_EQ(samples1.redundant_count(), samples1.TotalCount()); -} - -TEST(SampleMapIteratorTest, IterateTest) { - SampleMap samples; - samples.Accumulate(1, 100); - samples.Accumulate(2, 200); - samples.Accumulate(4, -300); - samples.Accumulate(5, 0); - - scoped_ptr it = samples.Iterator(); - - HistogramBase::Sample min; - HistogramBase::Sample max; - HistogramBase::Count count; - - it->Get(&min, &max, &count); - EXPECT_EQ(1, min); - EXPECT_EQ(2, max); - EXPECT_EQ(100, count); - EXPECT_FALSE(it->GetBucketIndex(NULL)); - - it->Next(); - it->Get(&min, &max, &count); - EXPECT_EQ(2, min); - EXPECT_EQ(3, max); - EXPECT_EQ(200, count); - - it->Next(); - it->Get(&min, &max, &count); - EXPECT_EQ(4, min); - EXPECT_EQ(5, max); - EXPECT_EQ(-300, count); - - it->Next(); - it->Get(&min, &max, &count); - EXPECT_EQ(5, min); - EXPECT_EQ(6, max); - EXPECT_EQ(0, count); - - it->Next(); - EXPECT_TRUE(it->Done()); -} - -#if (!defined(NDEBUG) || defined(DCHECK_ALWAYS_ON)) && GTEST_HAS_DEATH_TEST - -TEST(SampleMapIteratorDeathTest, IterateDoneTest) { - SampleMap samples; - - scoped_ptr it = samples.Iterator(); - - EXPECT_TRUE(it->Done()); - - HistogramBase::Sample min; - HistogramBase::Sample max; - HistogramBase::Count count; - EXPECT_DEATH(it->Get(&min, &max, &count), ""); - - EXPECT_DEATH(it->Next(), ""); - - samples.Accumulate(1, 100); - it = samples.Iterator(); - EXPECT_FALSE(it->Done()); -} - -#endif -// (!defined(NDEBUG) || defined(DCHECK_ALWAYS_ON)) && GTEST_HAS_DEATH_TEST - -} // namespace -} // namespace base diff --git a/base/metrics/sample_vector.cc b/base/metrics/sample_vector.cc deleted file mode 100644 index fe602eec80..0000000000 --- a/base/metrics/sample_vector.cc +++ /dev/null @@ -1,161 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "base/metrics/sample_vector.h" - -#include "base/logging.h" -#include "base/metrics/bucket_ranges.h" - -using std::vector; - -namespace base { - -typedef HistogramBase::Count Count; -typedef HistogramBase::Sample Sample; - -SampleVector::SampleVector(const BucketRanges* bucket_ranges) - : counts_(bucket_ranges->bucket_count()), - bucket_ranges_(bucket_ranges) { - CHECK_GE(bucket_ranges_->bucket_count(), 1u); -} - -SampleVector::~SampleVector() {} - -void SampleVector::Accumulate(Sample value, Count count) { - size_t bucket_index = GetBucketIndex(value); - counts_[bucket_index] += count; - IncreaseSum(count * value); - IncreaseRedundantCount(count); -} - -Count SampleVector::GetCount(Sample value) const { - size_t bucket_index = GetBucketIndex(value); - return counts_[bucket_index]; -} - -Count SampleVector::TotalCount() const { - Count count = 0; - for (size_t i = 0; i < counts_.size(); i++) { - count += counts_[i]; - } - return count; -} - -Count SampleVector::GetCountAtIndex(size_t bucket_index) const { - DCHECK(bucket_index < counts_.size()); - return counts_[bucket_index]; -} - -scoped_ptr SampleVector::Iterator() const { - return scoped_ptr( - new SampleVectorIterator(&counts_, bucket_ranges_)); -} - -bool SampleVector::AddSubtractImpl(SampleCountIterator* iter, - HistogramSamples::Operator op) { - HistogramBase::Sample min; - HistogramBase::Sample max; - HistogramBase::Count count; - - // Go through the iterator and add the counts into correct bucket. - size_t index = 0; - while (index < counts_.size() && !iter->Done()) { - iter->Get(&min, &max, &count); - if (min == bucket_ranges_->range(index) && - max == bucket_ranges_->range(index + 1)) { - // Sample matches this bucket! - counts_[index] += (op == HistogramSamples::ADD) ? count : -count; - iter->Next(); - } else if (min > bucket_ranges_->range(index)) { - // Sample is larger than current bucket range. Try next. - index++; - } else { - // Sample is smaller than current bucket range. We scan buckets from - // smallest to largest, so the sample value must be invalid. - return false; - } - } - - return iter->Done(); -} - -// Use simple binary search. This is very general, but there are better -// approaches if we knew that the buckets were linearly distributed. -size_t SampleVector::GetBucketIndex(Sample value) const { - size_t bucket_count = bucket_ranges_->bucket_count(); - CHECK_GE(bucket_count, 1u); - CHECK_GE(value, bucket_ranges_->range(0)); - CHECK_LT(value, bucket_ranges_->range(bucket_count)); - - size_t under = 0; - size_t over = bucket_count; - size_t mid; - do { - DCHECK_GE(over, under); - mid = under + (over - under)/2; - if (mid == under) - break; - if (bucket_ranges_->range(mid) <= value) - under = mid; - else - over = mid; - } while (true); - - DCHECK_LE(bucket_ranges_->range(mid), value); - CHECK_GT(bucket_ranges_->range(mid + 1), value); - return mid; -} - -SampleVectorIterator::SampleVectorIterator(const vector* counts, - const BucketRanges* bucket_ranges) - : counts_(counts), - bucket_ranges_(bucket_ranges), - index_(0) { - CHECK_GE(bucket_ranges_->bucket_count(), counts_->size()); - SkipEmptyBuckets(); -} - -SampleVectorIterator::~SampleVectorIterator() {} - -bool SampleVectorIterator::Done() const { - return index_ >= counts_->size(); -} - -void SampleVectorIterator::Next() { - DCHECK(!Done()); - index_++; - SkipEmptyBuckets(); -} - -void SampleVectorIterator::Get(HistogramBase::Sample* min, - HistogramBase::Sample* max, - HistogramBase::Count* count) const { - DCHECK(!Done()); - if (min != NULL) - *min = bucket_ranges_->range(index_); - if (max != NULL) - *max = bucket_ranges_->range(index_ + 1); - if (count != NULL) - *count = (*counts_)[index_]; -} - -bool SampleVectorIterator::GetBucketIndex(size_t* index) const { - DCHECK(!Done()); - if (index != NULL) - *index = index_; - return true; -} - -void SampleVectorIterator::SkipEmptyBuckets() { - if (Done()) - return; - - while (index_ < counts_->size()) { - if ((*counts_)[index_] != 0) - return; - index_++; - } -} - -} // namespace base diff --git a/base/metrics/sample_vector.h b/base/metrics/sample_vector.h deleted file mode 100644 index 67c344a97c..0000000000 --- a/base/metrics/sample_vector.h +++ /dev/null @@ -1,84 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -// SampleVector implements HistogramSamples interface. It is used by all -// Histogram based classes to store samples. - -#ifndef BASE_METRICS_SAMPLE_VECTOR_H_ -#define BASE_METRICS_SAMPLE_VECTOR_H_ - -#include - -#include "base/compiler_specific.h" -#include "base/gtest_prod_util.h" -#include "base/memory/scoped_ptr.h" -#include "base/metrics/histogram_base.h" -#include "base/metrics/histogram_samples.h" - -namespace base { - -class BucketRanges; - -class BASE_EXPORT_PRIVATE SampleVector : public HistogramSamples { - public: - explicit SampleVector(const BucketRanges* bucket_ranges); - virtual ~SampleVector(); - - // HistogramSamples implementation: - virtual void Accumulate(HistogramBase::Sample value, - HistogramBase::Count count) OVERRIDE; - virtual HistogramBase::Count GetCount( - HistogramBase::Sample value) const OVERRIDE; - virtual HistogramBase::Count TotalCount() const OVERRIDE; - virtual scoped_ptr Iterator() const OVERRIDE; - - // Get count of a specific bucket. - HistogramBase::Count GetCountAtIndex(size_t bucket_index) const; - - protected: - virtual bool AddSubtractImpl( - SampleCountIterator* iter, - HistogramSamples::Operator op) OVERRIDE; // |op| is ADD or SUBTRACT. - - virtual size_t GetBucketIndex(HistogramBase::Sample value) const; - - private: - FRIEND_TEST_ALL_PREFIXES(HistogramTest, CorruptSampleCounts); - - std::vector counts_; - - // Shares the same BucketRanges with Histogram object. - const BucketRanges* const bucket_ranges_; - - DISALLOW_COPY_AND_ASSIGN(SampleVector); -}; - -class BASE_EXPORT_PRIVATE SampleVectorIterator : public SampleCountIterator { - public: - SampleVectorIterator(const std::vector* counts, - const BucketRanges* bucket_ranges); - virtual ~SampleVectorIterator(); - - // SampleCountIterator implementation: - virtual bool Done() const OVERRIDE; - virtual void Next() OVERRIDE; - virtual void Get(HistogramBase::Sample* min, - HistogramBase::Sample* max, - HistogramBase::Count* count) const OVERRIDE; - - // SampleVector uses predefined buckets, so iterator can return bucket index. - virtual bool GetBucketIndex(size_t* index) const OVERRIDE; - - private: - void SkipEmptyBuckets(); - - const std::vector* counts_; - const BucketRanges* bucket_ranges_; - - size_t index_; -}; - -} // namespace base - -#endif // BASE_METRICS_SAMPLE_VECTOR_H_ diff --git a/base/metrics/sample_vector_unittest.cc b/base/metrics/sample_vector_unittest.cc deleted file mode 100644 index 9c7ba96233..0000000000 --- a/base/metrics/sample_vector_unittest.cc +++ /dev/null @@ -1,265 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include - -#include "base/memory/scoped_ptr.h" -#include "base/metrics/bucket_ranges.h" -#include "base/metrics/histogram.h" -#include "base/metrics/sample_vector.h" -#include "testing/gtest/include/gtest/gtest.h" - -using std::vector; - -namespace base { -namespace { - -TEST(SampleVectorTest, AccumulateTest) { - // Custom buckets: [1, 5) [5, 10) - BucketRanges ranges(3); - ranges.set_range(0, 1); - ranges.set_range(1, 5); - ranges.set_range(2, 10); - SampleVector samples(&ranges); - - samples.Accumulate(1, 200); - samples.Accumulate(2, -300); - EXPECT_EQ(-100, samples.GetCountAtIndex(0)); - - samples.Accumulate(5, 200); - EXPECT_EQ(200, samples.GetCountAtIndex(1)); - - EXPECT_EQ(600, samples.sum()); - EXPECT_EQ(100, samples.redundant_count()); - EXPECT_EQ(samples.TotalCount(), samples.redundant_count()); - - samples.Accumulate(5, -100); - EXPECT_EQ(100, samples.GetCountAtIndex(1)); - - EXPECT_EQ(100, samples.sum()); - EXPECT_EQ(0, samples.redundant_count()); - EXPECT_EQ(samples.TotalCount(), samples.redundant_count()); -} - -TEST(SampleVectorTest, AddSubtractTest) { - // Custom buckets: [0, 1) [1, 2) [2, 3) [3, INT_MAX) - BucketRanges ranges(5); - ranges.set_range(0, 0); - ranges.set_range(1, 1); - ranges.set_range(2, 2); - ranges.set_range(3, 3); - ranges.set_range(4, INT_MAX); - - SampleVector samples1(&ranges); - samples1.Accumulate(0, 100); - samples1.Accumulate(2, 100); - samples1.Accumulate(4, 100); - EXPECT_EQ(600, samples1.sum()); - EXPECT_EQ(300, samples1.TotalCount()); - EXPECT_EQ(samples1.redundant_count(), samples1.TotalCount()); - - SampleVector samples2(&ranges); - samples2.Accumulate(1, 200); - samples2.Accumulate(2, 200); - samples2.Accumulate(4, 200); - EXPECT_EQ(1400, samples2.sum()); - EXPECT_EQ(600, samples2.TotalCount()); - EXPECT_EQ(samples2.redundant_count(), samples2.TotalCount()); - - samples1.Add(samples2); - EXPECT_EQ(100, samples1.GetCountAtIndex(0)); - EXPECT_EQ(200, samples1.GetCountAtIndex(1)); - EXPECT_EQ(300, samples1.GetCountAtIndex(2)); - EXPECT_EQ(300, samples1.GetCountAtIndex(3)); - EXPECT_EQ(2000, samples1.sum()); - EXPECT_EQ(900, samples1.TotalCount()); - EXPECT_EQ(samples1.redundant_count(), samples1.TotalCount()); - - samples1.Subtract(samples2); - EXPECT_EQ(100, samples1.GetCountAtIndex(0)); - EXPECT_EQ(0, samples1.GetCountAtIndex(1)); - EXPECT_EQ(100, samples1.GetCountAtIndex(2)); - EXPECT_EQ(100, samples1.GetCountAtIndex(3)); - EXPECT_EQ(600, samples1.sum()); - EXPECT_EQ(300, samples1.TotalCount()); - EXPECT_EQ(samples1.redundant_count(), samples1.TotalCount()); -} - -#if (!defined(NDEBUG) || defined(DCHECK_ALWAYS_ON)) && GTEST_HAS_DEATH_TEST -TEST(SampleVectorDeathTest, BucketIndexTest) { - // 8 buckets with exponential layout: - // [0, 1) [1, 2) [2, 4) [4, 8) [8, 16) [16, 32) [32, 64) [64, INT_MAX) - BucketRanges ranges(9); - Histogram::InitializeBucketRanges(1, 64, &ranges); - SampleVector samples(&ranges); - - // Normal case - samples.Accumulate(0, 1); - samples.Accumulate(3, 2); - samples.Accumulate(64, 3); - EXPECT_EQ(1, samples.GetCount(0)); - EXPECT_EQ(2, samples.GetCount(2)); - EXPECT_EQ(3, samples.GetCount(65)); - - // Extreme case. - EXPECT_DEATH(samples.Accumulate(INT_MIN, 100), ""); - EXPECT_DEATH(samples.Accumulate(-1, 100), ""); - EXPECT_DEATH(samples.Accumulate(INT_MAX, 100), ""); - - // Custom buckets: [1, 5) [5, 10) - // Note, this is not a valid BucketRanges for Histogram because it does not - // have overflow buckets. - BucketRanges ranges2(3); - ranges2.set_range(0, 1); - ranges2.set_range(1, 5); - ranges2.set_range(2, 10); - SampleVector samples2(&ranges2); - - // Normal case. - samples2.Accumulate(1, 1); - samples2.Accumulate(4, 1); - samples2.Accumulate(5, 2); - samples2.Accumulate(9, 2); - EXPECT_EQ(2, samples2.GetCount(1)); - EXPECT_EQ(4, samples2.GetCount(5)); - - // Extreme case. - EXPECT_DEATH(samples2.Accumulate(0, 100), ""); - EXPECT_DEATH(samples2.Accumulate(10, 100), ""); -} - -TEST(SampleVectorDeathTest, AddSubtractBucketNotMatchTest) { - // Custom buckets 1: [1, 3) [3, 5) - BucketRanges ranges1(3); - ranges1.set_range(0, 1); - ranges1.set_range(1, 3); - ranges1.set_range(2, 5); - SampleVector samples1(&ranges1); - - // Custom buckets 2: [0, 1) [1, 3) [3, 6) [6, 7) - BucketRanges ranges2(5); - ranges2.set_range(0, 0); - ranges2.set_range(1, 1); - ranges2.set_range(2, 3); - ranges2.set_range(3, 6); - ranges2.set_range(4, 7); - SampleVector samples2(&ranges2); - - samples2.Accumulate(1, 100); - samples1.Add(samples2); - EXPECT_EQ(100, samples1.GetCountAtIndex(0)); - - // Extra bucket in the beginning. - samples2.Accumulate(0, 100); - EXPECT_DEATH(samples1.Add(samples2), ""); - EXPECT_DEATH(samples1.Subtract(samples2), ""); - - // Extra bucket in the end. - samples2.Accumulate(0, -100); - samples2.Accumulate(6, 100); - EXPECT_DEATH(samples1.Add(samples2), ""); - EXPECT_DEATH(samples1.Subtract(samples2), ""); - - // Bucket not match: [3, 5) VS [3, 6) - samples2.Accumulate(6, -100); - samples2.Accumulate(3, 100); - EXPECT_DEATH(samples1.Add(samples2), ""); - EXPECT_DEATH(samples1.Subtract(samples2), ""); -} - -#endif -// (!defined(NDEBUG) || defined(DCHECK_ALWAYS_ON)) && GTEST_HAS_DEATH_TEST - -TEST(SampleVectorIteratorTest, IterateTest) { - BucketRanges ranges(5); - ranges.set_range(0, 0); - ranges.set_range(1, 1); - ranges.set_range(2, 2); - ranges.set_range(3, 3); - ranges.set_range(4, 4); - - vector counts(3); - counts[0] = 1; - counts[1] = 0; // Iterator will bypass this empty bucket. - counts[2] = 2; - - // BucketRanges can have larger size than counts. - SampleVectorIterator it(&counts, &ranges); - size_t index; - - HistogramBase::Sample min; - HistogramBase::Sample max; - HistogramBase::Count count; - it.Get(&min, &max, &count); - EXPECT_EQ(0, min); - EXPECT_EQ(1, max); - EXPECT_EQ(1, count); - EXPECT_TRUE(it.GetBucketIndex(&index)); - EXPECT_EQ(0u, index); - - it.Next(); - it.Get(&min, &max, &count); - EXPECT_EQ(2, min); - EXPECT_EQ(3, max); - EXPECT_EQ(2, count); - EXPECT_TRUE(it.GetBucketIndex(&index)); - EXPECT_EQ(2u, index); - - it.Next(); - EXPECT_TRUE(it.Done()); - - // Create iterator from SampleVector. - SampleVector samples(&ranges); - samples.Accumulate(0, 0); - samples.Accumulate(1, 1); - samples.Accumulate(2, 2); - samples.Accumulate(3, 3); - scoped_ptr it2 = samples.Iterator(); - - int i; - for (i = 1; !it2->Done(); i++, it2->Next()) { - it2->Get(&min, &max, &count); - EXPECT_EQ(i, min); - EXPECT_EQ(i + 1, max); - EXPECT_EQ(i, count); - - size_t index; - EXPECT_TRUE(it2->GetBucketIndex(&index)); - EXPECT_EQ(static_cast(i), index); - } - EXPECT_EQ(4, i); -} - -#if (!defined(NDEBUG) || defined(DCHECK_ALWAYS_ON)) && GTEST_HAS_DEATH_TEST - -TEST(SampleVectorIteratorDeathTest, IterateDoneTest) { - BucketRanges ranges(5); - ranges.set_range(0, 0); - ranges.set_range(1, 1); - ranges.set_range(2, 2); - ranges.set_range(3, 3); - ranges.set_range(4, INT_MAX); - SampleVector samples(&ranges); - - scoped_ptr it = samples.Iterator(); - - EXPECT_TRUE(it->Done()); - - HistogramBase::Sample min; - HistogramBase::Sample max; - HistogramBase::Count count; - EXPECT_DEATH(it->Get(&min, &max, &count), ""); - - EXPECT_DEATH(it->Next(), ""); - - samples.Accumulate(2, 100); - it = samples.Iterator(); - EXPECT_FALSE(it->Done()); -} - -#endif -// (!defined(NDEBUG) || defined(DCHECK_ALWAYS_ON)) && GTEST_HAS_DEATH_TEST - -} // namespace -} // namespace base diff --git a/base/metrics/sparse_histogram.cc b/base/metrics/sparse_histogram.cc deleted file mode 100644 index 737ccad72f..0000000000 --- a/base/metrics/sparse_histogram.cc +++ /dev/null @@ -1,179 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "base/metrics/sparse_histogram.h" - -#include "base/metrics/sample_map.h" -#include "base/metrics/statistics_recorder.h" -#include "base/pickle.h" -#include "base/strings/stringprintf.h" -#include "base/synchronization/lock.h" - -using std::map; -using std::string; - -namespace base { - -typedef HistogramBase::Count Count; -typedef HistogramBase::Sample Sample; - -// static -HistogramBase* SparseHistogram::FactoryGet(const string& name, int32 flags) { - HistogramBase* histogram = StatisticsRecorder::FindHistogram(name); - - if (!histogram) { - // To avoid racy destruction at shutdown, the following will be leaked. - HistogramBase* tentative_histogram = new SparseHistogram(name); - tentative_histogram->SetFlags(flags); - histogram = - StatisticsRecorder::RegisterOrDeleteDuplicate(tentative_histogram); - } - DCHECK_EQ(SPARSE_HISTOGRAM, histogram->GetHistogramType()); - return histogram; -} - -SparseHistogram::~SparseHistogram() {} - -HistogramType SparseHistogram::GetHistogramType() const { - return SPARSE_HISTOGRAM; -} - -bool SparseHistogram::HasConstructionArguments( - Sample expected_minimum, - Sample expected_maximum, - size_t expected_bucket_count) const { - // SparseHistogram never has min/max/bucket_count limit. - return false; -} - -void SparseHistogram::Add(Sample value) { - base::AutoLock auto_lock(lock_); - samples_.Accumulate(value, 1); -} - -scoped_ptr SparseHistogram::SnapshotSamples() const { - scoped_ptr snapshot(new SampleMap()); - - base::AutoLock auto_lock(lock_); - snapshot->Add(samples_); - return snapshot.PassAs(); -} - -void SparseHistogram::AddSamples(const HistogramSamples& samples) { - base::AutoLock auto_lock(lock_); - samples_.Add(samples); -} - -bool SparseHistogram::AddSamplesFromPickle(PickleIterator* iter) { - base::AutoLock auto_lock(lock_); - return samples_.AddFromPickle(iter); -} - -void SparseHistogram::WriteHTMLGraph(string* output) const { - output->append("
");
-  WriteAsciiImpl(true, "
", output); - output->append("
"); -} - -void SparseHistogram::WriteAscii(string* output) const { - WriteAsciiImpl(true, "\n", output); -} - -bool SparseHistogram::SerializeInfoImpl(Pickle* pickle) const { - return pickle->WriteString(histogram_name()) && pickle->WriteInt(flags()); -} - -SparseHistogram::SparseHistogram(const string& name) - : HistogramBase(name) {} - -HistogramBase* SparseHistogram::DeserializeInfoImpl(PickleIterator* iter) { - string histogram_name; - int flags; - if (!iter->ReadString(&histogram_name) || !iter->ReadInt(&flags)) { - DLOG(ERROR) << "Pickle error decoding Histogram: " << histogram_name; - return NULL; - } - - DCHECK(flags & HistogramBase::kIPCSerializationSourceFlag); - flags &= ~HistogramBase::kIPCSerializationSourceFlag; - - return SparseHistogram::FactoryGet(histogram_name, flags); -} - -void SparseHistogram::GetParameters(DictionaryValue* params) const { - // TODO(kaiwang): Implement. (See HistogramBase::WriteJSON.) -} - -void SparseHistogram::GetCountAndBucketData(Count* count, - int64* sum, - ListValue* buckets) const { - // TODO(kaiwang): Implement. (See HistogramBase::WriteJSON.) -} - -void SparseHistogram::WriteAsciiImpl(bool graph_it, - const std::string& newline, - std::string* output) const { - // Get a local copy of the data so we are consistent. - scoped_ptr snapshot = SnapshotSamples(); - Count total_count = snapshot->TotalCount(); - double scaled_total_count = total_count / 100.0; - - WriteAsciiHeader(total_count, output); - output->append(newline); - - // Determine how wide the largest bucket range is (how many digits to print), - // so that we'll be able to right-align starts for the graphical bars. - // Determine which bucket has the largest sample count so that we can - // normalize the graphical bar-width relative to that sample count. - Count largest_count = 0; - Sample largest_sample = 0; - scoped_ptr it = snapshot->Iterator(); - while (!it->Done()) - { - Sample min; - Sample max; - Count count; - it->Get(&min, &max, &count); - if (min > largest_sample) - largest_sample = min; - if (count > largest_count) - largest_count = count; - it->Next(); - } - size_t print_width = GetSimpleAsciiBucketRange(largest_sample).size() + 1; - - // iterate over each item and display them - it = snapshot->Iterator(); - while (!it->Done()) - { - Sample min; - Sample max; - Count count; - it->Get(&min, &max, &count); - - // value is min, so display it - string range = GetSimpleAsciiBucketRange(min); - output->append(range); - for (size_t j = 0; range.size() + j < print_width + 1; ++j) - output->push_back(' '); - - if (graph_it) - WriteAsciiBucketGraph(count, largest_count, output); - WriteAsciiBucketValue(count, scaled_total_count, output); - output->append(newline); - it->Next(); - } -} - -void SparseHistogram::WriteAsciiHeader(const Count total_count, - std::string* output) const { - StringAppendF(output, - "Histogram: %s recorded %d samples", - histogram_name().c_str(), - total_count); - if (flags() & ~kHexRangePrintingFlag) - StringAppendF(output, " (flags = 0x%x)", flags() & ~kHexRangePrintingFlag); -} - -} // namespace base diff --git a/base/metrics/sparse_histogram.h b/base/metrics/sparse_histogram.h deleted file mode 100644 index 07d56603a5..0000000000 --- a/base/metrics/sparse_histogram.h +++ /dev/null @@ -1,117 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef BASE_METRICS_SPARSE_HISTOGRAM_H_ -#define BASE_METRICS_SPARSE_HISTOGRAM_H_ - -#include -#include - -#include "base/base_export.h" -#include "base/basictypes.h" -#include "base/compiler_specific.h" -#include "base/logging.h" -#include "base/memory/scoped_ptr.h" -#include "base/metrics/histogram_base.h" -#include "base/metrics/sample_map.h" -#include "base/synchronization/lock.h" - -namespace base { - -// The common code for different SparseHistogram macros. -#define HISTOGRAM_SPARSE_COMMON(name, sample, flag) \ - do { \ - base::HistogramBase* histogram( \ - base::SparseHistogram::FactoryGet(name, flag)); \ - DCHECK_EQ(histogram->histogram_name(), name); \ - histogram->Add(sample); \ - } while (0) - -#define HISTOGRAM_SPARSE_SLOWLY(name, sample) \ - HISTOGRAM_SPARSE_COMMON(name, sample, base::HistogramBase::kNoFlags) - -#define UMA_HISTOGRAM_SPARSE_SLOWLY(name, sample) \ - HISTOGRAM_SPARSE_COMMON(name, sample, \ - base::HistogramBase::kUmaTargetedHistogramFlag) - -//------------------------------------------------------------------------------ -// Define debug only version of macros. -#ifndef NDEBUG - -#define DHISTOGRAM_SPARSE_SLOWLY(name, sample) \ - HISTOGRAM_SPARSE_SLOWLY(name, sample) - -#else // NDEBUG - -#define DHISTOGRAM_SPARSE_SLOWLY(name, sample) \ - while (0) { \ - static_cast(name); \ - static_cast(sample); \ - } - -#endif // NDEBUG - -class HistogramSamples; - -class BASE_EXPORT_PRIVATE SparseHistogram : public HistogramBase { - public: - // If there's one with same name, return the existing one. If not, create a - // new one. - static HistogramBase* FactoryGet(const std::string& name, int32 flags); - - virtual ~SparseHistogram(); - - // HistogramBase implementation: - virtual HistogramType GetHistogramType() const OVERRIDE; - virtual bool HasConstructionArguments( - Sample expected_minimum, - Sample expected_maximum, - size_t expected_bucket_count) const OVERRIDE; - virtual void Add(Sample value) OVERRIDE; - virtual void AddSamples(const HistogramSamples& samples) OVERRIDE; - virtual bool AddSamplesFromPickle(PickleIterator* iter) OVERRIDE; - virtual scoped_ptr SnapshotSamples() const OVERRIDE; - virtual void WriteHTMLGraph(std::string* output) const OVERRIDE; - virtual void WriteAscii(std::string* output) const OVERRIDE; - - protected: - // HistogramBase implementation: - virtual bool SerializeInfoImpl(Pickle* pickle) const OVERRIDE; - - private: - // Clients should always use FactoryGet to create SparseHistogram. - explicit SparseHistogram(const std::string& name); - - friend BASE_EXPORT_PRIVATE HistogramBase* DeserializeHistogramInfo( - PickleIterator* iter); - static HistogramBase* DeserializeInfoImpl(PickleIterator* iter); - - virtual void GetParameters(DictionaryValue* params) const OVERRIDE; - virtual void GetCountAndBucketData(Count* count, - int64* sum, - ListValue* buckets) const OVERRIDE; - - // Helpers for emitting Ascii graphic. Each method appends data to output. - void WriteAsciiImpl(bool graph_it, - const std::string& newline, - std::string* output) const; - - // Write a common header message describing this histogram. - void WriteAsciiHeader(const Count total_count, - std::string* output) const; - - // For constuctor calling. - friend class SparseHistogramTest; - - // Protects access to |samples_|. - mutable base::Lock lock_; - - SampleMap samples_; - - DISALLOW_COPY_AND_ASSIGN(SparseHistogram); -}; - -} // namespace base - -#endif // BASE_METRICS_SPARSE_HISTOGRAM_H_ diff --git a/base/metrics/sparse_histogram_unittest.cc b/base/metrics/sparse_histogram_unittest.cc deleted file mode 100644 index 825381d853..0000000000 --- a/base/metrics/sparse_histogram_unittest.cc +++ /dev/null @@ -1,144 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include - -#include "base/memory/scoped_ptr.h" -#include "base/metrics/histogram_base.h" -#include "base/metrics/histogram_samples.h" -#include "base/metrics/sample_map.h" -#include "base/metrics/sparse_histogram.h" -#include "base/metrics/statistics_recorder.h" -#include "base/pickle.h" -#include "base/strings/stringprintf.h" -#include "testing/gtest/include/gtest/gtest.h" - -namespace base { - -class SparseHistogramTest : public testing::Test { - protected: - virtual void SetUp() { - // Each test will have a clean state (no Histogram / BucketRanges - // registered). - InitializeStatisticsRecorder(); - } - - virtual void TearDown() { - UninitializeStatisticsRecorder(); - } - - void InitializeStatisticsRecorder() { - statistics_recorder_ = new StatisticsRecorder(); - } - - void UninitializeStatisticsRecorder() { - delete statistics_recorder_; - statistics_recorder_ = NULL; - } - - scoped_ptr NewSparseHistogram(const std::string& name) { - return scoped_ptr(new SparseHistogram(name)); - } - - StatisticsRecorder* statistics_recorder_; -}; - -TEST_F(SparseHistogramTest, BasicTest) { - scoped_ptr histogram(NewSparseHistogram("Sparse")); - scoped_ptr snapshot(histogram->SnapshotSamples()); - EXPECT_EQ(0, snapshot->TotalCount()); - EXPECT_EQ(0, snapshot->sum()); - - histogram->Add(100); - scoped_ptr snapshot1(histogram->SnapshotSamples()); - EXPECT_EQ(1, snapshot1->TotalCount()); - EXPECT_EQ(1, snapshot1->GetCount(100)); - - histogram->Add(100); - histogram->Add(101); - scoped_ptr snapshot2(histogram->SnapshotSamples()); - EXPECT_EQ(3, snapshot2->TotalCount()); - EXPECT_EQ(2, snapshot2->GetCount(100)); - EXPECT_EQ(1, snapshot2->GetCount(101)); -} - -TEST_F(SparseHistogramTest, MacroBasicTest) { - HISTOGRAM_SPARSE_SLOWLY("Sparse", 100); - HISTOGRAM_SPARSE_SLOWLY("Sparse", 200); - HISTOGRAM_SPARSE_SLOWLY("Sparse", 100); - - StatisticsRecorder::Histograms histograms; - StatisticsRecorder::GetHistograms(&histograms); - - ASSERT_EQ(1U, histograms.size()); - HistogramBase* sparse_histogram = histograms[0]; - - EXPECT_EQ(SPARSE_HISTOGRAM, sparse_histogram->GetHistogramType()); - EXPECT_EQ("Sparse", sparse_histogram->histogram_name()); - EXPECT_EQ(HistogramBase::kNoFlags, sparse_histogram->flags()); - - scoped_ptr samples = sparse_histogram->SnapshotSamples(); - EXPECT_EQ(3, samples->TotalCount()); - EXPECT_EQ(2, samples->GetCount(100)); - EXPECT_EQ(1, samples->GetCount(200)); -} - -TEST_F(SparseHistogramTest, MacroUmaTest) { - UMA_HISTOGRAM_SPARSE_SLOWLY("Uma", 100); - - StatisticsRecorder::Histograms histograms; - StatisticsRecorder::GetHistograms(&histograms); - - ASSERT_EQ(1U, histograms.size()); - HistogramBase* sparse_histogram = histograms[0]; - - EXPECT_EQ("Uma", sparse_histogram->histogram_name()); - EXPECT_EQ(HistogramBase::kUmaTargetedHistogramFlag, - sparse_histogram->flags()); -} - -TEST_F(SparseHistogramTest, MacroInLoopTest) { - // Unlike the macros in histogram.h, SparseHistogram macros can have a - // variable as histogram name. - for (int i = 0; i < 2; i++) { - std::string name = StringPrintf("Sparse%d", i + 1); - UMA_HISTOGRAM_SPARSE_SLOWLY(name, 100); - } - - StatisticsRecorder::Histograms histograms; - StatisticsRecorder::GetHistograms(&histograms); - ASSERT_EQ(2U, histograms.size()); - - std::string name1 = histograms[0]->histogram_name(); - std::string name2 = histograms[1]->histogram_name(); - EXPECT_TRUE(("Sparse1" == name1 && "Sparse2" == name2) || - ("Sparse2" == name1 && "Sparse1" == name2)); -} - -TEST_F(SparseHistogramTest, Serialize) { - scoped_ptr histogram(NewSparseHistogram("Sparse")); - histogram->SetFlags(HistogramBase::kIPCSerializationSourceFlag); - - Pickle pickle; - histogram->SerializeInfo(&pickle); - - PickleIterator iter(pickle); - - int type; - EXPECT_TRUE(iter.ReadInt(&type)); - EXPECT_EQ(SPARSE_HISTOGRAM, type); - - std::string name; - EXPECT_TRUE(iter.ReadString(&name)); - EXPECT_EQ("Sparse", name); - - int flag; - EXPECT_TRUE(iter.ReadInt(&flag)); - EXPECT_EQ(HistogramBase::kIPCSerializationSourceFlag, flag); - - // No more data in the pickle. - EXPECT_FALSE(iter.SkipBytes(1)); -} - -} // namespace base diff --git a/base/metrics/statistics_recorder.cc b/base/metrics/statistics_recorder.cc deleted file mode 100644 index f23c81054c..0000000000 --- a/base/metrics/statistics_recorder.cc +++ /dev/null @@ -1,292 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "base/metrics/statistics_recorder.h" - -#include "base/at_exit.h" -#include "base/debug/leak_annotations.h" -#include "base/logging.h" -#include "base/memory/scoped_ptr.h" -#include "base/metrics/histogram.h" -#include "base/strings/stringprintf.h" -#include "base/synchronization/lock.h" - -using std::list; -using std::string; - -namespace { -// Initialize histogram statistics gathering system. -base::LazyInstance::Leaky g_statistics_recorder_ = - LAZY_INSTANCE_INITIALIZER; -} // namespace - -namespace base { - -// static -void StatisticsRecorder::Initialize() { - // Ensure that an instance of the StatisticsRecorder object is created. - g_statistics_recorder_.Get(); -} - - -// static -bool StatisticsRecorder::IsActive() { - if (lock_ == NULL) - return false; - base::AutoLock auto_lock(*lock_); - return NULL != histograms_; -} - -// static -HistogramBase* StatisticsRecorder::RegisterOrDeleteDuplicate( - HistogramBase* histogram) { - // As per crbug.com/79322 the histograms are intentionally leaked, so we need - // to annotate them. Because ANNOTATE_LEAKING_OBJECT_PTR may be used only once - // for an object, the duplicates should not be annotated. - // Callers are responsible for not calling RegisterOrDeleteDuplicate(ptr) - // twice if (lock_ == NULL) || (!histograms_). - if (lock_ == NULL) { - ANNOTATE_LEAKING_OBJECT_PTR(histogram); // see crbug.com/79322 - return histogram; - } - - HistogramBase* histogram_to_delete = NULL; - HistogramBase* histogram_to_return = NULL; - { - base::AutoLock auto_lock(*lock_); - if (histograms_ == NULL) { - histogram_to_return = histogram; - } else { - const string& name = histogram->histogram_name(); - HistogramMap::iterator it = histograms_->find(name); - if (histograms_->end() == it) { - (*histograms_)[name] = histogram; - ANNOTATE_LEAKING_OBJECT_PTR(histogram); // see crbug.com/79322 - histogram_to_return = histogram; - } else if (histogram == it->second) { - // The histogram was registered before. - histogram_to_return = histogram; - } else { - // We already have one histogram with this name. - histogram_to_return = it->second; - histogram_to_delete = histogram; - } - } - } - delete histogram_to_delete; - return histogram_to_return; -} - -// static -const BucketRanges* StatisticsRecorder::RegisterOrDeleteDuplicateRanges( - const BucketRanges* ranges) { - DCHECK(ranges->HasValidChecksum()); - scoped_ptr ranges_deleter; - - if (lock_ == NULL) { - ANNOTATE_LEAKING_OBJECT_PTR(ranges); - return ranges; - } - - base::AutoLock auto_lock(*lock_); - if (ranges_ == NULL) { - ANNOTATE_LEAKING_OBJECT_PTR(ranges); - return ranges; - } - - list* checksum_matching_list; - RangesMap::iterator ranges_it = ranges_->find(ranges->checksum()); - if (ranges_->end() == ranges_it) { - // Add a new matching list to map. - checksum_matching_list = new list(); - ANNOTATE_LEAKING_OBJECT_PTR(checksum_matching_list); - (*ranges_)[ranges->checksum()] = checksum_matching_list; - } else { - checksum_matching_list = ranges_it->second; - } - - list::iterator checksum_matching_list_it; - for (checksum_matching_list_it = checksum_matching_list->begin(); - checksum_matching_list_it != checksum_matching_list->end(); - ++checksum_matching_list_it) { - const BucketRanges* existing_ranges = *checksum_matching_list_it; - if (existing_ranges->Equals(ranges)) { - if (existing_ranges == ranges) { - return ranges; - } else { - ranges_deleter.reset(ranges); - return existing_ranges; - } - } - } - // We haven't found a BucketRanges which has the same ranges. Register the - // new BucketRanges. - checksum_matching_list->push_front(ranges); - return ranges; -} - -// static -void StatisticsRecorder::WriteHTMLGraph(const std::string& query, - std::string* output) { - if (!IsActive()) - return; - - Histograms snapshot; - GetSnapshot(query, &snapshot); - for (Histograms::iterator it = snapshot.begin(); - it != snapshot.end(); - ++it) { - (*it)->WriteHTMLGraph(output); - output->append("


"); - } -} - -// static -void StatisticsRecorder::WriteGraph(const std::string& query, - std::string* output) { - if (!IsActive()) - return; - if (query.length()) - StringAppendF(output, "Collections of histograms for %s\n", query.c_str()); - else - output->append("Collections of all histograms\n"); - - Histograms snapshot; - GetSnapshot(query, &snapshot); - for (Histograms::iterator it = snapshot.begin(); - it != snapshot.end(); - ++it) { - (*it)->WriteAscii(output); - output->append("\n"); - } -} - -// static -void StatisticsRecorder::GetHistograms(Histograms* output) { - if (lock_ == NULL) - return; - base::AutoLock auto_lock(*lock_); - if (histograms_ == NULL) - return; - - for (HistogramMap::iterator it = histograms_->begin(); - histograms_->end() != it; - ++it) { - DCHECK_EQ(it->first, it->second->histogram_name()); - output->push_back(it->second); - } -} - -// static -void StatisticsRecorder::GetBucketRanges( - std::vector* output) { - if (lock_ == NULL) - return; - base::AutoLock auto_lock(*lock_); - if (ranges_ == NULL) - return; - - for (RangesMap::iterator it = ranges_->begin(); - ranges_->end() != it; - ++it) { - list* ranges_list = it->second; - list::iterator ranges_list_it; - for (ranges_list_it = ranges_list->begin(); - ranges_list_it != ranges_list->end(); - ++ranges_list_it) { - output->push_back(*ranges_list_it); - } - } -} - -// static -HistogramBase* StatisticsRecorder::FindHistogram(const std::string& name) { - if (lock_ == NULL) - return NULL; - base::AutoLock auto_lock(*lock_); - if (histograms_ == NULL) - return NULL; - - HistogramMap::iterator it = histograms_->find(name); - if (histograms_->end() == it) - return NULL; - return it->second; -} - -// private static -void StatisticsRecorder::GetSnapshot(const std::string& query, - Histograms* snapshot) { - if (lock_ == NULL) - return; - base::AutoLock auto_lock(*lock_); - if (histograms_ == NULL) - return; - - for (HistogramMap::iterator it = histograms_->begin(); - histograms_->end() != it; - ++it) { - if (it->first.find(query) != std::string::npos) - snapshot->push_back(it->second); - } -} - -// This singleton instance should be started during the single threaded portion -// of main(), and hence it is not thread safe. It initializes globals to -// provide support for all future calls. -StatisticsRecorder::StatisticsRecorder() { - DCHECK(!histograms_); - if (lock_ == NULL) { - // This will leak on purpose. It's the only way to make sure we won't race - // against the static uninitialization of the module while one of our - // static methods relying on the lock get called at an inappropriate time - // during the termination phase. Since it's a static data member, we will - // leak one per process, which would be similar to the instance allocated - // during static initialization and released only on process termination. - lock_ = new base::Lock; - } - base::AutoLock auto_lock(*lock_); - histograms_ = new HistogramMap; - ranges_ = new RangesMap; - - if (VLOG_IS_ON(1)) - AtExitManager::RegisterCallback(&DumpHistogramsToVlog, this); -} - -// static -void StatisticsRecorder::DumpHistogramsToVlog(void* instance) { - DCHECK(VLOG_IS_ON(1)); - - StatisticsRecorder* me = reinterpret_cast(instance); - string output; - me->WriteGraph(std::string(), &output); - VLOG(1) << output; -} - -StatisticsRecorder::~StatisticsRecorder() { - DCHECK(histograms_ && ranges_ && lock_); - - // Clean up. - scoped_ptr histograms_deleter; - scoped_ptr ranges_deleter; - // We don't delete lock_ on purpose to avoid having to properly protect - // against it going away after we checked for NULL in the static methods. - { - base::AutoLock auto_lock(*lock_); - histograms_deleter.reset(histograms_); - ranges_deleter.reset(ranges_); - histograms_ = NULL; - ranges_ = NULL; - } - // We are going to leak the histograms and the ranges. -} - - -// static -StatisticsRecorder::HistogramMap* StatisticsRecorder::histograms_ = NULL; -// static -StatisticsRecorder::RangesMap* StatisticsRecorder::ranges_ = NULL; -// static -base::Lock* StatisticsRecorder::lock_ = NULL; - -} // namespace base diff --git a/base/metrics/statistics_recorder.h b/base/metrics/statistics_recorder.h deleted file mode 100644 index 9a55225324..0000000000 --- a/base/metrics/statistics_recorder.h +++ /dev/null @@ -1,108 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -// StatisticsRecorder holds all Histograms and BucketRanges that are used by -// Histograms in the system. It provides a general place for -// Histograms/BucketRanges to register, and supports a global API for accessing -// (i.e., dumping, or graphing) the data. - -#ifndef BASE_METRICS_STATISTICS_RECORDER_H_ -#define BASE_METRICS_STATISTICS_RECORDER_H_ - -#include -#include -#include -#include - -#include "base/base_export.h" -#include "base/basictypes.h" -#include "base/gtest_prod_util.h" -#include "base/lazy_instance.h" - -namespace base { - -class BucketRanges; -class HistogramBase; -class Lock; - -class BASE_EXPORT StatisticsRecorder { - public: - typedef std::vector Histograms; - - // Initializes the StatisticsRecorder system. - static void Initialize(); - - // Find out if histograms can now be registered into our list. - static bool IsActive(); - - // Register, or add a new histogram to the collection of statistics. If an - // identically named histogram is already registered, then the argument - // |histogram| will deleted. The returned value is always the registered - // histogram (either the argument, or the pre-existing registered histogram). - static HistogramBase* RegisterOrDeleteDuplicate(HistogramBase* histogram); - - // Register, or add a new BucketRanges. If an identically BucketRanges is - // already registered, then the argument |ranges| will deleted. The returned - // value is always the registered BucketRanges (either the argument, or the - // pre-existing one). - static const BucketRanges* RegisterOrDeleteDuplicateRanges( - const BucketRanges* ranges); - - // Methods for printing histograms. Only histograms which have query as - // a substring are written to output (an empty string will process all - // registered histograms). - static void WriteHTMLGraph(const std::string& query, std::string* output); - static void WriteGraph(const std::string& query, std::string* output); - - // Method for extracting histograms which were marked for use by UMA. - static void GetHistograms(Histograms* output); - - // Method for extracting BucketRanges used by all histograms registered. - static void GetBucketRanges(std::vector* output); - - // Find a histogram by name. It matches the exact name. This method is thread - // safe. It returns NULL if a matching histogram is not found. - static HistogramBase* FindHistogram(const std::string& name); - - // GetSnapshot copies some of the pointers to registered histograms into the - // caller supplied vector (Histograms). Only histograms with names matching - // query are returned. The query must be a substring of histogram name for its - // pointer to be copied. - static void GetSnapshot(const std::string& query, Histograms* snapshot); - - private: - // We keep all registered histograms in a map, from name to histogram. - typedef std::map HistogramMap; - - // We keep all |bucket_ranges_| in a map, from checksum to a list of - // |bucket_ranges_|. Checksum is calculated from the |ranges_| in - // |bucket_ranges_|. - typedef std::map*> RangesMap; - - friend struct DefaultLazyInstanceTraits; - friend class HistogramBaseTest; - friend class HistogramTest; - friend class SparseHistogramTest; - friend class StatisticsRecorderTest; - - // The constructor just initializes static members. Usually client code should - // use Initialize to do this. But in test code, you can friend this class and - // call destructor/constructor to get a clean StatisticsRecorder. - StatisticsRecorder(); - ~StatisticsRecorder(); - - static void DumpHistogramsToVlog(void* instance); - - static HistogramMap* histograms_; - static RangesMap* ranges_; - - // Lock protects access to above maps. - static base::Lock* lock_; - - DISALLOW_COPY_AND_ASSIGN(StatisticsRecorder); -}; - -} // namespace base - -#endif // BASE_METRICS_STATISTICS_RECORDER_H_ diff --git a/base/metrics/statistics_recorder_unittest.cc b/base/metrics/statistics_recorder_unittest.cc deleted file mode 100644 index 22504ddfdd..0000000000 --- a/base/metrics/statistics_recorder_unittest.cc +++ /dev/null @@ -1,266 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include - -#include "base/memory/scoped_ptr.h" -#include "base/metrics/histogram.h" -#include "base/metrics/statistics_recorder.h" -#include "testing/gtest/include/gtest/gtest.h" - -namespace base { - -class StatisticsRecorderTest : public testing::Test { - protected: - virtual void SetUp() { - // Each test will have a clean state (no Histogram / BucketRanges - // registered). - InitializeStatisticsRecorder(); - } - - virtual void TearDown() { - UninitializeStatisticsRecorder(); - } - - void InitializeStatisticsRecorder() { - statistics_recorder_ = new StatisticsRecorder(); - } - - void UninitializeStatisticsRecorder() { - delete statistics_recorder_; - statistics_recorder_ = NULL; - } - - Histogram* CreateHistogram(const std::string& name, - HistogramBase::Sample min, - HistogramBase::Sample max, - size_t bucket_count) { - BucketRanges* ranges = new BucketRanges(bucket_count + 1); - Histogram::InitializeBucketRanges(min, max, ranges); - const BucketRanges* registered_ranges = - StatisticsRecorder::RegisterOrDeleteDuplicateRanges(ranges); - return new Histogram(name, min, max, registered_ranges); - } - - void DeleteHistogram(HistogramBase* histogram) { - delete histogram; - } - - StatisticsRecorder* statistics_recorder_; -}; - -TEST_F(StatisticsRecorderTest, NotInitialized) { - UninitializeStatisticsRecorder(); - - ASSERT_FALSE(StatisticsRecorder::IsActive()); - - StatisticsRecorder::Histograms registered_histograms; - std::vector registered_ranges; - - StatisticsRecorder::GetHistograms(®istered_histograms); - EXPECT_EQ(0u, registered_histograms.size()); - - Histogram* histogram = CreateHistogram("TestHistogram", 1, 1000, 10); - - // When StatisticsRecorder is not initialized, register is a noop. - EXPECT_EQ(histogram, - StatisticsRecorder::RegisterOrDeleteDuplicate(histogram)); - // Manually delete histogram that was not registered. - DeleteHistogram(histogram); - - // RegisterOrDeleteDuplicateRanges is a no-op. - BucketRanges* ranges = new BucketRanges(3);; - ranges->ResetChecksum(); - EXPECT_EQ(ranges, - StatisticsRecorder::RegisterOrDeleteDuplicateRanges(ranges)); - StatisticsRecorder::GetBucketRanges(®istered_ranges); - EXPECT_EQ(0u, registered_ranges.size()); -} - -TEST_F(StatisticsRecorderTest, RegisterBucketRanges) { - std::vector registered_ranges; - - BucketRanges* ranges1 = new BucketRanges(3);; - ranges1->ResetChecksum(); - BucketRanges* ranges2 = new BucketRanges(4);; - ranges2->ResetChecksum(); - - // Register new ranges. - EXPECT_EQ(ranges1, - StatisticsRecorder::RegisterOrDeleteDuplicateRanges(ranges1)); - EXPECT_EQ(ranges2, - StatisticsRecorder::RegisterOrDeleteDuplicateRanges(ranges2)); - StatisticsRecorder::GetBucketRanges(®istered_ranges); - ASSERT_EQ(2u, registered_ranges.size()); - - // Register some ranges again. - EXPECT_EQ(ranges1, - StatisticsRecorder::RegisterOrDeleteDuplicateRanges(ranges1)); - registered_ranges.clear(); - StatisticsRecorder::GetBucketRanges(®istered_ranges); - ASSERT_EQ(2u, registered_ranges.size()); - // Make sure the ranges is still the one we know. - ASSERT_EQ(3u, ranges1->size()); - EXPECT_EQ(0, ranges1->range(0)); - EXPECT_EQ(0, ranges1->range(1)); - EXPECT_EQ(0, ranges1->range(2)); - - // Register ranges with same values. - BucketRanges* ranges3 = new BucketRanges(3);; - ranges3->ResetChecksum(); - EXPECT_EQ(ranges1, // returning ranges1 - StatisticsRecorder::RegisterOrDeleteDuplicateRanges(ranges3)); - registered_ranges.clear(); - StatisticsRecorder::GetBucketRanges(®istered_ranges); - ASSERT_EQ(2u, registered_ranges.size()); -} - -TEST_F(StatisticsRecorderTest, RegisterHistogram) { - // Create a Histogram that was not registered. - Histogram* histogram = CreateHistogram("TestHistogram", 1, 1000, 10); - - StatisticsRecorder::Histograms registered_histograms; - StatisticsRecorder::GetHistograms(®istered_histograms); - EXPECT_EQ(0u, registered_histograms.size()); - - // Register the Histogram. - EXPECT_EQ(histogram, - StatisticsRecorder::RegisterOrDeleteDuplicate(histogram)); - StatisticsRecorder::GetHistograms(®istered_histograms); - EXPECT_EQ(1u, registered_histograms.size()); - - // Register the same Histogram again. - EXPECT_EQ(histogram, - StatisticsRecorder::RegisterOrDeleteDuplicate(histogram)); - registered_histograms.clear(); - StatisticsRecorder::GetHistograms(®istered_histograms); - EXPECT_EQ(1u, registered_histograms.size()); -} - -TEST_F(StatisticsRecorderTest, FindHistogram) { - HistogramBase* histogram1 = Histogram::FactoryGet( - "TestHistogram1", 1, 1000, 10, HistogramBase::kNoFlags); - HistogramBase* histogram2 = Histogram::FactoryGet( - "TestHistogram2", 1, 1000, 10, HistogramBase::kNoFlags); - - EXPECT_EQ(histogram1, StatisticsRecorder::FindHistogram("TestHistogram1")); - EXPECT_EQ(histogram2, StatisticsRecorder::FindHistogram("TestHistogram2")); - EXPECT_TRUE(StatisticsRecorder::FindHistogram("TestHistogram") == NULL); -} - -TEST_F(StatisticsRecorderTest, GetSnapshot) { - Histogram::FactoryGet("TestHistogram1", 1, 1000, 10, Histogram::kNoFlags); - Histogram::FactoryGet("TestHistogram2", 1, 1000, 10, Histogram::kNoFlags); - Histogram::FactoryGet("TestHistogram3", 1, 1000, 10, Histogram::kNoFlags); - - StatisticsRecorder::Histograms snapshot; - StatisticsRecorder::GetSnapshot("Test", &snapshot); - EXPECT_EQ(3u, snapshot.size()); - - snapshot.clear(); - StatisticsRecorder::GetSnapshot("1", &snapshot); - EXPECT_EQ(1u, snapshot.size()); - - snapshot.clear(); - StatisticsRecorder::GetSnapshot("hello", &snapshot); - EXPECT_EQ(0u, snapshot.size()); -} - -TEST_F(StatisticsRecorderTest, RegisterHistogramWithFactoryGet) { - StatisticsRecorder::Histograms registered_histograms; - - StatisticsRecorder::GetHistograms(®istered_histograms); - ASSERT_EQ(0u, registered_histograms.size()); - - // Create a histogram. - HistogramBase* histogram = Histogram::FactoryGet( - "TestHistogram", 1, 1000, 10, HistogramBase::kNoFlags); - registered_histograms.clear(); - StatisticsRecorder::GetHistograms(®istered_histograms); - EXPECT_EQ(1u, registered_histograms.size()); - - // Get an existing histogram. - HistogramBase* histogram2 = Histogram::FactoryGet( - "TestHistogram", 1, 1000, 10, HistogramBase::kNoFlags); - registered_histograms.clear(); - StatisticsRecorder::GetHistograms(®istered_histograms); - EXPECT_EQ(1u, registered_histograms.size()); - EXPECT_EQ(histogram, histogram2); - - // Create a LinearHistogram. - histogram = LinearHistogram::FactoryGet( - "TestLinearHistogram", 1, 1000, 10, HistogramBase::kNoFlags); - registered_histograms.clear(); - StatisticsRecorder::GetHistograms(®istered_histograms); - EXPECT_EQ(2u, registered_histograms.size()); - - // Create a BooleanHistogram. - histogram = BooleanHistogram::FactoryGet( - "TestBooleanHistogram", HistogramBase::kNoFlags); - registered_histograms.clear(); - StatisticsRecorder::GetHistograms(®istered_histograms); - EXPECT_EQ(3u, registered_histograms.size()); - - // Create a CustomHistogram. - std::vector custom_ranges; - custom_ranges.push_back(1); - custom_ranges.push_back(5); - histogram = CustomHistogram::FactoryGet( - "TestCustomHistogram", custom_ranges, HistogramBase::kNoFlags); - registered_histograms.clear(); - StatisticsRecorder::GetHistograms(®istered_histograms); - EXPECT_EQ(4u, registered_histograms.size()); -} - -TEST_F(StatisticsRecorderTest, RegisterHistogramWithMacros) { - StatisticsRecorder::Histograms registered_histograms; - - HistogramBase* histogram = Histogram::FactoryGet( - "TestHistogramCounts", 1, 1000000, 50, HistogramBase::kNoFlags); - - // The histogram we got from macro is the same as from FactoryGet. - HISTOGRAM_COUNTS("TestHistogramCounts", 30); - registered_histograms.clear(); - StatisticsRecorder::GetHistograms(®istered_histograms); - ASSERT_EQ(1u, registered_histograms.size()); - EXPECT_EQ(histogram, registered_histograms[0]); - - HISTOGRAM_TIMES("TestHistogramTimes", TimeDelta::FromDays(1)); - HISTOGRAM_ENUMERATION("TestHistogramEnumeration", 20, 200); - - registered_histograms.clear(); - StatisticsRecorder::GetHistograms(®istered_histograms); - EXPECT_EQ(3u, registered_histograms.size()); - - // Debugging only macros. - DHISTOGRAM_TIMES("TestHistogramDebugTimes", TimeDelta::FromDays(1)); - DHISTOGRAM_COUNTS("TestHistogramDebugCounts", 30); - registered_histograms.clear(); - StatisticsRecorder::GetHistograms(®istered_histograms); -#ifndef NDEBUG - EXPECT_EQ(5u, registered_histograms.size()); -#else - EXPECT_EQ(3u, registered_histograms.size()); -#endif -} - -TEST_F(StatisticsRecorderTest, BucketRangesSharing) { - std::vector ranges; - StatisticsRecorder::GetBucketRanges(&ranges); - EXPECT_EQ(0u, ranges.size()); - - Histogram::FactoryGet("Histogram", 1, 64, 8, HistogramBase::kNoFlags); - Histogram::FactoryGet("Histogram2", 1, 64, 8, HistogramBase::kNoFlags); - - StatisticsRecorder::GetBucketRanges(&ranges); - EXPECT_EQ(1u, ranges.size()); - - Histogram::FactoryGet("Histogram3", 1, 64, 16, HistogramBase::kNoFlags); - - ranges.clear(); - StatisticsRecorder::GetBucketRanges(&ranges); - EXPECT_EQ(2u, ranges.size()); -} - -} // namespace base diff --git a/base/metrics/stats_counters.cc b/base/metrics/stats_counters.cc deleted file mode 100644 index 12416d9f0f..0000000000 --- a/base/metrics/stats_counters.cc +++ /dev/null @@ -1,125 +0,0 @@ -// Copyright (c) 2010 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "base/metrics/stats_counters.h" - -namespace base { - -StatsCounter::StatsCounter(const std::string& name) - : counter_id_(-1) { - // We prepend the name with 'c:' to indicate that it is a counter. - if (StatsTable::current()) { - // TODO(mbelshe): name_ construction is racy and it may corrupt memory for - // static. - name_ = "c:"; - name_.append(name); - } -} - -StatsCounter::~StatsCounter() { -} - -void StatsCounter::Set(int value) { - int* loc = GetPtr(); - if (loc) - *loc = value; -} - -void StatsCounter::Add(int value) { - int* loc = GetPtr(); - if (loc) - (*loc) += value; -} - -StatsCounter::StatsCounter() - : counter_id_(-1) { -} - -int* StatsCounter::GetPtr() { - StatsTable* table = StatsTable::current(); - if (!table) - return NULL; - - // If counter_id_ is -1, then we haven't looked it up yet. - if (counter_id_ == -1) { - counter_id_ = table->FindCounter(name_); - if (table->GetSlot() == 0) { - if (!table->RegisterThread(std::string())) { - // There is no room for this thread. This thread - // cannot use counters. - counter_id_ = 0; - return NULL; - } - } - } - - // If counter_id_ is > 0, then we have a valid counter. - if (counter_id_ > 0) - return table->GetLocation(counter_id_, table->GetSlot()); - - // counter_id_ was zero, which means the table is full. - return NULL; -} - - -StatsCounterTimer::StatsCounterTimer(const std::string& name) { - // we prepend the name with 't:' to indicate that it is a timer. - if (StatsTable::current()) { - // TODO(mbelshe): name_ construction is racy and it may corrupt memory for - // static. - name_ = "t:"; - name_.append(name); - } -} - -StatsCounterTimer::~StatsCounterTimer() { -} - -void StatsCounterTimer::Start() { - if (!Enabled()) - return; - start_time_ = TimeTicks::Now(); - stop_time_ = TimeTicks(); -} - -// Stop the timer and record the results. -void StatsCounterTimer::Stop() { - if (!Enabled() || !Running()) - return; - stop_time_ = TimeTicks::Now(); - Record(); -} - -// Returns true if the timer is running. -bool StatsCounterTimer::Running() { - return Enabled() && !start_time_.is_null() && stop_time_.is_null(); -} - -// Accept a TimeDelta to increment. -void StatsCounterTimer::AddTime(TimeDelta time) { - Add(static_cast(time.InMilliseconds())); -} - -void StatsCounterTimer::Record() { - AddTime(stop_time_ - start_time_); -} - - -StatsRate::StatsRate(const std::string& name) - : StatsCounterTimer(name), - counter_(name), - largest_add_(std::string(" ").append(name).append("MAX")) { -} - -StatsRate::~StatsRate() { -} - -void StatsRate::Add(int value) { - counter_.Increment(); - StatsCounterTimer::Add(value); - if (value > largest_add_.value()) - largest_add_.Set(value); -} - -} // namespace base diff --git a/base/metrics/stats_counters.h b/base/metrics/stats_counters.h deleted file mode 100644 index d47bab3e89..0000000000 --- a/base/metrics/stats_counters.h +++ /dev/null @@ -1,197 +0,0 @@ -// Copyright (c) 2011 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef BASE_METRICS_STATS_COUNTERS_H_ -#define BASE_METRICS_STATS_COUNTERS_H_ - -#include - -#include "base/base_export.h" -#include "base/compiler_specific.h" -#include "base/metrics/stats_table.h" -#include "base/time/time.h" - -namespace base { - -// StatsCounters are dynamically created values which can be tracked in -// the StatsTable. They are designed to be lightweight to create and -// easy to use. -// -// Since StatsCounters can be created dynamically by name, there is -// a hash table lookup to find the counter in the table. A StatsCounter -// object can be created once and used across multiple threads safely. -// -// Example usage: -// { -// StatsCounter request_count("RequestCount"); -// request_count.Increment(); -// } -// -// Note that creating counters on the stack does work, however creating -// the counter object requires a hash table lookup. For inner loops, it -// may be better to create the counter either as a member of another object -// (or otherwise outside of the loop) for maximum performance. -// -// Internally, a counter represents a value in a row of a StatsTable. -// The row has a 32bit value for each process/thread in the table and also -// a name (stored in the table metadata). -// -// NOTE: In order to make stats_counters usable in lots of different code, -// avoid any dependencies inside this header file. -// - -//------------------------------------------------------------------------------ -// Define macros for ease of use. They also allow us to change definitions -// as the implementation varies, or depending on compile options. -//------------------------------------------------------------------------------ -// First provide generic macros, which exist in production as well as debug. -#define STATS_COUNTER(name, delta) do { \ - base::StatsCounter counter(name); \ - counter.Add(delta); \ -} while (0) - -#define SIMPLE_STATS_COUNTER(name) STATS_COUNTER(name, 1) - -#define RATE_COUNTER(name, duration) do { \ - base::StatsRate hit_count(name); \ - hit_count.AddTime(duration); \ -} while (0) - -// Define Debug vs non-debug flavors of macros. -#ifndef NDEBUG - -#define DSTATS_COUNTER(name, delta) STATS_COUNTER(name, delta) -#define DSIMPLE_STATS_COUNTER(name) SIMPLE_STATS_COUNTER(name) -#define DRATE_COUNTER(name, duration) RATE_COUNTER(name, duration) - -#else // NDEBUG - -#define DSTATS_COUNTER(name, delta) do {} while (0) -#define DSIMPLE_STATS_COUNTER(name) do {} while (0) -#define DRATE_COUNTER(name, duration) do {} while (0) - -#endif // NDEBUG - -//------------------------------------------------------------------------------ -// StatsCounter represents a counter in the StatsTable class. -class BASE_EXPORT StatsCounter { - public: - // Create a StatsCounter object. - explicit StatsCounter(const std::string& name); - virtual ~StatsCounter(); - - // Sets the counter to a specific value. - void Set(int value); - - // Increments the counter. - void Increment() { - Add(1); - } - - virtual void Add(int value); - - // Decrements the counter. - void Decrement() { - Add(-1); - } - - void Subtract(int value) { - Add(-value); - } - - // Is this counter enabled? - // Returns false if table is full. - bool Enabled() { - return GetPtr() != NULL; - } - - int value() { - int* loc = GetPtr(); - if (loc) return *loc; - return 0; - } - - protected: - StatsCounter(); - - // Returns the cached address of this counter location. - int* GetPtr(); - - std::string name_; - // The counter id in the table. We initialize to -1 (an invalid value) - // and then cache it once it has been looked up. The counter_id is - // valid across all threads and processes. - int32 counter_id_; -}; - - -// A StatsCounterTimer is a StatsCounter which keeps a timer during -// the scope of the StatsCounterTimer. On destruction, it will record -// its time measurement. -class BASE_EXPORT StatsCounterTimer : protected StatsCounter { - public: - // Constructs and starts the timer. - explicit StatsCounterTimer(const std::string& name); - virtual ~StatsCounterTimer(); - - // Start the timer. - void Start(); - - // Stop the timer and record the results. - void Stop(); - - // Returns true if the timer is running. - bool Running(); - - // Accept a TimeDelta to increment. - virtual void AddTime(TimeDelta time); - - protected: - // Compute the delta between start and stop, in milliseconds. - void Record(); - - TimeTicks start_time_; - TimeTicks stop_time_; -}; - -// A StatsRate is a timer that keeps a count of the number of intervals added so -// that several statistics can be produced: -// min, max, avg, count, total -class BASE_EXPORT StatsRate : public StatsCounterTimer { - public: - // Constructs and starts the timer. - explicit StatsRate(const std::string& name); - virtual ~StatsRate(); - - virtual void Add(int value) OVERRIDE; - - private: - StatsCounter counter_; - StatsCounter largest_add_; -}; - - -// Helper class for scoping a timer or rate. -template class StatsScope { - public: - explicit StatsScope(T& timer) - : timer_(timer) { - timer_.Start(); - } - - ~StatsScope() { - timer_.Stop(); - } - - void Stop() { - timer_.Stop(); - } - - private: - T& timer_; -}; - -} // namespace base - -#endif // BASE_METRICS_STATS_COUNTERS_H_ diff --git a/base/metrics/stats_table.cc b/base/metrics/stats_table.cc deleted file mode 100644 index 4a3d939cfe..0000000000 --- a/base/metrics/stats_table.cc +++ /dev/null @@ -1,568 +0,0 @@ -// Copyright (c) 2011 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "base/metrics/stats_table.h" - -#include "base/logging.h" -#include "base/memory/scoped_ptr.h" -#include "base/memory/shared_memory.h" -#include "base/process/process_handle.h" -#include "base/strings/string_piece.h" -#include "base/strings/string_util.h" -#include "base/strings/utf_string_conversions.h" -#include "base/threading/platform_thread.h" -#include "base/threading/thread_local_storage.h" - -#if defined(OS_POSIX) -#include "errno.h" -#endif - -namespace base { - -// The StatsTable uses a shared memory segment that is laid out as follows -// -// +-------------------------------------------+ -// | Version | Size | MaxCounters | MaxThreads | -// +-------------------------------------------+ -// | Thread names table | -// +-------------------------------------------+ -// | Thread TID table | -// +-------------------------------------------+ -// | Thread PID table | -// +-------------------------------------------+ -// | Counter names table | -// +-------------------------------------------+ -// | Data | -// +-------------------------------------------+ -// -// The data layout is a grid, where the columns are the thread_ids and the -// rows are the counter_ids. -// -// If the first character of the thread_name is '\0', then that column is -// empty. -// If the first character of the counter_name is '\0', then that row is -// empty. -// -// About Locking: -// This class is designed to be both multi-thread and multi-process safe. -// Aside from initialization, this is done by partitioning the data which -// each thread uses so that no locking is required. However, to allocate -// the rows and columns of the table to particular threads, locking is -// required. -// -// At the shared-memory level, we have a lock. This lock protects the -// shared-memory table only, and is used when we create new counters (e.g. -// use rows) or when we register new threads (e.g. use columns). Reading -// data from the table does not require any locking at the shared memory -// level. -// -// Each process which accesses the table will create a StatsTable object. -// The StatsTable maintains a hash table of the existing counters in the -// table for faster lookup. Since the hash table is process specific, -// each process maintains its own cache. We avoid complexity here by never -// de-allocating from the hash table. (Counters are dynamically added, -// but not dynamically removed). - -// In order for external viewers to be able to read our shared memory, -// we all need to use the same size ints. -COMPILE_ASSERT(sizeof(int)==4, expect_4_byte_ints); - -namespace { - -// An internal version in case we ever change the format of this -// file, and so that we can identify our table. -const int kTableVersion = 0x13131313; - -// The name for un-named counters and threads in the table. -const char kUnknownName[] = ""; - -// Calculates delta to align an offset to the size of an int -inline int AlignOffset(int offset) { - return (sizeof(int) - (offset % sizeof(int))) % sizeof(int); -} - -inline int AlignedSize(int size) { - return size + AlignOffset(size); -} - -} // namespace - -// The StatsTable::Private maintains convenience pointers into the -// shared memory segment. Use this class to keep the data structure -// clean and accessible. -class StatsTable::Private { - public: - // Various header information contained in the memory mapped segment. - struct TableHeader { - int version; - int size; - int max_counters; - int max_threads; - }; - - // Construct a new Private based on expected size parameters, or - // return NULL on failure. - static Private* New(const std::string& name, int size, - int max_threads, int max_counters); - - SharedMemory* shared_memory() { return &shared_memory_; } - - // Accessors for our header pointers - TableHeader* table_header() const { return table_header_; } - int version() const { return table_header_->version; } - int size() const { return table_header_->size; } - int max_counters() const { return table_header_->max_counters; } - int max_threads() const { return table_header_->max_threads; } - - // Accessors for our tables - char* thread_name(int slot_id) const { - return &thread_names_table_[ - (slot_id-1) * (StatsTable::kMaxThreadNameLength)]; - } - PlatformThreadId* thread_tid(int slot_id) const { - return &(thread_tid_table_[slot_id-1]); - } - int* thread_pid(int slot_id) const { - return &(thread_pid_table_[slot_id-1]); - } - char* counter_name(int counter_id) const { - return &counter_names_table_[ - (counter_id-1) * (StatsTable::kMaxCounterNameLength)]; - } - int* row(int counter_id) const { - return &data_table_[(counter_id-1) * max_threads()]; - } - - private: - // Constructor is private because you should use New() instead. - Private() - : table_header_(NULL), - thread_names_table_(NULL), - thread_tid_table_(NULL), - thread_pid_table_(NULL), - counter_names_table_(NULL), - data_table_(NULL) { - } - - // Initializes the table on first access. Sets header values - // appropriately and zeroes all counters. - void InitializeTable(void* memory, int size, int max_counters, - int max_threads); - - // Initializes our in-memory pointers into a pre-created StatsTable. - void ComputeMappedPointers(void* memory); - - SharedMemory shared_memory_; - TableHeader* table_header_; - char* thread_names_table_; - PlatformThreadId* thread_tid_table_; - int* thread_pid_table_; - char* counter_names_table_; - int* data_table_; -}; - -// static -StatsTable::Private* StatsTable::Private::New(const std::string& name, - int size, - int max_threads, - int max_counters) { - scoped_ptr priv(new Private()); - if (!priv->shared_memory_.CreateNamed(name, true, size)) - return NULL; - if (!priv->shared_memory_.Map(size)) - return NULL; - void* memory = priv->shared_memory_.memory(); - - TableHeader* header = static_cast(memory); - - // If the version does not match, then assume the table needs - // to be initialized. - if (header->version != kTableVersion) - priv->InitializeTable(memory, size, max_counters, max_threads); - - // We have a valid table, so compute our pointers. - priv->ComputeMappedPointers(memory); - - return priv.release(); -} - -void StatsTable::Private::InitializeTable(void* memory, int size, - int max_counters, - int max_threads) { - // Zero everything. - memset(memory, 0, size); - - // Initialize the header. - TableHeader* header = static_cast(memory); - header->version = kTableVersion; - header->size = size; - header->max_counters = max_counters; - header->max_threads = max_threads; -} - -void StatsTable::Private::ComputeMappedPointers(void* memory) { - char* data = static_cast(memory); - int offset = 0; - - table_header_ = reinterpret_cast(data); - offset += sizeof(*table_header_); - offset += AlignOffset(offset); - - // Verify we're looking at a valid StatsTable. - DCHECK_EQ(table_header_->version, kTableVersion); - - thread_names_table_ = reinterpret_cast(data + offset); - offset += sizeof(char) * - max_threads() * StatsTable::kMaxThreadNameLength; - offset += AlignOffset(offset); - - thread_tid_table_ = reinterpret_cast(data + offset); - offset += sizeof(int) * max_threads(); - offset += AlignOffset(offset); - - thread_pid_table_ = reinterpret_cast(data + offset); - offset += sizeof(int) * max_threads(); - offset += AlignOffset(offset); - - counter_names_table_ = reinterpret_cast(data + offset); - offset += sizeof(char) * - max_counters() * StatsTable::kMaxCounterNameLength; - offset += AlignOffset(offset); - - data_table_ = reinterpret_cast(data + offset); - offset += sizeof(int) * max_threads() * max_counters(); - - DCHECK_EQ(offset, size()); -} - -// TLSData carries the data stored in the TLS slots for the -// StatsTable. This is used so that we can properly cleanup when the -// thread exits and return the table slot. -// -// Each thread that calls RegisterThread in the StatsTable will have -// a TLSData stored in its TLS. -struct StatsTable::TLSData { - StatsTable* table; - int slot; -}; - -// We keep a singleton table which can be easily accessed. -StatsTable* global_table = NULL; - -StatsTable::StatsTable(const std::string& name, int max_threads, - int max_counters) - : impl_(NULL), - tls_index_(SlotReturnFunction) { - int table_size = - AlignedSize(sizeof(Private::TableHeader)) + - AlignedSize((max_counters * sizeof(char) * kMaxCounterNameLength)) + - AlignedSize((max_threads * sizeof(char) * kMaxThreadNameLength)) + - AlignedSize(max_threads * sizeof(int)) + - AlignedSize(max_threads * sizeof(int)) + - AlignedSize((sizeof(int) * (max_counters * max_threads))); - - impl_ = Private::New(name, table_size, max_threads, max_counters); - - if (!impl_) - DPLOG(ERROR) << "StatsTable did not initialize"; -} - -StatsTable::~StatsTable() { - // Before we tear down our copy of the table, be sure to - // unregister our thread. - UnregisterThread(); - - // Return ThreadLocalStorage. At this point, if any registered threads - // still exist, they cannot Unregister. - tls_index_.Free(); - - // Cleanup our shared memory. - delete impl_; - - // If we are the global table, unregister ourselves. - if (global_table == this) - global_table = NULL; -} - -StatsTable* StatsTable::current() { - return global_table; -} - -void StatsTable::set_current(StatsTable* value) { - global_table = value; -} - -int StatsTable::GetSlot() const { - TLSData* data = GetTLSData(); - if (!data) - return 0; - return data->slot; -} - -int StatsTable::RegisterThread(const std::string& name) { - int slot = 0; - if (!impl_) - return 0; - - // Registering a thread requires that we lock the shared memory - // so that two threads don't grab the same slot. Fortunately, - // thread creation shouldn't happen in inner loops. - { - SharedMemoryAutoLock lock(impl_->shared_memory()); - slot = FindEmptyThread(); - if (!slot) { - return 0; - } - - // We have space, so consume a column in the table. - std::string thread_name = name; - if (name.empty()) - thread_name = kUnknownName; - strlcpy(impl_->thread_name(slot), thread_name.c_str(), - kMaxThreadNameLength); - *(impl_->thread_tid(slot)) = PlatformThread::CurrentId(); - *(impl_->thread_pid(slot)) = GetCurrentProcId(); - } - - // Set our thread local storage. - TLSData* data = new TLSData; - data->table = this; - data->slot = slot; - tls_index_.Set(data); - return slot; -} - -int StatsTable::CountThreadsRegistered() const { - if (!impl_) - return 0; - - // Loop through the shared memory and count the threads that are active. - // We intentionally do not lock the table during the operation. - int count = 0; - for (int index = 1; index <= impl_->max_threads(); index++) { - char* name = impl_->thread_name(index); - if (*name != '\0') - count++; - } - return count; -} - -int StatsTable::FindCounter(const std::string& name) { - // Note: the API returns counters numbered from 1..N, although - // internally, the array is 0..N-1. This is so that we can return - // zero as "not found". - if (!impl_) - return 0; - - // Create a scope for our auto-lock. - { - AutoLock scoped_lock(counters_lock_); - - // Attempt to find the counter. - CountersMap::const_iterator iter; - iter = counters_.find(name); - if (iter != counters_.end()) - return iter->second; - } - - // Counter does not exist, so add it. - return AddCounter(name); -} - -int* StatsTable::GetLocation(int counter_id, int slot_id) const { - if (!impl_) - return NULL; - if (slot_id > impl_->max_threads()) - return NULL; - - int* row = impl_->row(counter_id); - return &(row[slot_id-1]); -} - -const char* StatsTable::GetRowName(int index) const { - if (!impl_) - return NULL; - - return impl_->counter_name(index); -} - -int StatsTable::GetRowValue(int index) const { - return GetRowValue(index, 0); -} - -int StatsTable::GetRowValue(int index, int pid) const { - if (!impl_) - return 0; - - int rv = 0; - int* row = impl_->row(index); - for (int slot_id = 0; slot_id < impl_->max_threads(); slot_id++) { - if (pid == 0 || *impl_->thread_pid(slot_id) == pid) - rv += row[slot_id]; - } - return rv; -} - -int StatsTable::GetCounterValue(const std::string& name) { - return GetCounterValue(name, 0); -} - -int StatsTable::GetCounterValue(const std::string& name, int pid) { - if (!impl_) - return 0; - - int row = FindCounter(name); - if (!row) - return 0; - return GetRowValue(row, pid); -} - -int StatsTable::GetMaxCounters() const { - if (!impl_) - return 0; - return impl_->max_counters(); -} - -int StatsTable::GetMaxThreads() const { - if (!impl_) - return 0; - return impl_->max_threads(); -} - -int* StatsTable::FindLocation(const char* name) { - // Get the static StatsTable - StatsTable *table = StatsTable::current(); - if (!table) - return NULL; - - // Get the slot for this thread. Try to register - // it if none exists. - int slot = table->GetSlot(); - if (!slot && !(slot = table->RegisterThread(std::string()))) - return NULL; - - // Find the counter id for the counter. - std::string str_name(name); - int counter = table->FindCounter(str_name); - - // Now we can find the location in the table. - return table->GetLocation(counter, slot); -} - -void StatsTable::UnregisterThread() { - UnregisterThread(GetTLSData()); -} - -void StatsTable::UnregisterThread(TLSData* data) { - if (!data) - return; - DCHECK(impl_); - - // Mark the slot free by zeroing out the thread name. - char* name = impl_->thread_name(data->slot); - *name = '\0'; - - // Remove the calling thread's TLS so that it cannot use the slot. - tls_index_.Set(NULL); - delete data; -} - -void StatsTable::SlotReturnFunction(void* data) { - // This is called by the TLS destructor, which on some platforms has - // already cleared the TLS info, so use the tls_data argument - // rather than trying to fetch it ourselves. - TLSData* tls_data = static_cast(data); - if (tls_data) { - DCHECK(tls_data->table); - tls_data->table->UnregisterThread(tls_data); - } -} - -int StatsTable::FindEmptyThread() const { - // Note: the API returns slots numbered from 1..N, although - // internally, the array is 0..N-1. This is so that we can return - // zero as "not found". - // - // The reason for doing this is because the thread 'slot' is stored - // in TLS, which is always initialized to zero, not -1. If 0 were - // returned as a valid slot number, it would be confused with the - // uninitialized state. - if (!impl_) - return 0; - - int index = 1; - for (; index <= impl_->max_threads(); index++) { - char* name = impl_->thread_name(index); - if (!*name) - break; - } - if (index > impl_->max_threads()) - return 0; // The table is full. - return index; -} - -int StatsTable::FindCounterOrEmptyRow(const std::string& name) const { - // Note: the API returns slots numbered from 1..N, although - // internally, the array is 0..N-1. This is so that we can return - // zero as "not found". - // - // There isn't much reason for this other than to be consistent - // with the way we track columns for thread slots. (See comments - // in FindEmptyThread for why it is done this way). - if (!impl_) - return 0; - - int free_slot = 0; - for (int index = 1; index <= impl_->max_counters(); index++) { - char* row_name = impl_->counter_name(index); - if (!*row_name && !free_slot) - free_slot = index; // save that we found a free slot - else if (!strncmp(row_name, name.c_str(), kMaxCounterNameLength)) - return index; - } - return free_slot; -} - -int StatsTable::AddCounter(const std::string& name) { - if (!impl_) - return 0; - - int counter_id = 0; - { - // To add a counter to the shared memory, we need the - // shared memory lock. - SharedMemoryAutoLock lock(impl_->shared_memory()); - - // We have space, so create a new counter. - counter_id = FindCounterOrEmptyRow(name); - if (!counter_id) - return 0; - - std::string counter_name = name; - if (name.empty()) - counter_name = kUnknownName; - strlcpy(impl_->counter_name(counter_id), counter_name.c_str(), - kMaxCounterNameLength); - } - - // now add to our in-memory cache - { - AutoLock lock(counters_lock_); - counters_[name] = counter_id; - } - return counter_id; -} - -StatsTable::TLSData* StatsTable::GetTLSData() const { - TLSData* data = - static_cast(tls_index_.Get()); - if (!data) - return NULL; - - DCHECK(data->slot); - DCHECK_EQ(data->table, this); - return data; -} - -} // namespace base diff --git a/base/metrics/stats_table.h b/base/metrics/stats_table.h deleted file mode 100644 index 153af38c92..0000000000 --- a/base/metrics/stats_table.h +++ /dev/null @@ -1,193 +0,0 @@ -// Copyright (c) 2011 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. -// -// A StatsTable is a table of statistics. It can be used across multiple -// processes and threads, maintaining cheap statistics counters without -// locking. -// -// The goal is to make it very cheap and easy for developers to add -// counters to code, without having to build one-off utilities or mechanisms -// to track the counters, and also to allow a single "view" to display -// the contents of all counters. -// -// To achieve this, StatsTable creates a shared memory segment to store -// the data for the counters. Upon creation, it has a specific size -// which governs the maximum number of counters and concurrent -// threads/processes which can use it. -// - -#ifndef BASE_METRICS_STATS_TABLE_H_ -#define BASE_METRICS_STATS_TABLE_H_ - -#include - -#include "base/base_export.h" -#include "base/basictypes.h" -#include "base/containers/hash_tables.h" -#include "base/synchronization/lock.h" -#include "base/threading/thread_local_storage.h" - -namespace base { - -class BASE_EXPORT StatsTable { - public: - // Create a new StatsTable. - // If a StatsTable already exists with the specified name, this StatsTable - // will use the same shared memory segment as the original. Otherwise, - // a new StatsTable is created and all counters are zeroed. - // - // name is the name of the StatsTable to use. - // - // max_threads is the maximum number of threads the table will support. - // If the StatsTable already exists, this number is ignored. - // - // max_counters is the maximum number of counters the table will support. - // If the StatsTable already exists, this number is ignored. - StatsTable(const std::string& name, int max_threads, int max_counters); - - // Destroys the StatsTable. When the last StatsTable is destroyed - // (across all processes), the StatsTable is removed from disk. - ~StatsTable(); - - // For convenience, we create a static table. This is generally - // used automatically by the counters. - static StatsTable* current(); - - // Set the global table for use in this process. - static void set_current(StatsTable* value); - - // Get the slot id for the calling thread. Returns 0 if no - // slot is assigned. - int GetSlot() const; - - // All threads that contribute data to the table must register with the - // table first. This function will set thread local storage for the - // thread containing the location in the table where this thread will - // write its counter data. - // - // name is just a debugging tag to label the thread, and it does not - // need to be unique. It will be truncated to kMaxThreadNameLength-1 - // characters. - // - // On success, returns the slot id for this thread. On failure, - // returns 0. - int RegisterThread(const std::string& name); - - // Returns the number of threads currently registered. This is really not - // useful except for diagnostics and debugging. - int CountThreadsRegistered() const; - - // Find a counter in the StatsTable. - // - // Returns an id for the counter which can be used to call GetLocation(). - // If the counter does not exist, attempts to create a row for the new - // counter. If there is no space in the table for the new counter, - // returns 0. - int FindCounter(const std::string& name); - - // TODO(mbelshe): implement RemoveCounter. - - // Gets the location of a particular value in the table based on - // the counter id and slot id. - int* GetLocation(int counter_id, int slot_id) const; - - // Gets the counter name at a particular row. If the row is empty, - // returns NULL. - const char* GetRowName(int index) const; - - // Gets the sum of the values for a particular row. - int GetRowValue(int index) const; - - // Gets the sum of the values for a particular row for a given pid. - int GetRowValue(int index, int pid) const; - - // Gets the sum of the values for a particular counter. If the counter - // does not exist, creates the counter. - int GetCounterValue(const std::string& name); - - // Gets the sum of the values for a particular counter for a given pid. - // If the counter does not exist, creates the counter. - int GetCounterValue(const std::string& name, int pid); - - // The maxinum number of counters/rows in the table. - int GetMaxCounters() const; - - // The maxinum number of threads/columns in the table. - int GetMaxThreads() const; - - // The maximum length (in characters) of a Thread's name including - // null terminator, as stored in the shared memory. - static const int kMaxThreadNameLength = 32; - - // The maximum length (in characters) of a Counter's name including - // null terminator, as stored in the shared memory. - static const int kMaxCounterNameLength = 64; - - // Convenience function to lookup a counter location for a - // counter by name for the calling thread. Will register - // the thread if it is not already registered. - static int* FindLocation(const char *name); - - private: - class Private; - struct TLSData; - typedef hash_map CountersMap; - - // Returns the space occupied by a thread in the table. Generally used - // if a thread terminates but the process continues. This function - // does not zero out the thread's counters. - // Cannot be used inside a posix tls destructor. - void UnregisterThread(); - - // This variant expects the tls data to be passed in, so it is safe to - // call from inside a posix tls destructor (see doc for pthread_key_create). - void UnregisterThread(TLSData* tls_data); - - // The SlotReturnFunction is called at thread exit for each thread - // which used the StatsTable. - static void SlotReturnFunction(void* data); - - // Locates a free slot in the table. Returns a number > 0 on success, - // or 0 on failure. The caller must hold the shared_memory lock when - // calling this function. - int FindEmptyThread() const; - - // Locates a counter in the table or finds an empty row. Returns a - // number > 0 on success, or 0 on failure. The caller must hold the - // shared_memory_lock when calling this function. - int FindCounterOrEmptyRow(const std::string& name) const; - - // Internal function to add a counter to the StatsTable. Assumes that - // the counter does not already exist in the table. - // - // name is a unique identifier for this counter, and will be truncated - // to kMaxCounterNameLength-1 characters. - // - // On success, returns the counter_id for the newly added counter. - // On failure, returns 0. - int AddCounter(const std::string& name); - - // Get the TLS data for the calling thread. Returns NULL if none is - // initialized. - TLSData* GetTLSData() const; - - Private* impl_; - - // The counters_lock_ protects the counters_ hash table. - base::Lock counters_lock_; - - // The counters_ hash map is an in-memory hash of the counters. - // It is used for quick lookup of counters, but is cannot be used - // as a substitute for what is in the shared memory. Even though - // we don't have a counter in our hash table, another process may - // have created it. - CountersMap counters_; - ThreadLocalStorage::Slot tls_index_; - - DISALLOW_COPY_AND_ASSIGN(StatsTable); -}; - -} // namespace base - -#endif // BASE_METRICS_STATS_TABLE_H_ diff --git a/base/metrics/stats_table_unittest.cc b/base/metrics/stats_table_unittest.cc deleted file mode 100644 index 8fd33971f4..0000000000 --- a/base/metrics/stats_table_unittest.cc +++ /dev/null @@ -1,424 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "base/memory/shared_memory.h" -#include "base/metrics/stats_counters.h" -#include "base/metrics/stats_table.h" -#include "base/process/kill.h" -#include "base/strings/string_piece.h" -#include "base/strings/stringprintf.h" -#include "base/strings/utf_string_conversions.h" -#include "base/test/multiprocess_test.h" -#include "base/threading/platform_thread.h" -#include "base/threading/simple_thread.h" -#include "testing/gtest/include/gtest/gtest.h" -#include "testing/multiprocess_func_list.h" - -namespace base { - -class StatsTableTest : public MultiProcessTest { - public: - void DeleteShmem(const std::string& name) { - SharedMemory mem; - mem.Delete(name); - } -}; - -// Open a StatsTable and verify that we can write to each of the -// locations in the table. -TEST_F(StatsTableTest, VerifySlots) { - const std::string kTableName = "VerifySlotsStatTable"; - const int kMaxThreads = 1; - const int kMaxCounter = 5; - DeleteShmem(kTableName); - StatsTable table(kTableName, kMaxThreads, kMaxCounter); - - // Register a single thread. - std::string thread_name = "mainThread"; - int slot_id = table.RegisterThread(thread_name); - EXPECT_NE(slot_id, 0); - - // Fill up the table with counters. - std::string counter_base_name = "counter"; - for (int index = 0; index < kMaxCounter; index++) { - std::string counter_name = counter_base_name; - base::StringAppendF(&counter_name, "counter.ctr%d", index); - int counter_id = table.FindCounter(counter_name); - EXPECT_GT(counter_id, 0); - } - - // Try to allocate an additional thread. Verify it fails. - slot_id = table.RegisterThread("too many threads"); - EXPECT_EQ(slot_id, 0); - - // Try to allocate an additional counter. Verify it fails. - int counter_id = table.FindCounter(counter_base_name); - EXPECT_EQ(counter_id, 0); - - DeleteShmem(kTableName); -} - -// CounterZero will continually be set to 0. -const std::string kCounterZero = "CounterZero"; -// Counter1313 will continually be set to 1313. -const std::string kCounter1313 = "Counter1313"; -// CounterIncrement will be incremented each time. -const std::string kCounterIncrement = "CounterIncrement"; -// CounterDecrement will be decremented each time. -const std::string kCounterDecrement = "CounterDecrement"; -// CounterMixed will be incremented by odd numbered threads and -// decremented by even threads. -const std::string kCounterMixed = "CounterMixed"; -// The number of thread loops that we will do. -const int kThreadLoops = 100; - -class StatsTableThread : public SimpleThread { - public: - StatsTableThread(std::string name, int id) - : SimpleThread(name), - id_(id) {} - - virtual void Run() OVERRIDE; - - private: - int id_; -}; - -void StatsTableThread::Run() { - // Each thread will open the shared memory and set counters - // concurrently in a loop. We'll use some pauses to - // mixup the thread scheduling. - - StatsCounter zero_counter(kCounterZero); - StatsCounter lucky13_counter(kCounter1313); - StatsCounter increment_counter(kCounterIncrement); - StatsCounter decrement_counter(kCounterDecrement); - for (int index = 0; index < kThreadLoops; index++) { - StatsCounter mixed_counter(kCounterMixed); // create this one in the loop - zero_counter.Set(0); - lucky13_counter.Set(1313); - increment_counter.Increment(); - decrement_counter.Decrement(); - if (id_ % 2) - mixed_counter.Decrement(); - else - mixed_counter.Increment(); - PlatformThread::Sleep(TimeDelta::FromMilliseconds(index % 10)); - } -} - -// Create a few threads and have them poke on their counters. -// See http://crbug.com/10611 for more information. -#if defined(OS_MACOSX) || defined(THREAD_SANITIZER) -#define MAYBE_MultipleThreads DISABLED_MultipleThreads -#else -#define MAYBE_MultipleThreads MultipleThreads -#endif -TEST_F(StatsTableTest, MAYBE_MultipleThreads) { - // Create a stats table. - const std::string kTableName = "MultipleThreadStatTable"; - const int kMaxThreads = 20; - const int kMaxCounter = 5; - DeleteShmem(kTableName); - StatsTable table(kTableName, kMaxThreads, kMaxCounter); - StatsTable::set_current(&table); - - EXPECT_EQ(0, table.CountThreadsRegistered()); - - // Spin up a set of threads to go bang on the various counters. - // After we join the threads, we'll make sure the counters - // contain the values we expected. - StatsTableThread* threads[kMaxThreads]; - - // Spawn the threads. - for (int index = 0; index < kMaxThreads; index++) { - threads[index] = new StatsTableThread("MultipleThreadsTest", index); - threads[index]->Start(); - } - - // Wait for the threads to finish. - for (int index = 0; index < kMaxThreads; index++) { - threads[index]->Join(); - delete threads[index]; - } - - StatsCounter zero_counter(kCounterZero); - StatsCounter lucky13_counter(kCounter1313); - StatsCounter increment_counter(kCounterIncrement); - StatsCounter decrement_counter(kCounterDecrement); - StatsCounter mixed_counter(kCounterMixed); - - // Verify the various counters are correct. - std::string name; - name = "c:" + kCounterZero; - EXPECT_EQ(0, table.GetCounterValue(name)); - name = "c:" + kCounter1313; - EXPECT_EQ(1313 * kMaxThreads, - table.GetCounterValue(name)); - name = "c:" + kCounterIncrement; - EXPECT_EQ(kMaxThreads * kThreadLoops, - table.GetCounterValue(name)); - name = "c:" + kCounterDecrement; - EXPECT_EQ(-kMaxThreads * kThreadLoops, - table.GetCounterValue(name)); - name = "c:" + kCounterMixed; - EXPECT_EQ((kMaxThreads % 2) * kThreadLoops, - table.GetCounterValue(name)); - EXPECT_EQ(0, table.CountThreadsRegistered()); - - DeleteShmem(kTableName); -} - -const std::string kMPTableName = "MultipleProcessStatTable"; - -MULTIPROCESS_TEST_MAIN(StatsTableMultipleProcessMain) { - // Each process will open the shared memory and set counters - // concurrently in a loop. We'll use some pauses to - // mixup the scheduling. - - StatsTable table(kMPTableName, 0, 0); - StatsTable::set_current(&table); - StatsCounter zero_counter(kCounterZero); - StatsCounter lucky13_counter(kCounter1313); - StatsCounter increment_counter(kCounterIncrement); - StatsCounter decrement_counter(kCounterDecrement); - for (int index = 0; index < kThreadLoops; index++) { - zero_counter.Set(0); - lucky13_counter.Set(1313); - increment_counter.Increment(); - decrement_counter.Decrement(); - PlatformThread::Sleep(TimeDelta::FromMilliseconds(index % 10)); - } - return 0; -} - -// Create a few processes and have them poke on their counters. -// This test is slow and flaky http://crbug.com/10611 -TEST_F(StatsTableTest, DISABLED_MultipleProcesses) { - // Create a stats table. - const int kMaxProcs = 20; - const int kMaxCounter = 5; - DeleteShmem(kMPTableName); - StatsTable table(kMPTableName, kMaxProcs, kMaxCounter); - StatsTable::set_current(&table); - EXPECT_EQ(0, table.CountThreadsRegistered()); - - // Spin up a set of processes to go bang on the various counters. - // After we join the processes, we'll make sure the counters - // contain the values we expected. - ProcessHandle procs[kMaxProcs]; - - // Spawn the processes. - for (int16 index = 0; index < kMaxProcs; index++) { - procs[index] = this->SpawnChild("StatsTableMultipleProcessMain", false); - EXPECT_NE(kNullProcessHandle, procs[index]); - } - - // Wait for the processes to finish. - for (int index = 0; index < kMaxProcs; index++) { - EXPECT_TRUE(WaitForSingleProcess( - procs[index], base::TimeDelta::FromMinutes(1))); - CloseProcessHandle(procs[index]); - } - - StatsCounter zero_counter(kCounterZero); - StatsCounter lucky13_counter(kCounter1313); - StatsCounter increment_counter(kCounterIncrement); - StatsCounter decrement_counter(kCounterDecrement); - - // Verify the various counters are correct. - std::string name; - name = "c:" + kCounterZero; - EXPECT_EQ(0, table.GetCounterValue(name)); - name = "c:" + kCounter1313; - EXPECT_EQ(1313 * kMaxProcs, - table.GetCounterValue(name)); - name = "c:" + kCounterIncrement; - EXPECT_EQ(kMaxProcs * kThreadLoops, - table.GetCounterValue(name)); - name = "c:" + kCounterDecrement; - EXPECT_EQ(-kMaxProcs * kThreadLoops, - table.GetCounterValue(name)); - EXPECT_EQ(0, table.CountThreadsRegistered()); - - DeleteShmem(kMPTableName); -} - -class MockStatsCounter : public StatsCounter { - public: - explicit MockStatsCounter(const std::string& name) - : StatsCounter(name) {} - int* Pointer() { return GetPtr(); } -}; - -// Test some basic StatsCounter operations -TEST_F(StatsTableTest, StatsCounter) { - // Create a stats table. - const std::string kTableName = "StatTable"; - const int kMaxThreads = 20; - const int kMaxCounter = 5; - DeleteShmem(kTableName); - StatsTable table(kTableName, kMaxThreads, kMaxCounter); - StatsTable::set_current(&table); - - MockStatsCounter foo("foo"); - - // Test initial state. - EXPECT_TRUE(foo.Enabled()); - ASSERT_NE(foo.Pointer(), static_cast(0)); - EXPECT_EQ(0, *(foo.Pointer())); - EXPECT_EQ(0, table.GetCounterValue("c:foo")); - - // Test Increment. - while (*(foo.Pointer()) < 123) foo.Increment(); - EXPECT_EQ(123, table.GetCounterValue("c:foo")); - foo.Add(0); - EXPECT_EQ(123, table.GetCounterValue("c:foo")); - foo.Add(-1); - EXPECT_EQ(122, table.GetCounterValue("c:foo")); - - // Test Set. - foo.Set(0); - EXPECT_EQ(0, table.GetCounterValue("c:foo")); - foo.Set(100); - EXPECT_EQ(100, table.GetCounterValue("c:foo")); - foo.Set(-1); - EXPECT_EQ(-1, table.GetCounterValue("c:foo")); - foo.Set(0); - EXPECT_EQ(0, table.GetCounterValue("c:foo")); - - // Test Decrement. - foo.Subtract(1); - EXPECT_EQ(-1, table.GetCounterValue("c:foo")); - foo.Subtract(0); - EXPECT_EQ(-1, table.GetCounterValue("c:foo")); - foo.Subtract(-1); - EXPECT_EQ(0, table.GetCounterValue("c:foo")); - - DeleteShmem(kTableName); -} - -class MockStatsCounterTimer : public StatsCounterTimer { - public: - explicit MockStatsCounterTimer(const std::string& name) - : StatsCounterTimer(name) {} - - TimeTicks start_time() { return start_time_; } - TimeTicks stop_time() { return stop_time_; } -}; - -// Test some basic StatsCounterTimer operations -TEST_F(StatsTableTest, StatsCounterTimer) { - // Create a stats table. - const std::string kTableName = "StatTable"; - const int kMaxThreads = 20; - const int kMaxCounter = 5; - DeleteShmem(kTableName); - StatsTable table(kTableName, kMaxThreads, kMaxCounter); - StatsTable::set_current(&table); - - MockStatsCounterTimer bar("bar"); - - // Test initial state. - EXPECT_FALSE(bar.Running()); - EXPECT_TRUE(bar.start_time().is_null()); - EXPECT_TRUE(bar.stop_time().is_null()); - - const TimeDelta kDuration = TimeDelta::FromMilliseconds(100); - - // Do some timing. - bar.Start(); - PlatformThread::Sleep(kDuration); - bar.Stop(); - EXPECT_GT(table.GetCounterValue("t:bar"), 0); - EXPECT_LE(kDuration.InMilliseconds(), table.GetCounterValue("t:bar")); - - // Verify that timing again is additive. - bar.Start(); - PlatformThread::Sleep(kDuration); - bar.Stop(); - EXPECT_GT(table.GetCounterValue("t:bar"), 0); - EXPECT_LE(kDuration.InMilliseconds() * 2, table.GetCounterValue("t:bar")); - DeleteShmem(kTableName); -} - -// Test some basic StatsRate operations -TEST_F(StatsTableTest, StatsRate) { - // Create a stats table. - const std::string kTableName = "StatTable"; - const int kMaxThreads = 20; - const int kMaxCounter = 5; - DeleteShmem(kTableName); - StatsTable table(kTableName, kMaxThreads, kMaxCounter); - StatsTable::set_current(&table); - - StatsRate baz("baz"); - - // Test initial state. - EXPECT_FALSE(baz.Running()); - EXPECT_EQ(0, table.GetCounterValue("c:baz")); - EXPECT_EQ(0, table.GetCounterValue("t:baz")); - - const TimeDelta kDuration = TimeDelta::FromMilliseconds(100); - - // Do some timing. - baz.Start(); - PlatformThread::Sleep(kDuration); - baz.Stop(); - EXPECT_EQ(1, table.GetCounterValue("c:baz")); - EXPECT_LE(kDuration.InMilliseconds(), table.GetCounterValue("t:baz")); - - // Verify that timing again is additive. - baz.Start(); - PlatformThread::Sleep(kDuration); - baz.Stop(); - EXPECT_EQ(2, table.GetCounterValue("c:baz")); - EXPECT_LE(kDuration.InMilliseconds() * 2, table.GetCounterValue("t:baz")); - DeleteShmem(kTableName); -} - -// Test some basic StatsScope operations -TEST_F(StatsTableTest, StatsScope) { - // Create a stats table. - const std::string kTableName = "StatTable"; - const int kMaxThreads = 20; - const int kMaxCounter = 5; - DeleteShmem(kTableName); - StatsTable table(kTableName, kMaxThreads, kMaxCounter); - StatsTable::set_current(&table); - - StatsCounterTimer foo("foo"); - StatsRate bar("bar"); - - // Test initial state. - EXPECT_EQ(0, table.GetCounterValue("t:foo")); - EXPECT_EQ(0, table.GetCounterValue("t:bar")); - EXPECT_EQ(0, table.GetCounterValue("c:bar")); - - const TimeDelta kDuration = TimeDelta::FromMilliseconds(100); - - // Try a scope. - { - StatsScope timer(foo); - StatsScope timer2(bar); - PlatformThread::Sleep(kDuration); - } - EXPECT_LE(kDuration.InMilliseconds(), table.GetCounterValue("t:foo")); - EXPECT_LE(kDuration.InMilliseconds(), table.GetCounterValue("t:bar")); - EXPECT_EQ(1, table.GetCounterValue("c:bar")); - - // Try a second scope. - { - StatsScope timer(foo); - StatsScope timer2(bar); - PlatformThread::Sleep(kDuration); - } - EXPECT_LE(kDuration.InMilliseconds() * 2, table.GetCounterValue("t:foo")); - EXPECT_LE(kDuration.InMilliseconds() * 2, table.GetCounterValue("t:bar")); - EXPECT_EQ(2, table.GetCounterValue("c:bar")); - - DeleteShmem(kTableName); -} - -} // namespace base diff --git a/base/move.h b/base/move.h deleted file mode 100644 index d2cd3df4f7..0000000000 --- a/base/move.h +++ /dev/null @@ -1,207 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef BASE_MOVE_H_ -#define BASE_MOVE_H_ - -// Macro with the boilerplate that makes a type move-only in C++03. -// -// USAGE -// -// This macro should be used instead of DISALLOW_COPY_AND_ASSIGN to create -// a "move-only" type. Unlike DISALLOW_COPY_AND_ASSIGN, this macro should be -// the first line in a class declaration. -// -// A class using this macro must call .Pass() (or somehow be an r-value already) -// before it can be: -// -// * Passed as a function argument -// * Used as the right-hand side of an assignment -// * Returned from a function -// -// Each class will still need to define their own "move constructor" and "move -// operator=" to make this useful. Here's an example of the macro, the move -// constructor, and the move operator= from the scoped_ptr class: -// -// template -// class scoped_ptr { -// MOVE_ONLY_TYPE_FOR_CPP_03(scoped_ptr, RValue) -// public: -// scoped_ptr(RValue& other) : ptr_(other.release()) { } -// scoped_ptr& operator=(RValue& other) { -// swap(other); -// return *this; -// } -// }; -// -// Note that the constructor must NOT be marked explicit. -// -// For consistency, the second parameter to the macro should always be RValue -// unless you have a strong reason to do otherwise. It is only exposed as a -// macro parameter so that the move constructor and move operator= don't look -// like they're using a phantom type. -// -// -// HOW THIS WORKS -// -// For a thorough explanation of this technique, see: -// -// http://en.wikibooks.org/wiki/More_C%2B%2B_Idioms/Move_Constructor -// -// The summary is that we take advantage of 2 properties: -// -// 1) non-const references will not bind to r-values. -// 2) C++ can apply one user-defined conversion when initializing a -// variable. -// -// The first lets us disable the copy constructor and assignment operator -// by declaring private version of them with a non-const reference parameter. -// -// For l-values, direct initialization still fails like in -// DISALLOW_COPY_AND_ASSIGN because the copy constructor and assignment -// operators are private. -// -// For r-values, the situation is different. The copy constructor and -// assignment operator are not viable due to (1), so we are trying to call -// a non-existent constructor and non-existing operator= rather than a private -// one. Since we have not committed an error quite yet, we can provide an -// alternate conversion sequence and a constructor. We add -// -// * a private struct named "RValue" -// * a user-defined conversion "operator RValue()" -// * a "move constructor" and "move operator=" that take the RValue& as -// their sole parameter. -// -// Only r-values will trigger this sequence and execute our "move constructor" -// or "move operator=." L-values will match the private copy constructor and -// operator= first giving a "private in this context" error. This combination -// gives us a move-only type. -// -// For signaling a destructive transfer of data from an l-value, we provide a -// method named Pass() which creates an r-value for the current instance -// triggering the move constructor or move operator=. -// -// Other ways to get r-values is to use the result of an expression like a -// function call. -// -// Here's an example with comments explaining what gets triggered where: -// -// class Foo { -// MOVE_ONLY_TYPE_FOR_CPP_03(Foo, RValue); -// -// public: -// ... API ... -// Foo(RValue other); // Move constructor. -// Foo& operator=(RValue rhs); // Move operator= -// }; -// -// Foo MakeFoo(); // Function that returns a Foo. -// -// Foo f; -// Foo f_copy(f); // ERROR: Foo(Foo&) is private in this context. -// Foo f_assign; -// f_assign = f; // ERROR: operator=(Foo&) is private in this context. -// -// -// Foo f(MakeFoo()); // R-value so alternate conversion executed. -// Foo f_copy(f.Pass()); // R-value so alternate conversion executed. -// f = f_copy.Pass(); // R-value so alternate conversion executed. -// -// -// IMPLEMENTATION SUBTLETIES WITH RValue -// -// The RValue struct is just a container for a pointer back to the original -// object. It should only ever be created as a temporary, and no external -// class should ever declare it or use it in a parameter. -// -// It is tempting to want to use the RValue type in function parameters, but -// excluding the limited usage here for the move constructor and move -// operator=, doing so would mean that the function could take both r-values -// and l-values equially which is unexpected. See COMPARED To Boost.Move for -// more details. -// -// An alternate, and incorrect, implementation of the RValue class used by -// Boost.Move makes RValue a fieldless child of the move-only type. RValue& -// is then used in place of RValue in the various operators. The RValue& is -// "created" by doing *reinterpret_cast(this). This has the appeal -// of never creating a temporary RValue struct even with optimizations -// disabled. Also, by virtue of inheritance you can treat the RValue -// reference as if it were the move-only type itself. Unfortunately, -// using the result of this reinterpret_cast<> is actually undefined behavior -// due to C++98 5.2.10.7. In certain compilers (e.g., NaCl) the optimizer -// will generate non-working code. -// -// In optimized builds, both implementations generate the same assembly so we -// choose the one that adheres to the standard. -// -// -// COMPARED TO C++11 -// -// In C++11, you would implement this functionality using an r-value reference -// and our .Pass() method would be replaced with a call to std::move(). -// -// This emulation also has a deficiency where it uses up the single -// user-defined conversion allowed by C++ during initialization. This can -// cause problems in some API edge cases. For instance, in scoped_ptr, it is -// impossible to make a function "void Foo(scoped_ptr p)" accept a -// value of type scoped_ptr even if you add a constructor to -// scoped_ptr<> that would make it look like it should work. C++11 does not -// have this deficiency. -// -// -// COMPARED TO Boost.Move -// -// Our implementation similar to Boost.Move, but we keep the RValue struct -// private to the move-only type, and we don't use the reinterpret_cast<> hack. -// -// In Boost.Move, RValue is the boost::rv<> template. This type can be used -// when writing APIs like: -// -// void MyFunc(boost::rv& f) -// -// that can take advantage of rv<> to avoid extra copies of a type. However you -// would still be able to call this version of MyFunc with an l-value: -// -// Foo f; -// MyFunc(f); // Uh oh, we probably just destroyed |f| w/o calling Pass(). -// -// unless someone is very careful to also declare a parallel override like: -// -// void MyFunc(const Foo& f) -// -// that would catch the l-values first. This was declared unsafe in C++11 and -// a C++11 compiler will explicitly fail MyFunc(f). Unfortunately, we cannot -// ensure this in C++03. -// -// Since we have no need for writing such APIs yet, our implementation keeps -// RValue private and uses a .Pass() method to do the conversion instead of -// trying to write a version of "std::move()." Writing an API like std::move() -// would require the RValue struct to be public. -// -// -// CAVEATS -// -// If you include a move-only type as a field inside a class that does not -// explicitly declare a copy constructor, the containing class's implicit -// copy constructor will change from Containing(const Containing&) to -// Containing(Containing&). This can cause some unexpected errors. -// -// http://llvm.org/bugs/show_bug.cgi?id=11528 -// -// The workaround is to explicitly declare your copy constructor. -// -#define MOVE_ONLY_TYPE_FOR_CPP_03(type, rvalue_type) \ - private: \ - struct rvalue_type { \ - explicit rvalue_type(type* object) : object(object) {} \ - type* object; \ - }; \ - type(type&); \ - void operator=(type&); \ - public: \ - operator rvalue_type() { return rvalue_type(this); } \ - type Pass() { return type(rvalue_type(this)); } \ - private: - -#endif // BASE_MOVE_H_ diff --git a/base/native_library.h b/base/native_library.h deleted file mode 100644 index 891f35bd54..0000000000 --- a/base/native_library.h +++ /dev/null @@ -1,91 +0,0 @@ -// Copyright (c) 2011 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef BASE_NATIVE_LIBRARY_H_ -#define BASE_NATIVE_LIBRARY_H_ - -// This file defines a cross-platform "NativeLibrary" type which represents -// a loadable module. - -#include "base/base_export.h" -#include "build/build_config.h" - -#if defined(OS_WIN) -#include -#elif defined(OS_MACOSX) -#import -#endif // OS_* - -#include "base/strings/string16.h" - -// Macro useful for writing cross-platform function pointers. -#if defined(OS_WIN) && !defined(CDECL) -#define CDECL __cdecl -#else -#define CDECL -#endif - -namespace base { - -class FilePath; - -#if defined(OS_WIN) -typedef HMODULE NativeLibrary; -#elif defined(OS_MACOSX) -enum NativeLibraryType { - BUNDLE, - DYNAMIC_LIB -}; -enum NativeLibraryObjCStatus { - OBJC_UNKNOWN, - OBJC_PRESENT, - OBJC_NOT_PRESENT, -}; -struct NativeLibraryStruct { - NativeLibraryType type; - CFBundleRefNum bundle_resource_ref; - NativeLibraryObjCStatus objc_status; - union { - CFBundleRef bundle; - void* dylib; - }; -}; -typedef NativeLibraryStruct* NativeLibrary; -#elif defined(OS_POSIX) -typedef void* NativeLibrary; -#endif // OS_* - -// Loads a native library from disk. Release it with UnloadNativeLibrary when -// you're done. Returns NULL on failure. -// If |err| is not NULL, it may be filled in with an error message on -// error. -BASE_EXPORT NativeLibrary LoadNativeLibrary(const FilePath& library_path, - std::string* error); - -#if defined(OS_WIN) -// Loads a native library from disk. Release it with UnloadNativeLibrary when -// you're done. -// This function retrieves the LoadLibrary function exported from kernel32.dll -// and calls it instead of directly calling the LoadLibrary function via the -// import table. -BASE_EXPORT NativeLibrary LoadNativeLibraryDynamically( - const FilePath& library_path); -#endif // OS_WIN - -// Unloads a native library. -BASE_EXPORT void UnloadNativeLibrary(NativeLibrary library); - -// Gets a function pointer from a native library. -BASE_EXPORT void* GetFunctionPointerFromNativeLibrary(NativeLibrary library, - const char* name); - -// Returns the full platform specific name for a native library. -// For example: -// "mylib" returns "mylib.dll" on Windows, "libmylib.so" on Linux, -// "mylib.dylib" on Mac. -BASE_EXPORT string16 GetNativeLibraryName(const string16& name); - -} // namespace base - -#endif // BASE_NATIVE_LIBRARY_H_ diff --git a/base/native_library_mac.mm b/base/native_library_mac.mm deleted file mode 100644 index 6544fcaed9..0000000000 --- a/base/native_library_mac.mm +++ /dev/null @@ -1,125 +0,0 @@ -// Copyright (c) 2011 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "base/native_library.h" - -#include -#include - -#include "base/file_util.h" -#include "base/files/file_path.h" -#include "base/logging.h" -#include "base/mac/scoped_cftyperef.h" -#include "base/strings/string_util.h" -#include "base/strings/utf_string_conversions.h" -#include "base/threading/thread_restrictions.h" - -namespace base { - -static NativeLibraryObjCStatus GetObjCStatusForImage( - const void* function_pointer) { - Dl_info info; - if (!dladdr(function_pointer, &info)) - return OBJC_UNKNOWN; - - // See if the the image contains an "ObjC image info" segment. This method - // of testing is used in _CFBundleGrokObjcImageInfoFromFile in - // CF-744/CFBundle.c, around lines 2447-2474. - // - // In 32-bit images, ObjC can be recognized in __OBJC,__image_info, whereas - // in 64-bit, the data is in __DATA,__objc_imageinfo. -#if __LP64__ - const section_64* section = getsectbynamefromheader_64( - reinterpret_cast(info.dli_fbase), - SEG_DATA, "__objc_imageinfo"); -#else - const section* section = getsectbynamefromheader( - reinterpret_cast(info.dli_fbase), - SEG_OBJC, "__image_info"); -#endif - return section == NULL ? OBJC_NOT_PRESENT : OBJC_PRESENT; -} - -// static -NativeLibrary LoadNativeLibrary(const base::FilePath& library_path, - std::string* error) { - // dlopen() etc. open the file off disk. - if (library_path.Extension() == "dylib" || !DirectoryExists(library_path)) { - void* dylib = dlopen(library_path.value().c_str(), RTLD_LAZY); - if (!dylib) - return NULL; - NativeLibrary native_lib = new NativeLibraryStruct(); - native_lib->type = DYNAMIC_LIB; - native_lib->dylib = dylib; - native_lib->objc_status = OBJC_UNKNOWN; - return native_lib; - } - base::ScopedCFTypeRef url(CFURLCreateFromFileSystemRepresentation( - kCFAllocatorDefault, - (const UInt8*)library_path.value().c_str(), - library_path.value().length(), - true)); - if (!url) - return NULL; - CFBundleRef bundle = CFBundleCreate(kCFAllocatorDefault, url.get()); - if (!bundle) - return NULL; - - NativeLibrary native_lib = new NativeLibraryStruct(); - native_lib->type = BUNDLE; - native_lib->bundle = bundle; - native_lib->bundle_resource_ref = CFBundleOpenBundleResourceMap(bundle); - native_lib->objc_status = OBJC_UNKNOWN; - return native_lib; -} - -// static -void UnloadNativeLibrary(NativeLibrary library) { - if (library->objc_status == OBJC_NOT_PRESENT) { - if (library->type == BUNDLE) { - CFBundleCloseBundleResourceMap(library->bundle, - library->bundle_resource_ref); - CFRelease(library->bundle); - } else { - dlclose(library->dylib); - } - } else { - VLOG(2) << "Not unloading NativeLibrary because it may contain an ObjC " - "segment. library->objc_status = " << library->objc_status; - // Deliberately do not CFRelease the bundle or dlclose the dylib because - // doing so can corrupt the ObjC runtime method caches. See - // http://crbug.com/172319 for details. - } - delete library; -} - -// static -void* GetFunctionPointerFromNativeLibrary(NativeLibrary library, - const char* name) { - void* function_pointer = NULL; - - // Get the function pointer using the right API for the type. - if (library->type == BUNDLE) { - base::ScopedCFTypeRef symbol_name(CFStringCreateWithCString( - kCFAllocatorDefault, name, kCFStringEncodingUTF8)); - function_pointer = CFBundleGetFunctionPointerForName(library->bundle, - symbol_name); - } else { - function_pointer = dlsym(library->dylib, name); - } - - // If this library hasn't been tested for having ObjC, use the function - // pointer to look up the section information for the library. - if (function_pointer && library->objc_status == OBJC_UNKNOWN) - library->objc_status = GetObjCStatusForImage(function_pointer); - - return function_pointer; -} - -// static -string16 GetNativeLibraryName(const string16& name) { - return name + ASCIIToUTF16(".dylib"); -} - -} // namespace base diff --git a/base/native_library_posix.cc b/base/native_library_posix.cc deleted file mode 100644 index dfa20fc01c..0000000000 --- a/base/native_library_posix.cc +++ /dev/null @@ -1,53 +0,0 @@ -// Copyright (c) 2011 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "base/native_library.h" - -#include - -#include "base/files/file_path.h" -#include "base/logging.h" -#include "base/strings/utf_string_conversions.h" -#include "base/threading/thread_restrictions.h" - -namespace base { - -// static -NativeLibrary LoadNativeLibrary(const FilePath& library_path, - std::string* error) { - // dlopen() opens the file off disk. - base::ThreadRestrictions::AssertIOAllowed(); - - // We deliberately do not use RTLD_DEEPBIND. For the history why, please - // refer to the bug tracker. Some useful bug reports to read include: - // http://crbug.com/17943, http://crbug.com/17557, http://crbug.com/36892, - // and http://crbug.com/40794. - void* dl = dlopen(library_path.value().c_str(), RTLD_LAZY); - if (!dl && error) - *error = dlerror(); - - return dl; -} - -// static -void UnloadNativeLibrary(NativeLibrary library) { - int ret = dlclose(library); - if (ret < 0) { - DLOG(ERROR) << "dlclose failed: " << dlerror(); - NOTREACHED(); - } -} - -// static -void* GetFunctionPointerFromNativeLibrary(NativeLibrary library, - const char* name) { - return dlsym(library, name); -} - -// static -string16 GetNativeLibraryName(const string16& name) { - return ASCIIToUTF16("lib") + name + ASCIIToUTF16(".so"); -} - -} // namespace base diff --git a/base/native_library_win.cc b/base/native_library_win.cc deleted file mode 100644 index 2d437fa2a5..0000000000 --- a/base/native_library_win.cc +++ /dev/null @@ -1,73 +0,0 @@ -// Copyright (c) 2011 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "base/native_library.h" - -#include - -#include "base/file_util.h" -#include "base/strings/utf_string_conversions.h" -#include "base/threading/thread_restrictions.h" - -namespace base { - -typedef HMODULE (WINAPI* LoadLibraryFunction)(const wchar_t* file_name); - -NativeLibrary LoadNativeLibraryHelper(const FilePath& library_path, - LoadLibraryFunction load_library_api) { - // LoadLibrary() opens the file off disk. - base::ThreadRestrictions::AssertIOAllowed(); - - // Switch the current directory to the library directory as the library - // may have dependencies on DLLs in this directory. - bool restore_directory = false; - FilePath current_directory; - if (file_util::GetCurrentDirectory(¤t_directory)) { - FilePath plugin_path = library_path.DirName(); - if (!plugin_path.empty()) { - file_util::SetCurrentDirectory(plugin_path); - restore_directory = true; - } - } - - HMODULE module = (*load_library_api)(library_path.value().c_str()); - if (restore_directory) - file_util::SetCurrentDirectory(current_directory); - - return module; -} - -// static -NativeLibrary LoadNativeLibrary(const FilePath& library_path, - std::string* error) { - return LoadNativeLibraryHelper(library_path, LoadLibraryW); -} - -NativeLibrary LoadNativeLibraryDynamically(const FilePath& library_path) { - typedef HMODULE (WINAPI* LoadLibraryFunction)(const wchar_t* file_name); - - LoadLibraryFunction load_library; - load_library = reinterpret_cast( - GetProcAddress(GetModuleHandle(L"kernel32.dll"), "LoadLibraryW")); - - return LoadNativeLibraryHelper(library_path, load_library); -} - -// static -void UnloadNativeLibrary(NativeLibrary library) { - FreeLibrary(library); -} - -// static -void* GetFunctionPointerFromNativeLibrary(NativeLibrary library, - const char* name) { - return GetProcAddress(library, name); -} - -// static -string16 GetNativeLibraryName(const string16& name) { - return name + ASCIIToUTF16(".dll"); -} - -} // namespace base diff --git a/base/newlib-x86-32.base_untrusted.source_list.gypcmd b/base/newlib-x86-32.base_untrusted.source_list.gypcmd deleted file mode 100644 index 8dbe0ca926..0000000000 --- a/base/newlib-x86-32.base_untrusted.source_list.gypcmd +++ /dev/null @@ -1,353 +0,0 @@ -../build/build_config.h -third_party/dmg_fp/dmg_fp.h -third_party/dmg_fp/g_fmt.cc -third_party/dmg_fp/dtoa_wrapper.cc -third_party/icu/icu_utf.cc -third_party/icu/icu_utf.h -third_party/nspr/prcpucfg.h -third_party/nspr/prcpucfg_freebsd.h -third_party/nspr/prcpucfg_nacl.h -third_party/nspr/prcpucfg_openbsd.h -third_party/nspr/prcpucfg_solaris.h -third_party/nspr/prtime.cc -third_party/nspr/prtime.h -third_party/nspr/prtypes.h -third_party/xdg_mime/xdgmime.h -allocator/allocator_extension.cc -allocator/allocator_extension.h -at_exit.cc -at_exit.h -atomic_ref_count.h -atomic_sequence_num.h -atomicops.h -atomicops_internals_gcc.h -atomicops_internals_tsan.h -atomicops_internals_x86_gcc.h -atomicops_internals_x86_msvc.h -base_export.h -base_paths.h -base_paths_android.h -base_paths_posix.cc -base_paths_posix.h -base_switches.h -base64.cc -base64.h -basictypes.h -bind.h -bind_helpers.cc -bind_helpers.h -bind_internal.h -bits.h -build_time.cc -build_time.h -callback.h -callback_helpers.h -callback_internal.cc -callback_internal.h -cancelable_callback.h -command_line.cc -command_line.h -compiler_specific.h -containers/hash_tables.h -containers/linked_list.h -containers/mru_cache.h -containers/small_map.h -containers/stack_container.h -cpu.h -critical_closure.h -debug/alias.cc -debug/alias.h -debug/crash_logging.cc -debug/crash_logging.h -debug/debugger.cc -debug/debugger.h -debug/debugger_posix.cc -debug/leak_annotations.h -debug/leak_tracker.h -debug/profiler.cc -debug/profiler.h -debug/stack_trace.cc -debug/stack_trace.h -debug/trace_event.h -debug/trace_event_impl.cc -debug/trace_event_impl.h -debug/trace_event_impl_constants.cc -debug/trace_event_memory.cc -debug/trace_event_memory.h -deferred_sequenced_task_runner.cc -deferred_sequenced_task_runner.h -environment.cc -environment.h -file_descriptor_posix.h -file_util.h -file_version_info.h -files/dir_reader_fallback.h -files/dir_reader_posix.h -files/file_enumerator.cc -files/file_enumerator.h -files/file_path.cc -files/file_path.h -files/file_path_constants.cc -files/file_path_watcher.cc -files/file_path_watcher.h -files/file_path_watcher_stub.cc -files/file_util_proxy.h -files/important_file_writer.h -files/important_file_writer.cc -files/memory_mapped_file.cc -files/memory_mapped_file.h -files/memory_mapped_file_posix.cc -files/scoped_platform_file_closer.cc -files/scoped_platform_file_closer.h -files/scoped_temp_dir.h -float_util.h -format_macros.h -gtest_prod_util.h -guid.cc -guid.h -guid_posix.cc -hash.cc -hash.h -id_map.h -ini_parser.cc -ini_parser.h -json/json_file_value_serializer.cc -json/json_file_value_serializer.h -json/json_parser.cc -json/json_parser.h -json/json_reader.cc -json/json_reader.h -json/json_string_value_serializer.cc -json/json_string_value_serializer.h -json/json_value_converter.h -json/json_writer.cc -json/json_writer.h -json/string_escape.cc -json/string_escape.h -lazy_instance.cc -lazy_instance.h -location.cc -location.h -logging.cc -logging.h -memory/aligned_memory.cc -memory/aligned_memory.h -memory/discardable_memory.cc -memory/discardable_memory.h -memory/linked_ptr.h -memory/manual_constructor.h -memory/memory_pressure_listener.cc -memory/memory_pressure_listener.h -memory/raw_scoped_refptr_mismatch_checker.h -memory/ref_counted.cc -memory/ref_counted.h -memory/ref_counted_delete_on_message_loop.h -memory/ref_counted_memory.cc -memory/ref_counted_memory.h -memory/scoped_handle.h -memory/scoped_open_process.h -memory/scoped_policy.h -memory/scoped_ptr.h -memory/scoped_vector.h -memory/shared_memory.h -memory/shared_memory_nacl.cc -memory/singleton.cc -memory/singleton.h -memory/weak_ptr.cc -memory/weak_ptr.h -message_loop/incoming_task_queue.cc -message_loop/incoming_task_queue.h -message_loop/message_loop.cc -message_loop/message_loop.h -message_loop/message_loop_proxy.cc -message_loop/message_loop_proxy.h -message_loop/message_loop_proxy_impl.cc -message_loop/message_loop_proxy_impl.h -message_loop/message_pump.cc -message_loop/message_pump.h -message_loop/message_pump_android.h -message_loop/message_pump_default.cc -message_loop/message_pump_default.h -move.h -native_library.h -observer_list.h -observer_list_threadsafe.h -os_compat_android.h -os_compat_nacl.cc -os_compat_nacl.h -path_service.h -pending_task.cc -pending_task.h -pickle.cc -pickle.h -platform_file.cc -platform_file.h -platform_file_posix.cc -port.h -posix/eintr_wrapper.h -posix/global_descriptors.cc -posix/global_descriptors.h -power_monitor/power_monitor.cc -power_monitor/power_monitor.h -power_monitor/power_monitor_device_source_android.h -power_monitor/power_monitor_device_source.cc -power_monitor/power_monitor_device_source.h -power_monitor/power_monitor_device_source_posix.cc -power_monitor/power_monitor_source.cc -power_monitor/power_monitor_source.h -power_monitor/power_observer.h -process/kill.cc -process/kill.h -process/launch.h -process/memory.h -process/process.h -process/process_handle_posix.cc -process/process_info.h -process/process_iterator.cc -process/process_iterator.h -process/process_metrics.h -profiler/scoped_profile.cc -profiler/scoped_profile.h -profiler/alternate_timer.cc -profiler/alternate_timer.h -profiler/tracked_time.cc -profiler/tracked_time.h -rand_util.cc -rand_util.h -rand_util_nacl.cc -run_loop.cc -run_loop.h -safe_numerics.h -safe_strerror_posix.cc -safe_strerror_posix.h -scoped_native_library.h -sequence_checker.h -sequence_checker_impl.cc -sequence_checker_impl.h -sequenced_task_runner.cc -sequenced_task_runner.h -sequenced_task_runner_helpers.h -sha1.h -sha1_portable.cc -single_thread_task_runner.h -stl_util.h -strings/latin1_string_conversions.cc -strings/latin1_string_conversions.h -strings/nullable_string16.cc -strings/nullable_string16.h -strings/string16.cc -strings/string16.h -strings/string_number_conversions.cc -strings/string_split.cc -strings/string_split.h -strings/string_number_conversions.h -strings/string_piece.cc -strings/string_piece.h -strings/string_tokenizer.h -strings/string_util.cc -strings/string_util.h -strings/string_util_constants.cc -strings/string_util_posix.h -strings/stringize_macros.h -strings/stringprintf.cc -strings/stringprintf.h -strings/sys_string_conversions.h -strings/sys_string_conversions_posix.cc -strings/utf_offset_string_conversions.cc -strings/utf_offset_string_conversions.h -strings/utf_string_conversion_utils.cc -strings/utf_string_conversion_utils.h -strings/utf_string_conversions.cc -strings/utf_string_conversions.h -supports_user_data.cc -supports_user_data.h -synchronization/cancellation_flag.cc -synchronization/cancellation_flag.h -synchronization/condition_variable.h -synchronization/condition_variable_posix.cc -synchronization/lock.cc -synchronization/lock.h -synchronization/lock_impl.h -synchronization/lock_impl_posix.cc -synchronization/spin_wait.h -synchronization/waitable_event.h -synchronization/waitable_event_posix.cc -synchronization/waitable_event_watcher.h -synchronization/waitable_event_watcher_posix.cc -system_monitor/system_monitor.cc -system_monitor/system_monitor.h -sys_byteorder.h -sys_info.cc -sys_info.h -task_runner.cc -task_runner.h -task_runner_util.h -template_util.h -thread_task_runner_handle.cc -thread_task_runner_handle.h -threading/non_thread_safe.h -threading/non_thread_safe_impl.cc -threading/non_thread_safe_impl.h -threading/platform_thread.h -threading/platform_thread_linux.cc -threading/platform_thread_posix.cc -threading/post_task_and_reply_impl.cc -threading/post_task_and_reply_impl.h -threading/sequenced_worker_pool.cc -threading/sequenced_worker_pool.h -threading/simple_thread.cc -threading/simple_thread.h -threading/thread.cc -threading/thread.h -threading/thread_checker.h -threading/thread_checker_impl.cc -threading/thread_checker_impl.h -threading/thread_collision_warner.cc -threading/thread_collision_warner.h -threading/thread_id_name_manager.cc -threading/thread_id_name_manager.h -threading/thread_local.h -threading/thread_local_posix.cc -threading/thread_local_storage.h -threading/thread_local_storage_posix.cc -threading/thread_restrictions.h -threading/thread_restrictions.cc -threading/watchdog.cc -threading/watchdog.h -threading/worker_pool.h -threading/worker_pool.cc -threading/worker_pool_posix.cc -threading/worker_pool_posix.h -time/clock.cc -time/clock.h -time/default_clock.cc -time/default_clock.h -time/default_tick_clock.cc -time/default_tick_clock.h -time/tick_clock.cc -time/tick_clock.h -time/time.cc -time/time.h -time/time_posix.cc -timer/hi_res_timer_manager_posix.cc -timer/hi_res_timer_manager.h -timer/timer.cc -timer/timer.h -tracked_objects.cc -tracked_objects.h -tracking_info.cc -tracking_info.h -tuple.h -values.cc -values.h -value_conversions.cc -value_conversions.h -version.cc -version.h -vlog.cc -vlog.h -base_switches.cc -base_switches.h -strings/string16.cc -sync_socket_nacl.cc -time/time_posix.cc diff --git a/base/newlib-x86-64.base_untrusted.source_list.gypcmd b/base/newlib-x86-64.base_untrusted.source_list.gypcmd deleted file mode 100644 index 8dbe0ca926..0000000000 --- a/base/newlib-x86-64.base_untrusted.source_list.gypcmd +++ /dev/null @@ -1,353 +0,0 @@ -../build/build_config.h -third_party/dmg_fp/dmg_fp.h -third_party/dmg_fp/g_fmt.cc -third_party/dmg_fp/dtoa_wrapper.cc -third_party/icu/icu_utf.cc -third_party/icu/icu_utf.h -third_party/nspr/prcpucfg.h -third_party/nspr/prcpucfg_freebsd.h -third_party/nspr/prcpucfg_nacl.h -third_party/nspr/prcpucfg_openbsd.h -third_party/nspr/prcpucfg_solaris.h -third_party/nspr/prtime.cc -third_party/nspr/prtime.h -third_party/nspr/prtypes.h -third_party/xdg_mime/xdgmime.h -allocator/allocator_extension.cc -allocator/allocator_extension.h -at_exit.cc -at_exit.h -atomic_ref_count.h -atomic_sequence_num.h -atomicops.h -atomicops_internals_gcc.h -atomicops_internals_tsan.h -atomicops_internals_x86_gcc.h -atomicops_internals_x86_msvc.h -base_export.h -base_paths.h -base_paths_android.h -base_paths_posix.cc -base_paths_posix.h -base_switches.h -base64.cc -base64.h -basictypes.h -bind.h -bind_helpers.cc -bind_helpers.h -bind_internal.h -bits.h -build_time.cc -build_time.h -callback.h -callback_helpers.h -callback_internal.cc -callback_internal.h -cancelable_callback.h -command_line.cc -command_line.h -compiler_specific.h -containers/hash_tables.h -containers/linked_list.h -containers/mru_cache.h -containers/small_map.h -containers/stack_container.h -cpu.h -critical_closure.h -debug/alias.cc -debug/alias.h -debug/crash_logging.cc -debug/crash_logging.h -debug/debugger.cc -debug/debugger.h -debug/debugger_posix.cc -debug/leak_annotations.h -debug/leak_tracker.h -debug/profiler.cc -debug/profiler.h -debug/stack_trace.cc -debug/stack_trace.h -debug/trace_event.h -debug/trace_event_impl.cc -debug/trace_event_impl.h -debug/trace_event_impl_constants.cc -debug/trace_event_memory.cc -debug/trace_event_memory.h -deferred_sequenced_task_runner.cc -deferred_sequenced_task_runner.h -environment.cc -environment.h -file_descriptor_posix.h -file_util.h -file_version_info.h -files/dir_reader_fallback.h -files/dir_reader_posix.h -files/file_enumerator.cc -files/file_enumerator.h -files/file_path.cc -files/file_path.h -files/file_path_constants.cc -files/file_path_watcher.cc -files/file_path_watcher.h -files/file_path_watcher_stub.cc -files/file_util_proxy.h -files/important_file_writer.h -files/important_file_writer.cc -files/memory_mapped_file.cc -files/memory_mapped_file.h -files/memory_mapped_file_posix.cc -files/scoped_platform_file_closer.cc -files/scoped_platform_file_closer.h -files/scoped_temp_dir.h -float_util.h -format_macros.h -gtest_prod_util.h -guid.cc -guid.h -guid_posix.cc -hash.cc -hash.h -id_map.h -ini_parser.cc -ini_parser.h -json/json_file_value_serializer.cc -json/json_file_value_serializer.h -json/json_parser.cc -json/json_parser.h -json/json_reader.cc -json/json_reader.h -json/json_string_value_serializer.cc -json/json_string_value_serializer.h -json/json_value_converter.h -json/json_writer.cc -json/json_writer.h -json/string_escape.cc -json/string_escape.h -lazy_instance.cc -lazy_instance.h -location.cc -location.h -logging.cc -logging.h -memory/aligned_memory.cc -memory/aligned_memory.h -memory/discardable_memory.cc -memory/discardable_memory.h -memory/linked_ptr.h -memory/manual_constructor.h -memory/memory_pressure_listener.cc -memory/memory_pressure_listener.h -memory/raw_scoped_refptr_mismatch_checker.h -memory/ref_counted.cc -memory/ref_counted.h -memory/ref_counted_delete_on_message_loop.h -memory/ref_counted_memory.cc -memory/ref_counted_memory.h -memory/scoped_handle.h -memory/scoped_open_process.h -memory/scoped_policy.h -memory/scoped_ptr.h -memory/scoped_vector.h -memory/shared_memory.h -memory/shared_memory_nacl.cc -memory/singleton.cc -memory/singleton.h -memory/weak_ptr.cc -memory/weak_ptr.h -message_loop/incoming_task_queue.cc -message_loop/incoming_task_queue.h -message_loop/message_loop.cc -message_loop/message_loop.h -message_loop/message_loop_proxy.cc -message_loop/message_loop_proxy.h -message_loop/message_loop_proxy_impl.cc -message_loop/message_loop_proxy_impl.h -message_loop/message_pump.cc -message_loop/message_pump.h -message_loop/message_pump_android.h -message_loop/message_pump_default.cc -message_loop/message_pump_default.h -move.h -native_library.h -observer_list.h -observer_list_threadsafe.h -os_compat_android.h -os_compat_nacl.cc -os_compat_nacl.h -path_service.h -pending_task.cc -pending_task.h -pickle.cc -pickle.h -platform_file.cc -platform_file.h -platform_file_posix.cc -port.h -posix/eintr_wrapper.h -posix/global_descriptors.cc -posix/global_descriptors.h -power_monitor/power_monitor.cc -power_monitor/power_monitor.h -power_monitor/power_monitor_device_source_android.h -power_monitor/power_monitor_device_source.cc -power_monitor/power_monitor_device_source.h -power_monitor/power_monitor_device_source_posix.cc -power_monitor/power_monitor_source.cc -power_monitor/power_monitor_source.h -power_monitor/power_observer.h -process/kill.cc -process/kill.h -process/launch.h -process/memory.h -process/process.h -process/process_handle_posix.cc -process/process_info.h -process/process_iterator.cc -process/process_iterator.h -process/process_metrics.h -profiler/scoped_profile.cc -profiler/scoped_profile.h -profiler/alternate_timer.cc -profiler/alternate_timer.h -profiler/tracked_time.cc -profiler/tracked_time.h -rand_util.cc -rand_util.h -rand_util_nacl.cc -run_loop.cc -run_loop.h -safe_numerics.h -safe_strerror_posix.cc -safe_strerror_posix.h -scoped_native_library.h -sequence_checker.h -sequence_checker_impl.cc -sequence_checker_impl.h -sequenced_task_runner.cc -sequenced_task_runner.h -sequenced_task_runner_helpers.h -sha1.h -sha1_portable.cc -single_thread_task_runner.h -stl_util.h -strings/latin1_string_conversions.cc -strings/latin1_string_conversions.h -strings/nullable_string16.cc -strings/nullable_string16.h -strings/string16.cc -strings/string16.h -strings/string_number_conversions.cc -strings/string_split.cc -strings/string_split.h -strings/string_number_conversions.h -strings/string_piece.cc -strings/string_piece.h -strings/string_tokenizer.h -strings/string_util.cc -strings/string_util.h -strings/string_util_constants.cc -strings/string_util_posix.h -strings/stringize_macros.h -strings/stringprintf.cc -strings/stringprintf.h -strings/sys_string_conversions.h -strings/sys_string_conversions_posix.cc -strings/utf_offset_string_conversions.cc -strings/utf_offset_string_conversions.h -strings/utf_string_conversion_utils.cc -strings/utf_string_conversion_utils.h -strings/utf_string_conversions.cc -strings/utf_string_conversions.h -supports_user_data.cc -supports_user_data.h -synchronization/cancellation_flag.cc -synchronization/cancellation_flag.h -synchronization/condition_variable.h -synchronization/condition_variable_posix.cc -synchronization/lock.cc -synchronization/lock.h -synchronization/lock_impl.h -synchronization/lock_impl_posix.cc -synchronization/spin_wait.h -synchronization/waitable_event.h -synchronization/waitable_event_posix.cc -synchronization/waitable_event_watcher.h -synchronization/waitable_event_watcher_posix.cc -system_monitor/system_monitor.cc -system_monitor/system_monitor.h -sys_byteorder.h -sys_info.cc -sys_info.h -task_runner.cc -task_runner.h -task_runner_util.h -template_util.h -thread_task_runner_handle.cc -thread_task_runner_handle.h -threading/non_thread_safe.h -threading/non_thread_safe_impl.cc -threading/non_thread_safe_impl.h -threading/platform_thread.h -threading/platform_thread_linux.cc -threading/platform_thread_posix.cc -threading/post_task_and_reply_impl.cc -threading/post_task_and_reply_impl.h -threading/sequenced_worker_pool.cc -threading/sequenced_worker_pool.h -threading/simple_thread.cc -threading/simple_thread.h -threading/thread.cc -threading/thread.h -threading/thread_checker.h -threading/thread_checker_impl.cc -threading/thread_checker_impl.h -threading/thread_collision_warner.cc -threading/thread_collision_warner.h -threading/thread_id_name_manager.cc -threading/thread_id_name_manager.h -threading/thread_local.h -threading/thread_local_posix.cc -threading/thread_local_storage.h -threading/thread_local_storage_posix.cc -threading/thread_restrictions.h -threading/thread_restrictions.cc -threading/watchdog.cc -threading/watchdog.h -threading/worker_pool.h -threading/worker_pool.cc -threading/worker_pool_posix.cc -threading/worker_pool_posix.h -time/clock.cc -time/clock.h -time/default_clock.cc -time/default_clock.h -time/default_tick_clock.cc -time/default_tick_clock.h -time/tick_clock.cc -time/tick_clock.h -time/time.cc -time/time.h -time/time_posix.cc -timer/hi_res_timer_manager_posix.cc -timer/hi_res_timer_manager.h -timer/timer.cc -timer/timer.h -tracked_objects.cc -tracked_objects.h -tracking_info.cc -tracking_info.h -tuple.h -values.cc -values.h -value_conversions.cc -value_conversions.h -version.cc -version.h -vlog.cc -vlog.h -base_switches.cc -base_switches.h -strings/string16.cc -sync_socket_nacl.cc -time/time_posix.cc diff --git a/base/nix/mime_util_xdg.cc b/base/nix/mime_util_xdg.cc deleted file mode 100644 index 1a41394fc1..0000000000 --- a/base/nix/mime_util_xdg.cc +++ /dev/null @@ -1,655 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "base/nix/mime_util_xdg.h" - -#include -#include -#include -#include - -#include "base/environment.h" -#include "base/file_util.h" -#include "base/lazy_instance.h" -#include "base/logging.h" -#include "base/memory/scoped_ptr.h" -#include "base/memory/singleton.h" -#include "base/nix/xdg_util.h" -#include "base/strings/string_split.h" -#include "base/strings/string_util.h" -#include "base/synchronization/lock.h" -#include "base/third_party/xdg_mime/xdgmime.h" -#include "base/threading/thread_restrictions.h" -#include "base/time/time.h" - -namespace base { -namespace nix { - -namespace { - -class IconTheme; - -// None of the XDG stuff is thread-safe, so serialize all access under -// this lock. -base::LazyInstance::Leaky - g_mime_util_xdg_lock = LAZY_INSTANCE_INITIALIZER; - -class MimeUtilConstants { - public: - typedef std::map IconThemeMap; - typedef std::map IconDirMtimeMap; - typedef std::vector IconFormats; - - // Specified by XDG icon theme specs. - static const int kUpdateIntervalInSeconds = 5; - - static const size_t kDefaultThemeNum = 4; - - static MimeUtilConstants* GetInstance() { - return Singleton::get(); - } - - // Store icon directories and their mtimes. - IconDirMtimeMap icon_dirs_; - - // Store icon formats. - IconFormats icon_formats_; - - // Store loaded icon_theme. - IconThemeMap icon_themes_; - - // The default theme. - IconTheme* default_themes_[kDefaultThemeNum]; - - base::TimeTicks last_check_time_; - - // The current icon theme, usually set through GTK theme integration. - std::string icon_theme_name_; - - private: - MimeUtilConstants() { - icon_formats_.push_back(".png"); - icon_formats_.push_back(".svg"); - icon_formats_.push_back(".xpm"); - - for (size_t i = 0; i < kDefaultThemeNum; ++i) - default_themes_[i] = NULL; - } - ~MimeUtilConstants(); - - friend struct DefaultSingletonTraits; - - DISALLOW_COPY_AND_ASSIGN(MimeUtilConstants); -}; - -// IconTheme represents an icon theme as defined by the xdg icon theme spec. -// Example themes on GNOME include 'Human' and 'Mist'. -// Example themes on KDE include 'crystalsvg' and 'kdeclassic'. -class IconTheme { - public: - // A theme consists of multiple sub-directories, like '32x32' and 'scalable'. - class SubDirInfo { - public: - // See spec for details. - enum Type { - Fixed, - Scalable, - Threshold - }; - SubDirInfo() - : size(0), - type(Threshold), - max_size(0), - min_size(0), - threshold(2) { - } - size_t size; // Nominal size of the icons in this directory. - Type type; // Type of the icon size. - size_t max_size; // Maximum size that the icons can be scaled to. - size_t min_size; // Minimum size that the icons can be scaled to. - size_t threshold; // Maximum difference from desired size. 2 by default. - }; - - explicit IconTheme(const std::string& name); - - ~IconTheme() {} - - // Returns the path to an icon with the name |icon_name| and a size of |size| - // pixels. If the icon does not exist, but |inherits| is true, then look for - // the icon in the parent theme. - FilePath GetIconPath(const std::string& icon_name, int size, bool inherits); - - // Load a theme with the name |theme_name| into memory. Returns null if theme - // is invalid. - static IconTheme* LoadTheme(const std::string& theme_name); - - private: - // Returns the path to an icon with the name |icon_name| in |subdir|. - FilePath GetIconPathUnderSubdir(const std::string& icon_name, - const std::string& subdir); - - // Whether the theme loaded properly. - bool IsValid() { - return index_theme_loaded_; - } - - // Read and parse |file| which is usually named 'index.theme' per theme spec. - bool LoadIndexTheme(const FilePath& file); - - // Checks to see if the icons in |info| matches |size| (in pixels). Returns - // 0 if they match, or the size difference in pixels. - size_t MatchesSize(SubDirInfo* info, size_t size); - - // Yet another function to read a line. - std::string ReadLine(FILE* fp); - - // Set directories to search for icons to the comma-separated list |dirs|. - bool SetDirectories(const std::string& dirs); - - bool index_theme_loaded_; // True if an instance is properly loaded. - // store the scattered directories of this theme. - std::list dirs_; - - // store the subdirs of this theme and array index of |info_array_|. - std::map subdirs_; - scoped_ptr info_array_; // List of sub-directories. - std::string inherits_; // Name of the theme this one inherits from. -}; - -IconTheme::IconTheme(const std::string& name) - : index_theme_loaded_(false) { - base::ThreadRestrictions::AssertIOAllowed(); - // Iterate on all icon directories to find directories of the specified - // theme and load the first encountered index.theme. - MimeUtilConstants::IconDirMtimeMap::iterator iter; - FilePath theme_path; - MimeUtilConstants::IconDirMtimeMap* icon_dirs = - &MimeUtilConstants::GetInstance()->icon_dirs_; - for (iter = icon_dirs->begin(); iter != icon_dirs->end(); ++iter) { - theme_path = iter->first.Append(name); - if (!DirectoryExists(theme_path)) - continue; - FilePath theme_index = theme_path.Append("index.theme"); - if (!index_theme_loaded_ && PathExists(theme_index)) { - if (!LoadIndexTheme(theme_index)) - return; - index_theme_loaded_ = true; - } - dirs_.push_back(theme_path); - } -} - -FilePath IconTheme::GetIconPath(const std::string& icon_name, int size, - bool inherits) { - std::map::iterator subdir_iter; - FilePath icon_path; - - for (subdir_iter = subdirs_.begin(); - subdir_iter != subdirs_.end(); - ++subdir_iter) { - SubDirInfo* info = &info_array_[subdir_iter->second]; - if (MatchesSize(info, size) == 0) { - icon_path = GetIconPathUnderSubdir(icon_name, subdir_iter->first); - if (!icon_path.empty()) - return icon_path; - } - } - // Now looking for the mostly matched. - size_t min_delta_seen = 9999; - - for (subdir_iter = subdirs_.begin(); - subdir_iter != subdirs_.end(); - ++subdir_iter) { - SubDirInfo* info = &info_array_[subdir_iter->second]; - size_t delta = MatchesSize(info, size); - if (delta < min_delta_seen) { - FilePath path = GetIconPathUnderSubdir(icon_name, subdir_iter->first); - if (!path.empty()) { - min_delta_seen = delta; - icon_path = path; - } - } - } - - if (!icon_path.empty() || !inherits || inherits_ == "") - return icon_path; - - IconTheme* theme = LoadTheme(inherits_); - // Inheriting from itself means the theme is buggy but we shouldn't crash. - if (theme && theme != this) - return theme->GetIconPath(icon_name, size, inherits); - else - return FilePath(); -} - -IconTheme* IconTheme::LoadTheme(const std::string& theme_name) { - scoped_ptr theme; - MimeUtilConstants::IconThemeMap* icon_themes = - &MimeUtilConstants::GetInstance()->icon_themes_; - if (icon_themes->find(theme_name) != icon_themes->end()) { - theme.reset((*icon_themes)[theme_name]); - } else { - theme.reset(new IconTheme(theme_name)); - if (!theme->IsValid()) - theme.reset(); - (*icon_themes)[theme_name] = theme.get(); - } - return theme.release(); -} - -FilePath IconTheme::GetIconPathUnderSubdir(const std::string& icon_name, - const std::string& subdir) { - FilePath icon_path; - std::list::iterator dir_iter; - MimeUtilConstants::IconFormats* icon_formats = - &MimeUtilConstants::GetInstance()->icon_formats_; - for (dir_iter = dirs_.begin(); dir_iter != dirs_.end(); ++dir_iter) { - for (size_t i = 0; i < icon_formats->size(); ++i) { - icon_path = dir_iter->Append(subdir); - icon_path = icon_path.Append(icon_name + (*icon_formats)[i]); - if (PathExists(icon_path)) - return icon_path; - } - } - return FilePath(); -} - -bool IconTheme::LoadIndexTheme(const FilePath& file) { - FILE* fp = file_util::OpenFile(file, "r"); - SubDirInfo* current_info = NULL; - if (!fp) - return false; - - // Read entries. - while (!feof(fp) && !ferror(fp)) { - std::string buf = ReadLine(fp); - if (buf == "") - break; - - std::string entry; - TrimWhitespaceASCII(buf, TRIM_ALL, &entry); - if (entry.length() == 0 || entry[0] == '#') { - // Blank line or Comment. - continue; - } else if (entry[0] == '[' && info_array_.get()) { - current_info = NULL; - std::string subdir = entry.substr(1, entry.length() - 2); - if (subdirs_.find(subdir) != subdirs_.end()) - current_info = &info_array_[subdirs_[subdir]]; - } - - std::string key, value; - std::vector r; - base::SplitStringDontTrim(entry, '=', &r); - if (r.size() < 2) - continue; - - TrimWhitespaceASCII(r[0], TRIM_ALL, &key); - for (size_t i = 1; i < r.size(); i++) - value.append(r[i]); - TrimWhitespaceASCII(value, TRIM_ALL, &value); - - if (current_info) { - if (key == "Size") { - current_info->size = atoi(value.c_str()); - } else if (key == "Type") { - if (value == "Fixed") - current_info->type = SubDirInfo::Fixed; - else if (value == "Scalable") - current_info->type = SubDirInfo::Scalable; - else if (value == "Threshold") - current_info->type = SubDirInfo::Threshold; - } else if (key == "MaxSize") { - current_info->max_size = atoi(value.c_str()); - } else if (key == "MinSize") { - current_info->min_size = atoi(value.c_str()); - } else if (key == "Threshold") { - current_info->threshold = atoi(value.c_str()); - } - } else { - if (key.compare("Directories") == 0 && !info_array_.get()) { - if (!SetDirectories(value)) break; - } else if (key.compare("Inherits") == 0) { - if (value != "hicolor") - inherits_ = value; - } - } - } - - file_util::CloseFile(fp); - return info_array_.get() != NULL; -} - -size_t IconTheme::MatchesSize(SubDirInfo* info, size_t size) { - if (info->type == SubDirInfo::Fixed) { - if (size > info->size) - return size - info->size; - else - return info->size - size; - } else if (info->type == SubDirInfo::Scalable) { - if (size < info->min_size) - return info->min_size - size; - if (size > info->max_size) - return size - info->max_size; - return 0; - } else { - if (size + info->threshold < info->size) - return info->size - size - info->threshold; - if (size > info->size + info->threshold) - return size - info->size - info->threshold; - return 0; - } -} - -std::string IconTheme::ReadLine(FILE* fp) { - if (!fp) - return std::string(); - - std::string result; - const size_t kBufferSize = 100; - char buffer[kBufferSize]; - while ((fgets(buffer, kBufferSize - 1, fp)) != NULL) { - result += buffer; - size_t len = result.length(); - if (len == 0) - break; - char end = result[len - 1]; - if (end == '\n' || end == '\0') - break; - } - - return result; -} - -bool IconTheme::SetDirectories(const std::string& dirs) { - int num = 0; - std::string::size_type pos = 0, epos; - std::string dir; - while ((epos = dirs.find(',', pos)) != std::string::npos) { - TrimWhitespaceASCII(dirs.substr(pos, epos - pos), TRIM_ALL, &dir); - if (dir.length() == 0) { - DLOG(WARNING) << "Invalid index.theme: blank subdir"; - return false; - } - subdirs_[dir] = num++; - pos = epos + 1; - } - TrimWhitespaceASCII(dirs.substr(pos), TRIM_ALL, &dir); - if (dir.length() == 0) { - DLOG(WARNING) << "Invalid index.theme: blank subdir"; - return false; - } - subdirs_[dir] = num++; - info_array_.reset(new SubDirInfo[num]); - return true; -} - -bool CheckDirExistsAndGetMtime(const FilePath& dir, - base::Time* last_modified) { - if (!DirectoryExists(dir)) - return false; - base::PlatformFileInfo file_info; - if (!file_util::GetFileInfo(dir, &file_info)) - return false; - *last_modified = file_info.last_modified; - return true; -} - -// Make sure |dir| exists and add it to the list of icon directories. -void TryAddIconDir(const FilePath& dir) { - base::Time last_modified; - if (!CheckDirExistsAndGetMtime(dir, &last_modified)) - return; - MimeUtilConstants::GetInstance()->icon_dirs_[dir] = last_modified; -} - -// For a xdg directory |dir|, add the appropriate icon sub-directories. -void AddXDGDataDir(const FilePath& dir) { - if (!DirectoryExists(dir)) - return; - TryAddIconDir(dir.Append("icons")); - TryAddIconDir(dir.Append("pixmaps")); -} - -// Add all the xdg icon directories. -void InitIconDir() { - FilePath home = file_util::GetHomeDir(); - if (!home.empty()) { - FilePath legacy_data_dir(home); - legacy_data_dir = legacy_data_dir.AppendASCII(".icons"); - if (DirectoryExists(legacy_data_dir)) - TryAddIconDir(legacy_data_dir); - } - const char* env = getenv("XDG_DATA_HOME"); - if (env) { - AddXDGDataDir(FilePath(env)); - } else if (!home.empty()) { - FilePath local_data_dir(home); - local_data_dir = local_data_dir.AppendASCII(".local"); - local_data_dir = local_data_dir.AppendASCII("share"); - AddXDGDataDir(local_data_dir); - } - - env = getenv("XDG_DATA_DIRS"); - if (!env) { - AddXDGDataDir(FilePath("/usr/local/share")); - AddXDGDataDir(FilePath("/usr/share")); - } else { - std::string xdg_data_dirs = env; - std::string::size_type pos = 0, epos; - while ((epos = xdg_data_dirs.find(':', pos)) != std::string::npos) { - AddXDGDataDir(FilePath(xdg_data_dirs.substr(pos, epos - pos))); - pos = epos + 1; - } - AddXDGDataDir(FilePath(xdg_data_dirs.substr(pos))); - } -} - -void EnsureUpdated() { - MimeUtilConstants* constants = MimeUtilConstants::GetInstance(); - if (constants->last_check_time_.is_null()) { - constants->last_check_time_ = base::TimeTicks::Now(); - InitIconDir(); - return; - } - - // Per xdg theme spec, we should check the icon directories every so often - // for newly added icons. - base::TimeDelta time_since_last_check = - base::TimeTicks::Now() - constants->last_check_time_; - if (time_since_last_check.InSeconds() > constants->kUpdateIntervalInSeconds) { - constants->last_check_time_ += time_since_last_check; - - bool rescan_icon_dirs = false; - MimeUtilConstants::IconDirMtimeMap* icon_dirs = &constants->icon_dirs_; - MimeUtilConstants::IconDirMtimeMap::iterator iter; - for (iter = icon_dirs->begin(); iter != icon_dirs->end(); ++iter) { - base::Time last_modified; - if (!CheckDirExistsAndGetMtime(iter->first, &last_modified) || - last_modified != iter->second) { - rescan_icon_dirs = true; - break; - } - } - - if (rescan_icon_dirs) { - constants->icon_dirs_.clear(); - constants->icon_themes_.clear(); - InitIconDir(); - } - } -} - -// Find a fallback icon if we cannot find it in the default theme. -FilePath LookupFallbackIcon(const std::string& icon_name) { - MimeUtilConstants* constants = MimeUtilConstants::GetInstance(); - MimeUtilConstants::IconDirMtimeMap::iterator iter; - MimeUtilConstants::IconDirMtimeMap* icon_dirs = &constants->icon_dirs_; - MimeUtilConstants::IconFormats* icon_formats = &constants->icon_formats_; - for (iter = icon_dirs->begin(); iter != icon_dirs->end(); ++iter) { - for (size_t i = 0; i < icon_formats->size(); ++i) { - FilePath icon = iter->first.Append(icon_name + (*icon_formats)[i]); - if (PathExists(icon)) - return icon; - } - } - return FilePath(); -} - -// Initialize the list of default themes. -void InitDefaultThemes() { - IconTheme** default_themes = - MimeUtilConstants::GetInstance()->default_themes_; - - scoped_ptr env(base::Environment::Create()); - base::nix::DesktopEnvironment desktop_env = - base::nix::GetDesktopEnvironment(env.get()); - if (desktop_env == base::nix::DESKTOP_ENVIRONMENT_KDE3 || - desktop_env == base::nix::DESKTOP_ENVIRONMENT_KDE4) { - // KDE - std::string kde_default_theme; - std::string kde_fallback_theme; - - // TODO(thestig): Figure out how to get the current icon theme on KDE. - // Setting stored in ~/.kde/share/config/kdeglobals under Icons -> Theme. - default_themes[0] = NULL; - - // Try some reasonable defaults for KDE. - if (desktop_env == base::nix::DESKTOP_ENVIRONMENT_KDE3) { - // KDE 3 - kde_default_theme = "default.kde"; - kde_fallback_theme = "crystalsvg"; - } else { - // KDE 4 - kde_default_theme = "default.kde4"; - kde_fallback_theme = "oxygen"; - } - default_themes[1] = IconTheme::LoadTheme(kde_default_theme); - default_themes[2] = IconTheme::LoadTheme(kde_fallback_theme); - } else { - // Assume it's Gnome and use GTK to figure out the theme. - default_themes[1] = IconTheme::LoadTheme( - MimeUtilConstants::GetInstance()->icon_theme_name_); - default_themes[2] = IconTheme::LoadTheme("gnome"); - } - // hicolor needs to be last per icon theme spec. - default_themes[3] = IconTheme::LoadTheme("hicolor"); - - for (size_t i = 0; i < MimeUtilConstants::kDefaultThemeNum; i++) { - if (default_themes[i] == NULL) - continue; - // NULL out duplicate pointers. - for (size_t j = i + 1; j < MimeUtilConstants::kDefaultThemeNum; j++) { - if (default_themes[j] == default_themes[i]) - default_themes[j] = NULL; - } - } -} - -// Try to find an icon with the name |icon_name| that's |size| pixels. -FilePath LookupIconInDefaultTheme(const std::string& icon_name, int size) { - EnsureUpdated(); - MimeUtilConstants* constants = MimeUtilConstants::GetInstance(); - MimeUtilConstants::IconThemeMap* icon_themes = &constants->icon_themes_; - if (icon_themes->empty()) - InitDefaultThemes(); - - FilePath icon_path; - IconTheme** default_themes = constants->default_themes_; - for (size_t i = 0; i < MimeUtilConstants::kDefaultThemeNum; i++) { - if (default_themes[i]) { - icon_path = default_themes[i]->GetIconPath(icon_name, size, true); - if (!icon_path.empty()) - return icon_path; - } - } - return LookupFallbackIcon(icon_name); -} - -MimeUtilConstants::~MimeUtilConstants() { - for (size_t i = 0; i < kDefaultThemeNum; i++) - delete default_themes_[i]; -} - -} // namespace - -std::string GetFileMimeType(const FilePath& filepath) { - if (filepath.empty()) - return std::string(); - base::ThreadRestrictions::AssertIOAllowed(); - base::AutoLock scoped_lock(g_mime_util_xdg_lock.Get()); - return xdg_mime_get_mime_type_from_file_name(filepath.value().c_str()); -} - -std::string GetDataMimeType(const std::string& data) { - base::ThreadRestrictions::AssertIOAllowed(); - base::AutoLock scoped_lock(g_mime_util_xdg_lock.Get()); - return xdg_mime_get_mime_type_for_data(data.data(), data.length(), NULL); -} - -void SetIconThemeName(const std::string& name) { - // If the theme name is already loaded, do nothing. Chrome doesn't respond - // to changes in the system theme, so we never need to set this more than - // once. - if (!MimeUtilConstants::GetInstance()->icon_theme_name_.empty()) - return; - - MimeUtilConstants::GetInstance()->icon_theme_name_ = name; -} - -FilePath GetMimeIcon(const std::string& mime_type, size_t size) { - base::ThreadRestrictions::AssertIOAllowed(); - std::vector icon_names; - std::string icon_name; - FilePath icon_file; - - if (!mime_type.empty()) { - base::AutoLock scoped_lock(g_mime_util_xdg_lock.Get()); - const char *icon = xdg_mime_get_icon(mime_type.c_str()); - icon_name = std::string(icon ? icon : ""); - } - - if (icon_name.length()) - icon_names.push_back(icon_name); - - // For text/plain, try text-plain. - icon_name = mime_type; - for (size_t i = icon_name.find('/', 0); i != std::string::npos; - i = icon_name.find('/', i + 1)) { - icon_name[i] = '-'; - } - icon_names.push_back(icon_name); - // Also try gnome-mime-text-plain. - icon_names.push_back("gnome-mime-" + icon_name); - - // Try "deb" for "application/x-deb" in KDE 3. - size_t x_substr_pos = mime_type.find("/x-"); - if (x_substr_pos != std::string::npos) { - icon_name = mime_type.substr(x_substr_pos + 3); - icon_names.push_back(icon_name); - } - - // Try generic name like text-x-generic. - icon_name = mime_type.substr(0, mime_type.find('/')) + "-x-generic"; - icon_names.push_back(icon_name); - - // Last resort - icon_names.push_back("unknown"); - - for (size_t i = 0; i < icon_names.size(); i++) { - if (icon_names[i][0] == '/') { - icon_file = FilePath(icon_names[i]); - if (PathExists(icon_file)) - return icon_file; - } else { - icon_file = LookupIconInDefaultTheme(icon_names[i], size); - if (!icon_file.empty()) - return icon_file; - } - } - return FilePath(); -} - -} // namespace nix -} // namespace base diff --git a/base/nix/mime_util_xdg.h b/base/nix/mime_util_xdg.h deleted file mode 100644 index 79eb782e60..0000000000 --- a/base/nix/mime_util_xdg.h +++ /dev/null @@ -1,42 +0,0 @@ -// Copyright (c) 2011 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef BASE_NIX_MIME_UTIL_XDG_H_ -#define BASE_NIX_MIME_UTIL_XDG_H_ - -#include - -#include "base/base_export.h" -#include "build/build_config.h" - -namespace base { - -class FilePath; - -namespace nix { - -// Gets the mime type for a file based on its filename. The file path does not -// have to exist. Please note because it doesn't touch the disk, this does not -// work for directories. -// If the mime type is unknown, this will return application/octet-stream. -BASE_EXPORT std::string GetFileMimeType(const FilePath& filepath); - -// Get the mime type for a byte vector. -BASE_EXPORT std::string GetDataMimeType(const std::string& data); - -// Sets the current icon theme that we've detected from the desktop -// environment. Currently only works when we believe we're in a GTK -// environment. -BASE_EXPORT void SetIconThemeName(const std::string& name); - -// Gets the file name for an icon given the mime type and icon pixel size. -// Where an icon is a square image of |size| x |size|. -// This will try to find the closest matching icon. If that's not available, -// then a generic icon, and finally an empty FilePath if all else fails. -BASE_EXPORT FilePath GetMimeIcon(const std::string& mime_type, size_t size); - -} // namespace nix -} // namespace base - -#endif // BASE_NIX_MIME_UTIL_XDG_H_ diff --git a/base/nix/xdg_util.cc b/base/nix/xdg_util.cc deleted file mode 100644 index b3caf2abe0..0000000000 --- a/base/nix/xdg_util.cc +++ /dev/null @@ -1,115 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "base/nix/xdg_util.h" - -#include - -#include "base/environment.h" -#include "base/file_util.h" -#include "base/files/file_path.h" -#include "base/third_party/xdg_user_dirs/xdg_user_dir_lookup.h" - -namespace { - -// The KDE session version environment variable used in KDE 4. -const char kKDE4SessionEnvVar[] = "KDE_SESSION_VERSION"; - -} // namespace - -namespace base { -namespace nix { - -const char kDotConfigDir[] = ".config"; -const char kXdgConfigHomeEnvVar[] = "XDG_CONFIG_HOME"; - -FilePath GetXDGDirectory(Environment* env, const char* env_name, - const char* fallback_dir) { - FilePath path; - std::string env_value; - if (env->GetVar(env_name, &env_value) && !env_value.empty()) - path = FilePath(env_value); - else - path = file_util::GetHomeDir().Append(fallback_dir); - return path.StripTrailingSeparators(); -} - -FilePath GetXDGUserDirectory(const char* dir_name, const char* fallback_dir) { - FilePath path; - char* xdg_dir = xdg_user_dir_lookup(dir_name); - if (xdg_dir) { - path = FilePath(xdg_dir); - free(xdg_dir); - } else { - path = file_util::GetHomeDir().Append(fallback_dir); - } - return path.StripTrailingSeparators(); -} - -DesktopEnvironment GetDesktopEnvironment(Environment* env) { - // XDG_CURRENT_DESKTOP is the newest standard circa 2012. - std::string xdg_current_desktop; - if (env->GetVar("XDG_CURRENT_DESKTOP", &xdg_current_desktop)) { - // Not all desktop environments set this env var as of this writing. - if (xdg_current_desktop == "Unity") - return DESKTOP_ENVIRONMENT_UNITY; - else if (xdg_current_desktop == "GNOME") - return DESKTOP_ENVIRONMENT_GNOME; - } - - // DESKTOP_SESSION was what everyone used in 2010. - std::string desktop_session; - if (env->GetVar("DESKTOP_SESSION", &desktop_session)) { - if (desktop_session == "gnome") { - return DESKTOP_ENVIRONMENT_GNOME; - } else if (desktop_session == "kde4") { - return DESKTOP_ENVIRONMENT_KDE4; - } else if (desktop_session == "kde") { - // This may mean KDE4 on newer systems, so we have to check. - if (env->HasVar(kKDE4SessionEnvVar)) - return DESKTOP_ENVIRONMENT_KDE4; - return DESKTOP_ENVIRONMENT_KDE3; - } else if (desktop_session.find("xfce") != std::string::npos || - desktop_session == "xubuntu") { - return DESKTOP_ENVIRONMENT_XFCE; - } - } - - // Fall back on some older environment variables. - // Useful particularly in the DESKTOP_SESSION=default case. - if (env->HasVar("GNOME_DESKTOP_SESSION_ID")) { - return DESKTOP_ENVIRONMENT_GNOME; - } else if (env->HasVar("KDE_FULL_SESSION")) { - if (env->HasVar(kKDE4SessionEnvVar)) - return DESKTOP_ENVIRONMENT_KDE4; - return DESKTOP_ENVIRONMENT_KDE3; - } - - return DESKTOP_ENVIRONMENT_OTHER; -} - -const char* GetDesktopEnvironmentName(DesktopEnvironment env) { - switch (env) { - case DESKTOP_ENVIRONMENT_OTHER: - return NULL; - case DESKTOP_ENVIRONMENT_GNOME: - return "GNOME"; - case DESKTOP_ENVIRONMENT_KDE3: - return "KDE3"; - case DESKTOP_ENVIRONMENT_KDE4: - return "KDE4"; - case DESKTOP_ENVIRONMENT_UNITY: - return "UNITY"; - case DESKTOP_ENVIRONMENT_XFCE: - return "XFCE"; - } - return NULL; -} - -const char* GetDesktopEnvironmentName(Environment* env) { - return GetDesktopEnvironmentName(GetDesktopEnvironment(env)); -} - -} // namespace nix -} // namespace base diff --git a/base/nix/xdg_util.h b/base/nix/xdg_util.h deleted file mode 100644 index a8b778405f..0000000000 --- a/base/nix/xdg_util.h +++ /dev/null @@ -1,74 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef BASE_NIX_XDG_UTIL_H_ -#define BASE_NIX_XDG_UTIL_H_ - -// XDG refers to http://en.wikipedia.org/wiki/Freedesktop.org . -// This file contains utilities found across free desktop environments. -// -// TODO(brettw) this file should be in app/x11, but is currently used by -// net. We should have a net API to allow the embedder to specify the behavior -// that it uses XDG for, and then move this file. - -#include "base/base_export.h" - -#ifdef nix -#error asdf -#endif - -namespace base { - -class Environment; -class FilePath; - -namespace nix { - -// The default XDG config directory name. -BASE_EXPORT extern const char kDotConfigDir[]; - -// The XDG config directory environment variable. -BASE_EXPORT extern const char kXdgConfigHomeEnvVar[]; - -// Utility function for getting XDG directories. -// |env_name| is the name of an environment variable that we want to use to get -// a directory path. |fallback_dir| is the directory relative to $HOME that we -// use if |env_name| cannot be found or is empty. |fallback_dir| may be NULL. -// Examples of |env_name| are XDG_CONFIG_HOME and XDG_DATA_HOME. -BASE_EXPORT FilePath GetXDGDirectory(Environment* env, const char* env_name, - const char* fallback_dir); - -// Wrapper around xdg_user_dir_lookup() from src/base/third_party/xdg-user-dirs -// This looks up "well known" user directories like the desktop and music -// folder. Examples of |dir_name| are DESKTOP and MUSIC. -BASE_EXPORT FilePath GetXDGUserDirectory(const char* dir_name, - const char* fallback_dir); - -enum DesktopEnvironment { - DESKTOP_ENVIRONMENT_OTHER, - DESKTOP_ENVIRONMENT_GNOME, - // KDE3 and KDE4 are sufficiently different that we count - // them as two different desktop environments here. - DESKTOP_ENVIRONMENT_KDE3, - DESKTOP_ENVIRONMENT_KDE4, - DESKTOP_ENVIRONMENT_UNITY, - DESKTOP_ENVIRONMENT_XFCE, -}; - -// Return an entry from the DesktopEnvironment enum with a best guess -// of which desktop environment we're using. We use this to know when -// to attempt to use preferences from the desktop environment -- -// proxy settings, password manager, etc. -BASE_EXPORT DesktopEnvironment GetDesktopEnvironment(Environment* env); - -// Return a string representation of the given desktop environment. -// May return NULL in the case of DESKTOP_ENVIRONMENT_OTHER. -BASE_EXPORT const char* GetDesktopEnvironmentName(DesktopEnvironment env); -// Convenience wrapper that calls GetDesktopEnvironment() first. -BASE_EXPORT const char* GetDesktopEnvironmentName(Environment* env); - -} // namespace nix -} // namespace base - -#endif // BASE_NIX_XDG_UTIL_H_ diff --git a/base/nix/xdg_util_unittest.cc b/base/nix/xdg_util_unittest.cc deleted file mode 100644 index 2fc9d4c5c4..0000000000 --- a/base/nix/xdg_util_unittest.cc +++ /dev/null @@ -1,76 +0,0 @@ -// Copyright (c) 2010 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "base/nix/xdg_util.h" - -#include "base/environment.h" -#include "testing/gmock/include/gmock/gmock.h" -#include "testing/gtest/include/gtest/gtest.h" - -using ::testing::_; -using ::testing::Return; -using ::testing::SetArgumentPointee; -using ::testing::StrEq; - -namespace base { -namespace nix { - -namespace { - -class MockEnvironment : public Environment { - public: - MOCK_METHOD2(GetVar, bool(const char*, std::string* result)); - MOCK_METHOD2(SetVar, bool(const char*, const std::string& new_value)); - MOCK_METHOD1(UnSetVar, bool(const char*)); -}; - -const char* kGnome = "gnome"; -const char* kKDE4 = "kde4"; -const char* kKDE = "kde"; -const char* kXFCE = "xfce"; - -} // namespace - -TEST(XDGUtilTest, GetDesktopEnvironmentGnome) { - MockEnvironment getter; - EXPECT_CALL(getter, GetVar(_, _)).WillRepeatedly(Return(false)); - EXPECT_CALL(getter, GetVar(StrEq("DESKTOP_SESSION"), _)) - .WillOnce(DoAll(SetArgumentPointee<1>(kGnome), Return(true))); - - EXPECT_EQ(DESKTOP_ENVIRONMENT_GNOME, - GetDesktopEnvironment(&getter)); -} - -TEST(XDGUtilTest, GetDesktopEnvironmentKDE4) { - MockEnvironment getter; - EXPECT_CALL(getter, GetVar(_, _)).WillRepeatedly(Return(false)); - EXPECT_CALL(getter, GetVar(StrEq("DESKTOP_SESSION"), _)) - .WillOnce(DoAll(SetArgumentPointee<1>(kKDE4), Return(true))); - - EXPECT_EQ(DESKTOP_ENVIRONMENT_KDE4, - GetDesktopEnvironment(&getter)); -} - -TEST(XDGUtilTest, GetDesktopEnvironmentKDE3) { - MockEnvironment getter; - EXPECT_CALL(getter, GetVar(_, _)).WillRepeatedly(Return(false)); - EXPECT_CALL(getter, GetVar(StrEq("DESKTOP_SESSION"), _)) - .WillOnce(DoAll(SetArgumentPointee<1>(kKDE), Return(true))); - - EXPECT_EQ(DESKTOP_ENVIRONMENT_KDE3, - GetDesktopEnvironment(&getter)); -} - -TEST(XDGUtilTest, GetDesktopEnvironmentXFCE) { - MockEnvironment getter; - EXPECT_CALL(getter, GetVar(_, _)).WillRepeatedly(Return(false)); - EXPECT_CALL(getter, GetVar(StrEq("DESKTOP_SESSION"), _)) - .WillOnce(DoAll(SetArgumentPointee<1>(kXFCE), Return(true))); - - EXPECT_EQ(DESKTOP_ENVIRONMENT_XFCE, - GetDesktopEnvironment(&getter)); -} - -} // namespace nix -} // namespace base diff --git a/base/observer_list.h b/base/observer_list.h deleted file mode 100644 index 20f183d9cc..0000000000 --- a/base/observer_list.h +++ /dev/null @@ -1,216 +0,0 @@ -// Copyright (c) 2011 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef BASE_OBSERVER_LIST_H__ -#define BASE_OBSERVER_LIST_H__ - -#include -#include -#include - -#include "base/basictypes.h" -#include "base/logging.h" -#include "base/memory/weak_ptr.h" - -/////////////////////////////////////////////////////////////////////////////// -// -// OVERVIEW: -// -// A container for a list of observers. Unlike a normal STL vector or list, -// this container can be modified during iteration without invalidating the -// iterator. So, it safely handles the case of an observer removing itself -// or other observers from the list while observers are being notified. -// -// TYPICAL USAGE: -// -// class MyWidget { -// public: -// ... -// -// class Observer { -// public: -// virtual void OnFoo(MyWidget* w) = 0; -// virtual void OnBar(MyWidget* w, int x, int y) = 0; -// }; -// -// void AddObserver(Observer* obs) { -// observer_list_.AddObserver(obs); -// } -// -// void RemoveObserver(Observer* obs) { -// observer_list_.RemoveObserver(obs); -// } -// -// void NotifyFoo() { -// FOR_EACH_OBSERVER(Observer, observer_list_, OnFoo(this)); -// } -// -// void NotifyBar(int x, int y) { -// FOR_EACH_OBSERVER(Observer, observer_list_, OnBar(this, x, y)); -// } -// -// private: -// ObserverList observer_list_; -// }; -// -// -/////////////////////////////////////////////////////////////////////////////// - -template -class ObserverListThreadSafe; - -template -class ObserverListBase - : public base::SupportsWeakPtr > { - public: - // Enumeration of which observers are notified. - enum NotificationType { - // Specifies that any observers added during notification are notified. - // This is the default type if non type is provided to the constructor. - NOTIFY_ALL, - - // Specifies that observers added while sending out notification are not - // notified. - NOTIFY_EXISTING_ONLY - }; - - // An iterator class that can be used to access the list of observers. See - // also the FOR_EACH_OBSERVER macro defined below. - class Iterator { - public: - Iterator(ObserverListBase& list) - : list_(list.AsWeakPtr()), - index_(0), - max_index_(list.type_ == NOTIFY_ALL ? - std::numeric_limits::max() : - list.observers_.size()) { - ++list_->notify_depth_; - } - - ~Iterator() { - if (list_.get() && --list_->notify_depth_ == 0) - list_->Compact(); - } - - ObserverType* GetNext() { - if (!list_.get()) - return NULL; - ListType& observers = list_->observers_; - // Advance if the current element is null - size_t max_index = std::min(max_index_, observers.size()); - while (index_ < max_index && !observers[index_]) - ++index_; - return index_ < max_index ? observers[index_++] : NULL; - } - - private: - base::WeakPtr > list_; - size_t index_; - size_t max_index_; - }; - - ObserverListBase() : notify_depth_(0), type_(NOTIFY_ALL) {} - explicit ObserverListBase(NotificationType type) - : notify_depth_(0), type_(type) {} - - // Add an observer to the list. An observer should not be added to - // the same list more than once. - void AddObserver(ObserverType* obs) { - if (std::find(observers_.begin(), observers_.end(), obs) - != observers_.end()) { - NOTREACHED() << "Observers can only be added once!"; - return; - } - observers_.push_back(obs); - } - - // Remove an observer from the list if it is in the list. - void RemoveObserver(ObserverType* obs) { - typename ListType::iterator it = - std::find(observers_.begin(), observers_.end(), obs); - if (it != observers_.end()) { - if (notify_depth_) { - *it = 0; - } else { - observers_.erase(it); - } - } - } - - bool HasObserver(ObserverType* observer) const { - for (size_t i = 0; i < observers_.size(); ++i) { - if (observers_[i] == observer) - return true; - } - return false; - } - - void Clear() { - if (notify_depth_) { - for (typename ListType::iterator it = observers_.begin(); - it != observers_.end(); ++it) { - *it = 0; - } - } else { - observers_.clear(); - } - } - - size_t size() const { return observers_.size(); } - - protected: - void Compact() { - observers_.erase( - std::remove(observers_.begin(), observers_.end(), - static_cast(NULL)), observers_.end()); - } - - private: - friend class ObserverListThreadSafe; - - typedef std::vector ListType; - - ListType observers_; - int notify_depth_; - NotificationType type_; - - friend class ObserverListBase::Iterator; - - DISALLOW_COPY_AND_ASSIGN(ObserverListBase); -}; - -template -class ObserverList : public ObserverListBase { - public: - typedef typename ObserverListBase::NotificationType - NotificationType; - - ObserverList() {} - explicit ObserverList(NotificationType type) - : ObserverListBase(type) {} - - ~ObserverList() { - // When check_empty is true, assert that the list is empty on destruction. - if (check_empty) { - ObserverListBase::Compact(); - DCHECK_EQ(ObserverListBase::size(), 0U); - } - } - - bool might_have_observers() const { - return ObserverListBase::size() != 0; - } -}; - -#define FOR_EACH_OBSERVER(ObserverType, observer_list, func) \ - do { \ - if ((observer_list).might_have_observers()) { \ - ObserverListBase::Iterator it(observer_list); \ - ObserverType* obs; \ - while ((obs = it.GetNext()) != NULL) \ - obs->func; \ - } \ - } while (0) - -#endif // BASE_OBSERVER_LIST_H__ diff --git a/base/observer_list_threadsafe.h b/base/observer_list_threadsafe.h deleted file mode 100644 index 70b4f11ffa..0000000000 --- a/base/observer_list_threadsafe.h +++ /dev/null @@ -1,295 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef BASE_OBSERVER_LIST_THREADSAFE_H_ -#define BASE_OBSERVER_LIST_THREADSAFE_H_ - -#include -#include - -#include "base/basictypes.h" -#include "base/bind.h" -#include "base/location.h" -#include "base/logging.h" -#include "base/memory/ref_counted.h" -#include "base/message_loop/message_loop.h" -#include "base/message_loop/message_loop_proxy.h" -#include "base/observer_list.h" -#include "base/stl_util.h" -#include "base/threading/platform_thread.h" - -/////////////////////////////////////////////////////////////////////////////// -// -// OVERVIEW: -// -// A thread-safe container for a list of observers. -// This is similar to the observer_list (see observer_list.h), but it -// is more robust for multi-threaded situations. -// -// The following use cases are supported: -// * Observers can register for notifications from any thread. -// Callbacks to the observer will occur on the same thread where -// the observer initially called AddObserver() from. -// * Any thread may trigger a notification via Notify(). -// * Observers can remove themselves from the observer list inside -// of a callback. -// * If one thread is notifying observers concurrently with an observer -// removing itself from the observer list, the notifications will -// be silently dropped. -// -// The drawback of the threadsafe observer list is that notifications -// are not as real-time as the non-threadsafe version of this class. -// Notifications will always be done via PostTask() to another thread, -// whereas with the non-thread-safe observer_list, notifications happen -// synchronously and immediately. -// -// IMPLEMENTATION NOTES -// The ObserverListThreadSafe maintains an ObserverList for each thread -// which uses the ThreadSafeObserver. When Notifying the observers, -// we simply call PostTask to each registered thread, and then each thread -// will notify its regular ObserverList. -// -/////////////////////////////////////////////////////////////////////////////// - -// Forward declaration for ObserverListThreadSafeTraits. -template -class ObserverListThreadSafe; - -// An UnboundMethod is a wrapper for a method where the actual object is -// provided at Run dispatch time. -template -class UnboundMethod { - public: - UnboundMethod(Method m, const Params& p) : m_(m), p_(p) { - COMPILE_ASSERT( - (base::internal::ParamsUseScopedRefptrCorrectly::value), - badunboundmethodparams); - } - void Run(T* obj) const { - DispatchToMethod(obj, m_, p_); - } - private: - Method m_; - Params p_; -}; - -// This class is used to work around VS2005 not accepting: -// -// friend class -// base::RefCountedThreadSafe >; -// -// Instead of friending the class, we could friend the actual function -// which calls delete. However, this ends up being -// RefCountedThreadSafe::DeleteInternal(), which is private. So we -// define our own templated traits class so we can friend it. -template -struct ObserverListThreadSafeTraits { - static void Destruct(const ObserverListThreadSafe* x) { - delete x; - } -}; - -template -class ObserverListThreadSafe - : public base::RefCountedThreadSafe< - ObserverListThreadSafe, - ObserverListThreadSafeTraits > { - public: - typedef typename ObserverList::NotificationType - NotificationType; - - ObserverListThreadSafe() - : type_(ObserverListBase::NOTIFY_ALL) {} - explicit ObserverListThreadSafe(NotificationType type) : type_(type) {} - - // Add an observer to the list. An observer should not be added to - // the same list more than once. - void AddObserver(ObserverType* obs) { - // If there is not a current MessageLoop, it is impossible to notify on it, - // so do not add the observer. - if (!base::MessageLoop::current()) - return; - - ObserverList* list = NULL; - base::PlatformThreadId thread_id = base::PlatformThread::CurrentId(); - { - base::AutoLock lock(list_lock_); - if (observer_lists_.find(thread_id) == observer_lists_.end()) - observer_lists_[thread_id] = new ObserverListContext(type_); - list = &(observer_lists_[thread_id]->list); - } - list->AddObserver(obs); - } - - // Remove an observer from the list if it is in the list. - // If there are pending notifications in-transit to the observer, they will - // be aborted. - // If the observer to be removed is in the list, RemoveObserver MUST - // be called from the same thread which called AddObserver. - void RemoveObserver(ObserverType* obs) { - ObserverListContext* context = NULL; - ObserverList* list = NULL; - base::PlatformThreadId thread_id = base::PlatformThread::CurrentId(); - { - base::AutoLock lock(list_lock_); - typename ObserversListMap::iterator it = observer_lists_.find(thread_id); - if (it == observer_lists_.end()) { - // This will happen if we try to remove an observer on a thread - // we never added an observer for. - return; - } - context = it->second; - list = &context->list; - - // If we're about to remove the last observer from the list, - // then we can remove this observer_list entirely. - if (list->HasObserver(obs) && list->size() == 1) - observer_lists_.erase(it); - } - list->RemoveObserver(obs); - - // If RemoveObserver is called from a notification, the size will be - // nonzero. Instead of deleting here, the NotifyWrapper will delete - // when it finishes iterating. - if (list->size() == 0) - delete context; - } - - // Verifies that the list is currently empty (i.e. there are no observers). - void AssertEmpty() const { - base::AutoLock lock(list_lock_); - DCHECK(observer_lists_.empty()); - } - - // Notify methods. - // Make a thread-safe callback to each Observer in the list. - // Note, these calls are effectively asynchronous. You cannot assume - // that at the completion of the Notify call that all Observers have - // been Notified. The notification may still be pending delivery. - template - void Notify(Method m) { - UnboundMethod method(m, MakeTuple()); - Notify(method); - } - - template - void Notify(Method m, const A& a) { - UnboundMethod > method(m, MakeTuple(a)); - Notify >(method); - } - - template - void Notify(Method m, const A& a, const B& b) { - UnboundMethod > method( - m, MakeTuple(a, b)); - Notify >(method); - } - - template - void Notify(Method m, const A& a, const B& b, const C& c) { - UnboundMethod > method( - m, MakeTuple(a, b, c)); - Notify >(method); - } - - template - void Notify(Method m, const A& a, const B& b, const C& c, const D& d) { - UnboundMethod > method( - m, MakeTuple(a, b, c, d)); - Notify >(method); - } - - // TODO(mbelshe): Add more wrappers for Notify() with more arguments. - - private: - // See comment above ObserverListThreadSafeTraits' definition. - friend struct ObserverListThreadSafeTraits; - - struct ObserverListContext { - explicit ObserverListContext(NotificationType type) - : loop(base::MessageLoopProxy::current()), - list(type) { - } - - scoped_refptr loop; - ObserverList list; - - DISALLOW_COPY_AND_ASSIGN(ObserverListContext); - }; - - ~ObserverListThreadSafe() { - STLDeleteValues(&observer_lists_); - } - - template - void Notify(const UnboundMethod& method) { - base::AutoLock lock(list_lock_); - typename ObserversListMap::iterator it; - for (it = observer_lists_.begin(); it != observer_lists_.end(); ++it) { - ObserverListContext* context = (*it).second; - context->loop->PostTask( - FROM_HERE, - base::Bind(&ObserverListThreadSafe:: - template NotifyWrapper, this, context, method)); - } - } - - // Wrapper which is called to fire the notifications for each thread's - // ObserverList. This function MUST be called on the thread which owns - // the unsafe ObserverList. - template - void NotifyWrapper(ObserverListContext* context, - const UnboundMethod& method) { - - // Check that this list still needs notifications. - { - base::AutoLock lock(list_lock_); - typename ObserversListMap::iterator it = - observer_lists_.find(base::PlatformThread::CurrentId()); - - // The ObserverList could have been removed already. In fact, it could - // have been removed and then re-added! If the master list's loop - // does not match this one, then we do not need to finish this - // notification. - if (it == observer_lists_.end() || it->second != context) - return; - } - - { - typename ObserverList::Iterator it(context->list); - ObserverType* obs; - while ((obs = it.GetNext()) != NULL) - method.Run(obs); - } - - // If there are no more observers on the list, we can now delete it. - if (context->list.size() == 0) { - { - base::AutoLock lock(list_lock_); - // Remove |list| if it's not already removed. - // This can happen if multiple observers got removed in a notification. - // See http://crbug.com/55725. - typename ObserversListMap::iterator it = - observer_lists_.find(base::PlatformThread::CurrentId()); - if (it != observer_lists_.end() && it->second == context) - observer_lists_.erase(it); - } - delete context; - } - } - - // Key by PlatformThreadId because in tests, clients can attempt to remove - // observers without a MessageLoop. If this were keyed by MessageLoop, that - // operation would be silently ignored, leaving garbage in the ObserverList. - typedef std::map - ObserversListMap; - - mutable base::Lock list_lock_; // Protects the observer_lists_. - ObserversListMap observer_lists_; - const NotificationType type_; - - DISALLOW_COPY_AND_ASSIGN(ObserverListThreadSafe); -}; - -#endif // BASE_OBSERVER_LIST_THREADSAFE_H_ diff --git a/base/observer_list_unittest.cc b/base/observer_list_unittest.cc deleted file mode 100644 index 57843f401f..0000000000 --- a/base/observer_list_unittest.cc +++ /dev/null @@ -1,549 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "base/observer_list.h" -#include "base/observer_list_threadsafe.h" - -#include - -#include "base/compiler_specific.h" -#include "base/memory/weak_ptr.h" -#include "base/message_loop/message_loop.h" -#include "base/run_loop.h" -#include "base/threading/platform_thread.h" -#include "testing/gtest/include/gtest/gtest.h" - -namespace base { -namespace { - -class Foo { - public: - virtual void Observe(int x) = 0; - virtual ~Foo() {} -}; - -class Adder : public Foo { - public: - explicit Adder(int scaler) : total(0), scaler_(scaler) {} - virtual void Observe(int x) OVERRIDE { - total += x * scaler_; - } - virtual ~Adder() {} - int total; - - private: - int scaler_; -}; - -class Disrupter : public Foo { - public: - Disrupter(ObserverList* list, Foo* doomed) - : list_(list), - doomed_(doomed) { - } - virtual ~Disrupter() {} - virtual void Observe(int x) OVERRIDE { - list_->RemoveObserver(doomed_); - } - - private: - ObserverList* list_; - Foo* doomed_; -}; - -class ThreadSafeDisrupter : public Foo { - public: - ThreadSafeDisrupter(ObserverListThreadSafe* list, Foo* doomed) - : list_(list), - doomed_(doomed) { - } - virtual ~ThreadSafeDisrupter() {} - virtual void Observe(int x) OVERRIDE { - list_->RemoveObserver(doomed_); - } - - private: - ObserverListThreadSafe* list_; - Foo* doomed_; -}; - -template -class AddInObserve : public Foo { - public: - explicit AddInObserve(ObserverListType* observer_list) - : added(false), - observer_list(observer_list), - adder(1) { - } - - virtual void Observe(int x) OVERRIDE { - if (!added) { - added = true; - observer_list->AddObserver(&adder); - } - } - - bool added; - ObserverListType* observer_list; - Adder adder; -}; - - -static const int kThreadRunTime = 2000; // ms to run the multi-threaded test. - -// A thread for use in the ThreadSafeObserver test -// which will add and remove itself from the notification -// list repeatedly. -class AddRemoveThread : public PlatformThread::Delegate, - public Foo { - public: - AddRemoveThread(ObserverListThreadSafe* list, bool notify) - : list_(list), - loop_(NULL), - in_list_(false), - start_(Time::Now()), - count_observes_(0), - count_addtask_(0), - do_notifies_(notify), - weak_factory_(this) { - } - - virtual ~AddRemoveThread() { - } - - virtual void ThreadMain() OVERRIDE { - loop_ = new MessageLoop(); // Fire up a message loop. - loop_->PostTask( - FROM_HERE, - base::Bind(&AddRemoveThread::AddTask, weak_factory_.GetWeakPtr())); - loop_->Run(); - //LOG(ERROR) << "Loop 0x" << std::hex << loop_ << " done. " << - // count_observes_ << ", " << count_addtask_; - delete loop_; - loop_ = reinterpret_cast(0xdeadbeef); - delete this; - } - - // This task just keeps posting to itself in an attempt - // to race with the notifier. - void AddTask() { - count_addtask_++; - - if ((Time::Now() - start_).InMilliseconds() > kThreadRunTime) { - VLOG(1) << "DONE!"; - return; - } - - if (!in_list_) { - list_->AddObserver(this); - in_list_ = true; - } - - if (do_notifies_) { - list_->Notify(&Foo::Observe, 10); - } - - loop_->PostTask( - FROM_HERE, - base::Bind(&AddRemoveThread::AddTask, weak_factory_.GetWeakPtr())); - } - - void Quit() { - loop_->PostTask(FROM_HERE, MessageLoop::QuitWhenIdleClosure()); - } - - virtual void Observe(int x) OVERRIDE { - count_observes_++; - - // If we're getting called after we removed ourselves from - // the list, that is very bad! - DCHECK(in_list_); - - // This callback should fire on the appropriate thread - EXPECT_EQ(loop_, MessageLoop::current()); - - list_->RemoveObserver(this); - in_list_ = false; - } - - private: - ObserverListThreadSafe* list_; - MessageLoop* loop_; - bool in_list_; // Are we currently registered for notifications. - // in_list_ is only used on |this| thread. - Time start_; // The time we started the test. - - int count_observes_; // Number of times we observed. - int count_addtask_; // Number of times thread AddTask was called - bool do_notifies_; // Whether these threads should do notifications. - - base::WeakPtrFactory weak_factory_; -}; - -TEST(ObserverListTest, BasicTest) { - ObserverList observer_list; - Adder a(1), b(-1), c(1), d(-1), e(-1); - Disrupter evil(&observer_list, &c); - - observer_list.AddObserver(&a); - observer_list.AddObserver(&b); - - FOR_EACH_OBSERVER(Foo, observer_list, Observe(10)); - - observer_list.AddObserver(&evil); - observer_list.AddObserver(&c); - observer_list.AddObserver(&d); - - // Removing an observer not in the list should do nothing. - observer_list.RemoveObserver(&e); - - FOR_EACH_OBSERVER(Foo, observer_list, Observe(10)); - - EXPECT_EQ(20, a.total); - EXPECT_EQ(-20, b.total); - EXPECT_EQ(0, c.total); - EXPECT_EQ(-10, d.total); - EXPECT_EQ(0, e.total); -} - -TEST(ObserverListThreadSafeTest, BasicTest) { - MessageLoop loop; - - scoped_refptr > observer_list( - new ObserverListThreadSafe); - Adder a(1); - Adder b(-1); - Adder c(1); - Adder d(-1); - ThreadSafeDisrupter evil(observer_list.get(), &c); - - observer_list->AddObserver(&a); - observer_list->AddObserver(&b); - - observer_list->Notify(&Foo::Observe, 10); - RunLoop().RunUntilIdle(); - - observer_list->AddObserver(&evil); - observer_list->AddObserver(&c); - observer_list->AddObserver(&d); - - observer_list->Notify(&Foo::Observe, 10); - RunLoop().RunUntilIdle(); - - EXPECT_EQ(20, a.total); - EXPECT_EQ(-20, b.total); - EXPECT_EQ(0, c.total); - EXPECT_EQ(-10, d.total); -} - -TEST(ObserverListThreadSafeTest, RemoveObserver) { - MessageLoop loop; - - scoped_refptr > observer_list( - new ObserverListThreadSafe); - Adder a(1), b(1); - - // A workaround for the compiler bug. See http://crbug.com/121960. - EXPECT_NE(&a, &b); - - // Should do nothing. - observer_list->RemoveObserver(&a); - observer_list->RemoveObserver(&b); - - observer_list->Notify(&Foo::Observe, 10); - RunLoop().RunUntilIdle(); - - EXPECT_EQ(0, a.total); - EXPECT_EQ(0, b.total); - - observer_list->AddObserver(&a); - - // Should also do nothing. - observer_list->RemoveObserver(&b); - - observer_list->Notify(&Foo::Observe, 10); - RunLoop().RunUntilIdle(); - - EXPECT_EQ(10, a.total); - EXPECT_EQ(0, b.total); -} - -TEST(ObserverListThreadSafeTest, WithoutMessageLoop) { - scoped_refptr > observer_list( - new ObserverListThreadSafe); - - Adder a(1), b(1), c(1); - - // No MessageLoop, so these should not be added. - observer_list->AddObserver(&a); - observer_list->AddObserver(&b); - - { - // Add c when there's a loop. - MessageLoop loop; - observer_list->AddObserver(&c); - - observer_list->Notify(&Foo::Observe, 10); - RunLoop().RunUntilIdle(); - - EXPECT_EQ(0, a.total); - EXPECT_EQ(0, b.total); - EXPECT_EQ(10, c.total); - - // Now add a when there's a loop. - observer_list->AddObserver(&a); - - // Remove c when there's a loop. - observer_list->RemoveObserver(&c); - - // Notify again. - observer_list->Notify(&Foo::Observe, 20); - RunLoop().RunUntilIdle(); - - EXPECT_EQ(20, a.total); - EXPECT_EQ(0, b.total); - EXPECT_EQ(10, c.total); - } - - // Removing should always succeed with or without a loop. - observer_list->RemoveObserver(&a); - - // Notifying should not fail but should also be a no-op. - MessageLoop loop; - observer_list->AddObserver(&b); - observer_list->Notify(&Foo::Observe, 30); - RunLoop().RunUntilIdle(); - - EXPECT_EQ(20, a.total); - EXPECT_EQ(30, b.total); - EXPECT_EQ(10, c.total); -} - -class FooRemover : public Foo { - public: - explicit FooRemover(ObserverListThreadSafe* list) : list_(list) {} - virtual ~FooRemover() {} - - void AddFooToRemove(Foo* foo) { - foos_.push_back(foo); - } - - virtual void Observe(int x) OVERRIDE { - std::vector tmp; - tmp.swap(foos_); - for (std::vector::iterator it = tmp.begin(); - it != tmp.end(); ++it) { - list_->RemoveObserver(*it); - } - } - - private: - const scoped_refptr > list_; - std::vector foos_; -}; - -TEST(ObserverListThreadSafeTest, RemoveMultipleObservers) { - MessageLoop loop; - scoped_refptr > observer_list( - new ObserverListThreadSafe); - - FooRemover a(observer_list.get()); - Adder b(1); - - observer_list->AddObserver(&a); - observer_list->AddObserver(&b); - - a.AddFooToRemove(&a); - a.AddFooToRemove(&b); - - observer_list->Notify(&Foo::Observe, 1); - RunLoop().RunUntilIdle(); -} - -// A test driver for a multi-threaded notification loop. Runs a number -// of observer threads, each of which constantly adds/removes itself -// from the observer list. Optionally, if cross_thread_notifies is set -// to true, the observer threads will also trigger notifications to -// all observers. -static void ThreadSafeObserverHarness(int num_threads, - bool cross_thread_notifies) { - MessageLoop loop; - - const int kMaxThreads = 15; - num_threads = num_threads > kMaxThreads ? kMaxThreads : num_threads; - - scoped_refptr > observer_list( - new ObserverListThreadSafe); - Adder a(1); - Adder b(-1); - Adder c(1); - Adder d(-1); - - observer_list->AddObserver(&a); - observer_list->AddObserver(&b); - - AddRemoveThread* threaded_observer[kMaxThreads]; - base::PlatformThreadHandle threads[kMaxThreads]; - for (int index = 0; index < num_threads; index++) { - threaded_observer[index] = new AddRemoveThread(observer_list.get(), false); - EXPECT_TRUE(PlatformThread::Create(0, - threaded_observer[index], &threads[index])); - } - - Time start = Time::Now(); - while (true) { - if ((Time::Now() - start).InMilliseconds() > kThreadRunTime) - break; - - observer_list->Notify(&Foo::Observe, 10); - - RunLoop().RunUntilIdle(); - } - - for (int index = 0; index < num_threads; index++) { - threaded_observer[index]->Quit(); - PlatformThread::Join(threads[index]); - } -} - -TEST(ObserverListThreadSafeTest, CrossThreadObserver) { - // Use 7 observer threads. Notifications only come from - // the main thread. - ThreadSafeObserverHarness(7, false); -} - -TEST(ObserverListThreadSafeTest, CrossThreadNotifications) { - // Use 3 observer threads. Notifications will fire from - // the main thread and all 3 observer threads. - ThreadSafeObserverHarness(3, true); -} - -TEST(ObserverListThreadSafeTest, OutlivesMessageLoop) { - MessageLoop* loop = new MessageLoop; - scoped_refptr > observer_list( - new ObserverListThreadSafe); - - Adder a(1); - observer_list->AddObserver(&a); - delete loop; - // Test passes if we don't crash here. - observer_list->Notify(&Foo::Observe, 1); -} - -TEST(ObserverListTest, Existing) { - ObserverList observer_list(ObserverList::NOTIFY_EXISTING_ONLY); - Adder a(1); - AddInObserve > b(&observer_list); - - observer_list.AddObserver(&a); - observer_list.AddObserver(&b); - - FOR_EACH_OBSERVER(Foo, observer_list, Observe(1)); - - EXPECT_TRUE(b.added); - // B's adder should not have been notified because it was added during - // notificaiton. - EXPECT_EQ(0, b.adder.total); - - // Notify again to make sure b's adder is notified. - FOR_EACH_OBSERVER(Foo, observer_list, Observe(1)); - EXPECT_EQ(1, b.adder.total); -} - -// Same as above, but for ObserverListThreadSafe -TEST(ObserverListThreadSafeTest, Existing) { - MessageLoop loop; - scoped_refptr > observer_list( - new ObserverListThreadSafe(ObserverList::NOTIFY_EXISTING_ONLY)); - Adder a(1); - AddInObserve > b(observer_list.get()); - - observer_list->AddObserver(&a); - observer_list->AddObserver(&b); - - observer_list->Notify(&Foo::Observe, 1); - RunLoop().RunUntilIdle(); - - EXPECT_TRUE(b.added); - // B's adder should not have been notified because it was added during - // notificaiton. - EXPECT_EQ(0, b.adder.total); - - // Notify again to make sure b's adder is notified. - observer_list->Notify(&Foo::Observe, 1); - RunLoop().RunUntilIdle(); - EXPECT_EQ(1, b.adder.total); -} - -class AddInClearObserve : public Foo { - public: - explicit AddInClearObserve(ObserverList* list) - : list_(list), added_(false), adder_(1) {} - - virtual void Observe(int /* x */) OVERRIDE { - list_->Clear(); - list_->AddObserver(&adder_); - added_ = true; - } - - bool added() const { return added_; } - const Adder& adder() const { return adder_; } - - private: - ObserverList* const list_; - - bool added_; - Adder adder_; -}; - -TEST(ObserverListTest, ClearNotifyAll) { - ObserverList observer_list; - AddInClearObserve a(&observer_list); - - observer_list.AddObserver(&a); - - FOR_EACH_OBSERVER(Foo, observer_list, Observe(1)); - EXPECT_TRUE(a.added()); - EXPECT_EQ(1, a.adder().total) - << "Adder should observe once and have sum of 1."; -} - -TEST(ObserverListTest, ClearNotifyExistingOnly) { - ObserverList observer_list(ObserverList::NOTIFY_EXISTING_ONLY); - AddInClearObserve a(&observer_list); - - observer_list.AddObserver(&a); - - FOR_EACH_OBSERVER(Foo, observer_list, Observe(1)); - EXPECT_TRUE(a.added()); - EXPECT_EQ(0, a.adder().total) - << "Adder should not observe, so sum should still be 0."; -} - -class ListDestructor : public Foo { - public: - explicit ListDestructor(ObserverList* list) : list_(list) {} - virtual ~ListDestructor() {} - - virtual void Observe(int x) OVERRIDE { - delete list_; - } - - private: - ObserverList* list_; -}; - - -TEST(ObserverListTest, IteratorOutlivesList) { - ObserverList* observer_list = new ObserverList; - ListDestructor a(observer_list); - observer_list->AddObserver(&a); - - FOR_EACH_OBSERVER(Foo, *observer_list, Observe(0)); - // If this test fails, there'll be Valgrind errors when this function goes out - // of scope. -} - -} // namespace -} // namespace base diff --git a/base/os_compat_android.cc b/base/os_compat_android.cc deleted file mode 100644 index 2643dc30e1..0000000000 --- a/base/os_compat_android.cc +++ /dev/null @@ -1,170 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "base/os_compat_android.h" - -#include -#include -#include -#include -#include -#include - -#include "base/rand_util.h" -#include "base/strings/string_piece.h" -#include "base/strings/stringprintf.h" - -extern "C" { -// There is no futimes() avaiable in Bionic, so we provide our own -// implementation until it is there. -int futimes(int fd, const struct timeval tv[2]) { - if (tv == NULL) - return syscall(__NR_utimensat, fd, NULL, NULL, 0); - - if (tv[0].tv_usec < 0 || tv[0].tv_usec >= 1000000 || - tv[1].tv_usec < 0 || tv[1].tv_usec >= 1000000) { - errno = EINVAL; - return -1; - } - - // Convert timeval to timespec. - struct timespec ts[2]; - ts[0].tv_sec = tv[0].tv_sec; - ts[0].tv_nsec = tv[0].tv_usec * 1000; - ts[1].tv_sec = tv[1].tv_sec; - ts[1].tv_nsec = tv[1].tv_usec * 1000; - return syscall(__NR_utimensat, fd, NULL, ts, 0); -} - -// Android has only timegm64() and no timegm(). -// We replicate the behaviour of timegm() when the result overflows time_t. -time_t timegm(struct tm* const t) { - // time_t is signed on Android. - static const time_t kTimeMax = ~(1 << (sizeof(time_t) * CHAR_BIT - 1)); - static const time_t kTimeMin = (1 << (sizeof(time_t) * CHAR_BIT - 1)); - time64_t result = timegm64(t); - if (result < kTimeMin || result > kTimeMax) - return -1; - return result; -} - -// The following is only needed when building with GCC 4.6 or higher -// (i.e. not with Android GCC 4.4.3, nor with Clang). -// -// GCC is now capable of optimizing successive calls to sin() and cos() into -// a single call to sincos(). This means that source code that looks like: -// -// double c, s; -// c = cos(angle); -// s = sin(angle); -// -// Will generate machine code that looks like: -// -// double c, s; -// sincos(angle, &s, &c); -// -// Unfortunately, sincos() and friends are not part of the Android libm.so -// library provided by the NDK for API level 9. When the optimization kicks -// in, it makes the final build fail with a puzzling message (puzzling -// because 'sincos' doesn't appear anywhere in the sources!). -// -// To solve this, we provide our own implementation of the sincos() function -// and related friends. Note that we must also explicitely tell GCC to disable -// optimizations when generating these. Otherwise, the generated machine code -// for each function would simply end up calling itself, resulting in a -// runtime crash due to stack overflow. -// -#if defined(__GNUC__) && !defined(__clang__) - -// For the record, Clang does not support the 'optimize' attribute. -// In the unlikely event that it begins performing this optimization too, -// we'll have to find a different way to achieve this. NOTE: Tested with O1 -// which still performs the optimization. -// -#define GCC_NO_OPTIMIZE __attribute__((optimize("O0"))) - -GCC_NO_OPTIMIZE -void sincos(double angle, double* s, double *c) { - *c = cos(angle); - *s = sin(angle); -} - -GCC_NO_OPTIMIZE -void sincosf(float angle, float* s, float* c) { - *c = cosf(angle); - *s = sinf(angle); -} - -#endif // __GNUC__ && !__clang__ - -// An implementation of mkdtemp, since it is not exposed by the NDK -// for native API level 9 that we target. -// -// For any changes in the mkdtemp function, you should manually run the unittest -// OsCompatAndroidTest.DISABLED_TestMkdTemp in your local machine to check if it -// passes. Please don't enable it, since it creates a directory and may be -// source of flakyness. -char* mkdtemp(char* path) { - if (path == NULL) { - errno = EINVAL; - return NULL; - } - - const int path_len = strlen(path); - - // The last six characters of 'path' must be XXXXXX. - const base::StringPiece kSuffix("XXXXXX"); - const int kSuffixLen = kSuffix.length(); - if (!base::StringPiece(path, path_len).ends_with(kSuffix)) { - errno = EINVAL; - return NULL; - } - - // If the path contains a directory, as in /tmp/foo/XXXXXXXX, make sure - // that /tmp/foo exists, otherwise we're going to loop a really long - // time for nothing below - char* dirsep = strrchr(path, '/'); - if (dirsep != NULL) { - struct stat st; - int ret; - - *dirsep = '\0'; // Terminating directory path temporarily - - ret = stat(path, &st); - - *dirsep = '/'; // Restoring directory separator - if (ret < 0) // Directory probably does not exist - return NULL; - if (!S_ISDIR(st.st_mode)) { // Not a directory - errno = ENOTDIR; - return NULL; - } - } - - // Max number of tries using different random suffixes. - const int kMaxTries = 100; - - // Now loop until we CAN create a directory by that name or we reach the max - // number of tries. - for (int i = 0; i < kMaxTries; ++i) { - // Fill the suffix XXXXXX with a random string composed of a-z chars. - for (int pos = 0; pos < kSuffixLen; ++pos) { - char rand_char = static_cast(base::RandInt('a', 'z')); - path[path_len - kSuffixLen + pos] = rand_char; - } - if (mkdir(path, 0700) == 0) { - // We just created the directory succesfully. - return path; - } - if (errno != EEXIST) { - // The directory doesn't exist, but an error occured - return NULL; - } - } - - // We reached the max number of tries. - return NULL; -} - -} // extern "C" diff --git a/base/os_compat_android.h b/base/os_compat_android.h deleted file mode 100644 index 0f2544496d..0000000000 --- a/base/os_compat_android.h +++ /dev/null @@ -1,28 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef BASE_OS_COMPAT_ANDROID_H_ -#define BASE_OS_COMPAT_ANDROID_H_ - -#include -#include -#include - -// Not implemented in Bionic. -extern "C" int futimes(int fd, const struct timeval tv[2]); - -// Not exposed or implemented in Bionic. -extern "C" char* mkdtemp(char* path); - -// Android has no timegm(). -extern "C" time_t timegm(struct tm* const t); - -// The lockf() function is not available on Android; we translate to flock(). -#define F_LOCK LOCK_EX -#define F_ULOCK LOCK_UN -inline int lockf(int fd, int cmd, off_t ignored_len) { - return flock(fd, cmd); -} - -#endif // BASE_OS_COMPAT_ANDROID_H_ diff --git a/base/os_compat_android_unittest.cc b/base/os_compat_android_unittest.cc deleted file mode 100644 index c749b6a223..0000000000 --- a/base/os_compat_android_unittest.cc +++ /dev/null @@ -1,41 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "base/os_compat_android.h" - -#include "base/file_util.h" -#include "testing/gtest/include/gtest/gtest.h" - -namespace base { - -typedef testing::Test OsCompatAndroidTest; - -// Keep this Unittest DISABLED_ , because it actually creates a directory in the -// device and it may be source of flakyness. For any changes in the mkdtemp -// function, you should run this unittest in your local machine to check if it -// passes. -TEST_F(OsCompatAndroidTest, DISABLED_TestMkdTemp) { - FilePath tmp_dir; - EXPECT_TRUE(file_util::GetTempDir(&tmp_dir)); - - // Not six XXXXXX at the suffix of the path. - FilePath sub_dir = tmp_dir.Append("XX"); - std::string sub_dir_string = sub_dir.value(); - // this should be OK since mkdtemp just replaces characters in place - char* buffer = const_cast(sub_dir_string.c_str()); - EXPECT_EQ(NULL, mkdtemp(buffer)); - - // Directory does not exist - char invalid_path2[] = "doesntoexist/foobarXXXXXX"; - EXPECT_EQ(NULL, mkdtemp(invalid_path2)); - - // Successfully create a tmp dir. - FilePath sub_dir2 = tmp_dir.Append("XXXXXX"); - std::string sub_dir2_string = sub_dir2.value(); - // this should be OK since mkdtemp just replaces characters in place - char* buffer2 = const_cast(sub_dir2_string.c_str()); - EXPECT_TRUE(mkdtemp(buffer2) != NULL); -} - -} // namespace base diff --git a/base/os_compat_nacl.cc b/base/os_compat_nacl.cc deleted file mode 100644 index 58fe93e0cb..0000000000 --- a/base/os_compat_nacl.cc +++ /dev/null @@ -1,30 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "base/os_compat_nacl.h" - -#include -#include - -#if !defined (__GLIBC__) - -extern "C" { -// Native Client has no timegm(). -time_t timegm(struct tm* tm) { - time_t ret; - char* tz; - tz = getenv("TZ"); - setenv("TZ", "", 1); - tzset(); - ret = mktime(tm); - if (tz) - setenv("TZ", tz, 1); - else - unsetenv("TZ"); - tzset(); - return ret; -} -} // extern "C" - -#endif // !defined (__GLIBC__) diff --git a/base/os_compat_nacl.h b/base/os_compat_nacl.h deleted file mode 100644 index 13e0e3f8dd..0000000000 --- a/base/os_compat_nacl.h +++ /dev/null @@ -1,16 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef BASE_OS_COMPAT_NACL_H_ -#define BASE_OS_COMPAT_NACL_H_ - -#include - -#if !defined (__GLIBC__) -// NaCl has no timegm(). -extern "C" time_t timegm(struct tm* const t); -#endif // !defined (__GLIBC__) - -#endif // BASE_OS_COMPAT_NACL_H_ - diff --git a/base/path_service.cc b/base/path_service.cc deleted file mode 100644 index 89e58b2cdb..0000000000 --- a/base/path_service.cc +++ /dev/null @@ -1,336 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "base/path_service.h" - -#if defined(OS_WIN) -#include -#include -#include -#endif - -#include "base/containers/hash_tables.h" -#include "base/file_util.h" -#include "base/files/file_path.h" -#include "base/lazy_instance.h" -#include "base/logging.h" -#include "base/synchronization/lock.h" - -using base::FilePath; -using base::MakeAbsoluteFilePath; - -namespace base { - bool PathProvider(int key, FilePath* result); -#if defined(OS_WIN) - bool PathProviderWin(int key, FilePath* result); -#elif defined(OS_MACOSX) - bool PathProviderMac(int key, FilePath* result); -#elif defined(OS_ANDROID) - bool PathProviderAndroid(int key, FilePath* result); -#elif defined(OS_POSIX) - // PathProviderPosix is the default path provider on POSIX OSes other than - // Mac and Android. - bool PathProviderPosix(int key, FilePath* result); -#endif -} - -namespace { - -typedef base::hash_map PathMap; - -// We keep a linked list of providers. In a debug build we ensure that no two -// providers claim overlapping keys. -struct Provider { - PathService::ProviderFunc func; - struct Provider* next; -#ifndef NDEBUG - int key_start; - int key_end; -#endif - bool is_static; -}; - -Provider base_provider = { - base::PathProvider, - NULL, -#ifndef NDEBUG - base::PATH_START, - base::PATH_END, -#endif - true -}; - -#if defined(OS_WIN) -Provider base_provider_win = { - base::PathProviderWin, - &base_provider, -#ifndef NDEBUG - base::PATH_WIN_START, - base::PATH_WIN_END, -#endif - true -}; -#endif - -#if defined(OS_MACOSX) -Provider base_provider_mac = { - base::PathProviderMac, - &base_provider, -#ifndef NDEBUG - base::PATH_MAC_START, - base::PATH_MAC_END, -#endif - true -}; -#endif - -#if defined(OS_ANDROID) -Provider base_provider_android = { - base::PathProviderAndroid, - &base_provider, -#ifndef NDEBUG - base::PATH_ANDROID_START, - base::PATH_ANDROID_END, -#endif - true -}; -#endif - -#if defined(OS_POSIX) && !defined(OS_MACOSX) && !defined(OS_ANDROID) -Provider base_provider_posix = { - base::PathProviderPosix, - &base_provider, -#ifndef NDEBUG - base::PATH_POSIX_START, - base::PATH_POSIX_END, -#endif - true -}; -#endif - - -struct PathData { - base::Lock lock; - PathMap cache; // Cache mappings from path key to path value. - PathMap overrides; // Track path overrides. - Provider* providers; // Linked list of path service providers. - bool cache_disabled; // Don't use cache if true; - - PathData() : cache_disabled(false) { -#if defined(OS_WIN) - providers = &base_provider_win; -#elif defined(OS_MACOSX) - providers = &base_provider_mac; -#elif defined(OS_ANDROID) - providers = &base_provider_android; -#elif defined(OS_POSIX) - providers = &base_provider_posix; -#endif - } - - ~PathData() { - Provider* p = providers; - while (p) { - Provider* next = p->next; - if (!p->is_static) - delete p; - p = next; - } - } -}; - -static base::LazyInstance g_path_data = LAZY_INSTANCE_INITIALIZER; - -static PathData* GetPathData() { - return g_path_data.Pointer(); -} - -// Tries to find |key| in the cache. |path_data| should be locked by the caller! -bool LockedGetFromCache(int key, const PathData* path_data, FilePath* result) { - if (path_data->cache_disabled) - return false; - // check for a cached version - PathMap::const_iterator it = path_data->cache.find(key); - if (it != path_data->cache.end()) { - *result = it->second; - return true; - } - return false; -} - -// Tries to find |key| in the overrides map. |path_data| should be locked by the -// caller! -bool LockedGetFromOverrides(int key, PathData* path_data, FilePath* result) { - // check for an overridden version. - PathMap::const_iterator it = path_data->overrides.find(key); - if (it != path_data->overrides.end()) { - if (!path_data->cache_disabled) - path_data->cache[key] = it->second; - *result = it->second; - return true; - } - return false; -} - -} // namespace - -// TODO(brettw): this function does not handle long paths (filename > MAX_PATH) -// characters). This isn't supported very well by Windows right now, so it is -// moot, but we should keep this in mind for the future. -// static -bool PathService::Get(int key, FilePath* result) { - PathData* path_data = GetPathData(); - DCHECK(path_data); - DCHECK(result); - DCHECK_GE(key, base::DIR_CURRENT); - - // special case the current directory because it can never be cached - if (key == base::DIR_CURRENT) - return file_util::GetCurrentDirectory(result); - - Provider* provider = NULL; - { - base::AutoLock scoped_lock(path_data->lock); - if (LockedGetFromCache(key, path_data, result)) - return true; - - if (LockedGetFromOverrides(key, path_data, result)) - return true; - - // Get the beginning of the list while it is still locked. - provider = path_data->providers; - } - - FilePath path; - - // Iterating does not need the lock because only the list head might be - // modified on another thread. - while (provider) { - if (provider->func(key, &path)) - break; - DCHECK(path.empty()) << "provider should not have modified path"; - provider = provider->next; - } - - if (path.empty()) - return false; - - if (path.ReferencesParent()) { - // Make sure path service never returns a path with ".." in it. - path = MakeAbsoluteFilePath(path); - if (path.empty()) - return false; - } - *result = path; - - base::AutoLock scoped_lock(path_data->lock); - if (!path_data->cache_disabled) - path_data->cache[key] = path; - - return true; -} - -// static -bool PathService::Override(int key, const FilePath& path) { - // Just call the full function with true for the value of |create|. - return OverrideAndCreateIfNeeded(key, path, true); -} - -// static -bool PathService::OverrideAndCreateIfNeeded(int key, - const FilePath& path, - bool create) { - PathData* path_data = GetPathData(); - DCHECK(path_data); - DCHECK_GT(key, base::DIR_CURRENT) << "invalid path key"; - - FilePath file_path = path; - - // For some locations this will fail if called from inside the sandbox there- - // fore we protect this call with a flag. - if (create) { - // Make sure the directory exists. We need to do this before we translate - // this to the absolute path because on POSIX, MakeAbsoluteFilePath fails - // if called on a non-existent path. - if (!base::PathExists(file_path) && - !file_util::CreateDirectory(file_path)) - return false; - } - - // We need to have an absolute path. - file_path = MakeAbsoluteFilePath(file_path); - if (file_path.empty()) - return false; - - base::AutoLock scoped_lock(path_data->lock); - - // Clear the cache now. Some of its entries could have depended - // on the value we are overriding, and are now out of sync with reality. - path_data->cache.clear(); - - path_data->overrides[key] = file_path; - - return true; -} - -// static -bool PathService::RemoveOverride(int key) { - PathData* path_data = GetPathData(); - DCHECK(path_data); - - base::AutoLock scoped_lock(path_data->lock); - - if (path_data->overrides.find(key) == path_data->overrides.end()) - return false; - - // Clear the cache now. Some of its entries could have depended on the value - // we are going to remove, and are now out of sync. - path_data->cache.clear(); - - path_data->overrides.erase(key); - - return true; -} - -// static -void PathService::RegisterProvider(ProviderFunc func, int key_start, - int key_end) { - PathData* path_data = GetPathData(); - DCHECK(path_data); - DCHECK_GT(key_end, key_start); - - Provider* p; - - p = new Provider; - p->is_static = false; - p->func = func; -#ifndef NDEBUG - p->key_start = key_start; - p->key_end = key_end; -#endif - - base::AutoLock scoped_lock(path_data->lock); - -#ifndef NDEBUG - Provider *iter = path_data->providers; - while (iter) { - DCHECK(key_start >= iter->key_end || key_end <= iter->key_start) << - "path provider collision"; - iter = iter->next; - } -#endif - - p->next = path_data->providers; - path_data->providers = p; -} - -// static -void PathService::DisableCache() { - PathData* path_data = GetPathData(); - DCHECK(path_data); - - base::AutoLock scoped_lock(path_data->lock); - path_data->cache.clear(); - path_data->cache_disabled = true; -} diff --git a/base/path_service.h b/base/path_service.h deleted file mode 100644 index 832b92b158..0000000000 --- a/base/path_service.h +++ /dev/null @@ -1,82 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef BASE_PATH_SERVICE_H_ -#define BASE_PATH_SERVICE_H_ - -#include - -#include "base/base_export.h" -#include "base/base_paths.h" -#include "base/gtest_prod_util.h" -#include "build/build_config.h" - -namespace base { -class FilePath; -class ScopedPathOverride; -} // namespace - -// The path service is a global table mapping keys to file system paths. It is -// OK to use this service from multiple threads. -// -class BASE_EXPORT PathService { - public: - // Retrieves a path to a special directory or file and places it into the - // string pointed to by 'path'. If you ask for a directory it is guaranteed - // to NOT have a path separator at the end. For example, "c:\windows\temp" - // Directories are also guaranteed to exist when this function succeeds. - // - // Returns true if the directory or file was successfully retrieved. On - // failure, 'path' will not be changed. - static bool Get(int key, base::FilePath* path); - - // Overrides the path to a special directory or file. This cannot be used to - // change the value of DIR_CURRENT, but that should be obvious. Also, if the - // path specifies a directory that does not exist, the directory will be - // created by this method. This method returns true if successful. - // - // If the given path is relative, then it will be resolved against - // DIR_CURRENT. - // - // WARNING: Consumers of PathService::Get may expect paths to be constant - // over the lifetime of the app, so this method should be used with caution. - static bool Override(int key, const base::FilePath& path); - - // This function does the same as PathService::Override but it takes an extra - // parameter |create| which guides whether the directory to be overriden must - // be created in case it doesn't exist already. - static bool OverrideAndCreateIfNeeded(int key, - const base::FilePath& path, - bool create); - - // To extend the set of supported keys, you can register a path provider, - // which is just a function mirroring PathService::Get. The ProviderFunc - // returns false if it cannot provide a non-empty path for the given key. - // Otherwise, true is returned. - // - // WARNING: This function could be called on any thread from which the - // PathService is used, so a the ProviderFunc MUST BE THREADSAFE. - // - typedef bool (*ProviderFunc)(int, base::FilePath*); - - // Call to register a path provider. You must specify the range "[key_start, - // key_end)" of supported path keys. - static void RegisterProvider(ProviderFunc provider, - int key_start, - int key_end); - - // Disable internal cache. - static void DisableCache(); - - private: - friend class base::ScopedPathOverride; - FRIEND_TEST_ALL_PREFIXES(PathServiceTest, RemoveOverride); - - // Removes an override for a special directory or file. Returns true if there - // was an override to remove or false if none was present. - // NOTE: This function is intended to be used by tests only! - static bool RemoveOverride(int key); -}; - -#endif // BASE_PATH_SERVICE_H_ diff --git a/base/path_service_unittest.cc b/base/path_service_unittest.cc deleted file mode 100644 index fbb2d766de..0000000000 --- a/base/path_service_unittest.cc +++ /dev/null @@ -1,216 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "base/path_service.h" - -#include "base/basictypes.h" -#include "base/file_util.h" -#include "base/files/file_path.h" -#include "base/files/scoped_temp_dir.h" -#include "base/strings/string_util.h" -#include "build/build_config.h" -#include "testing/gtest/include/gtest/gtest-spi.h" -#include "testing/gtest/include/gtest/gtest.h" -#include "testing/platform_test.h" - -#if defined(OS_WIN) -#include -#include "base/win/windows_version.h" -// userenv.dll is required for GetDefaultUserProfileDirectory(). -#pragma comment(lib, "userenv.lib") -#endif - -namespace { - -// Returns true if PathService::Get returns true and sets the path parameter -// to non-empty for the given PathService::DirType enumeration value. -bool ReturnsValidPath(int dir_type) { - base::FilePath path; - bool result = PathService::Get(dir_type, &path); - - // Some paths might not exist on some platforms in which case confirming - // |result| is true and !path.empty() is the best we can do. - bool check_path_exists = true; -#if defined(OS_POSIX) - // If chromium has never been started on this account, the cache path may not - // exist. - if (dir_type == base::DIR_CACHE) - check_path_exists = false; -#endif -#if defined(OS_LINUX) - // On the linux try-bots: a path is returned (e.g. /home/chrome-bot/Desktop), - // but it doesn't exist. - if (dir_type == base::DIR_USER_DESKTOP) - check_path_exists = false; -#endif -#if defined(OS_WIN) - if (dir_type == base::DIR_DEFAULT_USER_QUICK_LAUNCH) { - // On Windows XP, the Quick Launch folder for the "Default User" doesn't - // exist by default. At least confirm that the path returned begins with the - // Default User's profile path. - if (base::win::GetVersion() < base::win::VERSION_VISTA) { - wchar_t default_profile_path[MAX_PATH]; - DWORD size = arraysize(default_profile_path); - return (result && - ::GetDefaultUserProfileDirectory(default_profile_path, &size) && - StartsWith(path.value(), default_profile_path, false)); - } - } else if (dir_type == base::DIR_TASKBAR_PINS) { - // There is no pinned-to-taskbar shortcuts prior to Win7. - if (base::win::GetVersion() < base::win::VERSION_WIN7) - check_path_exists = false; - } -#endif -#if defined(OS_MACOSX) - if (dir_type != base::DIR_EXE && dir_type != base::DIR_MODULE && - dir_type != base::FILE_EXE && dir_type != base::FILE_MODULE) { - if (path.ReferencesParent()) - return false; - } -#else - if (path.ReferencesParent()) - return false; -#endif - return result && !path.empty() && (!check_path_exists || - base::PathExists(path)); -} - -#if defined(OS_WIN) -// Function to test any directory keys that are not supported on some versions -// of Windows. Checks that the function fails and that the returned path is -// empty. -bool ReturnsInvalidPath(int dir_type) { - base::FilePath path; - bool result = PathService::Get(dir_type, &path); - return !result && path.empty(); -} -#endif - -} // namespace - -// On the Mac this winds up using some autoreleased objects, so we need to -// be a PlatformTest. -typedef PlatformTest PathServiceTest; - -// Test that all PathService::Get calls return a value and a true result -// in the development environment. (This test was created because a few -// later changes to Get broke the semantics of the function and yielded the -// correct value while returning false.) -TEST_F(PathServiceTest, Get) { - for (int key = base::PATH_START + 1; key < base::PATH_END; ++key) { -#if defined(OS_ANDROID) - if (key == base::FILE_MODULE || key == base::DIR_USER_DESKTOP) - continue; // Android doesn't implement FILE_MODULE and DIR_USER_DESKTOP; -#elif defined(OS_IOS) - if (key == base::DIR_USER_DESKTOP) - continue; // iOS doesn't implement DIR_USER_DESKTOP; -#endif - EXPECT_PRED1(ReturnsValidPath, key); - } -#if defined(OS_WIN) - for (int key = base::PATH_WIN_START + 1; key < base::PATH_WIN_END; ++key) { - bool valid = true; - switch(key) { - case base::DIR_LOCAL_APP_DATA_LOW: - // DIR_LOCAL_APP_DATA_LOW is not supported prior Vista and is expected - // to fail. - valid = base::win::GetVersion() >= base::win::VERSION_VISTA; - break; - case base::DIR_APP_SHORTCUTS: - // DIR_APP_SHORTCUTS is not supported prior Windows 8 and is expected to - // fail. - valid = base::win::GetVersion() >= base::win::VERSION_WIN8; - break; - } - - if (valid) - EXPECT_TRUE(ReturnsValidPath(key)) << key; - else - EXPECT_TRUE(ReturnsInvalidPath(key)) << key; - } -#elif defined(OS_MACOSX) - for (int key = base::PATH_MAC_START + 1; key < base::PATH_MAC_END; ++key) { - EXPECT_PRED1(ReturnsValidPath, key); - } -#elif defined(OS_ANDROID) - for (int key = base::PATH_ANDROID_START + 1; key < base::PATH_ANDROID_END; - ++key) { - EXPECT_PRED1(ReturnsValidPath, key); - } -#elif defined(OS_POSIX) - for (int key = base::PATH_POSIX_START + 1; key < base::PATH_POSIX_END; - ++key) { - EXPECT_PRED1(ReturnsValidPath, key); - } -#endif -} - -// test that all versions of the Override function of PathService do what they -// are supposed to do. -TEST_F(PathServiceTest, Override) { - int my_special_key = 666; - base::ScopedTempDir temp_dir; - ASSERT_TRUE(temp_dir.CreateUniqueTempDir()); - base::FilePath fake_cache_dir(temp_dir.path().AppendASCII("cache")); - // PathService::Override should always create the path provided if it doesn't - // exist. - EXPECT_TRUE(PathService::Override(my_special_key, fake_cache_dir)); - EXPECT_TRUE(base::PathExists(fake_cache_dir)); - - base::FilePath fake_cache_dir2(temp_dir.path().AppendASCII("cache2")); - // PathService::OverrideAndCreateIfNeeded should obey the |create| parameter. - PathService::OverrideAndCreateIfNeeded(my_special_key, - fake_cache_dir2, - false); - EXPECT_FALSE(base::PathExists(fake_cache_dir2)); - EXPECT_TRUE(PathService::OverrideAndCreateIfNeeded(my_special_key, - fake_cache_dir2, - true)); - EXPECT_TRUE(base::PathExists(fake_cache_dir2)); -} - -// Check if multiple overrides can co-exist. -TEST_F(PathServiceTest, OverrideMultiple) { - int my_special_key = 666; - base::ScopedTempDir temp_dir; - ASSERT_TRUE(temp_dir.CreateUniqueTempDir()); - base::FilePath fake_cache_dir1(temp_dir.path().AppendASCII("1")); - EXPECT_TRUE(PathService::Override(my_special_key, fake_cache_dir1)); - EXPECT_TRUE(base::PathExists(fake_cache_dir1)); - ASSERT_EQ(1, file_util::WriteFile(fake_cache_dir1.AppendASCII("t1"), ".", 1)); - - base::FilePath fake_cache_dir2(temp_dir.path().AppendASCII("2")); - EXPECT_TRUE(PathService::Override(my_special_key + 1, fake_cache_dir2)); - EXPECT_TRUE(base::PathExists(fake_cache_dir2)); - ASSERT_EQ(1, file_util::WriteFile(fake_cache_dir2.AppendASCII("t2"), ".", 1)); - - base::FilePath result; - EXPECT_TRUE(PathService::Get(my_special_key, &result)); - // Override might have changed the path representation but our test file - // should be still there. - EXPECT_TRUE(base::PathExists(result.AppendASCII("t1"))); - EXPECT_TRUE(PathService::Get(my_special_key + 1, &result)); - EXPECT_TRUE(base::PathExists(result.AppendASCII("t2"))); -} - -TEST_F(PathServiceTest, RemoveOverride) { - // Before we start the test we have to call RemoveOverride at least once to - // clear any overrides that might have been left from other tests. - PathService::RemoveOverride(base::DIR_TEMP); - - base::FilePath original_user_data_dir; - EXPECT_TRUE(PathService::Get(base::DIR_TEMP, &original_user_data_dir)); - EXPECT_FALSE(PathService::RemoveOverride(base::DIR_TEMP)); - - base::ScopedTempDir temp_dir; - ASSERT_TRUE(temp_dir.CreateUniqueTempDir()); - EXPECT_TRUE(PathService::Override(base::DIR_TEMP, temp_dir.path())); - base::FilePath new_user_data_dir; - EXPECT_TRUE(PathService::Get(base::DIR_TEMP, &new_user_data_dir)); - EXPECT_NE(original_user_data_dir, new_user_data_dir); - - EXPECT_TRUE(PathService::RemoveOverride(base::DIR_TEMP)); - EXPECT_TRUE(PathService::Get(base::DIR_TEMP, &new_user_data_dir)); - EXPECT_EQ(original_user_data_dir, new_user_data_dir); -} diff --git a/base/pending_task.cc b/base/pending_task.cc deleted file mode 100644 index b288f28d09..0000000000 --- a/base/pending_task.cc +++ /dev/null @@ -1,60 +0,0 @@ -// Copyright (c) 2011 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "base/pending_task.h" - -#include "base/tracked_objects.h" - -namespace base { - -#if _MSC_VER >= 1700 -// This a temporary fix for compiling on VS2012. http://crbug.com/154744 -PendingTask::PendingTask() : sequence_num(-1), nestable(false) { -} -#endif - -PendingTask::PendingTask(const tracked_objects::Location& posted_from, - const base::Closure& task) - : base::TrackingInfo(posted_from, TimeTicks()), - task(task), - posted_from(posted_from), - sequence_num(0), - nestable(true) { -} - -PendingTask::PendingTask(const tracked_objects::Location& posted_from, - const base::Closure& task, - TimeTicks delayed_run_time, - bool nestable) - : base::TrackingInfo(posted_from, delayed_run_time), - task(task), - posted_from(posted_from), - sequence_num(0), - nestable(nestable) { -} - -PendingTask::~PendingTask() { -} - -bool PendingTask::operator<(const PendingTask& other) const { - // Since the top of a priority queue is defined as the "greatest" element, we - // need to invert the comparison here. We want the smaller time to be at the - // top of the heap. - - if (delayed_run_time < other.delayed_run_time) - return false; - - if (delayed_run_time > other.delayed_run_time) - return true; - - // If the times happen to match, then we use the sequence number to decide. - // Compare the difference to support integer roll-over. - return (sequence_num - other.sequence_num) > 0; -} - -void TaskQueue::Swap(TaskQueue* queue) { - c.swap(queue->c); // Calls std::deque::swap. -} - -} // namespace base diff --git a/base/pending_task.h b/base/pending_task.h deleted file mode 100644 index 65e17f8d8c..0000000000 --- a/base/pending_task.h +++ /dev/null @@ -1,60 +0,0 @@ -// Copyright (c) 2011 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef PENDING_TASK_H_ -#define PENDING_TASK_H_ - -#include - -#include "base/base_export.h" -#include "base/callback.h" -#include "base/location.h" -#include "base/time/time.h" -#include "base/tracking_info.h" - -namespace base { - -// Contains data about a pending task. Stored in TaskQueue and DelayedTaskQueue -// for use by classes that queue and execute tasks. -struct BASE_EXPORT PendingTask : public TrackingInfo { -#if _MSC_VER >= 1700 - PendingTask(); -#endif - PendingTask(const tracked_objects::Location& posted_from, - const Closure& task); - PendingTask(const tracked_objects::Location& posted_from, - const Closure& task, - TimeTicks delayed_run_time, - bool nestable); - ~PendingTask(); - - // Used to support sorting. - bool operator<(const PendingTask& other) const; - - // The task to run. - Closure task; - - // The site this PendingTask was posted from. - tracked_objects::Location posted_from; - - // Secondary sort key for run time. - int sequence_num; - - // OK to dispatch from a nested loop. - bool nestable; -}; - -// Wrapper around std::queue specialized for PendingTask which adds a Swap -// helper method. -class BASE_EXPORT TaskQueue : public std::queue { - public: - void Swap(TaskQueue* queue); -}; - -// PendingTasks are sorted by their |delayed_run_time| property. -typedef std::priority_queue DelayedTaskQueue; - -} // namespace base - -#endif // PENDING_TASK_H_ diff --git a/base/perftimer.cc b/base/perftimer.cc deleted file mode 100644 index 9ab7c6b298..0000000000 --- a/base/perftimer.cc +++ /dev/null @@ -1,45 +0,0 @@ -// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "base/perftimer.h" - -#include -#include - -#include "base/basictypes.h" -#include "base/file_util.h" -#include "base/files/file_path.h" -#include "base/logging.h" - -static FILE* perf_log_file = NULL; - -bool InitPerfLog(const base::FilePath& log_file) { - if (perf_log_file) { - // trying to initialize twice - NOTREACHED(); - return false; - } - - perf_log_file = file_util::OpenFile(log_file, "w"); - return perf_log_file != NULL; -} - -void FinalizePerfLog() { - if (!perf_log_file) { - // trying to cleanup without initializing - NOTREACHED(); - return; - } - file_util::CloseFile(perf_log_file); -} - -void LogPerfResult(const char* test_name, double value, const char* units) { - if (!perf_log_file) { - NOTREACHED(); - return; - } - - fprintf(perf_log_file, "%s\t%g\t%s\n", test_name, value, units); - printf("%s\t%g\t%s\n", test_name, value, units); -} diff --git a/base/perftimer.h b/base/perftimer.h deleted file mode 100644 index 466f81d32b..0000000000 --- a/base/perftimer.h +++ /dev/null @@ -1,85 +0,0 @@ -// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef BASE_PERFTIMER_H_ -#define BASE_PERFTIMER_H_ - -#include - -#include "base/basictypes.h" -#include "base/time/time.h" - -namespace base { -class FilePath; -} - -// ---------------------------------------------------------------------- -// Initializes and finalizes the perf log. These functions should be -// called at the beginning and end (respectively) of running all the -// performance tests. The init function returns true on success. -// ---------------------------------------------------------------------- -bool InitPerfLog(const base::FilePath& log_path); -void FinalizePerfLog(); - -// ---------------------------------------------------------------------- -// LogPerfResult -// Writes to the perf result log the given 'value' resulting from the -// named 'test'. The units are to aid in reading the log by people. -// ---------------------------------------------------------------------- -void LogPerfResult(const char* test_name, double value, const char* units); - -// ---------------------------------------------------------------------- -// PerfTimer -// A simple wrapper around Now() -// ---------------------------------------------------------------------- -class PerfTimer { - public: - PerfTimer() { - begin_ = base::TimeTicks::Now(); - } - - // Returns the time elapsed since object construction - base::TimeDelta Elapsed() const { - return base::TimeTicks::Now() - begin_; - } - - private: - base::TimeTicks begin_; -}; - -// ---------------------------------------------------------------------- -// PerfTimeLogger -// Automates calling LogPerfResult for the common case where you want -// to measure the time that something took. Call Done() when the test -// is complete if you do extra work after the test or there are stack -// objects with potentially expensive constructors. Otherwise, this -// class with automatically log on destruction. -// ---------------------------------------------------------------------- -class PerfTimeLogger { - public: - explicit PerfTimeLogger(const char* test_name) - : logged_(false), - test_name_(test_name) { - } - - ~PerfTimeLogger() { - if (!logged_) - Done(); - } - - void Done() { - // we use a floating-point millisecond value because it is more - // intuitive than microseconds and we want more precision than - // integer milliseconds - LogPerfResult(test_name_.c_str(), timer_.Elapsed().InMillisecondsF(), "ms"); - logged_ = true; - } - - private: - bool logged_; - std::string test_name_; - PerfTimer timer_; -}; - -#endif // BASE_PERFTIMER_H_ diff --git a/base/pickle.cc b/base/pickle.cc deleted file mode 100644 index af3191b9d8..0000000000 --- a/base/pickle.cc +++ /dev/null @@ -1,361 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "base/pickle.h" - -#include - -#include // for max() - -//------------------------------------------------------------------------------ - -// static -const int Pickle::kPayloadUnit = 64; - -static const size_t kCapacityReadOnly = static_cast(-1); - -PickleIterator::PickleIterator(const Pickle& pickle) - : read_ptr_(pickle.payload()), - read_end_ptr_(pickle.end_of_payload()) { -} - -template -inline bool PickleIterator::ReadBuiltinType(Type* result) { - const char* read_from = GetReadPointerAndAdvance(); - if (!read_from) - return false; - if (sizeof(Type) > sizeof(uint32)) - memcpy(result, read_from, sizeof(*result)); - else - *result = *reinterpret_cast(read_from); - return true; -} - -template -inline const char* PickleIterator::GetReadPointerAndAdvance() { - const char* current_read_ptr = read_ptr_; - if (read_ptr_ + sizeof(Type) > read_end_ptr_) - return NULL; - if (sizeof(Type) < sizeof(uint32)) - read_ptr_ += AlignInt(sizeof(Type), sizeof(uint32)); - else - read_ptr_ += sizeof(Type); - return current_read_ptr; -} - -const char* PickleIterator::GetReadPointerAndAdvance(int num_bytes) { - if (num_bytes < 0 || read_end_ptr_ - read_ptr_ < num_bytes) - return NULL; - const char* current_read_ptr = read_ptr_; - read_ptr_ += AlignInt(num_bytes, sizeof(uint32)); - return current_read_ptr; -} - -inline const char* PickleIterator::GetReadPointerAndAdvance(int num_elements, - size_t size_element) { - // Check for int32 overflow. - int64 num_bytes = static_cast(num_elements) * size_element; - int num_bytes32 = static_cast(num_bytes); - if (num_bytes != static_cast(num_bytes32)) - return NULL; - return GetReadPointerAndAdvance(num_bytes32); -} - -bool PickleIterator::ReadBool(bool* result) { - return ReadBuiltinType(result); -} - -bool PickleIterator::ReadInt(int* result) { - return ReadBuiltinType(result); -} - -bool PickleIterator::ReadLong(long* result) { - return ReadBuiltinType(result); -} - -bool PickleIterator::ReadUInt16(uint16* result) { - return ReadBuiltinType(result); -} - -bool PickleIterator::ReadUInt32(uint32* result) { - return ReadBuiltinType(result); -} - -bool PickleIterator::ReadInt64(int64* result) { - return ReadBuiltinType(result); -} - -bool PickleIterator::ReadUInt64(uint64* result) { - return ReadBuiltinType(result); -} - -bool PickleIterator::ReadFloat(float* result) { - return ReadBuiltinType(result); -} - -bool PickleIterator::ReadString(std::string* result) { - int len; - if (!ReadInt(&len)) - return false; - const char* read_from = GetReadPointerAndAdvance(len); - if (!read_from) - return false; - - result->assign(read_from, len); - return true; -} - -bool PickleIterator::ReadWString(std::wstring* result) { - int len; - if (!ReadInt(&len)) - return false; - const char* read_from = GetReadPointerAndAdvance(len, sizeof(wchar_t)); - if (!read_from) - return false; - - result->assign(reinterpret_cast(read_from), len); - return true; -} - -bool PickleIterator::ReadString16(string16* result) { - int len; - if (!ReadInt(&len)) - return false; - const char* read_from = GetReadPointerAndAdvance(len, sizeof(char16)); - if (!read_from) - return false; - - result->assign(reinterpret_cast(read_from), len); - return true; -} - -bool PickleIterator::ReadData(const char** data, int* length) { - *length = 0; - *data = 0; - - if (!ReadInt(length)) - return false; - - return ReadBytes(data, *length); -} - -bool PickleIterator::ReadBytes(const char** data, int length) { - const char* read_from = GetReadPointerAndAdvance(length); - if (!read_from) - return false; - *data = read_from; - return true; -} - -// Payload is uint32 aligned. - -Pickle::Pickle() - : header_(NULL), - header_size_(sizeof(Header)), - capacity_(0), - variable_buffer_offset_(0) { - Resize(kPayloadUnit); - header_->payload_size = 0; -} - -Pickle::Pickle(int header_size) - : header_(NULL), - header_size_(AlignInt(header_size, sizeof(uint32))), - capacity_(0), - variable_buffer_offset_(0) { - DCHECK_GE(static_cast(header_size), sizeof(Header)); - DCHECK_LE(header_size, kPayloadUnit); - Resize(kPayloadUnit); - header_->payload_size = 0; -} - -Pickle::Pickle(const char* data, int data_len) - : header_(reinterpret_cast(const_cast(data))), - header_size_(0), - capacity_(kCapacityReadOnly), - variable_buffer_offset_(0) { - if (data_len >= static_cast(sizeof(Header))) - header_size_ = data_len - header_->payload_size; - - if (header_size_ > static_cast(data_len)) - header_size_ = 0; - - if (header_size_ != AlignInt(header_size_, sizeof(uint32))) - header_size_ = 0; - - // If there is anything wrong with the data, we're not going to use it. - if (!header_size_) - header_ = NULL; -} - -Pickle::Pickle(const Pickle& other) - : header_(NULL), - header_size_(other.header_size_), - capacity_(0), - variable_buffer_offset_(other.variable_buffer_offset_) { - size_t payload_size = header_size_ + other.header_->payload_size; - bool resized = Resize(payload_size); - CHECK(resized); // Realloc failed. - memcpy(header_, other.header_, payload_size); -} - -Pickle::~Pickle() { - if (capacity_ != kCapacityReadOnly) - free(header_); -} - -Pickle& Pickle::operator=(const Pickle& other) { - if (this == &other) { - NOTREACHED(); - return *this; - } - if (capacity_ == kCapacityReadOnly) { - header_ = NULL; - capacity_ = 0; - } - if (header_size_ != other.header_size_) { - free(header_); - header_ = NULL; - header_size_ = other.header_size_; - } - bool resized = Resize(other.header_size_ + other.header_->payload_size); - CHECK(resized); // Realloc failed. - memcpy(header_, other.header_, - other.header_size_ + other.header_->payload_size); - variable_buffer_offset_ = other.variable_buffer_offset_; - return *this; -} - -bool Pickle::WriteString(const std::string& value) { - if (!WriteInt(static_cast(value.size()))) - return false; - - return WriteBytes(value.data(), static_cast(value.size())); -} - -bool Pickle::WriteWString(const std::wstring& value) { - if (!WriteInt(static_cast(value.size()))) - return false; - - return WriteBytes(value.data(), - static_cast(value.size() * sizeof(wchar_t))); -} - -bool Pickle::WriteString16(const string16& value) { - if (!WriteInt(static_cast(value.size()))) - return false; - - return WriteBytes(value.data(), - static_cast(value.size()) * sizeof(char16)); -} - -bool Pickle::WriteData(const char* data, int length) { - return length >= 0 && WriteInt(length) && WriteBytes(data, length); -} - -bool Pickle::WriteBytes(const void* data, int data_len) { - DCHECK_NE(kCapacityReadOnly, capacity_) << "oops: pickle is readonly"; - - char* dest = BeginWrite(data_len); - if (!dest) - return false; - - memcpy(dest, data, data_len); - - EndWrite(dest, data_len); - return true; -} - -char* Pickle::BeginWriteData(int length) { - DCHECK_EQ(variable_buffer_offset_, 0U) << - "There can only be one variable buffer in a Pickle"; - - if (length < 0 || !WriteInt(length)) - return NULL; - - char *data_ptr = BeginWrite(length); - if (!data_ptr) - return NULL; - - variable_buffer_offset_ = - data_ptr - reinterpret_cast(header_) - sizeof(int); - - // EndWrite doesn't necessarily have to be called after the write operation, - // so we call it here to pad out what the caller will eventually write. - EndWrite(data_ptr, length); - return data_ptr; -} - -void Pickle::TrimWriteData(int new_length) { - DCHECK_NE(variable_buffer_offset_, 0U); - - // Fetch the the variable buffer size - int* cur_length = reinterpret_cast( - reinterpret_cast(header_) + variable_buffer_offset_); - - if (new_length < 0 || new_length > *cur_length) { - NOTREACHED() << "Invalid length in TrimWriteData."; - return; - } - - // Update the payload size and variable buffer size - header_->payload_size -= (*cur_length - new_length); - *cur_length = new_length; -} - -char* Pickle::BeginWrite(size_t length) { - // write at a uint32-aligned offset from the beginning of the header - size_t offset = AlignInt(header_->payload_size, sizeof(uint32)); - - size_t new_size = offset + length; - size_t needed_size = header_size_ + new_size; - if (needed_size > capacity_ && !Resize(std::max(capacity_ * 2, needed_size))) - return NULL; - -#ifdef ARCH_CPU_64_BITS - DCHECK_LE(length, kuint32max); -#endif - - header_->payload_size = static_cast(new_size); - return mutable_payload() + offset; -} - -void Pickle::EndWrite(char* dest, int length) { - // Zero-pad to keep tools like valgrind from complaining about uninitialized - // memory. - if (length % sizeof(uint32)) - memset(dest + length, 0, sizeof(uint32) - (length % sizeof(uint32))); -} - -bool Pickle::Resize(size_t new_capacity) { - new_capacity = AlignInt(new_capacity, kPayloadUnit); - - CHECK_NE(capacity_, kCapacityReadOnly); - void* p = realloc(header_, new_capacity); - if (!p) - return false; - - header_ = reinterpret_cast(p); - capacity_ = new_capacity; - return true; -} - -// static -const char* Pickle::FindNext(size_t header_size, - const char* start, - const char* end) { - DCHECK_EQ(header_size, AlignInt(header_size, sizeof(uint32))); - DCHECK_LE(header_size, static_cast(kPayloadUnit)); - - if (static_cast(end - start) < sizeof(Header)) - return NULL; - - const Header* hdr = reinterpret_cast(start); - const char* payload_base = start + header_size; - const char* payload_end = payload_base + hdr->payload_size; - if (payload_end < payload_base) - return NULL; - - return (payload_end > end) ? NULL : payload_end; -} diff --git a/base/pickle.h b/base/pickle.h deleted file mode 100644 index 3de2886e5d..0000000000 --- a/base/pickle.h +++ /dev/null @@ -1,347 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef BASE_PICKLE_H__ -#define BASE_PICKLE_H__ - -#include - -#include "base/base_export.h" -#include "base/basictypes.h" -#include "base/compiler_specific.h" -#include "base/gtest_prod_util.h" -#include "base/logging.h" -#include "base/strings/string16.h" - -class Pickle; - -// PickleIterator reads data from a Pickle. The Pickle object must remain valid -// while the PickleIterator object is in use. -class BASE_EXPORT PickleIterator { - public: - PickleIterator() : read_ptr_(NULL), read_end_ptr_(NULL) {} - explicit PickleIterator(const Pickle& pickle); - - // Methods for reading the payload of the Pickle. To read from the start of - // the Pickle, create a PickleIterator from a Pickle. If successful, these - // methods return true. Otherwise, false is returned to indicate that the - // result could not be extracted. - bool ReadBool(bool* result) WARN_UNUSED_RESULT; - bool ReadInt(int* result) WARN_UNUSED_RESULT; - bool ReadLong(long* result) WARN_UNUSED_RESULT; - bool ReadUInt16(uint16* result) WARN_UNUSED_RESULT; - bool ReadUInt32(uint32* result) WARN_UNUSED_RESULT; - bool ReadInt64(int64* result) WARN_UNUSED_RESULT; - bool ReadUInt64(uint64* result) WARN_UNUSED_RESULT; - bool ReadFloat(float* result) WARN_UNUSED_RESULT; - bool ReadString(std::string* result) WARN_UNUSED_RESULT; - bool ReadWString(std::wstring* result) WARN_UNUSED_RESULT; - bool ReadString16(string16* result) WARN_UNUSED_RESULT; - bool ReadData(const char** data, int* length) WARN_UNUSED_RESULT; - bool ReadBytes(const char** data, int length) WARN_UNUSED_RESULT; - - // Safer version of ReadInt() checks for the result not being negative. - // Use it for reading the object sizes. - bool ReadLength(int* result) WARN_UNUSED_RESULT { - return ReadInt(result) && *result >= 0; - } - - // Skips bytes in the read buffer and returns true if there are at least - // num_bytes available. Otherwise, does nothing and returns false. - bool SkipBytes(int num_bytes) WARN_UNUSED_RESULT { - return !!GetReadPointerAndAdvance(num_bytes); - } - - private: - // Aligns 'i' by rounding it up to the next multiple of 'alignment' - static size_t AlignInt(size_t i, int alignment) { - return i + (alignment - (i % alignment)) % alignment; - } - - // Read Type from Pickle. - template - inline bool ReadBuiltinType(Type* result); - - // Get read pointer for Type and advance read pointer. - template - inline const char* GetReadPointerAndAdvance(); - - // Get read pointer for |num_bytes| and advance read pointer. This method - // checks num_bytes for negativity and wrapping. - const char* GetReadPointerAndAdvance(int num_bytes); - - // Get read pointer for (num_elements * size_element) bytes and advance read - // pointer. This method checks for int overflow, negativity and wrapping. - inline const char* GetReadPointerAndAdvance(int num_elements, - size_t size_element); - - // Pointers to the Pickle data. - const char* read_ptr_; - const char* read_end_ptr_; - - FRIEND_TEST_ALL_PREFIXES(PickleTest, GetReadPointerAndAdvance); -}; - -// This class provides facilities for basic binary value packing and unpacking. -// -// The Pickle class supports appending primitive values (ints, strings, etc.) -// to a pickle instance. The Pickle instance grows its internal memory buffer -// dynamically to hold the sequence of primitive values. The internal memory -// buffer is exposed as the "data" of the Pickle. This "data" can be passed -// to a Pickle object to initialize it for reading. -// -// When reading from a Pickle object, it is important for the consumer to know -// what value types to read and in what order to read them as the Pickle does -// not keep track of the type of data written to it. -// -// The Pickle's data has a header which contains the size of the Pickle's -// payload. It can optionally support additional space in the header. That -// space is controlled by the header_size parameter passed to the Pickle -// constructor. -// -class BASE_EXPORT Pickle { - public: - // Initialize a Pickle object using the default header size. - Pickle(); - - // Initialize a Pickle object with the specified header size in bytes, which - // must be greater-than-or-equal-to sizeof(Pickle::Header). The header size - // will be rounded up to ensure that the header size is 32bit-aligned. - explicit Pickle(int header_size); - - // Initializes a Pickle from a const block of data. The data is not copied; - // instead the data is merely referenced by this Pickle. Only const methods - // should be used on the Pickle when initialized this way. The header - // padding size is deduced from the data length. - Pickle(const char* data, int data_len); - - // Initializes a Pickle as a deep copy of another Pickle. - Pickle(const Pickle& other); - - // Note: There are no virtual methods in this class. This destructor is - // virtual as an element of defensive coding. Other classes have derived from - // this class, and there is a *chance* that they will cast into this base - // class before destruction. At least one such class does have a virtual - // destructor, suggesting at least some need to call more derived destructors. - virtual ~Pickle(); - - // Performs a deep copy. - Pickle& operator=(const Pickle& other); - - // Returns the size of the Pickle's data. - size_t size() const { return header_size_ + header_->payload_size; } - - // Returns the data for this Pickle. - const void* data() const { return header_; } - - // For compatibility, these older style read methods pass through to the - // PickleIterator methods. - // TODO(jbates) Remove these methods. - bool ReadBool(PickleIterator* iter, bool* result) const { - return iter->ReadBool(result); - } - bool ReadInt(PickleIterator* iter, int* result) const { - return iter->ReadInt(result); - } - bool ReadLong(PickleIterator* iter, long* result) const { - return iter->ReadLong(result); - } - bool ReadUInt16(PickleIterator* iter, uint16* result) const { - return iter->ReadUInt16(result); - } - bool ReadUInt32(PickleIterator* iter, uint32* result) const { - return iter->ReadUInt32(result); - } - bool ReadInt64(PickleIterator* iter, int64* result) const { - return iter->ReadInt64(result); - } - bool ReadUInt64(PickleIterator* iter, uint64* result) const { - return iter->ReadUInt64(result); - } - bool ReadFloat(PickleIterator* iter, float* result) const { - return iter->ReadFloat(result); - } - bool ReadString(PickleIterator* iter, std::string* result) const { - return iter->ReadString(result); - } - bool ReadWString(PickleIterator* iter, std::wstring* result) const { - return iter->ReadWString(result); - } - bool ReadString16(PickleIterator* iter, string16* result) const { - return iter->ReadString16(result); - } - // A pointer to the data will be placed in *data, and the length will be - // placed in *length. This buffer will be into the message's buffer so will - // be scoped to the lifetime of the message (or until the message data is - // mutated). - bool ReadData(PickleIterator* iter, const char** data, int* length) const { - return iter->ReadData(data, length); - } - // A pointer to the data will be placed in *data. The caller specifies the - // number of bytes to read, and ReadBytes will validate this length. The - // returned buffer will be into the message's buffer so will be scoped to the - // lifetime of the message (or until the message data is mutated). - bool ReadBytes(PickleIterator* iter, const char** data, int length) const { - return iter->ReadBytes(data, length); - } - - // Safer version of ReadInt() checks for the result not being negative. - // Use it for reading the object sizes. - bool ReadLength(PickleIterator* iter, int* result) const { - return iter->ReadLength(result); - } - - // Methods for adding to the payload of the Pickle. These values are - // appended to the end of the Pickle's payload. When reading values from a - // Pickle, it is important to read them in the order in which they were added - // to the Pickle. - bool WriteBool(bool value) { - return WriteInt(value ? 1 : 0); - } - bool WriteInt(int value) { - return WriteBytes(&value, sizeof(value)); - } - // WARNING: DO NOT USE THIS METHOD IF PICKLES ARE PERSISTED IN ANY WAY. - // It will write whatever a "long" is on this architecture. On 32-bit - // platforms, it is 32 bits. On 64-bit platforms, it is 64 bits. If persisted - // pickles are still around after upgrading to 64-bit, or if they are copied - // between dissimilar systems, YOUR PICKLES WILL HAVE GONE BAD. - bool WriteLongUsingDangerousNonPortableLessPersistableForm(long value) { - return WriteBytes(&value, sizeof(value)); - } - bool WriteUInt16(uint16 value) { - return WriteBytes(&value, sizeof(value)); - } - bool WriteUInt32(uint32 value) { - return WriteBytes(&value, sizeof(value)); - } - bool WriteInt64(int64 value) { - return WriteBytes(&value, sizeof(value)); - } - bool WriteUInt64(uint64 value) { - return WriteBytes(&value, sizeof(value)); - } - bool WriteFloat(float value) { - return WriteBytes(&value, sizeof(value)); - } - bool WriteString(const std::string& value); - bool WriteWString(const std::wstring& value); - bool WriteString16(const string16& value); - // "Data" is a blob with a length. When you read it out you will be given the - // length. See also WriteBytes. - bool WriteData(const char* data, int length); - // "Bytes" is a blob with no length. The caller must specify the lenght both - // when reading and writing. It is normally used to serialize PoD types of a - // known size. See also WriteData. - bool WriteBytes(const void* data, int data_len); - - // Same as WriteData, but allows the caller to write directly into the - // Pickle. This saves a copy in cases where the data is not already - // available in a buffer. The caller should take care to not write more - // than the length it declares it will. Use ReadData to get the data. - // Returns NULL on failure. - // - // The returned pointer will only be valid until the next write operation - // on this Pickle. - char* BeginWriteData(int length); - - // For Pickles which contain variable length buffers (e.g. those created - // with BeginWriteData), the Pickle can - // be 'trimmed' if the amount of data required is less than originally - // requested. For example, you may have created a buffer with 10K of data, - // but decided to only fill 10 bytes of that data. Use this function - // to trim the buffer so that we don't send 9990 bytes of unused data. - // You cannot increase the size of the variable buffer; only shrink it. - // This function assumes that the length of the variable buffer has - // not been changed. - void TrimWriteData(int length); - - // Payload follows after allocation of Header (header size is customizable). - struct Header { - uint32 payload_size; // Specifies the size of the payload. - }; - - // Returns the header, cast to a user-specified type T. The type T must be a - // subclass of Header and its size must correspond to the header_size passed - // to the Pickle constructor. - template - T* headerT() { - DCHECK_EQ(header_size_, sizeof(T)); - return static_cast(header_); - } - template - const T* headerT() const { - DCHECK_EQ(header_size_, sizeof(T)); - return static_cast(header_); - } - - // The payload is the pickle data immediately following the header. - size_t payload_size() const { return header_->payload_size; } - - const char* payload() const { - return reinterpret_cast(header_) + header_size_; - } - - // Returns the address of the byte immediately following the currently valid - // header + payload. - const char* end_of_payload() const { - // This object may be invalid. - return header_ ? payload() + payload_size() : NULL; - } - - protected: - char* mutable_payload() { - return reinterpret_cast(header_) + header_size_; - } - - size_t capacity() const { - return capacity_; - } - - // Resizes the buffer for use when writing the specified amount of data. The - // location that the data should be written at is returned, or NULL if there - // was an error. Call EndWrite with the returned offset and the given length - // to pad out for the next write. - char* BeginWrite(size_t length); - - // Completes the write operation by padding the data with NULL bytes until it - // is padded. Should be paired with BeginWrite, but it does not necessarily - // have to be called after the data is written. - void EndWrite(char* dest, int length); - - // Resize the capacity, note that the input value should include the size of - // the header: new_capacity = sizeof(Header) + desired_payload_capacity. - // A realloc() failure will cause a Resize failure... and caller should check - // the return result for true (i.e., successful resizing). - bool Resize(size_t new_capacity); - - // Aligns 'i' by rounding it up to the next multiple of 'alignment' - static size_t AlignInt(size_t i, int alignment) { - return i + (alignment - (i % alignment)) % alignment; - } - - // Find the end of the pickled data that starts at range_start. Returns NULL - // if the entire Pickle is not found in the given data range. - static const char* FindNext(size_t header_size, - const char* range_start, - const char* range_end); - - // The allocation granularity of the payload. - static const int kPayloadUnit; - - private: - friend class PickleIterator; - - Header* header_; - size_t header_size_; // Supports extra data between header and payload. - // Allocation size of payload (or -1 if allocation is const). - size_t capacity_; - size_t variable_buffer_offset_; // IF non-zero, then offset to a buffer. - - FRIEND_TEST_ALL_PREFIXES(PickleTest, Resize); - FRIEND_TEST_ALL_PREFIXES(PickleTest, FindNext); - FRIEND_TEST_ALL_PREFIXES(PickleTest, FindNextWithIncompleteHeader); -}; - -#endif // BASE_PICKLE_H__ diff --git a/base/pickle_unittest.cc b/base/pickle_unittest.cc deleted file mode 100644 index cc384c7061..0000000000 --- a/base/pickle_unittest.cc +++ /dev/null @@ -1,342 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include - -#include "base/basictypes.h" -#include "base/memory/scoped_ptr.h" -#include "base/pickle.h" -#include "base/strings/string16.h" -#include "testing/gtest/include/gtest/gtest.h" - -namespace { - -const int testint = 2093847192; -const std::string teststr("Hello world"); // note non-aligned string length -const std::wstring testwstr(L"Hello, world"); -const char testdata[] = "AAA\0BBB\0"; -const int testdatalen = arraysize(testdata) - 1; -const bool testbool1 = false; -const bool testbool2 = true; -const uint16 testuint16 = 32123; -const float testfloat = 3.1415926935f; - -// checks that the result -void VerifyResult(const Pickle& pickle) { - PickleIterator iter(pickle); - - int outint; - EXPECT_TRUE(pickle.ReadInt(&iter, &outint)); - EXPECT_EQ(testint, outint); - - std::string outstr; - EXPECT_TRUE(pickle.ReadString(&iter, &outstr)); - EXPECT_EQ(teststr, outstr); - - std::wstring outwstr; - EXPECT_TRUE(pickle.ReadWString(&iter, &outwstr)); - EXPECT_EQ(testwstr, outwstr); - - bool outbool; - EXPECT_TRUE(pickle.ReadBool(&iter, &outbool)); - EXPECT_FALSE(outbool); - EXPECT_TRUE(pickle.ReadBool(&iter, &outbool)); - EXPECT_TRUE(outbool); - - uint16 outuint16; - EXPECT_TRUE(pickle.ReadUInt16(&iter, &outuint16)); - EXPECT_EQ(testuint16, outuint16); - - float outfloat; - EXPECT_TRUE(pickle.ReadFloat(&iter, &outfloat)); - EXPECT_EQ(testfloat, outfloat); - - const char* outdata; - int outdatalen; - EXPECT_TRUE(pickle.ReadData(&iter, &outdata, &outdatalen)); - EXPECT_EQ(testdatalen, outdatalen); - EXPECT_EQ(memcmp(testdata, outdata, outdatalen), 0); - - EXPECT_TRUE(pickle.ReadData(&iter, &outdata, &outdatalen)); - EXPECT_EQ(testdatalen, outdatalen); - EXPECT_EQ(memcmp(testdata, outdata, outdatalen), 0); - - // reads past the end should fail - EXPECT_FALSE(pickle.ReadInt(&iter, &outint)); -} - -} // namespace - -TEST(PickleTest, EncodeDecode) { - Pickle pickle; - - EXPECT_TRUE(pickle.WriteInt(testint)); - EXPECT_TRUE(pickle.WriteString(teststr)); - EXPECT_TRUE(pickle.WriteWString(testwstr)); - EXPECT_TRUE(pickle.WriteBool(testbool1)); - EXPECT_TRUE(pickle.WriteBool(testbool2)); - EXPECT_TRUE(pickle.WriteUInt16(testuint16)); - EXPECT_TRUE(pickle.WriteFloat(testfloat)); - EXPECT_TRUE(pickle.WriteData(testdata, testdatalen)); - - // Over allocate BeginWriteData so we can test TrimWriteData. - char* dest = pickle.BeginWriteData(testdatalen + 100); - EXPECT_TRUE(dest); - memcpy(dest, testdata, testdatalen); - - pickle.TrimWriteData(testdatalen); - - VerifyResult(pickle); - - // test copy constructor - Pickle pickle2(pickle); - VerifyResult(pickle2); - - // test operator= - Pickle pickle3; - pickle3 = pickle; - VerifyResult(pickle3); -} - -// Tests that we can handle really small buffers. -TEST(PickleTest, SmallBuffer) { - scoped_ptr buffer(new char[1]); - - // We should not touch the buffer. - Pickle pickle(buffer.get(), 1); - - PickleIterator iter(pickle); - int data; - EXPECT_FALSE(pickle.ReadInt(&iter, &data)); -} - -// Tests that we can handle improper headers. -TEST(PickleTest, BigSize) { - int buffer[] = { 0x56035200, 25, 40, 50 }; - - Pickle pickle(reinterpret_cast(buffer), sizeof(buffer)); - - PickleIterator iter(pickle); - int data; - EXPECT_FALSE(pickle.ReadInt(&iter, &data)); -} - -TEST(PickleTest, UnalignedSize) { - int buffer[] = { 10, 25, 40, 50 }; - - Pickle pickle(reinterpret_cast(buffer), sizeof(buffer)); - - PickleIterator iter(pickle); - int data; - EXPECT_FALSE(pickle.ReadInt(&iter, &data)); -} - -TEST(PickleTest, ZeroLenStr) { - Pickle pickle; - EXPECT_TRUE(pickle.WriteString(std::string())); - - PickleIterator iter(pickle); - std::string outstr; - EXPECT_TRUE(pickle.ReadString(&iter, &outstr)); - EXPECT_EQ("", outstr); -} - -TEST(PickleTest, ZeroLenWStr) { - Pickle pickle; - EXPECT_TRUE(pickle.WriteWString(std::wstring())); - - PickleIterator iter(pickle); - std::string outstr; - EXPECT_TRUE(pickle.ReadString(&iter, &outstr)); - EXPECT_EQ("", outstr); -} - -TEST(PickleTest, BadLenStr) { - Pickle pickle; - EXPECT_TRUE(pickle.WriteInt(-2)); - - PickleIterator iter(pickle); - std::string outstr; - EXPECT_FALSE(pickle.ReadString(&iter, &outstr)); -} - -TEST(PickleTest, BadLenWStr) { - Pickle pickle; - EXPECT_TRUE(pickle.WriteInt(-1)); - - PickleIterator iter(pickle); - std::wstring woutstr; - EXPECT_FALSE(pickle.ReadWString(&iter, &woutstr)); -} - -TEST(PickleTest, FindNext) { - Pickle pickle; - EXPECT_TRUE(pickle.WriteInt(1)); - EXPECT_TRUE(pickle.WriteString("Domo")); - - const char* start = reinterpret_cast(pickle.data()); - const char* end = start + pickle.size(); - - EXPECT_TRUE(end == Pickle::FindNext(pickle.header_size_, start, end)); - EXPECT_TRUE(NULL == Pickle::FindNext(pickle.header_size_, start, end - 1)); - EXPECT_TRUE(end == Pickle::FindNext(pickle.header_size_, start, end + 1)); -} - -TEST(PickleTest, FindNextWithIncompleteHeader) { - size_t header_size = sizeof(Pickle::Header); - scoped_ptr buffer(new char[header_size - 1]); - memset(buffer.get(), 0x1, header_size - 1); - - const char* start = buffer.get(); - const char* end = start + header_size - 1; - - EXPECT_TRUE(NULL == Pickle::FindNext(header_size, start, end)); -} - -TEST(PickleTest, GetReadPointerAndAdvance) { - Pickle pickle; - - PickleIterator iter(pickle); - EXPECT_FALSE(iter.GetReadPointerAndAdvance(1)); - - EXPECT_TRUE(pickle.WriteInt(1)); - EXPECT_TRUE(pickle.WriteInt(2)); - int bytes = sizeof(int) * 2; - - EXPECT_TRUE(PickleIterator(pickle).GetReadPointerAndAdvance(0)); - EXPECT_TRUE(PickleIterator(pickle).GetReadPointerAndAdvance(1)); - EXPECT_FALSE(PickleIterator(pickle).GetReadPointerAndAdvance(-1)); - EXPECT_TRUE(PickleIterator(pickle).GetReadPointerAndAdvance(bytes)); - EXPECT_FALSE(PickleIterator(pickle).GetReadPointerAndAdvance(bytes + 1)); - EXPECT_FALSE(PickleIterator(pickle).GetReadPointerAndAdvance(INT_MAX)); - EXPECT_FALSE(PickleIterator(pickle).GetReadPointerAndAdvance(INT_MIN)); -} - -TEST(PickleTest, Resize) { - size_t unit = Pickle::kPayloadUnit; - scoped_ptr data(new char[unit]); - char* data_ptr = data.get(); - for (size_t i = 0; i < unit; i++) - data_ptr[i] = 'G'; - - // construct a message that will be exactly the size of one payload unit, - // note that any data will have a 4-byte header indicating the size - const size_t payload_size_after_header = unit - sizeof(uint32); - Pickle pickle; - pickle.WriteData(data_ptr, - static_cast(payload_size_after_header - sizeof(uint32))); - size_t cur_payload = payload_size_after_header; - - // note: we assume 'unit' is a power of 2 - EXPECT_EQ(unit, pickle.capacity()); - EXPECT_EQ(pickle.payload_size(), payload_size_after_header); - - // fill out a full page (noting data header) - pickle.WriteData(data_ptr, static_cast(unit - sizeof(uint32))); - cur_payload += unit; - EXPECT_EQ(unit * 2, pickle.capacity()); - EXPECT_EQ(cur_payload, pickle.payload_size()); - - // one more byte should double the capacity - pickle.WriteData(data_ptr, 1); - cur_payload += 5; - EXPECT_EQ(unit * 4, pickle.capacity()); - EXPECT_EQ(cur_payload, pickle.payload_size()); -} - -namespace { - -struct CustomHeader : Pickle::Header { - int blah; -}; - -} // namespace - -TEST(PickleTest, HeaderPadding) { - const uint32 kMagic = 0x12345678; - - Pickle pickle(sizeof(CustomHeader)); - pickle.WriteInt(kMagic); - - // this should not overwrite the 'int' payload - pickle.headerT()->blah = 10; - - PickleIterator iter(pickle); - int result; - ASSERT_TRUE(pickle.ReadInt(&iter, &result)); - - EXPECT_EQ(static_cast(result), kMagic); -} - -TEST(PickleTest, EqualsOperator) { - Pickle source; - source.WriteInt(1); - - Pickle copy_refs_source_buffer(static_cast(source.data()), - source.size()); - Pickle copy; - copy = copy_refs_source_buffer; - ASSERT_EQ(source.size(), copy.size()); -} - -TEST(PickleTest, EvilLengths) { - Pickle source; - std::string str(100000, 'A'); - EXPECT_TRUE(source.WriteData(str.c_str(), 100000)); - // ReadString16 used to have its read buffer length calculation wrong leading - // to out-of-bounds reading. - PickleIterator iter(source); - string16 str16; - EXPECT_FALSE(source.ReadString16(&iter, &str16)); - - // And check we didn't break ReadString16. - str16 = (wchar_t) 'A'; - Pickle str16_pickle; - EXPECT_TRUE(str16_pickle.WriteString16(str16)); - iter = PickleIterator(str16_pickle); - EXPECT_TRUE(str16_pickle.ReadString16(&iter, &str16)); - EXPECT_EQ(1U, str16.length()); - - // Check we don't fail in a length check with invalid String16 size. - // (1<<31) * sizeof(char16) == 0, so this is particularly evil. - Pickle bad_len; - EXPECT_TRUE(bad_len.WriteInt(1 << 31)); - iter = PickleIterator(bad_len); - EXPECT_FALSE(bad_len.ReadString16(&iter, &str16)); - - // Check we don't fail in a length check with large WStrings. - Pickle big_len; - EXPECT_TRUE(big_len.WriteInt(1 << 30)); - iter = PickleIterator(big_len); - std::wstring wstr; - EXPECT_FALSE(big_len.ReadWString(&iter, &wstr)); -} - -// Check we can write zero bytes of data and 'data' can be NULL. -TEST(PickleTest, ZeroLength) { - Pickle pickle; - EXPECT_TRUE(pickle.WriteData(NULL, 0)); - - PickleIterator iter(pickle); - const char* outdata; - int outdatalen; - EXPECT_TRUE(pickle.ReadData(&iter, &outdata, &outdatalen)); - EXPECT_EQ(0, outdatalen); - // We can't assert that outdata is NULL. -} - -// Check that ReadBytes works properly with an iterator initialized to NULL. -TEST(PickleTest, ReadBytes) { - Pickle pickle; - int data = 0x7abcd; - EXPECT_TRUE(pickle.WriteBytes(&data, sizeof(data))); - - PickleIterator iter(pickle); - const char* outdata_char = NULL; - EXPECT_TRUE(pickle.ReadBytes(&iter, &outdata_char, sizeof(data))); - - int outdata; - memcpy(&outdata, outdata_char, sizeof(outdata)); - EXPECT_EQ(data, outdata); -} diff --git a/base/platform_file.cc b/base/platform_file.cc deleted file mode 100644 index bb411b893f..0000000000 --- a/base/platform_file.cc +++ /dev/null @@ -1,31 +0,0 @@ -// Copyright (c) 2011 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "base/platform_file.h" - -namespace base { - -PlatformFileInfo::PlatformFileInfo() - : size(0), - is_directory(false), - is_symbolic_link(false) { -} - -PlatformFileInfo::~PlatformFileInfo() {} - -#if !defined(OS_NACL) -PlatformFile CreatePlatformFile(const FilePath& name, - int flags, - bool* created, - PlatformFileError* error) { - if (name.ReferencesParent()) { - if (error) - *error = PLATFORM_FILE_ERROR_ACCESS_DENIED; - return kInvalidPlatformFileValue; - } - return CreatePlatformFileUnsafe(name, flags, created, error); -} -#endif - -} // namespace base diff --git a/base/platform_file.h b/base/platform_file.h deleted file mode 100644 index e94c7ed0e3..0000000000 --- a/base/platform_file.h +++ /dev/null @@ -1,254 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef BASE_PLATFORM_FILE_H_ -#define BASE_PLATFORM_FILE_H_ - -#include "build/build_config.h" -#if defined(OS_WIN) -#include -#endif - -#include - -#include "base/base_export.h" -#include "base/basictypes.h" -#include "base/files/file_path.h" -#include "base/time/time.h" - -namespace base { - -// PLATFORM_FILE_(OPEN|CREATE).* are mutually exclusive. You should specify -// exactly one of the five (possibly combining with other flags) when opening -// or creating a file. -// PLATFORM_FILE_(WRITE|APPEND) are mutually exclusive. This is so that APPEND -// behavior will be consistent with O_APPEND on POSIX. -enum PlatformFileFlags { - PLATFORM_FILE_OPEN = 1 << 0, // Opens a file, only if it exists. - PLATFORM_FILE_CREATE = 1 << 1, // Creates a new file, only if it - // does not already exist. - PLATFORM_FILE_OPEN_ALWAYS = 1 << 2, // May create a new file. - PLATFORM_FILE_CREATE_ALWAYS = 1 << 3, // May overwrite an old file. - PLATFORM_FILE_OPEN_TRUNCATED = 1 << 4, // Opens a file and truncates it, - // only if it exists. - PLATFORM_FILE_READ = 1 << 5, - PLATFORM_FILE_WRITE = 1 << 6, - PLATFORM_FILE_APPEND = 1 << 7, - PLATFORM_FILE_EXCLUSIVE_READ = 1 << 8, // EXCLUSIVE is opposite of Windows - // SHARE - PLATFORM_FILE_EXCLUSIVE_WRITE = 1 << 9, - PLATFORM_FILE_ASYNC = 1 << 10, - PLATFORM_FILE_TEMPORARY = 1 << 11, // Used on Windows only - PLATFORM_FILE_HIDDEN = 1 << 12, // Used on Windows only - PLATFORM_FILE_DELETE_ON_CLOSE = 1 << 13, - - PLATFORM_FILE_WRITE_ATTRIBUTES = 1 << 14, // Used on Windows only - PLATFORM_FILE_ENUMERATE = 1 << 15, // May enumerate directory - - PLATFORM_FILE_SHARE_DELETE = 1 << 16, // Used on Windows only - - PLATFORM_FILE_TERMINAL_DEVICE = 1 << 17, // Serial port flags - PLATFORM_FILE_BACKUP_SEMANTICS = 1 << 18, // Used on Windows only - - PLATFORM_FILE_EXECUTE = 1 << 19, // Used on Windows only -}; - -// PLATFORM_FILE_ERROR_ACCESS_DENIED is returned when a call fails because of -// a filesystem restriction. PLATFORM_FILE_ERROR_SECURITY is returned when a -// browser policy doesn't allow the operation to be executed. -enum PlatformFileError { - PLATFORM_FILE_OK = 0, - PLATFORM_FILE_ERROR_FAILED = -1, - PLATFORM_FILE_ERROR_IN_USE = -2, - PLATFORM_FILE_ERROR_EXISTS = -3, - PLATFORM_FILE_ERROR_NOT_FOUND = -4, - PLATFORM_FILE_ERROR_ACCESS_DENIED = -5, - PLATFORM_FILE_ERROR_TOO_MANY_OPENED = -6, - PLATFORM_FILE_ERROR_NO_MEMORY = -7, - PLATFORM_FILE_ERROR_NO_SPACE = -8, - PLATFORM_FILE_ERROR_NOT_A_DIRECTORY = -9, - PLATFORM_FILE_ERROR_INVALID_OPERATION = -10, - PLATFORM_FILE_ERROR_SECURITY = -11, - PLATFORM_FILE_ERROR_ABORT = -12, - PLATFORM_FILE_ERROR_NOT_A_FILE = -13, - PLATFORM_FILE_ERROR_NOT_EMPTY = -14, - PLATFORM_FILE_ERROR_INVALID_URL = -15, - PLATFORM_FILE_ERROR_IO = -16, - // Put new entries here and increment PLATFORM_FILE_ERROR_MAX. - PLATFORM_FILE_ERROR_MAX = -17 -}; - -// This explicit mapping matches both FILE_ on Windows and SEEK_ on Linux. -enum PlatformFileWhence { - PLATFORM_FILE_FROM_BEGIN = 0, - PLATFORM_FILE_FROM_CURRENT = 1, - PLATFORM_FILE_FROM_END = 2 -}; - -// Used to hold information about a given file. -// If you add more fields to this structure (platform-specific fields are OK), -// make sure to update all functions that use it in file_util_{win|posix}.cc -// too, and the ParamTraits implementation in -// chrome/common/common_param_traits.cc. -struct BASE_EXPORT PlatformFileInfo { - PlatformFileInfo(); - ~PlatformFileInfo(); - - // The size of the file in bytes. Undefined when is_directory is true. - int64 size; - - // True if the file corresponds to a directory. - bool is_directory; - - // True if the file corresponds to a symbolic link. - bool is_symbolic_link; - - // The last modified time of a file. - base::Time last_modified; - - // The last accessed time of a file. - base::Time last_accessed; - - // The creation time of a file. - base::Time creation_time; -}; - -#if defined(OS_WIN) -typedef HANDLE PlatformFile; -const PlatformFile kInvalidPlatformFileValue = INVALID_HANDLE_VALUE; -PlatformFileError LastErrorToPlatformFileError(DWORD saved_errno); -#elif defined(OS_POSIX) -typedef int PlatformFile; -const PlatformFile kInvalidPlatformFileValue = -1; -PlatformFileError ErrnoToPlatformFileError(int saved_errno); -#endif - -// Creates or opens the given file. If |created| is provided, it will be set to -// true if a new file was created [or an old one truncated to zero length to -// simulate a new file, which can happen with PLATFORM_FILE_CREATE_ALWAYS], and -// false otherwise. |error| can be NULL. -// -// This function fails with 'access denied' if the |name| contains path -// traversal ('..') components. -BASE_EXPORT PlatformFile CreatePlatformFile(const FilePath& name, - int flags, - bool* created, - PlatformFileError* error); - -// Same as CreatePlatformFile but allows paths with traversal (like \..\) -// components. Use only with extreme care. -BASE_EXPORT PlatformFile CreatePlatformFileUnsafe(const FilePath& name, - int flags, - bool* created, - PlatformFileError* error); - -BASE_EXPORT FILE* FdopenPlatformFile(PlatformFile file, const char* mode); - -// Closes a file handle. Returns |true| on success and |false| otherwise. -BASE_EXPORT bool ClosePlatformFile(PlatformFile file); - -// Changes current position in the file to an |offset| relative to an origin -// defined by |whence|. Returns the resultant current position in the file -// (relative to the start) or -1 in case of error. -BASE_EXPORT int64 SeekPlatformFile(PlatformFile file, - PlatformFileWhence whence, - int64 offset); - -// Reads the given number of bytes (or until EOF is reached) starting with the -// given offset. Returns the number of bytes read, or -1 on error. Note that -// this function makes a best effort to read all data on all platforms, so it is -// not intended for stream oriented files but instead for cases when the normal -// expectation is that actually |size| bytes are read unless there is an error. -BASE_EXPORT int ReadPlatformFile(PlatformFile file, int64 offset, - char* data, int size); - -// Same as above but without seek. -BASE_EXPORT int ReadPlatformFileAtCurrentPos(PlatformFile file, - char* data, int size); - -// Reads the given number of bytes (or until EOF is reached) starting with the -// given offset, but does not make any effort to read all data on all platforms. -// Returns the number of bytes read, or -1 on error. -BASE_EXPORT int ReadPlatformFileNoBestEffort(PlatformFile file, int64 offset, - char* data, int size); - -// Same as above but without seek. -BASE_EXPORT int ReadPlatformFileCurPosNoBestEffort(PlatformFile file, - char* data, int size); - -// Writes the given buffer into the file at the given offset, overwritting any -// data that was previously there. Returns the number of bytes written, or -1 -// on error. Note that this function makes a best effort to write all data on -// all platforms. -// Ignores the offset and writes to the end of the file if the file was opened -// with PLATFORM_FILE_APPEND. -BASE_EXPORT int WritePlatformFile(PlatformFile file, int64 offset, - const char* data, int size); - -// Save as above but without seek. -BASE_EXPORT int WritePlatformFileAtCurrentPos(PlatformFile file, - const char* data, int size); - -// Save as above but does not make any effort to write all data on all -// platforms. Returns the number of bytes written, or -1 on error. -BASE_EXPORT int WritePlatformFileCurPosNoBestEffort(PlatformFile file, - const char* data, int size); - -// Truncates the given file to the given length. If |length| is greater than -// the current size of the file, the file is extended with zeros. If the file -// doesn't exist, |false| is returned. -BASE_EXPORT bool TruncatePlatformFile(PlatformFile file, int64 length); - -// Flushes the buffers of the given file. -BASE_EXPORT bool FlushPlatformFile(PlatformFile file); - -// Touches the given file. -BASE_EXPORT bool TouchPlatformFile(PlatformFile file, - const Time& last_access_time, - const Time& last_modified_time); - -// Returns some information for the given file. -BASE_EXPORT bool GetPlatformFileInfo(PlatformFile file, PlatformFileInfo* info); - -// Use this class to pass ownership of a PlatformFile to a receiver that may or -// may not want to accept it. This class does not own the storage for the -// PlatformFile. -// -// EXAMPLE: -// -// void MaybeProcessFile(PassPlatformFile pass_file) { -// if (...) { -// PlatformFile file = pass_file.ReleaseValue(); -// // Now, we are responsible for closing |file|. -// } -// } -// -// void OpenAndMaybeProcessFile(const FilePath& path) { -// PlatformFile file = CreatePlatformFile(path, ...); -// MaybeProcessFile(PassPlatformFile(&file)); -// if (file != kInvalidPlatformFileValue) -// ClosePlatformFile(file); -// } -// -class BASE_EXPORT PassPlatformFile { - public: - explicit PassPlatformFile(PlatformFile* value) : value_(value) { - } - - // Called to retrieve the PlatformFile stored in this object. The caller - // gains ownership of the PlatformFile and is now responsible for closing it. - // Any subsequent calls to this method will return an invalid PlatformFile. - PlatformFile ReleaseValue() { - PlatformFile temp = *value_; - *value_ = kInvalidPlatformFileValue; - return temp; - } - - private: - PlatformFile* value_; -}; - -} // namespace base - -#endif // BASE_PLATFORM_FILE_H_ diff --git a/base/platform_file_posix.cc b/base/platform_file_posix.cc deleted file mode 100644 index 056577c581..0000000000 --- a/base/platform_file_posix.cc +++ /dev/null @@ -1,461 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "base/platform_file.h" - -#include -#include -#include -#include - -#include "base/files/file_path.h" -#include "base/logging.h" -#include "base/metrics/sparse_histogram.h" -#include "base/posix/eintr_wrapper.h" -#include "base/strings/utf_string_conversions.h" -#include "base/threading/thread_restrictions.h" - -#if defined(OS_ANDROID) -#include "base/os_compat_android.h" -#endif - -namespace base { - -// Make sure our Whence mappings match the system headers. -COMPILE_ASSERT(PLATFORM_FILE_FROM_BEGIN == SEEK_SET && - PLATFORM_FILE_FROM_CURRENT == SEEK_CUR && - PLATFORM_FILE_FROM_END == SEEK_END, whence_matches_system); - -namespace { - -#if defined(OS_BSD) || defined(OS_MACOSX) || defined(OS_NACL) -typedef struct stat stat_wrapper_t; -static int CallFstat(int fd, stat_wrapper_t *sb) { - base::ThreadRestrictions::AssertIOAllowed(); - return fstat(fd, sb); -} -#else -typedef struct stat64 stat_wrapper_t; -static int CallFstat(int fd, stat_wrapper_t *sb) { - base::ThreadRestrictions::AssertIOAllowed(); - return fstat64(fd, sb); -} -#endif - -// NaCl doesn't provide the following system calls, so either simulate them or -// wrap them in order to minimize the number of #ifdef's in this file. -#if !defined(OS_NACL) -static int DoPread(PlatformFile file, char* data, int size, int64 offset) { - return HANDLE_EINTR(pread(file, data, size, offset)); -} - -static int DoPwrite(PlatformFile file, const char* data, int size, - int64 offset) { - return HANDLE_EINTR(pwrite(file, data, size, offset)); -} - -static bool IsOpenAppend(PlatformFile file) { - return (fcntl(file, F_GETFL) & O_APPEND) != 0; -} - -static int CallFtruncate(PlatformFile file, int64 length) { - return HANDLE_EINTR(ftruncate(file, length)); -} - -static int CallFsync(PlatformFile file) { - return HANDLE_EINTR(fsync(file)); -} - -static int CallFutimes(PlatformFile file, const struct timeval times[2]) { -#ifdef __USE_XOPEN2K8 - // futimens should be available, but futimes might not be - // http://pubs.opengroup.org/onlinepubs/9699919799/ - - timespec ts_times[2]; - ts_times[0].tv_sec = times[0].tv_sec; - ts_times[0].tv_nsec = times[0].tv_usec * 1000; - ts_times[1].tv_sec = times[1].tv_sec; - ts_times[1].tv_nsec = times[1].tv_usec * 1000; - - return futimens(file, ts_times); -#else - return futimes(file, times); -#endif -} -#else // defined(OS_NACL) -// TODO(bbudge) Remove DoPread, DoPwrite when NaCl implements pread, pwrite. -static int DoPread(PlatformFile file, char* data, int size, int64 offset) { - lseek(file, static_cast(offset), SEEK_SET); - return HANDLE_EINTR(read(file, data, size)); -} - -static int DoPwrite(PlatformFile file, const char* data, int size, - int64 offset) { - lseek(file, static_cast(offset), SEEK_SET); - return HANDLE_EINTR(write(file, data, size)); -} - -static bool IsOpenAppend(PlatformFile file) { - // NaCl doesn't implement fcntl. Since NaCl's write conforms to the POSIX - // standard and always appends if the file is opened with O_APPEND, just - // return false here. - return false; -} - -static int CallFtruncate(PlatformFile file, int64 length) { - NOTIMPLEMENTED(); // NaCl doesn't implement ftruncate. - return 0; -} - -static int CallFsync(PlatformFile file) { - NOTIMPLEMENTED(); // NaCl doesn't implement fsync. - return 0; -} - -static int CallFutimes(PlatformFile file, const struct timeval times[2]) { - NOTIMPLEMENTED(); // NaCl doesn't implement futimes. - return 0; -} -#endif // defined(OS_NACL) - -} // namespace - -// NaCl doesn't implement system calls to open files directly. -#if !defined(OS_NACL) -// TODO(erikkay): does it make sense to support PLATFORM_FILE_EXCLUSIVE_* here? -PlatformFile CreatePlatformFileUnsafe(const FilePath& name, - int flags, - bool* created, - PlatformFileError* error) { - base::ThreadRestrictions::AssertIOAllowed(); - - int open_flags = 0; - if (flags & PLATFORM_FILE_CREATE) - open_flags = O_CREAT | O_EXCL; - - if (created) - *created = false; - - if (flags & PLATFORM_FILE_CREATE_ALWAYS) { - DCHECK(!open_flags); - open_flags = O_CREAT | O_TRUNC; - } - - if (flags & PLATFORM_FILE_OPEN_TRUNCATED) { - DCHECK(!open_flags); - DCHECK(flags & PLATFORM_FILE_WRITE); - open_flags = O_TRUNC; - } - - if (!open_flags && !(flags & PLATFORM_FILE_OPEN) && - !(flags & PLATFORM_FILE_OPEN_ALWAYS)) { - NOTREACHED(); - errno = EOPNOTSUPP; - if (error) - *error = PLATFORM_FILE_ERROR_FAILED; - return kInvalidPlatformFileValue; - } - - if (flags & PLATFORM_FILE_WRITE && flags & PLATFORM_FILE_READ) { - open_flags |= O_RDWR; - } else if (flags & PLATFORM_FILE_WRITE) { - open_flags |= O_WRONLY; - } else if (!(flags & PLATFORM_FILE_READ) && - !(flags & PLATFORM_FILE_WRITE_ATTRIBUTES) && - !(flags & PLATFORM_FILE_APPEND) && - !(flags & PLATFORM_FILE_OPEN_ALWAYS)) { - NOTREACHED(); - } - - if (flags & PLATFORM_FILE_TERMINAL_DEVICE) - open_flags |= O_NOCTTY | O_NDELAY; - - if (flags & PLATFORM_FILE_APPEND && flags & PLATFORM_FILE_READ) - open_flags |= O_APPEND | O_RDWR; - else if (flags & PLATFORM_FILE_APPEND) - open_flags |= O_APPEND | O_WRONLY; - - COMPILE_ASSERT(O_RDONLY == 0, O_RDONLY_must_equal_zero); - - int mode = S_IRUSR | S_IWUSR; -#if defined(OS_CHROMEOS) - mode |= S_IRGRP | S_IROTH; -#endif - - int descriptor = - HANDLE_EINTR(open(name.value().c_str(), open_flags, mode)); - - if (flags & PLATFORM_FILE_OPEN_ALWAYS) { - if (descriptor < 0) { - open_flags |= O_CREAT; - if (flags & PLATFORM_FILE_EXCLUSIVE_READ || - flags & PLATFORM_FILE_EXCLUSIVE_WRITE) { - open_flags |= O_EXCL; // together with O_CREAT implies O_NOFOLLOW - } - descriptor = HANDLE_EINTR( - open(name.value().c_str(), open_flags, mode)); - if (created && descriptor >= 0) - *created = true; - } - } - - if (created && (descriptor >= 0) && - (flags & (PLATFORM_FILE_CREATE_ALWAYS | PLATFORM_FILE_CREATE))) - *created = true; - - if ((descriptor >= 0) && (flags & PLATFORM_FILE_DELETE_ON_CLOSE)) { - unlink(name.value().c_str()); - } - - if (error) { - if (descriptor >= 0) - *error = PLATFORM_FILE_OK; - else - *error = ErrnoToPlatformFileError(errno); - } - - return descriptor; -} - -FILE* FdopenPlatformFile(PlatformFile file, const char* mode) { - return fdopen(file, mode); -} -#endif // !defined(OS_NACL) - -bool ClosePlatformFile(PlatformFile file) { - base::ThreadRestrictions::AssertIOAllowed(); - return !HANDLE_EINTR(close(file)); -} - -int64 SeekPlatformFile(PlatformFile file, - PlatformFileWhence whence, - int64 offset) { - base::ThreadRestrictions::AssertIOAllowed(); - if (file < 0 || offset < 0) - return -1; - - return lseek(file, static_cast(offset), static_cast(whence)); -} - -int ReadPlatformFile(PlatformFile file, int64 offset, char* data, int size) { - base::ThreadRestrictions::AssertIOAllowed(); - if (file < 0 || size < 0) - return -1; - - int bytes_read = 0; - int rv; - do { - rv = DoPread(file, data + bytes_read, - size - bytes_read, offset + bytes_read); - if (rv <= 0) - break; - - bytes_read += rv; - } while (bytes_read < size); - - return bytes_read ? bytes_read : rv; -} - -int ReadPlatformFileAtCurrentPos(PlatformFile file, char* data, int size) { - base::ThreadRestrictions::AssertIOAllowed(); - if (file < 0 || size < 0) - return -1; - - int bytes_read = 0; - int rv; - do { - rv = HANDLE_EINTR(read(file, data, size)); - if (rv <= 0) - break; - - bytes_read += rv; - } while (bytes_read < size); - - return bytes_read ? bytes_read : rv; -} - -int ReadPlatformFileNoBestEffort(PlatformFile file, int64 offset, - char* data, int size) { - base::ThreadRestrictions::AssertIOAllowed(); - if (file < 0) - return -1; - - return DoPread(file, data, size, offset); -} - -int ReadPlatformFileCurPosNoBestEffort(PlatformFile file, - char* data, int size) { - base::ThreadRestrictions::AssertIOAllowed(); - if (file < 0 || size < 0) - return -1; - - return HANDLE_EINTR(read(file, data, size)); -} - -int WritePlatformFile(PlatformFile file, int64 offset, - const char* data, int size) { - base::ThreadRestrictions::AssertIOAllowed(); - - if (IsOpenAppend(file)) - return WritePlatformFileAtCurrentPos(file, data, size); - - if (file < 0 || size < 0) - return -1; - - int bytes_written = 0; - int rv; - do { - rv = DoPwrite(file, data + bytes_written, - size - bytes_written, offset + bytes_written); - if (rv <= 0) - break; - - bytes_written += rv; - } while (bytes_written < size); - - return bytes_written ? bytes_written : rv; -} - -int WritePlatformFileAtCurrentPos(PlatformFile file, - const char* data, int size) { - base::ThreadRestrictions::AssertIOAllowed(); - if (file < 0 || size < 0) - return -1; - - int bytes_written = 0; - int rv; - do { - rv = HANDLE_EINTR(write(file, data, size)); - if (rv <= 0) - break; - - bytes_written += rv; - } while (bytes_written < size); - - return bytes_written ? bytes_written : rv; -} - -int WritePlatformFileCurPosNoBestEffort(PlatformFile file, - const char* data, int size) { - base::ThreadRestrictions::AssertIOAllowed(); - if (file < 0 || size < 0) - return -1; - - return HANDLE_EINTR(write(file, data, size)); -} - -bool TruncatePlatformFile(PlatformFile file, int64 length) { - base::ThreadRestrictions::AssertIOAllowed(); - return ((file >= 0) && !CallFtruncate(file, length)); -} - -bool FlushPlatformFile(PlatformFile file) { - base::ThreadRestrictions::AssertIOAllowed(); - return !CallFsync(file); -} - -bool TouchPlatformFile(PlatformFile file, const base::Time& last_access_time, - const base::Time& last_modified_time) { - base::ThreadRestrictions::AssertIOAllowed(); - if (file < 0) - return false; - - timeval times[2]; - times[0] = last_access_time.ToTimeVal(); - times[1] = last_modified_time.ToTimeVal(); - - return !CallFutimes(file, times); -} - -bool GetPlatformFileInfo(PlatformFile file, PlatformFileInfo* info) { - if (!info) - return false; - - stat_wrapper_t file_info; - if (CallFstat(file, &file_info)) - return false; - - info->is_directory = S_ISDIR(file_info.st_mode); - info->is_symbolic_link = S_ISLNK(file_info.st_mode); - info->size = file_info.st_size; - -#if defined(OS_LINUX) - const time_t last_modified_sec = file_info.st_mtim.tv_sec; - const int64 last_modified_nsec = file_info.st_mtim.tv_nsec; - const time_t last_accessed_sec = file_info.st_atim.tv_sec; - const int64 last_accessed_nsec = file_info.st_atim.tv_nsec; - const time_t creation_time_sec = file_info.st_ctim.tv_sec; - const int64 creation_time_nsec = file_info.st_ctim.tv_nsec; -#elif defined(OS_ANDROID) - const time_t last_modified_sec = file_info.st_mtime; - const int64 last_modified_nsec = file_info.st_mtime_nsec; - const time_t last_accessed_sec = file_info.st_atime; - const int64 last_accessed_nsec = file_info.st_atime_nsec; - const time_t creation_time_sec = file_info.st_ctime; - const int64 creation_time_nsec = file_info.st_ctime_nsec; -#elif defined(OS_MACOSX) || defined(OS_IOS) || defined(OS_BSD) - const time_t last_modified_sec = file_info.st_mtimespec.tv_sec; - const int64 last_modified_nsec = file_info.st_mtimespec.tv_nsec; - const time_t last_accessed_sec = file_info.st_atimespec.tv_sec; - const int64 last_accessed_nsec = file_info.st_atimespec.tv_nsec; - const time_t creation_time_sec = file_info.st_ctimespec.tv_sec; - const int64 creation_time_nsec = file_info.st_ctimespec.tv_nsec; -#else - // TODO(gavinp): Investigate a good high resolution option for OS_NACL. - const time_t last_modified_sec = file_info.st_mtime; - const int64 last_modified_nsec = 0; - const time_t last_accessed_sec = file_info.st_atime; - const int64 last_accessed_nsec = 0; - const time_t creation_time_sec = file_info.st_ctime; - const int64 creation_time_nsec = 0; -#endif - - info->last_modified = - base::Time::FromTimeT(last_modified_sec) + - base::TimeDelta::FromMicroseconds(last_modified_nsec / - base::Time::kNanosecondsPerMicrosecond); - info->last_accessed = - base::Time::FromTimeT(last_accessed_sec) + - base::TimeDelta::FromMicroseconds(last_accessed_nsec / - base::Time::kNanosecondsPerMicrosecond); - info->creation_time = - base::Time::FromTimeT(creation_time_sec) + - base::TimeDelta::FromMicroseconds(creation_time_nsec / - base::Time::kNanosecondsPerMicrosecond); - return true; -} - -PlatformFileError ErrnoToPlatformFileError(int saved_errno) { - switch (saved_errno) { - case EACCES: - case EISDIR: - case EROFS: - case EPERM: - return PLATFORM_FILE_ERROR_ACCESS_DENIED; -#if !defined(OS_NACL) // ETXTBSY not defined by NaCl. - case ETXTBSY: - return PLATFORM_FILE_ERROR_IN_USE; -#endif - case EEXIST: - return PLATFORM_FILE_ERROR_EXISTS; - case ENOENT: - return PLATFORM_FILE_ERROR_NOT_FOUND; - case EMFILE: - return PLATFORM_FILE_ERROR_TOO_MANY_OPENED; - case ENOMEM: - return PLATFORM_FILE_ERROR_NO_MEMORY; - case ENOSPC: - return PLATFORM_FILE_ERROR_NO_SPACE; - case ENOTDIR: - return PLATFORM_FILE_ERROR_NOT_A_DIRECTORY; - default: -#if !defined(OS_NACL) // NaCl build has no metrics code. - UMA_HISTOGRAM_SPARSE_SLOWLY("PlatformFile.UnknownErrors.Posix", - saved_errno); -#endif - return PLATFORM_FILE_ERROR_FAILED; - } -} - -} // namespace base diff --git a/base/platform_file_unittest.cc b/base/platform_file_unittest.cc deleted file mode 100644 index a1f3927edd..0000000000 --- a/base/platform_file_unittest.cc +++ /dev/null @@ -1,400 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "base/file_util.h" -#include "base/files/scoped_temp_dir.h" -#include "base/platform_file.h" -#include "base/time/time.h" -#include "testing/gtest/include/gtest/gtest.h" - -using base::FilePath; - -namespace { - -// Reads from a file the given number of bytes, or until EOF is reached. -// Returns the number of bytes read. -int ReadFully(base::PlatformFile file, int64 offset, char* data, int size) { - return base::ReadPlatformFile(file, offset, data, size); -} - -// Writes the given number of bytes to a file. -// Returns the number of bytes written. -int WriteFully(base::PlatformFile file, int64 offset, - const char* data, int size) { - return base::WritePlatformFile(file, offset, data, size); -} - -} // namespace - -TEST(PlatformFile, CreatePlatformFile) { - base::ScopedTempDir temp_dir; - ASSERT_TRUE(temp_dir.CreateUniqueTempDir()); - FilePath file_path = temp_dir.path().AppendASCII("create_file_1"); - - // Open a file that doesn't exist. - base::PlatformFileError error_code = base::PLATFORM_FILE_OK; - base::PlatformFile file = base::CreatePlatformFile( - file_path, - base::PLATFORM_FILE_OPEN | base::PLATFORM_FILE_READ, - NULL, - &error_code); - EXPECT_EQ(base::kInvalidPlatformFileValue, file); - EXPECT_EQ(base::PLATFORM_FILE_ERROR_NOT_FOUND, error_code); - - // Open or create a file. - bool created = false; - error_code = base::PLATFORM_FILE_OK; - file = base::CreatePlatformFile( - file_path, - base::PLATFORM_FILE_OPEN_ALWAYS | base::PLATFORM_FILE_READ, - &created, - &error_code); - EXPECT_NE(base::kInvalidPlatformFileValue, file); - EXPECT_TRUE(created); - EXPECT_EQ(base::PLATFORM_FILE_OK, error_code); - base::ClosePlatformFile(file); - - // Open an existing file. - created = false; - file = base::CreatePlatformFile( - file_path, - base::PLATFORM_FILE_OPEN | base::PLATFORM_FILE_READ, - &created, - &error_code); - EXPECT_NE(base::kInvalidPlatformFileValue, file); - EXPECT_FALSE(created); - EXPECT_EQ(base::PLATFORM_FILE_OK, error_code); - base::ClosePlatformFile(file); - - // Create a file that exists. - file = base::CreatePlatformFile( - file_path, - base::PLATFORM_FILE_CREATE | base::PLATFORM_FILE_READ, - &created, - &error_code); - EXPECT_EQ(base::kInvalidPlatformFileValue, file); - EXPECT_FALSE(created); - EXPECT_EQ(base::PLATFORM_FILE_ERROR_EXISTS, error_code); - - // Create or overwrite a file. - error_code = base::PLATFORM_FILE_OK; - file = base::CreatePlatformFile( - file_path, - base::PLATFORM_FILE_CREATE_ALWAYS | base::PLATFORM_FILE_READ, - &created, - &error_code); - EXPECT_NE(base::kInvalidPlatformFileValue, file); - EXPECT_TRUE(created); - EXPECT_EQ(base::PLATFORM_FILE_OK, error_code); - base::ClosePlatformFile(file); - - // Create a delete-on-close file. - created = false; - file_path = temp_dir.path().AppendASCII("create_file_2"); - file = base::CreatePlatformFile( - file_path, - base::PLATFORM_FILE_OPEN_ALWAYS | base::PLATFORM_FILE_DELETE_ON_CLOSE | - base::PLATFORM_FILE_READ, - &created, - &error_code); - EXPECT_NE(base::kInvalidPlatformFileValue, file); - EXPECT_TRUE(created); - EXPECT_EQ(base::PLATFORM_FILE_OK, error_code); - - EXPECT_TRUE(base::ClosePlatformFile(file)); - EXPECT_FALSE(base::PathExists(file_path)); -} - -TEST(PlatformFile, DeleteOpenFile) { - base::ScopedTempDir temp_dir; - ASSERT_TRUE(temp_dir.CreateUniqueTempDir()); - FilePath file_path = temp_dir.path().AppendASCII("create_file_1"); - - // Create a file. - bool created = false; - base::PlatformFileError error_code = base::PLATFORM_FILE_OK; - base::PlatformFile file = base::CreatePlatformFile( - file_path, - base::PLATFORM_FILE_OPEN_ALWAYS | base::PLATFORM_FILE_READ | - base::PLATFORM_FILE_SHARE_DELETE, - &created, - &error_code); - EXPECT_NE(base::kInvalidPlatformFileValue, file); - EXPECT_TRUE(created); - EXPECT_EQ(base::PLATFORM_FILE_OK, error_code); - - // Open an existing file and mark it as delete on close. - created = false; - base::PlatformFile same_file = base::CreatePlatformFile( - file_path, - base::PLATFORM_FILE_OPEN | base::PLATFORM_FILE_DELETE_ON_CLOSE | - base::PLATFORM_FILE_READ, - &created, - &error_code); - EXPECT_NE(base::kInvalidPlatformFileValue, file); - EXPECT_FALSE(created); - EXPECT_EQ(base::PLATFORM_FILE_OK, error_code); - - // Close both handles and check that the file is gone. - base::ClosePlatformFile(file); - base::ClosePlatformFile(same_file); - EXPECT_FALSE(base::PathExists(file_path)); -} - -TEST(PlatformFile, ReadWritePlatformFile) { - base::ScopedTempDir temp_dir; - ASSERT_TRUE(temp_dir.CreateUniqueTempDir()); - FilePath file_path = temp_dir.path().AppendASCII("read_write_file"); - base::PlatformFile file = base::CreatePlatformFile( - file_path, - base::PLATFORM_FILE_CREATE | base::PLATFORM_FILE_READ | - base::PLATFORM_FILE_WRITE, - NULL, - NULL); - EXPECT_NE(base::kInvalidPlatformFileValue, file); - - char data_to_write[] = "test"; - const int kTestDataSize = 4; - - // Write 0 bytes to the file. - int bytes_written = WriteFully(file, 0, data_to_write, 0); - EXPECT_EQ(0, bytes_written); - - // Write "test" to the file. - bytes_written = WriteFully(file, 0, data_to_write, kTestDataSize); - EXPECT_EQ(kTestDataSize, bytes_written); - - // Read from EOF. - char data_read_1[32]; - int bytes_read = ReadFully(file, kTestDataSize, data_read_1, kTestDataSize); - EXPECT_EQ(0, bytes_read); - - // Read from somewhere in the middle of the file. - const int kPartialReadOffset = 1; - bytes_read = ReadFully(file, kPartialReadOffset, data_read_1, kTestDataSize); - EXPECT_EQ(kTestDataSize - kPartialReadOffset, bytes_read); - for (int i = 0; i < bytes_read; i++) - EXPECT_EQ(data_to_write[i + kPartialReadOffset], data_read_1[i]); - - // Read 0 bytes. - bytes_read = ReadFully(file, 0, data_read_1, 0); - EXPECT_EQ(0, bytes_read); - - // Read the entire file. - bytes_read = ReadFully(file, 0, data_read_1, kTestDataSize); - EXPECT_EQ(kTestDataSize, bytes_read); - for (int i = 0; i < bytes_read; i++) - EXPECT_EQ(data_to_write[i], data_read_1[i]); - - // Read again, but using the trivial native wrapper. - bytes_read = base::ReadPlatformFileNoBestEffort(file, 0, data_read_1, - kTestDataSize); - EXPECT_LE(bytes_read, kTestDataSize); - for (int i = 0; i < bytes_read; i++) - EXPECT_EQ(data_to_write[i], data_read_1[i]); - - // Write past the end of the file. - const int kOffsetBeyondEndOfFile = 10; - const int kPartialWriteLength = 2; - bytes_written = WriteFully(file, kOffsetBeyondEndOfFile, - data_to_write, kPartialWriteLength); - EXPECT_EQ(kPartialWriteLength, bytes_written); - - // Make sure the file was extended. - int64 file_size = 0; - EXPECT_TRUE(file_util::GetFileSize(file_path, &file_size)); - EXPECT_EQ(kOffsetBeyondEndOfFile + kPartialWriteLength, file_size); - - // Make sure the file was zero-padded. - char data_read_2[32]; - bytes_read = ReadFully(file, 0, data_read_2, static_cast(file_size)); - EXPECT_EQ(file_size, bytes_read); - for (int i = 0; i < kTestDataSize; i++) - EXPECT_EQ(data_to_write[i], data_read_2[i]); - for (int i = kTestDataSize; i < kOffsetBeyondEndOfFile; i++) - EXPECT_EQ(0, data_read_2[i]); - for (int i = kOffsetBeyondEndOfFile; i < file_size; i++) - EXPECT_EQ(data_to_write[i - kOffsetBeyondEndOfFile], data_read_2[i]); - - // Close the file handle to allow the temp directory to be deleted. - base::ClosePlatformFile(file); -} - -TEST(PlatformFile, AppendPlatformFile) { - base::ScopedTempDir temp_dir; - ASSERT_TRUE(temp_dir.CreateUniqueTempDir()); - FilePath file_path = temp_dir.path().AppendASCII("append_file"); - base::PlatformFile file = base::CreatePlatformFile( - file_path, - base::PLATFORM_FILE_CREATE | base::PLATFORM_FILE_APPEND, - NULL, - NULL); - EXPECT_NE(base::kInvalidPlatformFileValue, file); - - char data_to_write[] = "test"; - const int kTestDataSize = 4; - - // Write 0 bytes to the file. - int bytes_written = WriteFully(file, 0, data_to_write, 0); - EXPECT_EQ(0, bytes_written); - - // Write "test" to the file. - bytes_written = WriteFully(file, 0, data_to_write, kTestDataSize); - EXPECT_EQ(kTestDataSize, bytes_written); - - base::ClosePlatformFile(file); - file = base::CreatePlatformFile( - file_path, - base::PLATFORM_FILE_OPEN | base::PLATFORM_FILE_READ | - base::PLATFORM_FILE_APPEND, - NULL, - NULL); - EXPECT_NE(base::kInvalidPlatformFileValue, file); - - char append_data_to_write[] = "78"; - const int kAppendDataSize = 2; - - // Append "78" to the file. - bytes_written = WriteFully(file, 0, append_data_to_write, kAppendDataSize); - EXPECT_EQ(kAppendDataSize, bytes_written); - - // Read the entire file. - char data_read_1[32]; - int bytes_read = ReadFully(file, 0, data_read_1, - kTestDataSize + kAppendDataSize); - EXPECT_EQ(kTestDataSize + kAppendDataSize, bytes_read); - for (int i = 0; i < kTestDataSize; i++) - EXPECT_EQ(data_to_write[i], data_read_1[i]); - for (int i = 0; i < kAppendDataSize; i++) - EXPECT_EQ(append_data_to_write[i], data_read_1[kTestDataSize + i]); - - // Close the file handle to allow the temp directory to be deleted. - base::ClosePlatformFile(file); -} - - -TEST(PlatformFile, TruncatePlatformFile) { - base::ScopedTempDir temp_dir; - ASSERT_TRUE(temp_dir.CreateUniqueTempDir()); - FilePath file_path = temp_dir.path().AppendASCII("truncate_file"); - base::PlatformFile file = base::CreatePlatformFile( - file_path, - base::PLATFORM_FILE_CREATE | base::PLATFORM_FILE_READ | - base::PLATFORM_FILE_WRITE, - NULL, - NULL); - EXPECT_NE(base::kInvalidPlatformFileValue, file); - - // Write "test" to the file. - char data_to_write[] = "test"; - int kTestDataSize = 4; - int bytes_written = WriteFully(file, 0, data_to_write, kTestDataSize); - EXPECT_EQ(kTestDataSize, bytes_written); - - // Extend the file. - const int kExtendedFileLength = 10; - int64 file_size = 0; - EXPECT_TRUE(base::TruncatePlatformFile(file, kExtendedFileLength)); - EXPECT_TRUE(file_util::GetFileSize(file_path, &file_size)); - EXPECT_EQ(kExtendedFileLength, file_size); - - // Make sure the file was zero-padded. - char data_read[32]; - int bytes_read = ReadFully(file, 0, data_read, static_cast(file_size)); - EXPECT_EQ(file_size, bytes_read); - for (int i = 0; i < kTestDataSize; i++) - EXPECT_EQ(data_to_write[i], data_read[i]); - for (int i = kTestDataSize; i < file_size; i++) - EXPECT_EQ(0, data_read[i]); - - // Truncate the file. - const int kTruncatedFileLength = 2; - EXPECT_TRUE(base::TruncatePlatformFile(file, kTruncatedFileLength)); - EXPECT_TRUE(file_util::GetFileSize(file_path, &file_size)); - EXPECT_EQ(kTruncatedFileLength, file_size); - - // Make sure the file was truncated. - bytes_read = ReadFully(file, 0, data_read, kTestDataSize); - EXPECT_EQ(file_size, bytes_read); - for (int i = 0; i < file_size; i++) - EXPECT_EQ(data_to_write[i], data_read[i]); - - // Close the file handle to allow the temp directory to be deleted. - base::ClosePlatformFile(file); -} - -// Flakily fails: http://crbug.com/86494 -#if defined(OS_ANDROID) -TEST(PlatformFile, TouchGetInfoPlatformFile) { -#else -TEST(PlatformFile, DISABLED_TouchGetInfoPlatformFile) { -#endif - base::ScopedTempDir temp_dir; - ASSERT_TRUE(temp_dir.CreateUniqueTempDir()); - base::PlatformFile file = base::CreatePlatformFile( - temp_dir.path().AppendASCII("touch_get_info_file"), - base::PLATFORM_FILE_CREATE | base::PLATFORM_FILE_WRITE | - base::PLATFORM_FILE_WRITE_ATTRIBUTES, - NULL, - NULL); - EXPECT_NE(base::kInvalidPlatformFileValue, file); - - // Get info for a newly created file. - base::PlatformFileInfo info; - EXPECT_TRUE(base::GetPlatformFileInfo(file, &info)); - - // Add 2 seconds to account for possible rounding errors on - // filesystems that use a 1s or 2s timestamp granularity. - base::Time now = base::Time::Now() + base::TimeDelta::FromSeconds(2); - EXPECT_EQ(0, info.size); - EXPECT_FALSE(info.is_directory); - EXPECT_FALSE(info.is_symbolic_link); - EXPECT_LE(info.last_accessed.ToInternalValue(), now.ToInternalValue()); - EXPECT_LE(info.last_modified.ToInternalValue(), now.ToInternalValue()); - EXPECT_LE(info.creation_time.ToInternalValue(), now.ToInternalValue()); - base::Time creation_time = info.creation_time; - - // Write "test" to the file. - char data[] = "test"; - const int kTestDataSize = 4; - int bytes_written = WriteFully(file, 0, data, kTestDataSize); - EXPECT_EQ(kTestDataSize, bytes_written); - - // Change the last_accessed and last_modified dates. - // It's best to add values that are multiples of 2 (in seconds) - // to the current last_accessed and last_modified times, because - // FATxx uses a 2s timestamp granularity. - base::Time new_last_accessed = - info.last_accessed + base::TimeDelta::FromSeconds(234); - base::Time new_last_modified = - info.last_modified + base::TimeDelta::FromMinutes(567); - - EXPECT_TRUE(base::TouchPlatformFile(file, new_last_accessed, - new_last_modified)); - - // Make sure the file info was updated accordingly. - EXPECT_TRUE(base::GetPlatformFileInfo(file, &info)); - EXPECT_EQ(info.size, kTestDataSize); - EXPECT_FALSE(info.is_directory); - EXPECT_FALSE(info.is_symbolic_link); - - // ext2/ext3 and HPS/HPS+ seem to have a timestamp granularity of 1s. -#if defined(OS_POSIX) - EXPECT_EQ(info.last_accessed.ToTimeVal().tv_sec, - new_last_accessed.ToTimeVal().tv_sec); - EXPECT_EQ(info.last_modified.ToTimeVal().tv_sec, - new_last_modified.ToTimeVal().tv_sec); -#else - EXPECT_EQ(info.last_accessed.ToInternalValue(), - new_last_accessed.ToInternalValue()); - EXPECT_EQ(info.last_modified.ToInternalValue(), - new_last_modified.ToInternalValue()); -#endif - - EXPECT_EQ(info.creation_time.ToInternalValue(), - creation_time.ToInternalValue()); - - // Close the file handle to allow the temp directory to be deleted. - base::ClosePlatformFile(file); -} diff --git a/base/platform_file_win.cc b/base/platform_file_win.cc deleted file mode 100644 index c5b49fa7e8..0000000000 --- a/base/platform_file_win.cc +++ /dev/null @@ -1,301 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "base/platform_file.h" - -#include - -#include "base/files/file_path.h" -#include "base/logging.h" -#include "base/metrics/sparse_histogram.h" -#include "base/threading/thread_restrictions.h" - -namespace base { -PlatformFile CreatePlatformFileUnsafe(const FilePath& name, - int flags, - bool* created, - PlatformFileError* error) { - base::ThreadRestrictions::AssertIOAllowed(); - - DWORD disposition = 0; - if (created) - *created = false; - - if (flags & PLATFORM_FILE_OPEN) - disposition = OPEN_EXISTING; - - if (flags & PLATFORM_FILE_CREATE) { - DCHECK(!disposition); - disposition = CREATE_NEW; - } - - if (flags & PLATFORM_FILE_OPEN_ALWAYS) { - DCHECK(!disposition); - disposition = OPEN_ALWAYS; - } - - if (flags & PLATFORM_FILE_CREATE_ALWAYS) { - DCHECK(!disposition); - disposition = CREATE_ALWAYS; - } - - if (flags & PLATFORM_FILE_OPEN_TRUNCATED) { - DCHECK(!disposition); - DCHECK(flags & PLATFORM_FILE_WRITE); - disposition = TRUNCATE_EXISTING; - } - - if (!disposition) { - NOTREACHED(); - return NULL; - } - - DWORD access = 0; - if (flags & PLATFORM_FILE_WRITE) - access = GENERIC_WRITE; - if (flags & PLATFORM_FILE_APPEND) { - DCHECK(!access); - access = FILE_APPEND_DATA; - } - if (flags & PLATFORM_FILE_READ) - access |= GENERIC_READ; - if (flags & PLATFORM_FILE_WRITE_ATTRIBUTES) - access |= FILE_WRITE_ATTRIBUTES; - if (flags & PLATFORM_FILE_EXECUTE) - access |= GENERIC_EXECUTE; - - DWORD sharing = (flags & PLATFORM_FILE_EXCLUSIVE_READ) ? 0 : FILE_SHARE_READ; - if (!(flags & PLATFORM_FILE_EXCLUSIVE_WRITE)) - sharing |= FILE_SHARE_WRITE; - if (flags & PLATFORM_FILE_SHARE_DELETE) - sharing |= FILE_SHARE_DELETE; - - DWORD create_flags = 0; - if (flags & PLATFORM_FILE_ASYNC) - create_flags |= FILE_FLAG_OVERLAPPED; - if (flags & PLATFORM_FILE_TEMPORARY) - create_flags |= FILE_ATTRIBUTE_TEMPORARY; - if (flags & PLATFORM_FILE_HIDDEN) - create_flags |= FILE_ATTRIBUTE_HIDDEN; - if (flags & PLATFORM_FILE_DELETE_ON_CLOSE) - create_flags |= FILE_FLAG_DELETE_ON_CLOSE; - if (flags & PLATFORM_FILE_BACKUP_SEMANTICS) - create_flags |= FILE_FLAG_BACKUP_SEMANTICS; - - HANDLE file = CreateFile(name.value().c_str(), access, sharing, NULL, - disposition, create_flags, NULL); - - if (created && (INVALID_HANDLE_VALUE != file)) { - if (flags & (PLATFORM_FILE_OPEN_ALWAYS)) - *created = (ERROR_ALREADY_EXISTS != GetLastError()); - else if (flags & (PLATFORM_FILE_CREATE_ALWAYS | PLATFORM_FILE_CREATE)) - *created = true; - } - - if (error) { - if (file != kInvalidPlatformFileValue) - *error = PLATFORM_FILE_OK; - else - *error = LastErrorToPlatformFileError(GetLastError()); - } - - return file; -} - -FILE* FdopenPlatformFile(PlatformFile file, const char* mode) { - if (file == kInvalidPlatformFileValue) - return NULL; - int fd = _open_osfhandle(reinterpret_cast(file), 0); - if (fd < 0) - return NULL; - return _fdopen(fd, mode); -} - -bool ClosePlatformFile(PlatformFile file) { - base::ThreadRestrictions::AssertIOAllowed(); - return (CloseHandle(file) != 0); -} - -int64 SeekPlatformFile(PlatformFile file, - PlatformFileWhence whence, - int64 offset) { - base::ThreadRestrictions::AssertIOAllowed(); - if (file == kInvalidPlatformFileValue || offset < 0) - return -1; - - LARGE_INTEGER distance, res; - distance.QuadPart = offset; - DWORD move_method = static_cast(whence); - if (!SetFilePointerEx(file, distance, &res, move_method)) - return -1; - return res.QuadPart; -} - -int ReadPlatformFile(PlatformFile file, int64 offset, char* data, int size) { - base::ThreadRestrictions::AssertIOAllowed(); - if (file == kInvalidPlatformFileValue) - return -1; - - LARGE_INTEGER offset_li; - offset_li.QuadPart = offset; - - OVERLAPPED overlapped = {0}; - overlapped.Offset = offset_li.LowPart; - overlapped.OffsetHigh = offset_li.HighPart; - - DWORD bytes_read; - if (::ReadFile(file, data, size, &bytes_read, &overlapped) != 0) - return bytes_read; - else if (ERROR_HANDLE_EOF == GetLastError()) - return 0; - - return -1; -} - -int ReadPlatformFileAtCurrentPos(PlatformFile file, char* data, int size) { - return ReadPlatformFile(file, 0, data, size); -} - -int ReadPlatformFileNoBestEffort(PlatformFile file, int64 offset, char* data, - int size) { - return ReadPlatformFile(file, offset, data, size); -} - -int ReadPlatformFileCurPosNoBestEffort(PlatformFile file, - char* data, int size) { - return ReadPlatformFile(file, 0, data, size); -} - -int WritePlatformFile(PlatformFile file, int64 offset, - const char* data, int size) { - base::ThreadRestrictions::AssertIOAllowed(); - if (file == kInvalidPlatformFileValue) - return -1; - - LARGE_INTEGER offset_li; - offset_li.QuadPart = offset; - - OVERLAPPED overlapped = {0}; - overlapped.Offset = offset_li.LowPart; - overlapped.OffsetHigh = offset_li.HighPart; - - DWORD bytes_written; - if (::WriteFile(file, data, size, &bytes_written, &overlapped) != 0) - return bytes_written; - - return -1; -} - -int WritePlatformFileAtCurrentPos(PlatformFile file, const char* data, - int size) { - return WritePlatformFile(file, 0, data, size); -} - -int WritePlatformFileCurPosNoBestEffort(PlatformFile file, - const char* data, int size) { - return WritePlatformFile(file, 0, data, size); -} - -bool TruncatePlatformFile(PlatformFile file, int64 length) { - base::ThreadRestrictions::AssertIOAllowed(); - if (file == kInvalidPlatformFileValue) - return false; - - // Get the current file pointer. - LARGE_INTEGER file_pointer; - LARGE_INTEGER zero; - zero.QuadPart = 0; - if (::SetFilePointerEx(file, zero, &file_pointer, FILE_CURRENT) == 0) - return false; - - LARGE_INTEGER length_li; - length_li.QuadPart = length; - // If length > file size, SetFilePointerEx() should extend the file - // with zeroes on all Windows standard file systems (NTFS, FATxx). - if (!::SetFilePointerEx(file, length_li, NULL, FILE_BEGIN)) - return false; - - // Set the new file length and move the file pointer to its old position. - // This is consistent with ftruncate()'s behavior, even when the file - // pointer points to a location beyond the end of the file. - return ((::SetEndOfFile(file) != 0) && - (::SetFilePointerEx(file, file_pointer, NULL, FILE_BEGIN) != 0)); -} - -bool FlushPlatformFile(PlatformFile file) { - base::ThreadRestrictions::AssertIOAllowed(); - return ((file != kInvalidPlatformFileValue) && ::FlushFileBuffers(file)); -} - -bool TouchPlatformFile(PlatformFile file, const base::Time& last_access_time, - const base::Time& last_modified_time) { - base::ThreadRestrictions::AssertIOAllowed(); - if (file == kInvalidPlatformFileValue) - return false; - - FILETIME last_access_filetime = last_access_time.ToFileTime(); - FILETIME last_modified_filetime = last_modified_time.ToFileTime(); - return (::SetFileTime(file, NULL, &last_access_filetime, - &last_modified_filetime) != 0); -} - -bool GetPlatformFileInfo(PlatformFile file, PlatformFileInfo* info) { - base::ThreadRestrictions::AssertIOAllowed(); - if (!info) - return false; - - BY_HANDLE_FILE_INFORMATION file_info; - if (GetFileInformationByHandle(file, &file_info) == 0) - return false; - - LARGE_INTEGER size; - size.HighPart = file_info.nFileSizeHigh; - size.LowPart = file_info.nFileSizeLow; - info->size = size.QuadPart; - info->is_directory = - (file_info.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) != 0; - info->is_symbolic_link = false; // Windows doesn't have symbolic links. - info->last_modified = base::Time::FromFileTime(file_info.ftLastWriteTime); - info->last_accessed = base::Time::FromFileTime(file_info.ftLastAccessTime); - info->creation_time = base::Time::FromFileTime(file_info.ftCreationTime); - return true; -} - -PlatformFileError LastErrorToPlatformFileError(DWORD last_error) { - switch (last_error) { - case ERROR_SHARING_VIOLATION: - return PLATFORM_FILE_ERROR_IN_USE; - case ERROR_FILE_EXISTS: - return PLATFORM_FILE_ERROR_EXISTS; - case ERROR_FILE_NOT_FOUND: - case ERROR_PATH_NOT_FOUND: - return PLATFORM_FILE_ERROR_NOT_FOUND; - case ERROR_ACCESS_DENIED: - return PLATFORM_FILE_ERROR_ACCESS_DENIED; - case ERROR_TOO_MANY_OPEN_FILES: - return PLATFORM_FILE_ERROR_TOO_MANY_OPENED; - case ERROR_OUTOFMEMORY: - case ERROR_NOT_ENOUGH_MEMORY: - return PLATFORM_FILE_ERROR_NO_MEMORY; - case ERROR_HANDLE_DISK_FULL: - case ERROR_DISK_FULL: - case ERROR_DISK_RESOURCES_EXHAUSTED: - return PLATFORM_FILE_ERROR_NO_SPACE; - case ERROR_USER_MAPPED_FILE: - return PLATFORM_FILE_ERROR_INVALID_OPERATION; - case ERROR_NOT_READY: - case ERROR_SECTOR_NOT_FOUND: - case ERROR_DEV_NOT_EXIST: - case ERROR_IO_DEVICE: - case ERROR_FILE_CORRUPT: - case ERROR_DISK_CORRUPT: - return PLATFORM_FILE_ERROR_IO; - default: - UMA_HISTOGRAM_SPARSE_SLOWLY("PlatformFile.UnknownErrors.Windows", - last_error); - return PLATFORM_FILE_ERROR_FAILED; - } -} - -} // namespace base diff --git a/base/port.h b/base/port.h deleted file mode 100644 index af4e450afe..0000000000 --- a/base/port.h +++ /dev/null @@ -1,54 +0,0 @@ -// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef BASE_PORT_H_ -#define BASE_PORT_H_ - -#include -#include "build/build_config.h" - -#ifdef COMPILER_MSVC -#define GG_LONGLONG(x) x##I64 -#define GG_ULONGLONG(x) x##UI64 -#else -#define GG_LONGLONG(x) x##LL -#define GG_ULONGLONG(x) x##ULL -#endif - -// Per C99 7.8.14, define __STDC_CONSTANT_MACROS before including -// to get the INTn_C and UINTn_C macros for integer constants. It's difficult -// to guarantee any specific ordering of header includes, so it's difficult to -// guarantee that the INTn_C macros can be defined by including at -// any specific point. Provide GG_INTn_C macros instead. - -#define GG_INT8_C(x) (x) -#define GG_INT16_C(x) (x) -#define GG_INT32_C(x) (x) -#define GG_INT64_C(x) GG_LONGLONG(x) - -#define GG_UINT8_C(x) (x ## U) -#define GG_UINT16_C(x) (x ## U) -#define GG_UINT32_C(x) (x ## U) -#define GG_UINT64_C(x) GG_ULONGLONG(x) - -// It's possible for functions that use a va_list, such as StringPrintf, to -// invalidate the data in it upon use. The fix is to make a copy of the -// structure before using it and use that copy instead. va_copy is provided -// for this purpose. MSVC does not provide va_copy, so define an -// implementation here. It is not guaranteed that assignment is a copy, so the -// StringUtil.VariableArgsFunc unit test tests this capability. -#if defined(COMPILER_GCC) -#define GG_VA_COPY(a, b) (va_copy(a, b)) -#elif defined(COMPILER_MSVC) -#define GG_VA_COPY(a, b) (a = b) -#endif - -// Define an OS-neutral wrapper for shared library entry points -#if defined(OS_WIN) -#define API_CALL __stdcall -#else -#define API_CALL -#endif - -#endif // BASE_PORT_H_ diff --git a/base/posix/eintr_wrapper.h b/base/posix/eintr_wrapper.h deleted file mode 100644 index 8e26752337..0000000000 --- a/base/posix/eintr_wrapper.h +++ /dev/null @@ -1,51 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -// This provides a wrapper around system calls which may be interrupted by a -// signal and return EINTR. See man 7 signal. -// To prevent long-lasting loops (which would likely be a bug, such as a signal -// that should be masked) to go unnoticed, there is a limit after which the -// caller will nonetheless see an EINTR in Debug builds. -// -// On Windows, this wrapper macro does nothing. - -#ifndef BASE_POSIX_EINTR_WRAPPER_H_ -#define BASE_POSIX_EINTR_WRAPPER_H_ - -#include "build/build_config.h" - -#if defined(OS_POSIX) - -#include - -#if defined(NDEBUG) -#define HANDLE_EINTR(x) ({ \ - typeof(x) eintr_wrapper_result; \ - do { \ - eintr_wrapper_result = (x); \ - } while (eintr_wrapper_result == -1 && errno == EINTR); \ - eintr_wrapper_result; \ -}) - -#else - -#define HANDLE_EINTR(x) ({ \ - int eintr_wrapper_counter = 0; \ - typeof(x) eintr_wrapper_result; \ - do { \ - eintr_wrapper_result = (x); \ - } while (eintr_wrapper_result == -1 && errno == EINTR && \ - eintr_wrapper_counter++ < 100); \ - eintr_wrapper_result; \ -}) - -#endif // NDEBUG - -#else - -#define HANDLE_EINTR(x) (x) - -#endif // OS_POSIX - -#endif // BASE_POSIX_EINTR_WRAPPER_H_ diff --git a/base/posix/file_descriptor_shuffle.cc b/base/posix/file_descriptor_shuffle.cc deleted file mode 100644 index b5b7339bdf..0000000000 --- a/base/posix/file_descriptor_shuffle.cc +++ /dev/null @@ -1,96 +0,0 @@ -// Copyright (c) 2011 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "base/posix/file_descriptor_shuffle.h" - -#include -#include -#include - -#include "base/posix/eintr_wrapper.h" -#include "base/logging.h" - -namespace base { - -bool PerformInjectiveMultimapDestructive( - InjectiveMultimap* m, InjectionDelegate* delegate) { - static const size_t kMaxExtraFDs = 16; - int extra_fds[kMaxExtraFDs]; - unsigned next_extra_fd = 0; - - // DANGER: this function may not allocate. - - for (InjectiveMultimap::iterator i = m->begin(); i != m->end(); ++i) { - int temp_fd = -1; - - // We DCHECK the injectiveness of the mapping. - for (InjectiveMultimap::iterator j = i + 1; j != m->end(); ++j) { - DCHECK(i->dest != j->dest) << "Both fd " << i->source - << " and " << j->source << " map to " << i->dest; - } - - const bool is_identity = i->source == i->dest; - - for (InjectiveMultimap::iterator j = i + 1; j != m->end(); ++j) { - if (!is_identity && i->dest == j->source) { - if (temp_fd == -1) { - if (!delegate->Duplicate(&temp_fd, i->dest)) - return false; - if (next_extra_fd < kMaxExtraFDs) { - extra_fds[next_extra_fd++] = temp_fd; - } else { - RAW_LOG(ERROR, "PerformInjectiveMultimapDestructive overflowed " - "extra_fds. Leaking file descriptors!"); - } - } - - j->source = temp_fd; - j->close = false; - } - - if (i->close && i->source == j->dest) - i->close = false; - - if (i->close && i->source == j->source) { - i->close = false; - j->close = true; - } - } - - if (!is_identity) { - if (!delegate->Move(i->source, i->dest)) - return false; - } - - if (!is_identity && i->close) - delegate->Close(i->source); - } - - for (unsigned i = 0; i < next_extra_fd; i++) - delegate->Close(extra_fds[i]); - - return true; -} - -bool PerformInjectiveMultimap(const InjectiveMultimap& m_in, - InjectionDelegate* delegate) { - InjectiveMultimap m(m_in); - return PerformInjectiveMultimapDestructive(&m, delegate); -} - -bool FileDescriptorTableInjection::Duplicate(int* result, int fd) { - *result = HANDLE_EINTR(dup(fd)); - return *result >= 0; -} - -bool FileDescriptorTableInjection::Move(int src, int dest) { - return HANDLE_EINTR(dup2(src, dest)) != -1; -} - -void FileDescriptorTableInjection::Close(int fd) { - int ret = HANDLE_EINTR(close(fd)); - DPCHECK(ret == 0); -} - -} // namespace base diff --git a/base/posix/file_descriptor_shuffle.h b/base/posix/file_descriptor_shuffle.h deleted file mode 100644 index 9cd918f2e1..0000000000 --- a/base/posix/file_descriptor_shuffle.h +++ /dev/null @@ -1,87 +0,0 @@ -// Copyright (c) 2011 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef BASE_POSIX_FILE_DESCRIPTOR_SHUFFLE_H_ -#define BASE_POSIX_FILE_DESCRIPTOR_SHUFFLE_H_ - -// This code exists to perform the shuffling of file descriptors which is -// commonly needed when forking subprocesses. The naive approve is very simple, -// just call dup2 to setup the desired descriptors, but wrong. It's tough to -// handle the edge cases (like mapping 0 -> 1, 1 -> 0) correctly. -// -// In order to unittest this code, it's broken into the abstract action (an -// injective multimap) and the concrete code for dealing with file descriptors. -// Users should use the code like this: -// base::InjectiveMultimap file_descriptor_map; -// file_descriptor_map.push_back(base::InjectionArc(devnull, 0, true)); -// file_descriptor_map.push_back(base::InjectionArc(devnull, 2, true)); -// file_descriptor_map.push_back(base::InjectionArc(pipe[1], 1, true)); -// base::ShuffleFileDescriptors(file_descriptor_map); -// -// and trust the the Right Thing will get done. - -#include - -#include "base/base_export.h" -#include "base/compiler_specific.h" - -namespace base { - -// A Delegate which performs the actions required to perform an injective -// multimapping in place. -class InjectionDelegate { - public: - // Duplicate |fd|, an element of the domain, and write a fresh element of the - // domain into |result|. Returns true iff successful. - virtual bool Duplicate(int* result, int fd) = 0; - // Destructively move |src| to |dest|, overwriting |dest|. Returns true iff - // successful. - virtual bool Move(int src, int dest) = 0; - // Delete an element of the domain. - virtual void Close(int fd) = 0; - - protected: - virtual ~InjectionDelegate() {} -}; - -// An implementation of the InjectionDelegate interface using the file -// descriptor table of the current process as the domain. -class BASE_EXPORT FileDescriptorTableInjection : public InjectionDelegate { - virtual bool Duplicate(int* result, int fd) OVERRIDE; - virtual bool Move(int src, int dest) OVERRIDE; - virtual void Close(int fd) OVERRIDE; -}; - -// A single arc of the directed graph which describes an injective multimapping. -struct InjectionArc { - InjectionArc(int in_source, int in_dest, bool in_close) - : source(in_source), - dest(in_dest), - close(in_close) { - } - - int source; - int dest; - bool close; // if true, delete the source element after performing the - // mapping. -}; - -typedef std::vector InjectiveMultimap; - -BASE_EXPORT bool PerformInjectiveMultimap(const InjectiveMultimap& map, - InjectionDelegate* delegate); - -BASE_EXPORT bool PerformInjectiveMultimapDestructive( - InjectiveMultimap* map, - InjectionDelegate* delegate); - -// This function will not call malloc but will mutate |map| -static inline bool ShuffleFileDescriptors(InjectiveMultimap* map) { - FileDescriptorTableInjection delegate; - return PerformInjectiveMultimapDestructive(map, &delegate); -} - -} // namespace base - -#endif // BASE_POSIX_FILE_DESCRIPTOR_SHUFFLE_H_ diff --git a/base/posix/file_descriptor_shuffle_unittest.cc b/base/posix/file_descriptor_shuffle_unittest.cc deleted file mode 100644 index 9e1b25000e..0000000000 --- a/base/posix/file_descriptor_shuffle_unittest.cc +++ /dev/null @@ -1,287 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "base/posix/file_descriptor_shuffle.h" -#include "testing/gtest/include/gtest/gtest.h" - -namespace { - -// 'Duplicated' file descriptors start at this number -const int kDuplicateBase = 1000; - -} // namespace - -namespace base { - -struct Action { - enum Type { - CLOSE, - MOVE, - DUPLICATE, - }; - - Action(Type in_type, int in_fd1, int in_fd2 = -1) - : type(in_type), - fd1(in_fd1), - fd2(in_fd2) { - } - - bool operator==(const Action& other) const { - return other.type == type && - other.fd1 == fd1 && - other.fd2 == fd2; - } - - Type type; - int fd1; - int fd2; -}; - -class InjectionTracer : public InjectionDelegate { - public: - InjectionTracer() - : next_duplicate_(kDuplicateBase) { - } - - virtual bool Duplicate(int* result, int fd) OVERRIDE { - *result = next_duplicate_++; - actions_.push_back(Action(Action::DUPLICATE, *result, fd)); - return true; - } - - virtual bool Move(int src, int dest) OVERRIDE { - actions_.push_back(Action(Action::MOVE, src, dest)); - return true; - } - - virtual void Close(int fd) OVERRIDE { - actions_.push_back(Action(Action::CLOSE, fd)); - } - - const std::vector& actions() const { return actions_; } - - private: - int next_duplicate_; - std::vector actions_; -}; - -TEST(FileDescriptorShuffleTest, Empty) { - InjectiveMultimap map; - InjectionTracer tracer; - - EXPECT_TRUE(PerformInjectiveMultimap(map, &tracer)); - EXPECT_EQ(0u, tracer.actions().size()); -} - -TEST(FileDescriptorShuffleTest, Noop) { - InjectiveMultimap map; - InjectionTracer tracer; - map.push_back(InjectionArc(0, 0, false)); - - EXPECT_TRUE(PerformInjectiveMultimap(map, &tracer)); - EXPECT_EQ(0u, tracer.actions().size()); -} - -TEST(FileDescriptorShuffleTest, NoopAndClose) { - InjectiveMultimap map; - InjectionTracer tracer; - map.push_back(InjectionArc(0, 0, true)); - - EXPECT_TRUE(PerformInjectiveMultimap(map, &tracer)); - EXPECT_EQ(0u, tracer.actions().size()); -} - -TEST(FileDescriptorShuffleTest, Simple1) { - InjectiveMultimap map; - InjectionTracer tracer; - map.push_back(InjectionArc(0, 1, false)); - - EXPECT_TRUE(PerformInjectiveMultimap(map, &tracer)); - ASSERT_EQ(1u, tracer.actions().size()); - EXPECT_TRUE(tracer.actions()[0] == Action(Action::MOVE, 0, 1)); -} - -TEST(FileDescriptorShuffleTest, Simple2) { - InjectiveMultimap map; - InjectionTracer tracer; - map.push_back(InjectionArc(0, 1, false)); - map.push_back(InjectionArc(2, 3, false)); - - EXPECT_TRUE(PerformInjectiveMultimap(map, &tracer)); - ASSERT_EQ(2u, tracer.actions().size()); - EXPECT_TRUE(tracer.actions()[0] == Action(Action::MOVE, 0, 1)); - EXPECT_TRUE(tracer.actions()[1] == Action(Action::MOVE, 2, 3)); -} - -TEST(FileDescriptorShuffleTest, Simple3) { - InjectiveMultimap map; - InjectionTracer tracer; - map.push_back(InjectionArc(0, 1, true)); - - EXPECT_TRUE(PerformInjectiveMultimap(map, &tracer)); - ASSERT_EQ(2u, tracer.actions().size()); - EXPECT_TRUE(tracer.actions()[0] == Action(Action::MOVE, 0, 1)); - EXPECT_TRUE(tracer.actions()[1] == Action(Action::CLOSE, 0)); -} - -TEST(FileDescriptorShuffleTest, Simple4) { - InjectiveMultimap map; - InjectionTracer tracer; - map.push_back(InjectionArc(10, 0, true)); - map.push_back(InjectionArc(1, 1, true)); - - EXPECT_TRUE(PerformInjectiveMultimap(map, &tracer)); - ASSERT_EQ(2u, tracer.actions().size()); - EXPECT_TRUE(tracer.actions()[0] == Action(Action::MOVE, 10, 0)); - EXPECT_TRUE(tracer.actions()[1] == Action(Action::CLOSE, 10)); -} - -TEST(FileDescriptorShuffleTest, Cycle) { - InjectiveMultimap map; - InjectionTracer tracer; - map.push_back(InjectionArc(0, 1, false)); - map.push_back(InjectionArc(1, 0, false)); - - EXPECT_TRUE(PerformInjectiveMultimap(map, &tracer)); - ASSERT_EQ(4u, tracer.actions().size()); - EXPECT_TRUE(tracer.actions()[0] == - Action(Action::DUPLICATE, kDuplicateBase, 1)); - EXPECT_TRUE(tracer.actions()[1] == Action(Action::MOVE, 0, 1)); - EXPECT_TRUE(tracer.actions()[2] == Action(Action::MOVE, kDuplicateBase, 0)); - EXPECT_TRUE(tracer.actions()[3] == Action(Action::CLOSE, kDuplicateBase)); -} - -TEST(FileDescriptorShuffleTest, CycleAndClose1) { - InjectiveMultimap map; - InjectionTracer tracer; - map.push_back(InjectionArc(0, 1, true)); - map.push_back(InjectionArc(1, 0, false)); - - EXPECT_TRUE(PerformInjectiveMultimap(map, &tracer)); - ASSERT_EQ(4u, tracer.actions().size()); - EXPECT_TRUE(tracer.actions()[0] == - Action(Action::DUPLICATE, kDuplicateBase, 1)); - EXPECT_TRUE(tracer.actions()[1] == Action(Action::MOVE, 0, 1)); - EXPECT_TRUE(tracer.actions()[2] == Action(Action::MOVE, kDuplicateBase, 0)); - EXPECT_TRUE(tracer.actions()[3] == Action(Action::CLOSE, kDuplicateBase)); -} - -TEST(FileDescriptorShuffleTest, CycleAndClose2) { - InjectiveMultimap map; - InjectionTracer tracer; - map.push_back(InjectionArc(0, 1, false)); - map.push_back(InjectionArc(1, 0, true)); - - EXPECT_TRUE(PerformInjectiveMultimap(map, &tracer)); - ASSERT_EQ(4u, tracer.actions().size()); - EXPECT_TRUE(tracer.actions()[0] == - Action(Action::DUPLICATE, kDuplicateBase, 1)); - EXPECT_TRUE(tracer.actions()[1] == Action(Action::MOVE, 0, 1)); - EXPECT_TRUE(tracer.actions()[2] == Action(Action::MOVE, kDuplicateBase, 0)); - EXPECT_TRUE(tracer.actions()[3] == Action(Action::CLOSE, kDuplicateBase)); -} - -TEST(FileDescriptorShuffleTest, CycleAndClose3) { - InjectiveMultimap map; - InjectionTracer tracer; - map.push_back(InjectionArc(0, 1, true)); - map.push_back(InjectionArc(1, 0, true)); - - EXPECT_TRUE(PerformInjectiveMultimap(map, &tracer)); - ASSERT_EQ(4u, tracer.actions().size()); - EXPECT_TRUE(tracer.actions()[0] == - Action(Action::DUPLICATE, kDuplicateBase, 1)); - EXPECT_TRUE(tracer.actions()[1] == Action(Action::MOVE, 0, 1)); - EXPECT_TRUE(tracer.actions()[2] == Action(Action::MOVE, kDuplicateBase, 0)); - EXPECT_TRUE(tracer.actions()[3] == Action(Action::CLOSE, kDuplicateBase)); -} - -TEST(FileDescriptorShuffleTest, Fanout) { - InjectiveMultimap map; - InjectionTracer tracer; - map.push_back(InjectionArc(0, 1, false)); - map.push_back(InjectionArc(0, 2, false)); - - EXPECT_TRUE(PerformInjectiveMultimap(map, &tracer)); - ASSERT_EQ(2u, tracer.actions().size()); - EXPECT_TRUE(tracer.actions()[0] == Action(Action::MOVE, 0, 1)); - EXPECT_TRUE(tracer.actions()[1] == Action(Action::MOVE, 0, 2)); -} - -TEST(FileDescriptorShuffleTest, FanoutAndClose1) { - InjectiveMultimap map; - InjectionTracer tracer; - map.push_back(InjectionArc(0, 1, true)); - map.push_back(InjectionArc(0, 2, false)); - - EXPECT_TRUE(PerformInjectiveMultimap(map, &tracer)); - ASSERT_EQ(3u, tracer.actions().size()); - EXPECT_TRUE(tracer.actions()[0] == Action(Action::MOVE, 0, 1)); - EXPECT_TRUE(tracer.actions()[1] == Action(Action::MOVE, 0, 2)); - EXPECT_TRUE(tracer.actions()[2] == Action(Action::CLOSE, 0)); -} - -TEST(FileDescriptorShuffleTest, FanoutAndClose2) { - InjectiveMultimap map; - InjectionTracer tracer; - map.push_back(InjectionArc(0, 1, false)); - map.push_back(InjectionArc(0, 2, true)); - - EXPECT_TRUE(PerformInjectiveMultimap(map, &tracer)); - ASSERT_EQ(3u, tracer.actions().size()); - EXPECT_TRUE(tracer.actions()[0] == Action(Action::MOVE, 0, 1)); - EXPECT_TRUE(tracer.actions()[1] == Action(Action::MOVE, 0, 2)); - EXPECT_TRUE(tracer.actions()[2] == Action(Action::CLOSE, 0)); -} - -TEST(FileDescriptorShuffleTest, FanoutAndClose3) { - InjectiveMultimap map; - InjectionTracer tracer; - map.push_back(InjectionArc(0, 1, true)); - map.push_back(InjectionArc(0, 2, true)); - - EXPECT_TRUE(PerformInjectiveMultimap(map, &tracer)); - ASSERT_EQ(3u, tracer.actions().size()); - EXPECT_TRUE(tracer.actions()[0] == Action(Action::MOVE, 0, 1)); - EXPECT_TRUE(tracer.actions()[1] == Action(Action::MOVE, 0, 2)); - EXPECT_TRUE(tracer.actions()[2] == Action(Action::CLOSE, 0)); -} - -class FailingDelegate : public InjectionDelegate { - public: - virtual bool Duplicate(int* result, int fd) OVERRIDE { - return false; - } - - virtual bool Move(int src, int dest) OVERRIDE { - return false; - } - - virtual void Close(int fd) OVERRIDE {} -}; - -TEST(FileDescriptorShuffleTest, EmptyWithFailure) { - InjectiveMultimap map; - FailingDelegate failing; - - EXPECT_TRUE(PerformInjectiveMultimap(map, &failing)); -} - -TEST(FileDescriptorShuffleTest, NoopWithFailure) { - InjectiveMultimap map; - FailingDelegate failing; - map.push_back(InjectionArc(0, 0, false)); - - EXPECT_TRUE(PerformInjectiveMultimap(map, &failing)); -} - -TEST(FileDescriptorShuffleTest, Simple1WithFailure) { - InjectiveMultimap map; - FailingDelegate failing; - map.push_back(InjectionArc(0, 1, false)); - - EXPECT_FALSE(PerformInjectiveMultimap(map, &failing)); -} - -} // namespace base diff --git a/base/posix/global_descriptors.cc b/base/posix/global_descriptors.cc deleted file mode 100644 index bcca443acc..0000000000 --- a/base/posix/global_descriptors.cc +++ /dev/null @@ -1,60 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "base/posix/global_descriptors.h" - -#include -#include - -#include "base/logging.h" - -namespace base { - -// static -GlobalDescriptors* GlobalDescriptors::GetInstance() { - typedef Singleton > - GlobalDescriptorsSingleton; - return GlobalDescriptorsSingleton::get(); -} - -int GlobalDescriptors::Get(Key key) const { - const int ret = MaybeGet(key); - - if (ret == -1) - DLOG(FATAL) << "Unknown global descriptor: " << key; - return ret; -} - -int GlobalDescriptors::MaybeGet(Key key) const { - for (Mapping::const_iterator - i = descriptors_.begin(); i != descriptors_.end(); ++i) { - if (i->first == key) - return i->second; - } - - return -1; -} - -void GlobalDescriptors::Set(Key key, int fd) { - for (Mapping::iterator - i = descriptors_.begin(); i != descriptors_.end(); ++i) { - if (i->first == key) { - i->second = fd; - return; - } - } - - descriptors_.push_back(std::make_pair(key, fd)); -} - -void GlobalDescriptors::Reset(const Mapping& mapping) { - descriptors_ = mapping; -} - -GlobalDescriptors::GlobalDescriptors() {} - -GlobalDescriptors::~GlobalDescriptors() {} - -} // namespace base diff --git a/base/posix/global_descriptors.h b/base/posix/global_descriptors.h deleted file mode 100644 index c7b9f87fa4..0000000000 --- a/base/posix/global_descriptors.h +++ /dev/null @@ -1,70 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef BASE_POSIX_GLOBAL_DESCRIPTORS_H_ -#define BASE_POSIX_GLOBAL_DESCRIPTORS_H_ - -#include "build/build_config.h" - -#include -#include - -#include - -#include "base/memory/singleton.h" - -namespace base { - -// It's common practice to install file descriptors into well known slot -// numbers before execing a child; stdin, stdout and stderr are ubiqutous -// examples. -// -// However, when using a zygote model, this becomes troublesome. Since the -// descriptors which need to be in these slots generally aren't known, any code -// could open a resource and take one of the reserved descriptors. Simply -// overwriting the slot isn't a viable solution. -// -// We could try to fill the reserved slots as soon as possible, but this is a -// fragile solution since global constructors etc are able to open files. -// -// Instead, we retreat from the idea of installing descriptors in specific -// slots and add a layer of indirection in the form of this singleton object. -// It maps from an abstract key to a descriptor. If independent modules each -// need to define keys, then values should be chosen randomly so as not to -// collide. -class BASE_EXPORT GlobalDescriptors { - public: - typedef uint32_t Key; - typedef std::pair KeyFDPair; - typedef std::vector Mapping; - - // Often we want a canonical descriptor for a given Key. In this case, we add - // the following constant to the key value: - static const int kBaseDescriptor = 3; // 0, 1, 2 are already taken. - - // Return the singleton instance of GlobalDescriptors. - static GlobalDescriptors* GetInstance(); - - // Get a descriptor given a key. It is a fatal error if the key is not known. - int Get(Key key) const; - - // Get a descriptor give a key. Returns -1 on error. - int MaybeGet(Key key) const; - - // Set the descriptor for the given key. - void Set(Key key, int fd); - - void Reset(const Mapping& mapping); - - private: - friend struct DefaultSingletonTraits; - GlobalDescriptors(); - ~GlobalDescriptors(); - - Mapping descriptors_; -}; - -} // namespace base - -#endif // BASE_POSIX_GLOBAL_DESCRIPTORS_H_ diff --git a/base/posix/unix_domain_socket_linux.cc b/base/posix/unix_domain_socket_linux.cc deleted file mode 100644 index 757db983cd..0000000000 --- a/base/posix/unix_domain_socket_linux.cc +++ /dev/null @@ -1,173 +0,0 @@ -// Copyright (c) 2011 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "base/posix/unix_domain_socket_linux.h" - -#include -#include -#include -#include - -#include "base/logging.h" -#include "base/pickle.h" -#include "base/posix/eintr_wrapper.h" -#include "base/stl_util.h" - -const size_t UnixDomainSocket::kMaxFileDescriptors = 16; - -// static -bool UnixDomainSocket::SendMsg(int fd, - const void* buf, - size_t length, - const std::vector& fds) { - struct msghdr msg = {}; - struct iovec iov = { const_cast(buf), length }; - msg.msg_iov = &iov; - msg.msg_iovlen = 1; - - char* control_buffer = NULL; - if (fds.size()) { - const unsigned control_len = CMSG_SPACE(sizeof(int) * fds.size()); - control_buffer = new char[control_len]; - - struct cmsghdr* cmsg; - msg.msg_control = control_buffer; - msg.msg_controllen = control_len; - cmsg = CMSG_FIRSTHDR(&msg); - cmsg->cmsg_level = SOL_SOCKET; - cmsg->cmsg_type = SCM_RIGHTS; - cmsg->cmsg_len = CMSG_LEN(sizeof(int) * fds.size()); - memcpy(CMSG_DATA(cmsg), &fds[0], sizeof(int) * fds.size()); - msg.msg_controllen = cmsg->cmsg_len; - } - - // Avoid a SIGPIPE if the other end breaks the connection. - // Due to a bug in the Linux kernel (net/unix/af_unix.c) MSG_NOSIGNAL isn't - // regarded for SOCK_SEQPACKET in the AF_UNIX domain, but it is mandated by - // POSIX. - const int flags = MSG_NOSIGNAL; - const ssize_t r = HANDLE_EINTR(sendmsg(fd, &msg, flags)); - const bool ret = static_cast(length) == r; - delete[] control_buffer; - return ret; -} - -// static -ssize_t UnixDomainSocket::RecvMsg(int fd, - void* buf, - size_t length, - std::vector* fds) { - return UnixDomainSocket::RecvMsgWithFlags(fd, buf, length, 0, fds); -} - -// static -ssize_t UnixDomainSocket::RecvMsgWithFlags(int fd, - void* buf, - size_t length, - int flags, - std::vector* fds) { - fds->clear(); - - struct msghdr msg = {}; - struct iovec iov = { buf, length }; - msg.msg_iov = &iov; - msg.msg_iovlen = 1; - - char control_buffer[CMSG_SPACE(sizeof(int) * kMaxFileDescriptors)]; - msg.msg_control = control_buffer; - msg.msg_controllen = sizeof(control_buffer); - - const ssize_t r = HANDLE_EINTR(recvmsg(fd, &msg, flags)); - if (r == -1) - return -1; - - int* wire_fds = NULL; - unsigned wire_fds_len = 0; - - if (msg.msg_controllen > 0) { - struct cmsghdr* cmsg; - for (cmsg = CMSG_FIRSTHDR(&msg); cmsg; cmsg = CMSG_NXTHDR(&msg, cmsg)) { - if (cmsg->cmsg_level == SOL_SOCKET && - cmsg->cmsg_type == SCM_RIGHTS) { - const unsigned payload_len = cmsg->cmsg_len - CMSG_LEN(0); - DCHECK(payload_len % sizeof(int) == 0); - wire_fds = reinterpret_cast(CMSG_DATA(cmsg)); - wire_fds_len = payload_len / sizeof(int); - break; - } - } - } - - if (msg.msg_flags & MSG_TRUNC || msg.msg_flags & MSG_CTRUNC) { - for (unsigned i = 0; i < wire_fds_len; ++i) - close(wire_fds[i]); - errno = EMSGSIZE; - return -1; - } - - fds->resize(wire_fds_len); - memcpy(vector_as_array(fds), wire_fds, sizeof(int) * wire_fds_len); - - return r; -} - -// static -ssize_t UnixDomainSocket::SendRecvMsg(int fd, - uint8_t* reply, - unsigned max_reply_len, - int* result_fd, - const Pickle& request) { - return UnixDomainSocket::SendRecvMsgWithFlags(fd, reply, max_reply_len, - 0, /* recvmsg_flags */ - result_fd, request); -} - -// static -ssize_t UnixDomainSocket::SendRecvMsgWithFlags(int fd, - uint8_t* reply, - unsigned max_reply_len, - int recvmsg_flags, - int* result_fd, - const Pickle& request) { - int fds[2]; - - // This socketpair is only used for the IPC and is cleaned up before - // returning. - if (socketpair(AF_UNIX, SOCK_SEQPACKET, 0, fds) == -1) - return -1; - - std::vector fd_vector; - fd_vector.push_back(fds[1]); - if (!SendMsg(fd, request.data(), request.size(), fd_vector)) { - close(fds[0]); - close(fds[1]); - return -1; - } - close(fds[1]); - - fd_vector.clear(); - // When porting to OSX keep in mind it doesn't support MSG_NOSIGNAL, so the - // sender might get a SIGPIPE. - const ssize_t reply_len = RecvMsgWithFlags(fds[0], reply, max_reply_len, - recvmsg_flags, &fd_vector); - close(fds[0]); - if (reply_len == -1) - return -1; - - if ((!fd_vector.empty() && result_fd == NULL) || fd_vector.size() > 1) { - for (std::vector::const_iterator - i = fd_vector.begin(); i != fd_vector.end(); ++i) { - close(*i); - } - - NOTREACHED(); - - return -1; - } - - if (result_fd) - *result_fd = fd_vector.empty() ? -1 : fd_vector[0]; - - return reply_len; -} diff --git a/base/posix/unix_domain_socket_linux.h b/base/posix/unix_domain_socket_linux.h deleted file mode 100644 index 66fb8bb1bf..0000000000 --- a/base/posix/unix_domain_socket_linux.h +++ /dev/null @@ -1,76 +0,0 @@ -// Copyright (c) 2011 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef BASE_POSIX_UNIX_DOMAIN_SOCKET_LINUX_H_ -#define BASE_POSIX_UNIX_DOMAIN_SOCKET_LINUX_H_ - -#include -#include -#include - -#include "base/base_export.h" - -class Pickle; - -class BASE_EXPORT UnixDomainSocket { - public: - // Maximum number of file descriptors that can be read by RecvMsg(). - static const size_t kMaxFileDescriptors; - - // Use sendmsg to write the given msg and include a vector of file - // descriptors. Returns true if successful. - static bool SendMsg(int fd, - const void* msg, - size_t length, - const std::vector& fds); - - // Use recvmsg to read a message and an array of file descriptors. Returns - // -1 on failure. Note: will read, at most, |kMaxFileDescriptors| descriptors. - static ssize_t RecvMsg(int fd, - void* msg, - size_t length, - std::vector* fds); - - // Perform a sendmsg/recvmsg pair. - // 1. This process creates a UNIX SEQPACKET socketpair. Using - // connection-oriented sockets (SEQPACKET or STREAM) is critical here, - // because if one of the ends closes the other one must be notified. - // 2. This process writes a request to |fd| with an SCM_RIGHTS control - // message containing on end of the fresh socket pair. - // 3. This process blocks reading from the other end of the fresh - // socketpair. - // 4. The target process receives the request, processes it and writes the - // reply to the end of the socketpair contained in the request. - // 5. This process wakes up and continues. - // - // fd: descriptor to send the request on - // reply: buffer for the reply - // reply_len: size of |reply| - // result_fd: (may be NULL) the file descriptor returned in the reply - // (if any) - // request: the bytes to send in the request - static ssize_t SendRecvMsg(int fd, - uint8_t* reply, - unsigned reply_len, - int* result_fd, - const Pickle& request); - - // Similar to SendRecvMsg(), but |recvmsg_flags| allows to control the flags - // of the recvmsg(2) call. - static ssize_t SendRecvMsgWithFlags(int fd, - uint8_t* reply, - unsigned reply_len, - int recvmsg_flags, - int* result_fd, - const Pickle& request); - private: - // Similar to RecvMsg, but allows to specify |flags| for recvmsg(2). - static ssize_t RecvMsgWithFlags(int fd, - void* msg, - size_t length, - int flags, - std::vector* fds); -}; - -#endif // BASE_POSIX_UNIX_DOMAIN_SOCKET_LINUX_H_ diff --git a/base/posix/unix_domain_socket_linux_unittest.cc b/base/posix/unix_domain_socket_linux_unittest.cc deleted file mode 100644 index 1343555b33..0000000000 --- a/base/posix/unix_domain_socket_linux_unittest.cc +++ /dev/null @@ -1,81 +0,0 @@ -// Copyright (c) 2013 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include -#include -#include - -#include "base/bind.h" -#include "base/bind_helpers.h" -#include "base/file_util.h" -#include "base/pickle.h" -#include "base/posix/unix_domain_socket_linux.h" -#include "base/synchronization/waitable_event.h" -#include "base/threading/thread.h" -#include "testing/gtest/include/gtest/gtest.h" - -namespace base { - -namespace { - -TEST(UnixDomainSocketTest, SendRecvMsgAbortOnReplyFDClose) { - Thread message_thread("UnixDomainSocketTest"); - ASSERT_TRUE(message_thread.Start()); - - int fds[2]; - ASSERT_EQ(0, socketpair(AF_UNIX, SOCK_SEQPACKET, 0, fds)); - file_util::ScopedFD scoped_fd0(&fds[0]); - file_util::ScopedFD scoped_fd1(&fds[1]); - - // Have the thread send a synchronous message via the socket. - Pickle request; - message_thread.message_loop()->PostTask( - FROM_HERE, - Bind(IgnoreResult(&UnixDomainSocket::SendRecvMsg), - fds[1], static_cast(NULL), 0U, static_cast(NULL), - request)); - - // Receive the message. - std::vector message_fds; - uint8_t buffer[16]; - ASSERT_EQ(static_cast(request.size()), - UnixDomainSocket::RecvMsg(fds[0], buffer, sizeof(buffer), - &message_fds)); - ASSERT_EQ(1U, message_fds.size()); - - // Close the reply FD. - ASSERT_EQ(0, HANDLE_EINTR(close(message_fds.front()))); - - // Check that the thread didn't get blocked. - WaitableEvent event(false, false); - message_thread.message_loop()->PostTask( - FROM_HERE, - Bind(&WaitableEvent::Signal, Unretained(&event))); - ASSERT_TRUE(event.TimedWait(TimeDelta::FromMilliseconds(5000))); -} - -TEST(UnixDomainSocketTest, SendRecvMsgAvoidsSIGPIPE) { - // Make sure SIGPIPE isn't being ignored. - struct sigaction act = {}, oldact; - act.sa_handler = SIG_DFL; - ASSERT_EQ(0, sigaction(SIGPIPE, &act, &oldact)); - int fds[2]; - ASSERT_EQ(0, socketpair(AF_UNIX, SOCK_SEQPACKET, 0, fds)); - file_util::ScopedFD scoped_fd1(&fds[1]); - ASSERT_EQ(0, HANDLE_EINTR(close(fds[0]))); - - // Have the thread send a synchronous message via the socket. Unless the - // message is sent with MSG_NOSIGNAL, this shall result in SIGPIPE. - Pickle request; - ASSERT_EQ(-1, - UnixDomainSocket::SendRecvMsg(fds[1], static_cast(NULL), - 0U, static_cast(NULL), request)); - ASSERT_EQ(EPIPE, errno); - // Restore the SIGPIPE handler. - ASSERT_EQ(0, sigaction(SIGPIPE, &oldact, NULL)); -} - -} // namespace - -} // namespace base diff --git a/base/power_monitor/power_monitor.cc b/base/power_monitor/power_monitor.cc deleted file mode 100644 index 14dc4b5178..0000000000 --- a/base/power_monitor/power_monitor.cc +++ /dev/null @@ -1,61 +0,0 @@ -// Copyright 2013 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "base/power_monitor/power_monitor.h" -#include "base/power_monitor/power_monitor_source.h" - -namespace base { - -static PowerMonitor* g_power_monitor = NULL; - -PowerMonitor::PowerMonitor(scoped_ptr source) - : observers_(new ObserverListThreadSafe()), - source_(source.Pass()) { - DCHECK(!g_power_monitor); - g_power_monitor = this; -} - -PowerMonitor::~PowerMonitor() { - DCHECK_EQ(this, g_power_monitor); - g_power_monitor = NULL; -} - -// static -PowerMonitor* PowerMonitor::Get() { - return g_power_monitor; -} - -void PowerMonitor::AddObserver(PowerObserver* obs) { - observers_->AddObserver(obs); -} - -void PowerMonitor::RemoveObserver(PowerObserver* obs) { - observers_->RemoveObserver(obs); -} - -PowerMonitorSource* PowerMonitor::Source() { - return source_.get(); -} - -bool PowerMonitor::IsOnBatteryPower() { - return source_->IsOnBatteryPower(); -} - -void PowerMonitor::NotifyPowerStateChange(bool battery_in_use) { - DVLOG(1) << "PowerStateChange: " << (battery_in_use ? "On" : "Off") - << " battery"; - observers_->Notify(&PowerObserver::OnPowerStateChange, battery_in_use); -} - -void PowerMonitor::NotifySuspend() { - DVLOG(1) << "Power Suspending"; - observers_->Notify(&PowerObserver::OnSuspend); -} - -void PowerMonitor::NotifyResume() { - DVLOG(1) << "Power Resuming"; - observers_->Notify(&PowerObserver::OnResume); -} - -} // namespace base diff --git a/base/power_monitor/power_monitor.h b/base/power_monitor/power_monitor.h deleted file mode 100644 index 4acb3bf122..0000000000 --- a/base/power_monitor/power_monitor.h +++ /dev/null @@ -1,55 +0,0 @@ -// Copyright 2013 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef BASE_POWER_MONITOR_POWER_MONITOR_H_ -#define BASE_POWER_MONITOR_POWER_MONITOR_H_ - -#include "base/base_export.h" -#include "base/basictypes.h" -#include "base/memory/ref_counted.h" -#include "base/observer_list_threadsafe.h" -#include "base/power_monitor/power_observer.h" - -namespace base { - -class PowerMonitorSource; - -// A class used to monitor the power state change and notify the observers about -// the change event. -class BASE_EXPORT PowerMonitor { - public: - // Takes ownership of |source|. - explicit PowerMonitor(scoped_ptr source); - ~PowerMonitor(); - - // Get the process-wide PowerMonitor (if not present, returns NULL). - static PowerMonitor* Get(); - - // Add and remove an observer. - // Can be called from any thread. - // Must not be called from within a notification callback. - void AddObserver(PowerObserver* observer); - void RemoveObserver(PowerObserver* observer); - - // Is the computer currently on battery power. - bool IsOnBatteryPower(); - - private: - friend class PowerMonitorSource; - - PowerMonitorSource* Source(); - - void NotifyPowerStateChange(bool battery_in_use); - void NotifySuspend(); - void NotifyResume(); - - scoped_refptr > observers_; - scoped_ptr source_; - - DISALLOW_COPY_AND_ASSIGN(PowerMonitor); -}; - -} // namespace base - -#endif // BASE_POWER_MONITOR_POWER_MONITOR_H_ diff --git a/base/power_monitor/power_monitor_device_source.cc b/base/power_monitor/power_monitor_device_source.cc deleted file mode 100644 index 0a3997517e..0000000000 --- a/base/power_monitor/power_monitor_device_source.cc +++ /dev/null @@ -1,39 +0,0 @@ -// Copyright 2013 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "base/power_monitor/power_monitor_device_source.h" - -#include "base/time/time.h" - -namespace base { - -#if defined(ENABLE_BATTERY_MONITORING) -// The amount of time (in ms) to wait before running the initial -// battery check. -static int kDelayedBatteryCheckMs = 10 * 1000; -#endif // defined(ENABLE_BATTERY_MONITORING) - -PowerMonitorDeviceSource::PowerMonitorDeviceSource() { - DCHECK(MessageLoop::current()); -#if defined(ENABLE_BATTERY_MONITORING) - delayed_battery_check_.Start(FROM_HERE, - base::TimeDelta::FromMilliseconds(kDelayedBatteryCheckMs), this, - &PowerMonitorDeviceSource::BatteryCheck); -#endif // defined(ENABLE_BATTERY_MONITORING) -#if defined(OS_MACOSX) - PlatformInit(); -#endif -} - -PowerMonitorDeviceSource::~PowerMonitorDeviceSource() { -#if defined(OS_MACOSX) - PlatformDestroy(); -#endif -} - -void PowerMonitorDeviceSource::BatteryCheck() { - ProcessPowerEvent(PowerMonitorSource::POWER_STATE_EVENT); -} - -} // namespace base diff --git a/base/power_monitor/power_monitor_device_source.h b/base/power_monitor/power_monitor_device_source.h deleted file mode 100644 index 993956031c..0000000000 --- a/base/power_monitor/power_monitor_device_source.h +++ /dev/null @@ -1,110 +0,0 @@ -// Copyright 2013 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef BASE_POWER_MONITOR_POWER_MONITOR_DEVICE_SOURCE_H_ -#define BASE_POWER_MONITOR_POWER_MONITOR_DEVICE_SOURCE_H_ - -#include "base/base_export.h" -#include "base/basictypes.h" -#include "base/memory/ref_counted.h" -#include "base/observer_list_threadsafe.h" -#include "base/power_monitor/power_monitor_source.h" -#include "base/power_monitor/power_observer.h" - -#if defined(OS_WIN) -#include - -// Windows HiRes timers drain the battery faster so we need to know the battery -// status. This isn't true for other platforms. -#define ENABLE_BATTERY_MONITORING 1 -#else -#undef ENABLE_BATTERY_MONITORING -#endif // !OS_WIN - -#if defined(ENABLE_BATTERY_MONITORING) -#include "base/timer/timer.h" -#endif // defined(ENABLE_BATTERY_MONITORING) - -#if defined(OS_IOS) -#include -#endif // OS_IOS - -namespace base { - -// A class used to monitor the power state change and notify the observers about -// the change event. -class BASE_EXPORT PowerMonitorDeviceSource : public PowerMonitorSource { - public: - PowerMonitorDeviceSource(); - virtual ~PowerMonitorDeviceSource(); - -#if defined(OS_MACOSX) - // Allocate system resources needed by the PowerMonitor class. - // - // This function must be called before instantiating an instance of the class - // and before the Sandbox is initialized. -#if !defined(OS_IOS) - static void AllocateSystemIOPorts(); -#else - static void AllocateSystemIOPorts() {} -#endif // OS_IOS -#endif // OS_MACOSX - - private: -#if defined(OS_WIN) - // Represents a message-only window for power message handling on Windows. - // Only allow PowerMonitor to create it. - class PowerMessageWindow { - public: - PowerMessageWindow(); - ~PowerMessageWindow(); - - private: - void ProcessWmPowerBroadcastMessage(int event_id); - LRESULT CALLBACK WndProc(HWND hwnd, UINT message, - WPARAM wparam, LPARAM lparam); - static LRESULT CALLBACK WndProcThunk(HWND hwnd, - UINT message, - WPARAM wparam, - LPARAM lparam); - // Instance of the module containing the window procedure. - HMODULE instance_; - // A hidden message-only window. - HWND message_hwnd_; - }; -#endif // OS_WIN - -#if defined(OS_MACOSX) - void PlatformInit(); - void PlatformDestroy(); -#endif - - // Platform-specific method to check whether the system is currently - // running on battery power. Returns true if running on batteries, - // false otherwise. - virtual bool IsOnBatteryPowerImpl() OVERRIDE; - - // Checks the battery status and notifies observers if the battery - // status has changed. - void BatteryCheck(); - -#if defined(OS_IOS) - // Holds pointers to system event notification observers. - std::vector notification_observers_; -#endif - -#if defined(ENABLE_BATTERY_MONITORING) - base::OneShotTimer delayed_battery_check_; -#endif - -#if defined(OS_WIN) - PowerMessageWindow power_message_window_; -#endif - - DISALLOW_COPY_AND_ASSIGN(PowerMonitorDeviceSource); -}; - -} // namespace base - -#endif // BASE_POWER_MONITOR_POWER_MONITOR_DEVICE_SOURCE_H_ diff --git a/base/power_monitor/power_monitor_device_source_android.cc b/base/power_monitor/power_monitor_device_source_android.cc deleted file mode 100644 index 4d9eb52780..0000000000 --- a/base/power_monitor/power_monitor_device_source_android.cc +++ /dev/null @@ -1,45 +0,0 @@ -// Copyright 2013 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "base/power_monitor/power_monitor_device_source_android.h" - -#include "base/power_monitor/power_monitor.h" -#include "base/power_monitor/power_monitor_device_source.h" -#include "base/power_monitor/power_monitor_source.h" -#include "jni/PowerMonitor_jni.h" - -namespace base { - -// A helper function which is a friend of PowerMonitorSource. -void ProcessPowerEventHelper(PowerMonitorSource::PowerEvent event) { - PowerMonitorSource::ProcessPowerEvent(event); -} - -namespace android { - -// Native implementation of PowerMonitor.java. -void OnBatteryChargingChanged(JNIEnv* env, jclass clazz) { - ProcessPowerEventHelper(PowerMonitorSource::POWER_STATE_EVENT); -} - -void OnMainActivityResumed(JNIEnv* env, jclass clazz) { - ProcessPowerEventHelper(PowerMonitorSource::RESUME_EVENT); -} - -void OnMainActivitySuspended(JNIEnv* env, jclass clazz) { - ProcessPowerEventHelper(PowerMonitorSource::SUSPEND_EVENT); -} - -} // namespace android - -bool PowerMonitorDeviceSource::IsOnBatteryPowerImpl() { - JNIEnv* env = base::android::AttachCurrentThread(); - return base::android::Java_PowerMonitor_isBatteryPower(env); -} - -bool RegisterPowerMonitor(JNIEnv* env) { - return base::android::RegisterNativesImpl(env); -} - -} // namespace base diff --git a/base/power_monitor/power_monitor_device_source_android.h b/base/power_monitor/power_monitor_device_source_android.h deleted file mode 100644 index 024f95ab00..0000000000 --- a/base/power_monitor/power_monitor_device_source_android.h +++ /dev/null @@ -1,17 +0,0 @@ -// Copyright 2013 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef BASE_POWER_MONITOR_POWER_MONITOR_DEVICE_SOURCE_ANDROID_H_ -#define BASE_POWER_MONITOR_POWER_MONITOR_DEVICE_SOURCE_ANDROID_H_ - -#include - -namespace base { - -// Registers the JNI bindings for PowerMonitorDeviceSource. -bool RegisterPowerMonitor(JNIEnv* env); - -} // namespace base - -#endif // BASE_POWER_MONITOR_POWER_MONITOR_DEVICE_SOURCE_ANDROID_H_ diff --git a/base/power_monitor/power_monitor_device_source_ios.mm b/base/power_monitor/power_monitor_device_source_ios.mm deleted file mode 100644 index dc12f1c295..0000000000 --- a/base/power_monitor/power_monitor_device_source_ios.mm +++ /dev/null @@ -1,40 +0,0 @@ -// Copyright 2013 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "base/power_monitor/power_monitor_device_source.h" - -#import - -namespace base { - -void PowerMonitorDeviceSource::PlatformInit() { - NSNotificationCenter* nc = [NSNotificationCenter defaultCenter]; - id foreground = - [nc addObserverForName:UIApplicationWillEnterForegroundNotification - object:nil - queue:nil - usingBlock:^(NSNotification* notification) { - ProcessPowerEvent(RESUME_EVENT); - }]; - id background = - [nc addObserverForName:UIApplicationDidEnterBackgroundNotification - object:nil - queue:nil - usingBlock:^(NSNotification* notification) { - ProcessPowerEvent(SUSPEND_EVENT); - }]; - notification_observers_.push_back(foreground); - notification_observers_.push_back(background); -} - -void PowerMonitorDeviceSource::PlatformDestroy() { - NSNotificationCenter* nc = [NSNotificationCenter defaultCenter]; - for (std::vector::iterator it = notification_observers_.begin(); - it != notification_observers_.end(); ++it) { - [nc removeObserver:*it]; - } - notification_observers_.clear(); -} - -} // namespace base diff --git a/base/power_monitor/power_monitor_device_source_mac.mm b/base/power_monitor/power_monitor_device_source_mac.mm deleted file mode 100644 index 61e439630e..0000000000 --- a/base/power_monitor/power_monitor_device_source_mac.mm +++ /dev/null @@ -1,107 +0,0 @@ -// Copyright 2013 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -// Implementation based on sample code from -// http://developer.apple.com/library/mac/#qa/qa1340/_index.html. - -#include "base/power_monitor/power_monitor_device_source.h" - -#include "base/power_monitor/power_monitor.h" -#include "base/power_monitor/power_monitor_source.h" - -#include -#include - -namespace base { - -void ProcessPowerEventHelper(PowerMonitorSource::PowerEvent event) { - PowerMonitorSource::ProcessPowerEvent(event); -} - -namespace { - -io_connect_t g_system_power_io_port = 0; -IONotificationPortRef g_notification_port_ref = 0; -io_object_t g_notifier_object = 0; - -void SystemPowerEventCallback(void*, - io_service_t service, - natural_t message_type, - void* message_argument) { - switch (message_type) { - // If this message is not handled the system may delay sleep for 30 seconds. - case kIOMessageCanSystemSleep: - IOAllowPowerChange(g_system_power_io_port, - reinterpret_cast(message_argument)); - break; - case kIOMessageSystemWillSleep: - ProcessPowerEventHelper(base::PowerMonitorSource::SUSPEND_EVENT); - IOAllowPowerChange(g_system_power_io_port, - reinterpret_cast(message_argument)); - break; - - case kIOMessageSystemWillPowerOn: - ProcessPowerEventHelper(PowerMonitorSource::RESUME_EVENT); - break; - } -} - -} // namespace - -// The reason we can't include this code in the constructor is because -// PlatformInit() requires an active runloop and the IO port needs to be -// allocated at sandbox initialization time, before there's a runloop. -// See crbug.com/83783 . - -// static -void PowerMonitorDeviceSource::AllocateSystemIOPorts() { - DCHECK_EQ(g_system_power_io_port, 0u); - - // Notification port allocated by IORegisterForSystemPower. - g_system_power_io_port = IORegisterForSystemPower( - NULL, &g_notification_port_ref, SystemPowerEventCallback, - &g_notifier_object); - - DCHECK_NE(g_system_power_io_port, 0u); -} - -void PowerMonitorDeviceSource::PlatformInit() { - // Need to call AllocateSystemIOPorts() before creating a PowerMonitor - // object. - DCHECK_NE(g_system_power_io_port, 0u); - if (g_system_power_io_port == 0) - return; - - // Add the notification port to the application runloop - CFRunLoopAddSource( - CFRunLoopGetCurrent(), - IONotificationPortGetRunLoopSource(g_notification_port_ref), - kCFRunLoopCommonModes); -} - -void PowerMonitorDeviceSource::PlatformDestroy() { - DCHECK_NE(g_system_power_io_port, 0u); - if (g_system_power_io_port == 0) - return; - - // Remove the sleep notification port from the application runloop - CFRunLoopRemoveSource( - CFRunLoopGetCurrent(), - IONotificationPortGetRunLoopSource(g_notification_port_ref), - kCFRunLoopCommonModes); - - // Deregister for system sleep notifications - IODeregisterForSystemPower(&g_notifier_object); - - // IORegisterForSystemPower implicitly opens the Root Power Domain IOService, - // so we close it here. - IOServiceClose(g_system_power_io_port); - - g_system_power_io_port = 0; - - // Destroy the notification port allocated by IORegisterForSystemPower. - IONotificationPortDestroy(g_notification_port_ref); -} - -} // namespace base diff --git a/base/power_monitor/power_monitor_device_source_posix.cc b/base/power_monitor/power_monitor_device_source_posix.cc deleted file mode 100644 index f24e5b23f0..0000000000 --- a/base/power_monitor/power_monitor_device_source_posix.cc +++ /dev/null @@ -1,14 +0,0 @@ -// Copyright 2013 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "base/power_monitor/power_monitor_device_source.h" - -namespace base { - -bool PowerMonitorDeviceSource::IsOnBatteryPowerImpl() { - NOTIMPLEMENTED(); - return false; -} - -} // namespace base diff --git a/base/power_monitor/power_monitor_device_source_win.cc b/base/power_monitor/power_monitor_device_source_win.cc deleted file mode 100644 index 6f4c1319b3..0000000000 --- a/base/power_monitor/power_monitor_device_source_win.cc +++ /dev/null @@ -1,130 +0,0 @@ -// Copyright 2013 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "base/power_monitor/power_monitor.h" -#include "base/power_monitor/power_monitor_device_source.h" -#include "base/power_monitor/power_monitor_source.h" -#include "base/win/wrapped_window_proc.h" - -namespace base { - -void ProcessPowerEventHelper(PowerMonitorSource::PowerEvent event) { - PowerMonitorSource::ProcessPowerEvent(event); -} - -namespace { - -const wchar_t kWindowClassName[] = L"Base_PowerMessageWindow"; - -} // namespace - -// Function to query the system to see if it is currently running on -// battery power. Returns true if running on battery. -bool PowerMonitorDeviceSource::IsOnBatteryPowerImpl() { - SYSTEM_POWER_STATUS status; - if (!GetSystemPowerStatus(&status)) { - DLOG_GETLASTERROR(ERROR) << "GetSystemPowerStatus failed"; - return false; - } - return (status.ACLineStatus == 0); -} - -PowerMonitorDeviceSource::PowerMessageWindow::PowerMessageWindow() - : instance_(NULL), message_hwnd_(NULL) { - if (MessageLoop::current()->type() != MessageLoop::TYPE_UI) { - // Creating this window in (e.g.) a renderer inhibits shutdown on Windows. - // See http://crbug.com/230122. TODO(vandebo): http://crbug.com/236031 - DLOG(ERROR) - << "Cannot create windows on non-UI thread, power monitor disabled!"; - return; - } - WNDCLASSEX window_class; - base::win::InitializeWindowClass( - kWindowClassName, - &base::win::WrappedWindowProc< - PowerMonitorDeviceSource::PowerMessageWindow::WndProcThunk>, - 0, 0, 0, NULL, NULL, NULL, NULL, NULL, - &window_class); - instance_ = window_class.hInstance; - ATOM clazz = RegisterClassEx(&window_class); - DCHECK(clazz); - - message_hwnd_ = CreateWindowEx(WS_EX_NOACTIVATE, kWindowClassName, - NULL, WS_POPUP, 0, 0, 0, 0, NULL, NULL, instance_, NULL); - SetWindowLongPtr(message_hwnd_, GWLP_USERDATA, - reinterpret_cast(this)); -} - -PowerMonitorDeviceSource::PowerMessageWindow::~PowerMessageWindow() { - if (message_hwnd_) { - DestroyWindow(message_hwnd_); - UnregisterClass(kWindowClassName, instance_); - } -} - -void -PowerMonitorDeviceSource::PowerMessageWindow::ProcessWmPowerBroadcastMessage( - int event_id) { - PowerMonitorSource::PowerEvent power_event; - switch (event_id) { - case PBT_APMPOWERSTATUSCHANGE: // The power status changed. - power_event = PowerMonitorSource::POWER_STATE_EVENT; - break; - case PBT_APMRESUMEAUTOMATIC: // Resume from suspend. - //case PBT_APMRESUMESUSPEND: // User-initiated resume from suspend. - // We don't notify for this latter event - // because if it occurs it is always sent as a - // second event after PBT_APMRESUMEAUTOMATIC. - power_event = PowerMonitorSource::RESUME_EVENT; - break; - case PBT_APMSUSPEND: // System has been suspended. - power_event = PowerMonitorSource::SUSPEND_EVENT; - break; - default: - return; - - // Other Power Events: - // PBT_APMBATTERYLOW - removed in Vista. - // PBT_APMOEMEVENT - removed in Vista. - // PBT_APMQUERYSUSPEND - removed in Vista. - // PBT_APMQUERYSUSPENDFAILED - removed in Vista. - // PBT_APMRESUMECRITICAL - removed in Vista. - // PBT_POWERSETTINGCHANGE - user changed the power settings. - } - - ProcessPowerEventHelper(power_event); -} - -LRESULT CALLBACK PowerMonitorDeviceSource::PowerMessageWindow::WndProc( - HWND hwnd, - UINT message, - WPARAM wparam, - LPARAM lparam) { - switch (message) { - case WM_POWERBROADCAST: { - DWORD power_event = static_cast(message); - ProcessWmPowerBroadcastMessage(power_event); - return TRUE; - } - default: - break; - } - return ::DefWindowProc(hwnd, message, wparam, lparam); -} - -// static -LRESULT CALLBACK PowerMonitorDeviceSource::PowerMessageWindow::WndProcThunk( - HWND hwnd, - UINT message, - WPARAM wparam, - LPARAM lparam) { - PowerMonitorDeviceSource::PowerMessageWindow* message_hwnd = - reinterpret_cast( - GetWindowLongPtr(hwnd, GWLP_USERDATA)); - if (message_hwnd) - return message_hwnd->WndProc(hwnd, message, wparam, lparam); - return ::DefWindowProc(hwnd, message, wparam, lparam); -} - -} // namespace base diff --git a/base/power_monitor/power_monitor_source.cc b/base/power_monitor/power_monitor_source.cc deleted file mode 100644 index 6868cb19e3..0000000000 --- a/base/power_monitor/power_monitor_source.cc +++ /dev/null @@ -1,66 +0,0 @@ -// Copyright 2013 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "base/power_monitor/power_monitor_source.h" - -#include "base/power_monitor/power_monitor.h" - -namespace base { - -PowerMonitorSource::PowerMonitorSource() - : on_battery_power_(false), - suspended_(false) { -} - -PowerMonitorSource::~PowerMonitorSource() { -} - -bool PowerMonitorSource::IsOnBatteryPower() { - AutoLock auto_lock(battery_lock_); - return on_battery_power_; -} - -void PowerMonitorSource::ProcessPowerEvent(PowerEvent event_id) { - PowerMonitor* monitor = PowerMonitor::Get(); - if (!monitor) - return; - - PowerMonitorSource* source = monitor->Source(); - - // Suppress duplicate notifications. Some platforms may - // send multiple notifications of the same event. - switch (event_id) { - case POWER_STATE_EVENT: - { - bool new_on_battery_power = source->IsOnBatteryPowerImpl(); - bool changed = false; - - { - AutoLock auto_lock(source->battery_lock_); - if (source->on_battery_power_ != new_on_battery_power) { - changed = true; - source->on_battery_power_ = new_on_battery_power; - } - } - - if (changed) - monitor->NotifyPowerStateChange(new_on_battery_power); - } - break; - case RESUME_EVENT: - if (source->suspended_) { - source->suspended_ = false; - monitor->NotifyResume(); - } - break; - case SUSPEND_EVENT: - if (!source->suspended_) { - source->suspended_ = true; - monitor->NotifySuspend(); - } - break; - } -} - -} // namespace base diff --git a/base/power_monitor/power_monitor_source.h b/base/power_monitor/power_monitor_source.h deleted file mode 100644 index b8f41850ef..0000000000 --- a/base/power_monitor/power_monitor_source.h +++ /dev/null @@ -1,65 +0,0 @@ -// Copyright 2013 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef BASE_POWER_MONITOR_POWER_MONITOR_SOURCE_H_ -#define BASE_POWER_MONITOR_POWER_MONITOR_SOURCE_H_ - -#include "base/base_export.h" -#include "base/basictypes.h" -#include "base/memory/ref_counted.h" -#include "base/observer_list_threadsafe.h" -#include "base/synchronization/lock.h" - -namespace base { - -class PowerMonitor; - -// Communicates power state changes to the power monitor. -class BASE_EXPORT PowerMonitorSource { - public: - PowerMonitorSource(); - virtual ~PowerMonitorSource(); - - // Normalized list of power events. - enum PowerEvent { - POWER_STATE_EVENT, // The Power status of the system has changed. - SUSPEND_EVENT, // The system is being suspended. - RESUME_EVENT // The system is being resumed. - }; - - // Is the computer currently on battery power. Can be called on any thread. - bool IsOnBatteryPower(); - - protected: - friend class PowerMonitorTest; - - // Friend function that is allowed to access the protected ProcessPowerEvent. - friend void ProcessPowerEventHelper(PowerEvent); - - // Get the process-wide PowerMonitorSource (if not present, returns NULL). - static PowerMonitorSource* Get(); - - // ProcessPowerEvent should only be called from a single thread, most likely - // the UI thread or, in child processes, the IO thread. - static void ProcessPowerEvent(PowerEvent event_id); - - // Platform-specific method to check whether the system is currently - // running on battery power. Returns true if running on batteries, - // false otherwise. - virtual bool IsOnBatteryPowerImpl() = 0; - - private: - bool on_battery_power_; - bool suspended_; - - // This lock guards access to on_battery_power_, to ensure that - // IsOnBatteryPower can be called from any thread. - Lock battery_lock_; - - DISALLOW_COPY_AND_ASSIGN(PowerMonitorSource); -}; - -} // namespace base - -#endif // BASE_POWER_MONITOR_POWER_MONITOR_SOURCE_H_ diff --git a/base/power_monitor/power_monitor_unittest.cc b/base/power_monitor/power_monitor_unittest.cc deleted file mode 100644 index 5f7b531206..0000000000 --- a/base/power_monitor/power_monitor_unittest.cc +++ /dev/null @@ -1,80 +0,0 @@ -// Copyright 2013 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "base/power_monitor/power_monitor.h" -#include "base/test/power_monitor_test_base.h" -#include "testing/gtest/include/gtest/gtest.h" - -namespace base { - -class PowerMonitorTest : public testing::Test { - protected: - PowerMonitorTest() { - power_monitor_source_ = new PowerMonitorTestSource(); - power_monitor_.reset(new PowerMonitor( - scoped_ptr(power_monitor_source_))); - } - virtual ~PowerMonitorTest() {}; - - PowerMonitorTestSource* source() { return power_monitor_source_; } - PowerMonitor* monitor() { return power_monitor_.get(); } - - private: - PowerMonitorTestSource* power_monitor_source_; - scoped_ptr power_monitor_; - - DISALLOW_COPY_AND_ASSIGN(PowerMonitorTest); -}; - -// PowerMonitorSource is tightly coupled with the PowerMonitor, so this test -// Will cover both classes -TEST_F(PowerMonitorTest, PowerNotifications) { - const int kObservers = 5; - - PowerMonitorTestObserver observers[kObservers]; - for (int index = 0; index < kObservers; ++index) - monitor()->AddObserver(&observers[index]); - - // Sending resume when not suspended should have no effect. - source()->GenerateResumeEvent(); - EXPECT_EQ(observers[0].resumes(), 0); - - // Pretend we suspended. - source()->GenerateSuspendEvent(); - // Ensure all observers were notified of the event - for (int index = 0; index < kObservers; ++index) - EXPECT_EQ(observers[index].suspends(), 1); - - // Send a second suspend notification. This should be suppressed. - source()->GenerateSuspendEvent(); - EXPECT_EQ(observers[0].suspends(), 1); - - // Pretend we were awakened. - source()->GenerateResumeEvent(); - EXPECT_EQ(observers[0].resumes(), 1); - - // Send a duplicate resume notification. This should be suppressed. - source()->GenerateResumeEvent(); - EXPECT_EQ(observers[0].resumes(), 1); - - // Pretend the device has gone on battery power - source()->GeneratePowerStateEvent(true); - EXPECT_EQ(observers[0].power_state_changes(), 1); - EXPECT_EQ(observers[0].last_power_state(), true); - - // Repeated indications the device is on battery power should be suppressed. - source()->GeneratePowerStateEvent(true); - EXPECT_EQ(observers[0].power_state_changes(), 1); - - // Pretend the device has gone off battery power - source()->GeneratePowerStateEvent(false); - EXPECT_EQ(observers[0].power_state_changes(), 2); - EXPECT_EQ(observers[0].last_power_state(), false); - - // Repeated indications the device is off battery power should be suppressed. - source()->GeneratePowerStateEvent(false); - EXPECT_EQ(observers[0].power_state_changes(), 2); -} - -} // namespace base diff --git a/base/power_monitor/power_observer.h b/base/power_monitor/power_observer.h deleted file mode 100644 index 6be70bba9d..0000000000 --- a/base/power_monitor/power_observer.h +++ /dev/null @@ -1,31 +0,0 @@ -// Copyright 2013 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef BASE_POWER_MONITOR_POWER_OBSERVER_H_ -#define BASE_POWER_MONITOR_POWER_OBSERVER_H_ - -#include "base/base_export.h" -#include "base/compiler_specific.h" - -namespace base { - -class BASE_EXPORT PowerObserver { - public: - // Notification of a change in power status of the computer, such - // as from switching between battery and A/C power. - virtual void OnPowerStateChange(bool on_battery_power) {}; - - // Notification that the system is suspending. - virtual void OnSuspend() {} - - // Notification that the system is resuming. - virtual void OnResume() {} - - protected: - virtual ~PowerObserver() {} -}; - -} // namespace base - -#endif // BASE_POWER_MONITOR_POWER_OBSERVER_H_ diff --git a/base/prefs/OWNERS b/base/prefs/OWNERS deleted file mode 100644 index f3708afe55..0000000000 --- a/base/prefs/OWNERS +++ /dev/null @@ -1,7 +0,0 @@ -battre@chromium.org -bauerb@chromium.org -mnissler@chromium.org -pam@chromium.org - -# For refactoring changes -joi@chromium.org diff --git a/base/prefs/README b/base/prefs/README deleted file mode 100644 index 52d9c43e2e..0000000000 --- a/base/prefs/README +++ /dev/null @@ -1,6 +0,0 @@ -Prefs is a general-purpose key-value store for application preferences. - -The Prefs code lives in base/prefs but is not part of the -'base/base.gyp:base' library because of a desire to keep its use -optional. If you use Prefs, you should add a GYP dependency on -base/base.gyp:base_prefs. diff --git a/base/prefs/base_prefs_export.h b/base/prefs/base_prefs_export.h deleted file mode 100644 index 3d207db890..0000000000 --- a/base/prefs/base_prefs_export.h +++ /dev/null @@ -1,29 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef BASE_PREFS_BASE_PREFS_EXPORT_H_ -#define BASE_PREFS_BASE_PREFS_EXPORT_H_ - -#if defined(COMPONENT_BUILD) -#if defined(WIN32) - -#if defined(BASE_PREFS_IMPLEMENTATION) -#define BASE_PREFS_EXPORT __declspec(dllexport) -#else -#define BASE_PREFS_EXPORT __declspec(dllimport) -#endif // defined(BASE_PREFS_IMPLEMENTATION) - -#else // defined(WIN32) -#if defined(BASE_PREFS_IMPLEMENTATION) -#define BASE_PREFS_EXPORT __attribute__((visibility("default"))) -#else -#define BASE_PREFS_EXPORT -#endif -#endif - -#else // defined(COMPONENT_BUILD) -#define BASE_PREFS_EXPORT -#endif - -#endif // BASE_PREFS_BASE_PREFS_EXPORT_H_ diff --git a/base/prefs/default_pref_store.cc b/base/prefs/default_pref_store.cc deleted file mode 100644 index babb4d5362..0000000000 --- a/base/prefs/default_pref_store.cc +++ /dev/null @@ -1,53 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "base/prefs/default_pref_store.h" -#include "base/logging.h" - -using base::Value; - -DefaultPrefStore::DefaultPrefStore() {} - -bool DefaultPrefStore::GetValue(const std::string& key, - const Value** result) const { - return prefs_.GetValue(key, result); -} - -void DefaultPrefStore::AddObserver(PrefStore::Observer* observer) { - observers_.AddObserver(observer); -} - -void DefaultPrefStore::RemoveObserver(PrefStore::Observer* observer) { - observers_.RemoveObserver(observer); -} - -size_t DefaultPrefStore::NumberOfObservers() const { - return observers_.size(); -} - -void DefaultPrefStore::SetDefaultValue(const std::string& key, - scoped_ptr value) { - DCHECK(!GetValue(key, NULL)); - prefs_.SetValue(key, value.release()); -} - -void DefaultPrefStore::ReplaceDefaultValue(const std::string& key, - scoped_ptr value) { - const Value* old_value = NULL; - GetValue(key, &old_value); - bool notify = !old_value->Equals(value.get()); - prefs_.SetValue(key, value.release()); - if (notify) - FOR_EACH_OBSERVER(Observer, observers_, OnPrefValueChanged(key)); -} - -DefaultPrefStore::const_iterator DefaultPrefStore::begin() const { - return prefs_.begin(); -} - -DefaultPrefStore::const_iterator DefaultPrefStore::end() const { - return prefs_.end(); -} - -DefaultPrefStore::~DefaultPrefStore() {} diff --git a/base/prefs/default_pref_store.h b/base/prefs/default_pref_store.h deleted file mode 100644 index 97b3960b00..0000000000 --- a/base/prefs/default_pref_store.h +++ /dev/null @@ -1,52 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef BASE_PREFS_DEFAULT_PREF_STORE_H_ -#define BASE_PREFS_DEFAULT_PREF_STORE_H_ - -#include - -#include "base/observer_list.h" -#include "base/prefs/base_prefs_export.h" -#include "base/prefs/pref_store.h" -#include "base/prefs/pref_value_map.h" -#include "base/values.h" - -// Used within a PrefRegistry to keep track of default preference values. -class BASE_PREFS_EXPORT DefaultPrefStore : public PrefStore { - public: - typedef PrefValueMap::const_iterator const_iterator; - - DefaultPrefStore(); - - // PrefStore implementation: - virtual bool GetValue(const std::string& key, - const base::Value** result) const OVERRIDE; - virtual void AddObserver(PrefStore::Observer* observer) OVERRIDE; - virtual void RemoveObserver(PrefStore::Observer* observer) OVERRIDE; - virtual size_t NumberOfObservers() const OVERRIDE; - - // Sets a |value| for |key|. Should only be called if a value has not been - // set yet; otherwise call ReplaceDefaultValue(). - void SetDefaultValue(const std::string& key, scoped_ptr value); - - // Replaces the the value for |key| with a new value. Should only be called - // if a value has alreday been set; otherwise call SetDefaultValue(). - void ReplaceDefaultValue(const std::string& key, - scoped_ptr value); - - const_iterator begin() const; - const_iterator end() const; - - private: - virtual ~DefaultPrefStore(); - - PrefValueMap prefs_; - - ObserverList observers_; - - DISALLOW_COPY_AND_ASSIGN(DefaultPrefStore); -}; - -#endif // BASE_PREFS_DEFAULT_PREF_STORE_H_ diff --git a/base/prefs/default_pref_store_unittest.cc b/base/prefs/default_pref_store_unittest.cc deleted file mode 100644 index 7181989173..0000000000 --- a/base/prefs/default_pref_store_unittest.cc +++ /dev/null @@ -1,69 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "base/prefs/default_pref_store.h" -#include "testing/gtest/include/gtest/gtest.h" - -using base::StringValue; -using base::Value; - -namespace { - -class MockPrefStoreObserver : public PrefStore::Observer { - public: - explicit MockPrefStoreObserver(DefaultPrefStore* pref_store); - virtual ~MockPrefStoreObserver(); - - int change_count() { - return change_count_; - } - - // PrefStore::Observer implementation: - virtual void OnPrefValueChanged(const std::string& key) OVERRIDE; - virtual void OnInitializationCompleted(bool succeeded) OVERRIDE {} - - private: - DefaultPrefStore* pref_store_; - - int change_count_; - - DISALLOW_COPY_AND_ASSIGN(MockPrefStoreObserver); -}; - -MockPrefStoreObserver::MockPrefStoreObserver(DefaultPrefStore* pref_store) - : pref_store_(pref_store), change_count_(0) { - pref_store_->AddObserver(this); -} - -MockPrefStoreObserver::~MockPrefStoreObserver() { - pref_store_->RemoveObserver(this); -} - -void MockPrefStoreObserver::OnPrefValueChanged(const std::string& key) { - change_count_++; -} - -} // namespace - -TEST(DefaultPrefStoreTest, NotifyPrefValueChanged) { - scoped_refptr pref_store(new DefaultPrefStore); - MockPrefStoreObserver observer(pref_store.get()); - std::string kPrefKey("pref_key"); - - // Setting a default value shouldn't send a change notification. - pref_store->SetDefaultValue(kPrefKey, - scoped_ptr(new StringValue("foo"))); - EXPECT_EQ(0, observer.change_count()); - - // Replacing the default value should send a change notification... - pref_store->ReplaceDefaultValue(kPrefKey, - scoped_ptr(new StringValue("bar"))); - EXPECT_EQ(1, observer.change_count()); - - // But only if the value actually changed. - pref_store->ReplaceDefaultValue(kPrefKey, - scoped_ptr(new StringValue("bar"))); - EXPECT_EQ(1, observer.change_count()); -} - diff --git a/base/prefs/json_pref_store.cc b/base/prefs/json_pref_store.cc deleted file mode 100644 index 0b93f74394..0000000000 --- a/base/prefs/json_pref_store.cc +++ /dev/null @@ -1,358 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "base/prefs/json_pref_store.h" - -#include - -#include "base/bind.h" -#include "base/callback.h" -#include "base/file_util.h" -#include "base/json/json_file_value_serializer.h" -#include "base/json/json_string_value_serializer.h" -#include "base/memory/ref_counted.h" -#include "base/message_loop/message_loop_proxy.h" -#include "base/sequenced_task_runner.h" -#include "base/threading/sequenced_worker_pool.h" -#include "base/values.h" - -namespace { - -// Some extensions we'll tack on to copies of the Preferences files. -const base::FilePath::CharType* kBadExtension = FILE_PATH_LITERAL("bad"); - -// Differentiates file loading between origin thread and passed -// (aka file) thread. -class FileThreadDeserializer - : public base::RefCountedThreadSafe { - public: - FileThreadDeserializer(JsonPrefStore* delegate, - base::SequencedTaskRunner* sequenced_task_runner) - : no_dir_(false), - error_(PersistentPrefStore::PREF_READ_ERROR_NONE), - delegate_(delegate), - sequenced_task_runner_(sequenced_task_runner), - origin_loop_proxy_(base::MessageLoopProxy::current()) { - } - - void Start(const base::FilePath& path) { - DCHECK(origin_loop_proxy_->BelongsToCurrentThread()); - sequenced_task_runner_->PostTask( - FROM_HERE, - base::Bind(&FileThreadDeserializer::ReadFileAndReport, - this, path)); - } - - // Deserializes JSON on the sequenced task runner. - void ReadFileAndReport(const base::FilePath& path) { - DCHECK(sequenced_task_runner_->RunsTasksOnCurrentThread()); - - value_.reset(DoReading(path, &error_, &no_dir_)); - - origin_loop_proxy_->PostTask( - FROM_HERE, - base::Bind(&FileThreadDeserializer::ReportOnOriginThread, this)); - } - - // Reports deserialization result on the origin thread. - void ReportOnOriginThread() { - DCHECK(origin_loop_proxy_->BelongsToCurrentThread()); - delegate_->OnFileRead(value_.release(), error_, no_dir_); - } - - static base::Value* DoReading(const base::FilePath& path, - PersistentPrefStore::PrefReadError* error, - bool* no_dir) { - int error_code; - std::string error_msg; - JSONFileValueSerializer serializer(path); - base::Value* value = serializer.Deserialize(&error_code, &error_msg); - HandleErrors(value, path, error_code, error_msg, error); - *no_dir = !base::PathExists(path.DirName()); - return value; - } - - static void HandleErrors(const base::Value* value, - const base::FilePath& path, - int error_code, - const std::string& error_msg, - PersistentPrefStore::PrefReadError* error); - - private: - friend class base::RefCountedThreadSafe; - ~FileThreadDeserializer() {} - - bool no_dir_; - PersistentPrefStore::PrefReadError error_; - scoped_ptr value_; - const scoped_refptr delegate_; - const scoped_refptr sequenced_task_runner_; - const scoped_refptr origin_loop_proxy_; -}; - -// static -void FileThreadDeserializer::HandleErrors( - const base::Value* value, - const base::FilePath& path, - int error_code, - const std::string& error_msg, - PersistentPrefStore::PrefReadError* error) { - *error = PersistentPrefStore::PREF_READ_ERROR_NONE; - if (!value) { - DVLOG(1) << "Error while loading JSON file: " << error_msg - << ", file: " << path.value(); - switch (error_code) { - case JSONFileValueSerializer::JSON_ACCESS_DENIED: - *error = PersistentPrefStore::PREF_READ_ERROR_ACCESS_DENIED; - break; - case JSONFileValueSerializer::JSON_CANNOT_READ_FILE: - *error = PersistentPrefStore::PREF_READ_ERROR_FILE_OTHER; - break; - case JSONFileValueSerializer::JSON_FILE_LOCKED: - *error = PersistentPrefStore::PREF_READ_ERROR_FILE_LOCKED; - break; - case JSONFileValueSerializer::JSON_NO_SUCH_FILE: - *error = PersistentPrefStore::PREF_READ_ERROR_NO_FILE; - break; - default: - *error = PersistentPrefStore::PREF_READ_ERROR_JSON_PARSE; - // JSON errors indicate file corruption of some sort. - // Since the file is corrupt, move it to the side and continue with - // empty preferences. This will result in them losing their settings. - // We keep the old file for possible support and debugging assistance - // as well as to detect if they're seeing these errors repeatedly. - // TODO(erikkay) Instead, use the last known good file. - base::FilePath bad = path.ReplaceExtension(kBadExtension); - - // If they've ever had a parse error before, put them in another bucket. - // TODO(erikkay) if we keep this error checking for very long, we may - // want to differentiate between recent and long ago errors. - if (base::PathExists(bad)) - *error = PersistentPrefStore::PREF_READ_ERROR_JSON_REPEAT; - base::Move(path, bad); - break; - } - } else if (!value->IsType(base::Value::TYPE_DICTIONARY)) { - *error = PersistentPrefStore::PREF_READ_ERROR_JSON_TYPE; - } -} - -} // namespace - -scoped_refptr JsonPrefStore::GetTaskRunnerForFile( - const base::FilePath& filename, - base::SequencedWorkerPool* worker_pool) { - std::string token("json_pref_store-"); - token.append(filename.AsUTF8Unsafe()); - return worker_pool->GetSequencedTaskRunnerWithShutdownBehavior( - worker_pool->GetNamedSequenceToken(token), - base::SequencedWorkerPool::BLOCK_SHUTDOWN); -} - -JsonPrefStore::JsonPrefStore(const base::FilePath& filename, - base::SequencedTaskRunner* sequenced_task_runner) - : path_(filename), - sequenced_task_runner_(sequenced_task_runner), - prefs_(new base::DictionaryValue()), - read_only_(false), - writer_(filename, sequenced_task_runner), - initialized_(false), - read_error_(PREF_READ_ERROR_OTHER) {} - -bool JsonPrefStore::GetValue(const std::string& key, - const base::Value** result) const { - base::Value* tmp = NULL; - if (!prefs_->Get(key, &tmp)) - return false; - - if (result) - *result = tmp; - return true; -} - -void JsonPrefStore::AddObserver(PrefStore::Observer* observer) { - observers_.AddObserver(observer); -} - -void JsonPrefStore::RemoveObserver(PrefStore::Observer* observer) { - observers_.RemoveObserver(observer); -} - -size_t JsonPrefStore::NumberOfObservers() const { - return observers_.size(); -} - -bool JsonPrefStore::IsInitializationComplete() const { - return initialized_; -} - -bool JsonPrefStore::GetMutableValue(const std::string& key, - base::Value** result) { - return prefs_->Get(key, result); -} - -void JsonPrefStore::SetValue(const std::string& key, base::Value* value) { - DCHECK(value); - scoped_ptr new_value(value); - base::Value* old_value = NULL; - prefs_->Get(key, &old_value); - if (!old_value || !value->Equals(old_value)) { - prefs_->Set(key, new_value.release()); - ReportValueChanged(key); - } -} - -void JsonPrefStore::SetValueSilently(const std::string& key, - base::Value* value) { - DCHECK(value); - scoped_ptr new_value(value); - base::Value* old_value = NULL; - prefs_->Get(key, &old_value); - if (!old_value || !value->Equals(old_value)) { - prefs_->Set(key, new_value.release()); - if (!read_only_) - writer_.ScheduleWrite(this); - } -} - -void JsonPrefStore::RemoveValue(const std::string& key) { - if (prefs_->Remove(key, NULL)) - ReportValueChanged(key); -} - -void JsonPrefStore::MarkNeedsEmptyValue(const std::string& key) { - keys_need_empty_value_.insert(key); -} - -bool JsonPrefStore::ReadOnly() const { - return read_only_; -} - -PersistentPrefStore::PrefReadError JsonPrefStore::GetReadError() const { - return read_error_; -} - -PersistentPrefStore::PrefReadError JsonPrefStore::ReadPrefs() { - if (path_.empty()) { - OnFileRead(NULL, PREF_READ_ERROR_FILE_NOT_SPECIFIED, false); - return PREF_READ_ERROR_FILE_NOT_SPECIFIED; - } - - PrefReadError error; - bool no_dir; - base::Value* value = - FileThreadDeserializer::DoReading(path_, &error, &no_dir); - OnFileRead(value, error, no_dir); - return error; -} - -void JsonPrefStore::ReadPrefsAsync(ReadErrorDelegate *error_delegate) { - initialized_ = false; - error_delegate_.reset(error_delegate); - if (path_.empty()) { - OnFileRead(NULL, PREF_READ_ERROR_FILE_NOT_SPECIFIED, false); - return; - } - - // Start async reading of the preferences file. It will delete itself - // in the end. - scoped_refptr deserializer( - new FileThreadDeserializer(this, sequenced_task_runner_.get())); - deserializer->Start(path_); -} - -void JsonPrefStore::CommitPendingWrite() { - if (writer_.HasPendingWrite() && !read_only_) - writer_.DoScheduledWrite(); -} - -void JsonPrefStore::ReportValueChanged(const std::string& key) { - FOR_EACH_OBSERVER(PrefStore::Observer, observers_, OnPrefValueChanged(key)); - if (!read_only_) - writer_.ScheduleWrite(this); -} - -void JsonPrefStore::OnFileRead(base::Value* value_owned, - PersistentPrefStore::PrefReadError error, - bool no_dir) { - scoped_ptr value(value_owned); - read_error_ = error; - - if (no_dir) { - FOR_EACH_OBSERVER(PrefStore::Observer, - observers_, - OnInitializationCompleted(false)); - return; - } - - initialized_ = true; - - switch (error) { - case PREF_READ_ERROR_ACCESS_DENIED: - case PREF_READ_ERROR_FILE_OTHER: - case PREF_READ_ERROR_FILE_LOCKED: - case PREF_READ_ERROR_JSON_TYPE: - case PREF_READ_ERROR_FILE_NOT_SPECIFIED: - read_only_ = true; - break; - case PREF_READ_ERROR_NONE: - DCHECK(value.get()); - prefs_.reset(static_cast(value.release())); - break; - case PREF_READ_ERROR_NO_FILE: - // If the file just doesn't exist, maybe this is first run. In any case - // there's no harm in writing out default prefs in this case. - break; - case PREF_READ_ERROR_JSON_PARSE: - case PREF_READ_ERROR_JSON_REPEAT: - break; - default: - NOTREACHED() << "Unknown error: " << error; - } - - if (error_delegate_.get() && error != PREF_READ_ERROR_NONE) - error_delegate_->OnError(error); - - FOR_EACH_OBSERVER(PrefStore::Observer, - observers_, - OnInitializationCompleted(true)); -} - -JsonPrefStore::~JsonPrefStore() { - CommitPendingWrite(); -} - -bool JsonPrefStore::SerializeData(std::string* output) { - // TODO(tc): Do we want to prune webkit preferences that match the default - // value? - JSONStringValueSerializer serializer(output); - serializer.set_pretty_print(true); - scoped_ptr copy( - prefs_->DeepCopyWithoutEmptyChildren()); - - // Iterates |keys_need_empty_value_| and if the key exists in |prefs_|, - // ensure its empty ListValue or DictonaryValue is preserved. - for (std::set::const_iterator - it = keys_need_empty_value_.begin(); - it != keys_need_empty_value_.end(); - ++it) { - const std::string& key = *it; - - base::Value* value = NULL; - if (!prefs_->Get(key, &value)) - continue; - - if (value->IsType(base::Value::TYPE_LIST)) { - const base::ListValue* list = NULL; - if (value->GetAsList(&list) && list->empty()) - copy->Set(key, new base::ListValue); - } else if (value->IsType(base::Value::TYPE_DICTIONARY)) { - const base::DictionaryValue* dict = NULL; - if (value->GetAsDictionary(&dict) && dict->empty()) - copy->Set(key, new base::DictionaryValue); - } - } - - return serializer.Serialize(*(copy.get())); -} diff --git a/base/prefs/json_pref_store.h b/base/prefs/json_pref_store.h deleted file mode 100644 index 738b917a59..0000000000 --- a/base/prefs/json_pref_store.h +++ /dev/null @@ -1,103 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef BASE_PREFS_JSON_PREF_STORE_H_ -#define BASE_PREFS_JSON_PREF_STORE_H_ - -#include -#include - -#include "base/basictypes.h" -#include "base/compiler_specific.h" -#include "base/files/file_path.h" -#include "base/files/important_file_writer.h" -#include "base/memory/scoped_ptr.h" -#include "base/message_loop/message_loop_proxy.h" -#include "base/observer_list.h" -#include "base/prefs/base_prefs_export.h" -#include "base/prefs/persistent_pref_store.h" - -namespace base { -class DictionaryValue; -class FilePath; -class SequencedWorkerPool; -class SequencedTaskRunner; -class Value; -} - - -// A writable PrefStore implementation that is used for user preferences. -class BASE_PREFS_EXPORT JsonPrefStore - : public PersistentPrefStore, - public base::ImportantFileWriter::DataSerializer { - public: - // Returns instance of SequencedTaskRunner which guarantees that file - // operations on the same file will be executed in sequenced order. - static scoped_refptr GetTaskRunnerForFile( - const base::FilePath& pref_filename, - base::SequencedWorkerPool* worker_pool); - - // |sequenced_task_runner| is must be a shutdown-blocking task runner, ideally - // created by GetTaskRunnerForFile() method above. - JsonPrefStore(const base::FilePath& pref_filename, - base::SequencedTaskRunner* sequenced_task_runner); - - // PrefStore overrides: - virtual bool GetValue(const std::string& key, - const base::Value** result) const OVERRIDE; - virtual void AddObserver(PrefStore::Observer* observer) OVERRIDE; - virtual void RemoveObserver(PrefStore::Observer* observer) OVERRIDE; - virtual size_t NumberOfObservers() const OVERRIDE; - virtual bool IsInitializationComplete() const OVERRIDE; - - // PersistentPrefStore overrides: - virtual bool GetMutableValue(const std::string& key, - base::Value** result) OVERRIDE; - virtual void SetValue(const std::string& key, base::Value* value) OVERRIDE; - virtual void SetValueSilently(const std::string& key, - base::Value* value) OVERRIDE; - virtual void RemoveValue(const std::string& key) OVERRIDE; - virtual void MarkNeedsEmptyValue(const std::string& key) OVERRIDE; - virtual bool ReadOnly() const OVERRIDE; - virtual PrefReadError GetReadError() const OVERRIDE; - virtual PrefReadError ReadPrefs() OVERRIDE; - virtual void ReadPrefsAsync(ReadErrorDelegate* error_delegate) OVERRIDE; - virtual void CommitPendingWrite() OVERRIDE; - virtual void ReportValueChanged(const std::string& key) OVERRIDE; - - // This method is called after JSON file has been read. Method takes - // ownership of the |value| pointer. Note, this method is used with - // asynchronous file reading, so class exposes it only for the internal needs. - // (read: do not call it manually). - void OnFileRead(base::Value* value_owned, PrefReadError error, bool no_dir); - - private: - virtual ~JsonPrefStore(); - - // ImportantFileWriter::DataSerializer overrides: - virtual bool SerializeData(std::string* output) OVERRIDE; - - base::FilePath path_; - const scoped_refptr sequenced_task_runner_; - - scoped_ptr prefs_; - - bool read_only_; - - // Helper for safely writing pref data. - base::ImportantFileWriter writer_; - - ObserverList observers_; - - scoped_ptr error_delegate_; - - bool initialized_; - PrefReadError read_error_; - - std::set keys_need_empty_value_; - - DISALLOW_COPY_AND_ASSIGN(JsonPrefStore); -}; - -#endif // BASE_PREFS_JSON_PREF_STORE_H_ diff --git a/base/prefs/json_pref_store_unittest.cc b/base/prefs/json_pref_store_unittest.cc deleted file mode 100644 index 34e1b8a9ed..0000000000 --- a/base/prefs/json_pref_store_unittest.cc +++ /dev/null @@ -1,287 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "base/prefs/json_pref_store.h" - -#include "base/file_util.h" -#include "base/files/scoped_temp_dir.h" -#include "base/memory/ref_counted.h" -#include "base/memory/scoped_ptr.h" -#include "base/path_service.h" -#include "base/run_loop.h" -#include "base/strings/string_number_conversions.h" -#include "base/strings/string_util.h" -#include "base/strings/utf_string_conversions.h" -#include "base/threading/sequenced_worker_pool.h" -#include "base/threading/thread.h" -#include "base/values.h" -#include "testing/gmock/include/gmock/gmock.h" -#include "testing/gtest/include/gtest/gtest.h" - -namespace base { -namespace { - -const char kHomePage[] = "homepage"; - -class MockPrefStoreObserver : public PrefStore::Observer { - public: - MOCK_METHOD1(OnPrefValueChanged, void (const std::string&)); - MOCK_METHOD1(OnInitializationCompleted, void (bool)); -}; - -class MockReadErrorDelegate : public PersistentPrefStore::ReadErrorDelegate { - public: - MOCK_METHOD1(OnError, void(PersistentPrefStore::PrefReadError)); -}; - -} // namespace - -class JsonPrefStoreTest : public testing::Test { - protected: - virtual void SetUp() OVERRIDE { - ASSERT_TRUE(temp_dir_.CreateUniqueTempDir()); - - ASSERT_TRUE(PathService::Get(base::DIR_TEST_DATA, &data_dir_)); - data_dir_ = data_dir_.AppendASCII("prefs"); - ASSERT_TRUE(PathExists(data_dir_)); - } - - // The path to temporary directory used to contain the test operations. - base::ScopedTempDir temp_dir_; - // The path to the directory where the test data is stored. - base::FilePath data_dir_; - // A message loop that we can use as the file thread message loop. - MessageLoop message_loop_; -}; - -// Test fallback behavior for a nonexistent file. -TEST_F(JsonPrefStoreTest, NonExistentFile) { - base::FilePath bogus_input_file = data_dir_.AppendASCII("read.txt"); - ASSERT_FALSE(PathExists(bogus_input_file)); - scoped_refptr pref_store = new JsonPrefStore( - bogus_input_file, message_loop_.message_loop_proxy().get()); - EXPECT_EQ(PersistentPrefStore::PREF_READ_ERROR_NO_FILE, - pref_store->ReadPrefs()); - EXPECT_FALSE(pref_store->ReadOnly()); -} - -// Test fallback behavior for an invalid file. -TEST_F(JsonPrefStoreTest, InvalidFile) { - base::FilePath invalid_file_original = data_dir_.AppendASCII("invalid.json"); - base::FilePath invalid_file = temp_dir_.path().AppendASCII("invalid.json"); - ASSERT_TRUE(base::CopyFile(invalid_file_original, invalid_file)); - scoped_refptr pref_store = - new JsonPrefStore(invalid_file, message_loop_.message_loop_proxy().get()); - EXPECT_EQ(PersistentPrefStore::PREF_READ_ERROR_JSON_PARSE, - pref_store->ReadPrefs()); - EXPECT_FALSE(pref_store->ReadOnly()); - - // The file should have been moved aside. - EXPECT_FALSE(PathExists(invalid_file)); - base::FilePath moved_aside = temp_dir_.path().AppendASCII("invalid.bad"); - EXPECT_TRUE(PathExists(moved_aside)); - EXPECT_TRUE(TextContentsEqual(invalid_file_original, moved_aside)); -} - -// This function is used to avoid code duplication while testing synchronous and -// asynchronous version of the JsonPrefStore loading. -void RunBasicJsonPrefStoreTest(JsonPrefStore* pref_store, - const base::FilePath& output_file, - const base::FilePath& golden_output_file) { - const char kNewWindowsInTabs[] = "tabs.new_windows_in_tabs"; - const char kMaxTabs[] = "tabs.max_tabs"; - const char kLongIntPref[] = "long_int.pref"; - - std::string cnn("http://www.cnn.com"); - - const Value* actual; - EXPECT_TRUE(pref_store->GetValue(kHomePage, &actual)); - std::string string_value; - EXPECT_TRUE(actual->GetAsString(&string_value)); - EXPECT_EQ(cnn, string_value); - - const char kSomeDirectory[] = "some_directory"; - - EXPECT_TRUE(pref_store->GetValue(kSomeDirectory, &actual)); - base::FilePath::StringType path; - EXPECT_TRUE(actual->GetAsString(&path)); - EXPECT_EQ(base::FilePath::StringType(FILE_PATH_LITERAL("/usr/local/")), path); - base::FilePath some_path(FILE_PATH_LITERAL("/usr/sbin/")); - - pref_store->SetValue(kSomeDirectory, new StringValue(some_path.value())); - EXPECT_TRUE(pref_store->GetValue(kSomeDirectory, &actual)); - EXPECT_TRUE(actual->GetAsString(&path)); - EXPECT_EQ(some_path.value(), path); - - // Test reading some other data types from sub-dictionaries. - EXPECT_TRUE(pref_store->GetValue(kNewWindowsInTabs, &actual)); - bool boolean = false; - EXPECT_TRUE(actual->GetAsBoolean(&boolean)); - EXPECT_TRUE(boolean); - - pref_store->SetValue(kNewWindowsInTabs, new FundamentalValue(false)); - EXPECT_TRUE(pref_store->GetValue(kNewWindowsInTabs, &actual)); - EXPECT_TRUE(actual->GetAsBoolean(&boolean)); - EXPECT_FALSE(boolean); - - EXPECT_TRUE(pref_store->GetValue(kMaxTabs, &actual)); - int integer = 0; - EXPECT_TRUE(actual->GetAsInteger(&integer)); - EXPECT_EQ(20, integer); - pref_store->SetValue(kMaxTabs, new FundamentalValue(10)); - EXPECT_TRUE(pref_store->GetValue(kMaxTabs, &actual)); - EXPECT_TRUE(actual->GetAsInteger(&integer)); - EXPECT_EQ(10, integer); - - pref_store->SetValue(kLongIntPref, - new StringValue(base::Int64ToString(214748364842LL))); - EXPECT_TRUE(pref_store->GetValue(kLongIntPref, &actual)); - EXPECT_TRUE(actual->GetAsString(&string_value)); - int64 value; - base::StringToInt64(string_value, &value); - EXPECT_EQ(214748364842LL, value); - - // Serialize and compare to expected output. - ASSERT_TRUE(PathExists(golden_output_file)); - pref_store->CommitPendingWrite(); - RunLoop().RunUntilIdle(); - EXPECT_TRUE(TextContentsEqual(golden_output_file, output_file)); - ASSERT_TRUE(base::DeleteFile(output_file, false)); -} - -TEST_F(JsonPrefStoreTest, Basic) { - ASSERT_TRUE(base::CopyFile(data_dir_.AppendASCII("read.json"), - temp_dir_.path().AppendASCII("write.json"))); - - // Test that the persistent value can be loaded. - base::FilePath input_file = temp_dir_.path().AppendASCII("write.json"); - ASSERT_TRUE(PathExists(input_file)); - scoped_refptr pref_store = - new JsonPrefStore(input_file, message_loop_.message_loop_proxy().get()); - ASSERT_EQ(PersistentPrefStore::PREF_READ_ERROR_NONE, pref_store->ReadPrefs()); - ASSERT_FALSE(pref_store->ReadOnly()); - - // The JSON file looks like this: - // { - // "homepage": "http://www.cnn.com", - // "some_directory": "/usr/local/", - // "tabs": { - // "new_windows_in_tabs": true, - // "max_tabs": 20 - // } - // } - - RunBasicJsonPrefStoreTest( - pref_store.get(), input_file, data_dir_.AppendASCII("write.golden.json")); -} - -TEST_F(JsonPrefStoreTest, BasicAsync) { - ASSERT_TRUE(base::CopyFile(data_dir_.AppendASCII("read.json"), - temp_dir_.path().AppendASCII("write.json"))); - - // Test that the persistent value can be loaded. - base::FilePath input_file = temp_dir_.path().AppendASCII("write.json"); - ASSERT_TRUE(PathExists(input_file)); - scoped_refptr pref_store = - new JsonPrefStore(input_file, message_loop_.message_loop_proxy().get()); - - { - MockPrefStoreObserver mock_observer; - pref_store->AddObserver(&mock_observer); - - MockReadErrorDelegate* mock_error_delegate = new MockReadErrorDelegate; - pref_store->ReadPrefsAsync(mock_error_delegate); - - EXPECT_CALL(mock_observer, OnInitializationCompleted(true)).Times(1); - EXPECT_CALL(*mock_error_delegate, - OnError(PersistentPrefStore::PREF_READ_ERROR_NONE)).Times(0); - RunLoop().RunUntilIdle(); - pref_store->RemoveObserver(&mock_observer); - - ASSERT_FALSE(pref_store->ReadOnly()); - } - - // The JSON file looks like this: - // { - // "homepage": "http://www.cnn.com", - // "some_directory": "/usr/local/", - // "tabs": { - // "new_windows_in_tabs": true, - // "max_tabs": 20 - // } - // } - - RunBasicJsonPrefStoreTest( - pref_store.get(), input_file, data_dir_.AppendASCII("write.golden.json")); -} - -// Tests asynchronous reading of the file when there is no file. -TEST_F(JsonPrefStoreTest, AsyncNonExistingFile) { - base::FilePath bogus_input_file = data_dir_.AppendASCII("read.txt"); - ASSERT_FALSE(PathExists(bogus_input_file)); - scoped_refptr pref_store = new JsonPrefStore( - bogus_input_file, message_loop_.message_loop_proxy().get()); - MockPrefStoreObserver mock_observer; - pref_store->AddObserver(&mock_observer); - - MockReadErrorDelegate *mock_error_delegate = new MockReadErrorDelegate; - pref_store->ReadPrefsAsync(mock_error_delegate); - - EXPECT_CALL(mock_observer, OnInitializationCompleted(true)).Times(1); - EXPECT_CALL(*mock_error_delegate, - OnError(PersistentPrefStore::PREF_READ_ERROR_NO_FILE)).Times(1); - RunLoop().RunUntilIdle(); - pref_store->RemoveObserver(&mock_observer); - - EXPECT_FALSE(pref_store->ReadOnly()); -} - -TEST_F(JsonPrefStoreTest, NeedsEmptyValue) { - base::FilePath pref_file = temp_dir_.path().AppendASCII("write.json"); - - ASSERT_TRUE(base::CopyFile( - data_dir_.AppendASCII("read.need_empty_value.json"), - pref_file)); - - // Test that the persistent value can be loaded. - ASSERT_TRUE(PathExists(pref_file)); - scoped_refptr pref_store = - new JsonPrefStore(pref_file, message_loop_.message_loop_proxy().get()); - ASSERT_EQ(PersistentPrefStore::PREF_READ_ERROR_NONE, pref_store->ReadPrefs()); - ASSERT_FALSE(pref_store->ReadOnly()); - - // The JSON file looks like this: - // { - // "list": [ 1 ], - // "list_needs_empty_value": [ 2 ], - // "dict": { - // "dummy": true, - // }, - // "dict_needs_empty_value": { - // "dummy": true, - // }, - // } - - // Set flag to preserve empty values for the following keys. - pref_store->MarkNeedsEmptyValue("list_needs_empty_value"); - pref_store->MarkNeedsEmptyValue("dict_needs_empty_value"); - - // Set all keys to empty values. - pref_store->SetValue("list", new base::ListValue); - pref_store->SetValue("list_needs_empty_value", new base::ListValue); - pref_store->SetValue("dict", new base::DictionaryValue); - pref_store->SetValue("dict_needs_empty_value", new base::DictionaryValue); - - // Write to file. - pref_store->CommitPendingWrite(); - RunLoop().RunUntilIdle(); - - // Compare to expected output. - base::FilePath golden_output_file = - data_dir_.AppendASCII("write.golden.need_empty_value.json"); - ASSERT_TRUE(PathExists(golden_output_file)); - EXPECT_TRUE(TextContentsEqual(golden_output_file, pref_file)); -} - -} // namespace base diff --git a/base/prefs/mock_pref_change_callback.cc b/base/prefs/mock_pref_change_callback.cc deleted file mode 100644 index 96b71974eb..0000000000 --- a/base/prefs/mock_pref_change_callback.cc +++ /dev/null @@ -1,24 +0,0 @@ -// Copyright (c) 2011 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "base/prefs/mock_pref_change_callback.h" - -#include "base/bind.h" - -MockPrefChangeCallback::MockPrefChangeCallback(PrefService* prefs) - : prefs_(prefs) { -} - -MockPrefChangeCallback::~MockPrefChangeCallback() {} - -PrefChangeRegistrar::NamedChangeCallback MockPrefChangeCallback::GetCallback() { - return base::Bind(&MockPrefChangeCallback::OnPreferenceChanged, - base::Unretained(this)); -} - -void MockPrefChangeCallback::Expect(const std::string& pref_name, - const base::Value* value) { - EXPECT_CALL(*this, OnPreferenceChanged(pref_name)) - .With(PrefValueMatches(prefs_, pref_name, value)); -} diff --git a/base/prefs/mock_pref_change_callback.h b/base/prefs/mock_pref_change_callback.h deleted file mode 100644 index 422754afd6..0000000000 --- a/base/prefs/mock_pref_change_callback.h +++ /dev/null @@ -1,52 +0,0 @@ -// Copyright (c) 2011 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef BASE_PREFS_MOCK_PREF_CHANGE_CALLBACK_H_ -#define BASE_PREFS_MOCK_PREF_CHANGE_CALLBACK_H_ - -#include - -#include "base/prefs/pref_change_registrar.h" -#include "base/prefs/pref_service.h" -#include "testing/gmock/include/gmock/gmock.h" - -using testing::Pointee; -using testing::Property; -using testing::Truly; - -// Matcher that checks whether the current value of the preference named -// |pref_name| in |prefs| matches |value|. If |value| is NULL, the matcher -// checks that the value is not set. -MATCHER_P3(PrefValueMatches, prefs, pref_name, value, "") { - const PrefService::Preference* pref = - prefs->FindPreference(pref_name.c_str()); - if (!pref) - return false; - - const base::Value* actual_value = pref->GetValue(); - if (!actual_value) - return value == NULL; - if (!value) - return actual_value == NULL; - return value->Equals(actual_value); -} - -// A mock for testing preference notifications and easy setup of expectations. -class MockPrefChangeCallback { - public: - explicit MockPrefChangeCallback(PrefService* prefs); - virtual ~MockPrefChangeCallback(); - - PrefChangeRegistrar::NamedChangeCallback GetCallback(); - - MOCK_METHOD1(OnPreferenceChanged, void(const std::string&)); - - void Expect(const std::string& pref_name, - const base::Value* value); - - private: - PrefService* prefs_; -}; - -#endif // BASE_PREFS_MOCK_PREF_CHANGE_CALLBACK_H_ diff --git a/base/prefs/overlay_user_pref_store.cc b/base/prefs/overlay_user_pref_store.cc deleted file mode 100644 index 628d3b4e33..0000000000 --- a/base/prefs/overlay_user_pref_store.cc +++ /dev/null @@ -1,182 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "base/prefs/overlay_user_pref_store.h" - -#include "base/memory/scoped_ptr.h" -#include "base/values.h" - -OverlayUserPrefStore::OverlayUserPrefStore( - PersistentPrefStore* underlay) - : underlay_(underlay) { - underlay_->AddObserver(this); -} - -bool OverlayUserPrefStore::IsSetInOverlay(const std::string& key) const { - return overlay_.GetValue(key, NULL); -} - -void OverlayUserPrefStore::AddObserver(PrefStore::Observer* observer) { - observers_.AddObserver(observer); -} - -void OverlayUserPrefStore::RemoveObserver(PrefStore::Observer* observer) { - observers_.RemoveObserver(observer); -} - -size_t OverlayUserPrefStore::NumberOfObservers() const { - return observers_.size(); -} - -bool OverlayUserPrefStore::IsInitializationComplete() const { - return underlay_->IsInitializationComplete(); -} - -bool OverlayUserPrefStore::GetValue(const std::string& key, - const base::Value** result) const { - // If the |key| shall NOT be stored in the overlay store, there must not - // be an entry. - DCHECK(ShallBeStoredInOverlay(key) || !overlay_.GetValue(key, NULL)); - - if (overlay_.GetValue(key, result)) - return true; - return underlay_->GetValue(GetUnderlayKey(key), result); -} - -bool OverlayUserPrefStore::GetMutableValue(const std::string& key, - base::Value** result) { - if (!ShallBeStoredInOverlay(key)) - return underlay_->GetMutableValue(GetUnderlayKey(key), result); - - if (overlay_.GetValue(key, result)) - return true; - - // Try to create copy of underlay if the overlay does not contain a value. - base::Value* underlay_value = NULL; - if (!underlay_->GetMutableValue(GetUnderlayKey(key), &underlay_value)) - return false; - - *result = underlay_value->DeepCopy(); - overlay_.SetValue(key, *result); - return true; -} - -void OverlayUserPrefStore::SetValue(const std::string& key, - base::Value* value) { - if (!ShallBeStoredInOverlay(key)) { - underlay_->SetValue(GetUnderlayKey(key), value); - return; - } - - if (overlay_.SetValue(key, value)) - ReportValueChanged(key); -} - -void OverlayUserPrefStore::SetValueSilently(const std::string& key, - base::Value* value) { - if (!ShallBeStoredInOverlay(key)) { - underlay_->SetValueSilently(GetUnderlayKey(key), value); - return; - } - - overlay_.SetValue(key, value); -} - -void OverlayUserPrefStore::RemoveValue(const std::string& key) { - if (!ShallBeStoredInOverlay(key)) { - underlay_->RemoveValue(GetUnderlayKey(key)); - return; - } - - if (overlay_.RemoveValue(key)) - ReportValueChanged(key); -} - -void OverlayUserPrefStore::MarkNeedsEmptyValue(const std::string& key) { - if (!ShallBeStoredInOverlay(key)) - underlay_->MarkNeedsEmptyValue(key); -} - -bool OverlayUserPrefStore::ReadOnly() const { - return false; -} - -PersistentPrefStore::PrefReadError OverlayUserPrefStore::GetReadError() const { - return PersistentPrefStore::PREF_READ_ERROR_NONE; -} - -PersistentPrefStore::PrefReadError OverlayUserPrefStore::ReadPrefs() { - // We do not read intentionally. - OnInitializationCompleted(true); - return PersistentPrefStore::PREF_READ_ERROR_NONE; -} - -void OverlayUserPrefStore::ReadPrefsAsync( - ReadErrorDelegate* error_delegate_raw) { - scoped_ptr error_delegate(error_delegate_raw); - // We do not read intentionally. - OnInitializationCompleted(true); -} - -void OverlayUserPrefStore::CommitPendingWrite() { - underlay_->CommitPendingWrite(); - // We do not write our content intentionally. -} - -void OverlayUserPrefStore::ReportValueChanged(const std::string& key) { - FOR_EACH_OBSERVER(PrefStore::Observer, observers_, OnPrefValueChanged(key)); -} - -void OverlayUserPrefStore::OnPrefValueChanged(const std::string& key) { - if (!overlay_.GetValue(GetOverlayKey(key), NULL)) - ReportValueChanged(GetOverlayKey(key)); -} - -void OverlayUserPrefStore::OnInitializationCompleted(bool succeeded) { - FOR_EACH_OBSERVER(PrefStore::Observer, observers_, - OnInitializationCompleted(succeeded)); -} - -void OverlayUserPrefStore::RegisterOverlayPref(const std::string& key) { - RegisterOverlayPref(key, key); -} - -void OverlayUserPrefStore::RegisterOverlayPref( - const std::string& overlay_key, - const std::string& underlay_key) { - DCHECK(!overlay_key.empty()) << "Overlay key is empty"; - DCHECK(overlay_to_underlay_names_map_.find(overlay_key) == - overlay_to_underlay_names_map_.end()) << - "Overlay key already registered"; - DCHECK(!underlay_key.empty()) << "Underlay key is empty"; - DCHECK(underlay_to_overlay_names_map_.find(underlay_key) == - underlay_to_overlay_names_map_.end()) << - "Underlay key already registered"; - overlay_to_underlay_names_map_[overlay_key] = underlay_key; - underlay_to_overlay_names_map_[underlay_key] = overlay_key; -} - -OverlayUserPrefStore::~OverlayUserPrefStore() { - underlay_->RemoveObserver(this); -} - -const std::string& OverlayUserPrefStore::GetOverlayKey( - const std::string& underlay_key) const { - NamesMap::const_iterator i = - underlay_to_overlay_names_map_.find(underlay_key); - return i != underlay_to_overlay_names_map_.end() ? i->second : underlay_key; -} - -const std::string& OverlayUserPrefStore::GetUnderlayKey( - const std::string& overlay_key) const { - NamesMap::const_iterator i = - overlay_to_underlay_names_map_.find(overlay_key); - return i != overlay_to_underlay_names_map_.end() ? i->second : overlay_key; -} - -bool OverlayUserPrefStore::ShallBeStoredInOverlay( - const std::string& key) const { - return overlay_to_underlay_names_map_.find(key) != - overlay_to_underlay_names_map_.end(); -} diff --git a/base/prefs/overlay_user_pref_store.h b/base/prefs/overlay_user_pref_store.h deleted file mode 100644 index 120d405246..0000000000 --- a/base/prefs/overlay_user_pref_store.h +++ /dev/null @@ -1,85 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef BASE_PREFS_OVERLAY_USER_PREF_STORE_H_ -#define BASE_PREFS_OVERLAY_USER_PREF_STORE_H_ - -#include -#include - -#include "base/basictypes.h" -#include "base/memory/ref_counted.h" -#include "base/observer_list.h" -#include "base/prefs/base_prefs_export.h" -#include "base/prefs/persistent_pref_store.h" -#include "base/prefs/pref_value_map.h" - -// PersistentPrefStore that directs all write operations into an in-memory -// PrefValueMap. Read operations are first answered by the PrefValueMap. -// If the PrefValueMap does not contain a value for the requested key, -// the look-up is passed on to an underlying PersistentPrefStore |underlay_|. -class BASE_PREFS_EXPORT OverlayUserPrefStore : public PersistentPrefStore, - public PrefStore::Observer { - public: - explicit OverlayUserPrefStore(PersistentPrefStore* underlay); - - // Returns true if a value has been set for the |key| in this - // OverlayUserPrefStore, i.e. if it potentially overrides a value - // from the |underlay_|. - virtual bool IsSetInOverlay(const std::string& key) const; - - // Methods of PrefStore. - virtual void AddObserver(PrefStore::Observer* observer) OVERRIDE; - virtual void RemoveObserver(PrefStore::Observer* observer) OVERRIDE; - virtual size_t NumberOfObservers() const OVERRIDE; - virtual bool IsInitializationComplete() const OVERRIDE; - virtual bool GetValue(const std::string& key, - const base::Value** result) const OVERRIDE; - - // Methods of PersistentPrefStore. - virtual bool GetMutableValue(const std::string& key, - base::Value** result) OVERRIDE; - virtual void SetValue(const std::string& key, base::Value* value) OVERRIDE; - virtual void SetValueSilently(const std::string& key, - base::Value* value) OVERRIDE; - virtual void RemoveValue(const std::string& key) OVERRIDE; - virtual void MarkNeedsEmptyValue(const std::string& key) OVERRIDE; - virtual bool ReadOnly() const OVERRIDE; - virtual PrefReadError GetReadError() const OVERRIDE; - virtual PrefReadError ReadPrefs() OVERRIDE; - virtual void ReadPrefsAsync(ReadErrorDelegate* delegate) OVERRIDE; - virtual void CommitPendingWrite() OVERRIDE; - virtual void ReportValueChanged(const std::string& key) OVERRIDE; - - // Methods of PrefStore::Observer. - virtual void OnPrefValueChanged(const std::string& key) OVERRIDE; - virtual void OnInitializationCompleted(bool succeeded) OVERRIDE; - - void RegisterOverlayPref(const std::string& key); - void RegisterOverlayPref(const std::string& overlay_key, - const std::string& underlay_key); - - protected: - virtual ~OverlayUserPrefStore(); - - private: - typedef std::map NamesMap; - - const std::string& GetOverlayKey(const std::string& underlay_key) const; - const std::string& GetUnderlayKey(const std::string& overlay_key) const; - - // Returns true if |key| corresponds to a preference that shall be stored in - // an in-memory PrefStore that is not persisted to disk. - bool ShallBeStoredInOverlay(const std::string& key) const; - - ObserverList observers_; - PrefValueMap overlay_; - scoped_refptr underlay_; - NamesMap overlay_to_underlay_names_map_; - NamesMap underlay_to_overlay_names_map_; - - DISALLOW_COPY_AND_ASSIGN(OverlayUserPrefStore); -}; - -#endif // BASE_PREFS_OVERLAY_USER_PREF_STORE_H_ diff --git a/base/prefs/overlay_user_pref_store_unittest.cc b/base/prefs/overlay_user_pref_store_unittest.cc deleted file mode 100644 index c4e980bbae..0000000000 --- a/base/prefs/overlay_user_pref_store_unittest.cc +++ /dev/null @@ -1,278 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "base/prefs/overlay_user_pref_store.h" - -#include "base/prefs/pref_store_observer_mock.h" -#include "base/prefs/testing_pref_store.h" -#include "base/values.h" -#include "testing/gmock/include/gmock/gmock.h" -#include "testing/gtest/include/gtest/gtest.h" - -using ::testing::Mock; -using ::testing::StrEq; - -namespace base { -namespace { - -const char kBrowserWindowPlacement[] = "browser.window_placement"; -const char kShowBookmarkBar[] = "bookmark_bar.show_on_all_tabs"; - -const char* overlay_key = kBrowserWindowPlacement; -const char* regular_key = kShowBookmarkBar; -// With the removal of the kWebKitGlobalXXX prefs, we'll no longer have real -// prefs using the overlay pref store, so make up keys here. -const char* mapped_overlay_key = "test.per_tab.javascript_enabled"; -const char* mapped_underlay_key = "test.per_profile.javascript_enabled"; - -} // namespace - -class OverlayUserPrefStoreTest : public testing::Test { - protected: - OverlayUserPrefStoreTest() - : underlay_(new TestingPrefStore()), - overlay_(new OverlayUserPrefStore(underlay_.get())) { - overlay_->RegisterOverlayPref(overlay_key); - overlay_->RegisterOverlayPref(mapped_overlay_key, mapped_underlay_key); - } - - virtual ~OverlayUserPrefStoreTest() {} - - scoped_refptr underlay_; - scoped_refptr overlay_; -}; - -TEST_F(OverlayUserPrefStoreTest, Observer) { - PrefStoreObserverMock obs; - overlay_->AddObserver(&obs); - - // Check that underlay first value is reported. - EXPECT_CALL(obs, OnPrefValueChanged(StrEq(overlay_key))).Times(1); - underlay_->SetValue(overlay_key, new FundamentalValue(42)); - Mock::VerifyAndClearExpectations(&obs); - - // Check that underlay overwriting is reported. - EXPECT_CALL(obs, OnPrefValueChanged(StrEq(overlay_key))).Times(1); - underlay_->SetValue(overlay_key, new FundamentalValue(43)); - Mock::VerifyAndClearExpectations(&obs); - - // Check that overwriting change in overlay is reported. - EXPECT_CALL(obs, OnPrefValueChanged(StrEq(overlay_key))).Times(1); - overlay_->SetValue(overlay_key, new FundamentalValue(44)); - Mock::VerifyAndClearExpectations(&obs); - - // Check that hidden underlay change is not reported. - EXPECT_CALL(obs, OnPrefValueChanged(StrEq(overlay_key))).Times(0); - underlay_->SetValue(overlay_key, new FundamentalValue(45)); - Mock::VerifyAndClearExpectations(&obs); - - // Check that overlay remove is reported. - EXPECT_CALL(obs, OnPrefValueChanged(StrEq(overlay_key))).Times(1); - overlay_->RemoveValue(overlay_key); - Mock::VerifyAndClearExpectations(&obs); - - // Check that underlay remove is reported. - EXPECT_CALL(obs, OnPrefValueChanged(StrEq(overlay_key))).Times(1); - underlay_->RemoveValue(overlay_key); - Mock::VerifyAndClearExpectations(&obs); - - // Check respecting of silence. - EXPECT_CALL(obs, OnPrefValueChanged(StrEq(overlay_key))).Times(0); - overlay_->SetValueSilently(overlay_key, new FundamentalValue(46)); - Mock::VerifyAndClearExpectations(&obs); - - overlay_->RemoveObserver(&obs); - - // Check successful unsubscription. - EXPECT_CALL(obs, OnPrefValueChanged(StrEq(overlay_key))).Times(0); - underlay_->SetValue(overlay_key, new FundamentalValue(47)); - overlay_->SetValue(overlay_key, new FundamentalValue(48)); - Mock::VerifyAndClearExpectations(&obs); -} - -TEST_F(OverlayUserPrefStoreTest, GetAndSet) { - const Value* value = NULL; - EXPECT_FALSE(overlay_->GetValue(overlay_key, &value)); - EXPECT_FALSE(underlay_->GetValue(overlay_key, &value)); - - underlay_->SetValue(overlay_key, new FundamentalValue(42)); - - // Value shines through: - EXPECT_TRUE(overlay_->GetValue(overlay_key, &value)); - EXPECT_TRUE(base::FundamentalValue(42).Equals(value)); - - EXPECT_TRUE(underlay_->GetValue(overlay_key, &value)); - EXPECT_TRUE(base::FundamentalValue(42).Equals(value)); - - overlay_->SetValue(overlay_key, new FundamentalValue(43)); - - EXPECT_TRUE(overlay_->GetValue(overlay_key, &value)); - EXPECT_TRUE(base::FundamentalValue(43).Equals(value)); - - EXPECT_TRUE(underlay_->GetValue(overlay_key, &value)); - EXPECT_TRUE(base::FundamentalValue(42).Equals(value)); - - overlay_->RemoveValue(overlay_key); - - // Value shines through: - EXPECT_TRUE(overlay_->GetValue(overlay_key, &value)); - EXPECT_TRUE(base::FundamentalValue(42).Equals(value)); - - EXPECT_TRUE(underlay_->GetValue(overlay_key, &value)); - EXPECT_TRUE(base::FundamentalValue(42).Equals(value)); -} - -// Check that GetMutableValue does not return the dictionary of the underlay. -TEST_F(OverlayUserPrefStoreTest, ModifyDictionaries) { - underlay_->SetValue(overlay_key, new DictionaryValue); - - Value* modify = NULL; - EXPECT_TRUE(overlay_->GetMutableValue(overlay_key, &modify)); - ASSERT_TRUE(modify); - ASSERT_TRUE(modify->IsType(Value::TYPE_DICTIONARY)); - static_cast(modify)->SetInteger(overlay_key, 42); - - Value* original_in_underlay = NULL; - EXPECT_TRUE(underlay_->GetMutableValue(overlay_key, &original_in_underlay)); - ASSERT_TRUE(original_in_underlay); - ASSERT_TRUE(original_in_underlay->IsType(Value::TYPE_DICTIONARY)); - EXPECT_TRUE(static_cast(original_in_underlay)->empty()); - - Value* modified = NULL; - EXPECT_TRUE(overlay_->GetMutableValue(overlay_key, &modified)); - ASSERT_TRUE(modified); - ASSERT_TRUE(modified->IsType(Value::TYPE_DICTIONARY)); - EXPECT_TRUE(Value::Equals(modify, static_cast(modified))); -} - -// Here we consider a global preference that is not overlayed. -TEST_F(OverlayUserPrefStoreTest, GlobalPref) { - PrefStoreObserverMock obs; - overlay_->AddObserver(&obs); - - const Value* value = NULL; - - // Check that underlay first value is reported. - EXPECT_CALL(obs, OnPrefValueChanged(StrEq(regular_key))).Times(1); - underlay_->SetValue(regular_key, new FundamentalValue(42)); - Mock::VerifyAndClearExpectations(&obs); - - // Check that underlay overwriting is reported. - EXPECT_CALL(obs, OnPrefValueChanged(StrEq(regular_key))).Times(1); - underlay_->SetValue(regular_key, new FundamentalValue(43)); - Mock::VerifyAndClearExpectations(&obs); - - // Check that we get this value from the overlay - EXPECT_TRUE(overlay_->GetValue(regular_key, &value)); - EXPECT_TRUE(base::FundamentalValue(43).Equals(value)); - - // Check that overwriting change in overlay is reported. - EXPECT_CALL(obs, OnPrefValueChanged(StrEq(regular_key))).Times(1); - overlay_->SetValue(regular_key, new FundamentalValue(44)); - Mock::VerifyAndClearExpectations(&obs); - - // Check that we get this value from the overlay and the underlay. - EXPECT_TRUE(overlay_->GetValue(regular_key, &value)); - EXPECT_TRUE(base::FundamentalValue(44).Equals(value)); - EXPECT_TRUE(underlay_->GetValue(regular_key, &value)); - EXPECT_TRUE(base::FundamentalValue(44).Equals(value)); - - // Check that overlay remove is reported. - EXPECT_CALL(obs, OnPrefValueChanged(StrEq(regular_key))).Times(1); - overlay_->RemoveValue(regular_key); - Mock::VerifyAndClearExpectations(&obs); - - // Check that value was removed from overlay and underlay - EXPECT_FALSE(overlay_->GetValue(regular_key, &value)); - EXPECT_FALSE(underlay_->GetValue(regular_key, &value)); - - // Check respecting of silence. - EXPECT_CALL(obs, OnPrefValueChanged(StrEq(regular_key))).Times(0); - overlay_->SetValueSilently(regular_key, new FundamentalValue(46)); - Mock::VerifyAndClearExpectations(&obs); - - overlay_->RemoveObserver(&obs); - - // Check successful unsubscription. - EXPECT_CALL(obs, OnPrefValueChanged(StrEq(regular_key))).Times(0); - underlay_->SetValue(regular_key, new FundamentalValue(47)); - overlay_->SetValue(regular_key, new FundamentalValue(48)); - Mock::VerifyAndClearExpectations(&obs); -} - -// Check that names mapping works correctly. -TEST_F(OverlayUserPrefStoreTest, NamesMapping) { - PrefStoreObserverMock obs; - overlay_->AddObserver(&obs); - - const Value* value = NULL; - - // Check that if there is no override in the overlay, changing underlay value - // is reported as changing an overlay value. - EXPECT_CALL(obs, OnPrefValueChanged(StrEq(mapped_overlay_key))).Times(1); - underlay_->SetValue(mapped_underlay_key, new FundamentalValue(42)); - Mock::VerifyAndClearExpectations(&obs); - - // Check that underlay overwriting is reported. - EXPECT_CALL(obs, OnPrefValueChanged(StrEq(mapped_overlay_key))).Times(1); - underlay_->SetValue(mapped_underlay_key, new FundamentalValue(43)); - Mock::VerifyAndClearExpectations(&obs); - - // Check that we get this value from the overlay with both keys - EXPECT_TRUE(overlay_->GetValue(mapped_overlay_key, &value)); - EXPECT_TRUE(base::FundamentalValue(43).Equals(value)); - // In this case, overlay reads directly from the underlay. - EXPECT_TRUE(overlay_->GetValue(mapped_underlay_key, &value)); - EXPECT_TRUE(base::FundamentalValue(43).Equals(value)); - - // Check that overwriting change in overlay is reported. - EXPECT_CALL(obs, OnPrefValueChanged(StrEq(mapped_overlay_key))).Times(1); - overlay_->SetValue(mapped_overlay_key, new FundamentalValue(44)); - Mock::VerifyAndClearExpectations(&obs); - - // Check that we get an overriden value from overlay, while reading the - // value from underlay still holds an old value. - EXPECT_TRUE(overlay_->GetValue(mapped_overlay_key, &value)); - EXPECT_TRUE(base::FundamentalValue(44).Equals(value)); - EXPECT_TRUE(overlay_->GetValue(mapped_underlay_key, &value)); - EXPECT_TRUE(base::FundamentalValue(43).Equals(value)); - EXPECT_TRUE(underlay_->GetValue(mapped_underlay_key, &value)); - EXPECT_TRUE(base::FundamentalValue(43).Equals(value)); - - // Check that hidden underlay change is not reported. - EXPECT_CALL(obs, OnPrefValueChanged(StrEq(mapped_overlay_key))).Times(0); - underlay_->SetValue(mapped_underlay_key, new FundamentalValue(45)); - Mock::VerifyAndClearExpectations(&obs); - - // Check that overlay remove is reported. - EXPECT_CALL(obs, OnPrefValueChanged(StrEq(mapped_overlay_key))).Times(1); - overlay_->RemoveValue(mapped_overlay_key); - Mock::VerifyAndClearExpectations(&obs); - - // Check that underlay remove is reported. - EXPECT_CALL(obs, OnPrefValueChanged(StrEq(mapped_overlay_key))).Times(1); - underlay_->RemoveValue(mapped_underlay_key); - Mock::VerifyAndClearExpectations(&obs); - - // Check that value was removed. - EXPECT_FALSE(overlay_->GetValue(mapped_overlay_key, &value)); - EXPECT_FALSE(overlay_->GetValue(mapped_underlay_key, &value)); - - // Check respecting of silence. - EXPECT_CALL(obs, OnPrefValueChanged(StrEq(mapped_overlay_key))).Times(0); - EXPECT_CALL(obs, OnPrefValueChanged(StrEq(mapped_underlay_key))).Times(0); - overlay_->SetValueSilently(mapped_overlay_key, new FundamentalValue(46)); - Mock::VerifyAndClearExpectations(&obs); - - overlay_->RemoveObserver(&obs); - - // Check successful unsubscription. - EXPECT_CALL(obs, OnPrefValueChanged(StrEq(mapped_overlay_key))).Times(0); - EXPECT_CALL(obs, OnPrefValueChanged(StrEq(mapped_underlay_key))).Times(0); - underlay_->SetValue(mapped_underlay_key, new FundamentalValue(47)); - overlay_->SetValue(mapped_overlay_key, new FundamentalValue(48)); - Mock::VerifyAndClearExpectations(&obs); -} - -} // namespace base diff --git a/base/prefs/persistent_pref_store.h b/base/prefs/persistent_pref_store.h deleted file mode 100644 index 0baf02ac89..0000000000 --- a/base/prefs/persistent_pref_store.h +++ /dev/null @@ -1,95 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef BASE_PREFS_PERSISTENT_PREF_STORE_H_ -#define BASE_PREFS_PERSISTENT_PREF_STORE_H_ - -#include - -#include "base/prefs/base_prefs_export.h" -#include "base/prefs/pref_store.h" - -// This interface is complementary to the PrefStore interface, declaring -// additional functionality that adds support for setting values and persisting -// the data to some backing store. -class BASE_PREFS_EXPORT PersistentPrefStore : public PrefStore { - public: - // Unique integer code for each type of error so we can report them - // distinctly in a histogram. - // NOTE: Don't change the order here as it will change the server's meaning - // of the histogram. - enum PrefReadError { - PREF_READ_ERROR_NONE = 0, - PREF_READ_ERROR_JSON_PARSE, - PREF_READ_ERROR_JSON_TYPE, - PREF_READ_ERROR_ACCESS_DENIED, - PREF_READ_ERROR_FILE_OTHER, - PREF_READ_ERROR_FILE_LOCKED, - PREF_READ_ERROR_NO_FILE, - PREF_READ_ERROR_JSON_REPEAT, - PREF_READ_ERROR_OTHER, - PREF_READ_ERROR_FILE_NOT_SPECIFIED, - PREF_READ_ERROR_MAX_ENUM - }; - - class ReadErrorDelegate { - public: - virtual ~ReadErrorDelegate() {} - - virtual void OnError(PrefReadError error) = 0; - }; - - // Equivalent to PrefStore::GetValue but returns a mutable value. - virtual bool GetMutableValue(const std::string& key, - base::Value** result) = 0; - - // Triggers a value changed notification. This function needs to be called - // if one retrieves a list or dictionary with GetMutableValue and change its - // value. SetValue takes care of notifications itself. Note that - // ReportValueChanged will trigger notifications even if nothing has changed. - virtual void ReportValueChanged(const std::string& key) = 0; - - // Sets a |value| for |key| in the store. Assumes ownership of |value|, which - // must be non-NULL. - virtual void SetValue(const std::string& key, base::Value* value) = 0; - - // Same as SetValue, but doesn't generate notifications. This is used by - // PrefService::GetMutableUserPref() in order to put empty entries - // into the user pref store. Using SetValue is not an option since existing - // tests rely on the number of notifications generated. - virtual void SetValueSilently(const std::string& key, base::Value* value) = 0; - - // Removes the value for |key|. - virtual void RemoveValue(const std::string& key) = 0; - - // Marks that the |key| with empty ListValue/DictionaryValue needs to be - // persisted. - virtual void MarkNeedsEmptyValue(const std::string& key) = 0; - - // Whether the store is in a pseudo-read-only mode where changes are not - // actually persisted to disk. This happens in some cases when there are - // read errors during startup. - virtual bool ReadOnly() const = 0; - - // Gets the read error. Only valid if IsInitializationComplete() returns true. - virtual PrefReadError GetReadError() const = 0; - - // Reads the preferences from disk. Notifies observers via - // "PrefStore::OnInitializationCompleted" when done. - virtual PrefReadError ReadPrefs() = 0; - - // Reads the preferences from disk asynchronously. Notifies observers via - // "PrefStore::OnInitializationCompleted" when done. Also it fires - // |error_delegate| if it is not NULL and reading error has occurred. - // Owns |error_delegate|. - virtual void ReadPrefsAsync(ReadErrorDelegate* error_delegate) = 0; - - // Lands any pending writes to disk. - virtual void CommitPendingWrite() = 0; - - protected: - virtual ~PersistentPrefStore() {} -}; - -#endif // BASE_PREFS_PERSISTENT_PREF_STORE_H_ diff --git a/base/prefs/pref_change_registrar.cc b/base/prefs/pref_change_registrar.cc deleted file mode 100644 index 28ac374034..0000000000 --- a/base/prefs/pref_change_registrar.cc +++ /dev/null @@ -1,95 +0,0 @@ -// Copyright (c) 2010 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "base/prefs/pref_change_registrar.h" - -#include "base/bind.h" -#include "base/logging.h" -#include "base/prefs/pref_service.h" - -PrefChangeRegistrar::PrefChangeRegistrar() : service_(NULL) {} - -PrefChangeRegistrar::~PrefChangeRegistrar() { - // If you see an invalid memory access in this destructor, this - // PrefChangeRegistrar might be subscribed to an OffTheRecordProfileImpl that - // has been destroyed. This should not happen any more but be warned. - // Feel free to contact battre@chromium.org in case this happens. - RemoveAll(); -} - -void PrefChangeRegistrar::Init(PrefService* service) { - DCHECK(IsEmpty() || service_ == service); - service_ = service; -} - -void PrefChangeRegistrar::Add(const char* path, - const base::Closure& obs) { - Add(path, base::Bind(&PrefChangeRegistrar::InvokeUnnamedCallback, obs)); -} - -void PrefChangeRegistrar::Add(const char* path, - const NamedChangeCallback& obs) { - if (!service_) { - NOTREACHED(); - return; - } - DCHECK(!IsObserved(path)) << "Already had this pref registered."; - - service_->AddPrefObserver(path, this); - observers_[path] = obs; -} - -void PrefChangeRegistrar::Remove(const char* path) { - DCHECK(IsObserved(path)); - - observers_.erase(path); - service_->RemovePrefObserver(path, this); -} - -void PrefChangeRegistrar::RemoveAll() { - for (ObserverMap::const_iterator it = observers_.begin(); - it != observers_.end(); ++it) { - service_->RemovePrefObserver(it->first.c_str(), this); - } - - observers_.clear(); -} - -bool PrefChangeRegistrar::IsEmpty() const { - return observers_.empty(); -} - -bool PrefChangeRegistrar::IsObserved(const std::string& pref) { - return observers_.find(pref) != observers_.end(); -} - -bool PrefChangeRegistrar::IsManaged() { - for (ObserverMap::const_iterator it = observers_.begin(); - it != observers_.end(); ++it) { - const PrefService::Preference* pref = - service_->FindPreference(it->first.c_str()); - if (pref && pref->IsManaged()) - return true; - } - return false; -} - -void PrefChangeRegistrar::OnPreferenceChanged(PrefService* service, - const std::string& pref) { - if (IsObserved(pref)) - observers_[pref].Run(pref); -} - -void PrefChangeRegistrar::InvokeUnnamedCallback(const base::Closure& callback, - const std::string& pref_name) { - callback.Run(); -} - -PrefService* PrefChangeRegistrar::prefs() { - return service_; -} - -const PrefService* PrefChangeRegistrar::prefs() const { - return service_; -} diff --git a/base/prefs/pref_change_registrar.h b/base/prefs/pref_change_registrar.h deleted file mode 100644 index a914bea7d4..0000000000 --- a/base/prefs/pref_change_registrar.h +++ /dev/null @@ -1,81 +0,0 @@ -// Copyright (c) 2010 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef BASE_PREFS_PREF_CHANGE_REGISTRAR_H_ -#define BASE_PREFS_PREF_CHANGE_REGISTRAR_H_ - -#include -#include - -#include "base/basictypes.h" -#include "base/callback.h" -#include "base/prefs/base_prefs_export.h" -#include "base/prefs/pref_observer.h" - -class PrefService; - -// Automatically manages the registration of one or more pref change observers -// with a PrefStore. Functions much like NotificationRegistrar, but specifically -// manages observers of preference changes. When the Registrar is destroyed, -// all registered observers are automatically unregistered with the PrefStore. -class BASE_PREFS_EXPORT PrefChangeRegistrar : public PrefObserver { - public: - // You can register this type of callback if you need to know the - // path of the preference that is changing. - typedef base::Callback NamedChangeCallback; - - PrefChangeRegistrar(); - virtual ~PrefChangeRegistrar(); - - // Must be called before adding or removing observers. Can be called more - // than once as long as the value of |service| doesn't change. - void Init(PrefService* service); - - // Adds a pref observer for the specified pref |path| and |obs| observer - // object. All registered observers will be automatically unregistered - // when the registrar's destructor is called. - // - // The second version binds a callback that will receive the path of - // the preference that is changing as its parameter. - // - // Only one observer may be registered per path. - void Add(const char* path, const base::Closure& obs); - void Add(const char* path, const NamedChangeCallback& obs); - - // Removes the pref observer registered for |path|. - void Remove(const char* path); - - // Removes all observers that have been previously added with a call to Add. - void RemoveAll(); - - // Returns true if no pref observers are registered. - bool IsEmpty() const; - - // Check whether |pref| is in the set of preferences being observed. - bool IsObserved(const std::string& pref); - - // Check whether any of the observed preferences has the managed bit set. - bool IsManaged(); - - // Return the PrefService for this registrar. - PrefService* prefs(); - const PrefService* prefs() const; - - private: - // PrefObserver: - virtual void OnPreferenceChanged(PrefService* service, - const std::string& pref_name) OVERRIDE; - - static void InvokeUnnamedCallback(const base::Closure& callback, - const std::string& pref_name); - - typedef std::map ObserverMap; - - ObserverMap observers_; - PrefService* service_; - - DISALLOW_COPY_AND_ASSIGN(PrefChangeRegistrar); -}; - -#endif // BASE_PREFS_PREF_CHANGE_REGISTRAR_H_ diff --git a/base/prefs/pref_change_registrar_unittest.cc b/base/prefs/pref_change_registrar_unittest.cc deleted file mode 100644 index f353a8fb3c..0000000000 --- a/base/prefs/pref_change_registrar_unittest.cc +++ /dev/null @@ -1,200 +0,0 @@ -// Copyright (c) 2010 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "base/bind.h" -#include "base/bind_helpers.h" -#include "base/prefs/pref_change_registrar.h" -#include "base/prefs/pref_observer.h" -#include "base/prefs/pref_registry_simple.h" -#include "base/prefs/testing_pref_service.h" -#include "testing/gmock/include/gmock/gmock.h" -#include "testing/gtest/include/gtest/gtest.h" - -using testing::Mock; -using testing::Eq; - -namespace base { -namespace { - -const char kHomePage[] = "homepage"; -const char kHomePageIsNewTabPage[] = "homepage_is_newtabpage"; -const char kApplicationLocale[] = "intl.app_locale"; - -// A mock provider that allows us to capture pref observer changes. -class MockPrefService : public TestingPrefServiceSimple { - public: - MockPrefService() {} - virtual ~MockPrefService() {} - - MOCK_METHOD2(AddPrefObserver, - void(const char*, PrefObserver*)); - MOCK_METHOD2(RemovePrefObserver, - void(const char*, PrefObserver*)); -}; - -} // namespace - -class PrefChangeRegistrarTest : public testing::Test { - public: - PrefChangeRegistrarTest() {} - virtual ~PrefChangeRegistrarTest() {} - - protected: - virtual void SetUp() OVERRIDE; - - base::Closure observer() const { - return base::Bind(&base::DoNothing); - } - - MockPrefService* service() const { return service_.get(); } - - private: - scoped_ptr service_; -}; - -void PrefChangeRegistrarTest::SetUp() { - service_.reset(new MockPrefService()); -} - -TEST_F(PrefChangeRegistrarTest, AddAndRemove) { - PrefChangeRegistrar registrar; - registrar.Init(service()); - - // Test adding. - EXPECT_CALL(*service(), - AddPrefObserver(Eq(std::string("test.pref.1")), ®istrar)); - EXPECT_CALL(*service(), - AddPrefObserver(Eq(std::string("test.pref.2")), ®istrar)); - registrar.Add("test.pref.1", observer()); - registrar.Add("test.pref.2", observer()); - EXPECT_FALSE(registrar.IsEmpty()); - - // Test removing. - Mock::VerifyAndClearExpectations(service()); - EXPECT_CALL(*service(), - RemovePrefObserver(Eq(std::string("test.pref.1")), ®istrar)); - EXPECT_CALL(*service(), - RemovePrefObserver(Eq(std::string("test.pref.2")), ®istrar)); - registrar.Remove("test.pref.1"); - registrar.Remove("test.pref.2"); - EXPECT_TRUE(registrar.IsEmpty()); - - // Explicitly check the expectations now to make sure that the Removes - // worked (rather than the registrar destructor doing the work). - Mock::VerifyAndClearExpectations(service()); -} - -TEST_F(PrefChangeRegistrarTest, AutoRemove) { - PrefChangeRegistrar registrar; - registrar.Init(service()); - - // Setup of auto-remove. - EXPECT_CALL(*service(), - AddPrefObserver(Eq(std::string("test.pref.1")), ®istrar)); - registrar.Add("test.pref.1", observer()); - Mock::VerifyAndClearExpectations(service()); - EXPECT_FALSE(registrar.IsEmpty()); - - // Test auto-removing. - EXPECT_CALL(*service(), - RemovePrefObserver(Eq(std::string("test.pref.1")), ®istrar)); -} - -TEST_F(PrefChangeRegistrarTest, RemoveAll) { - PrefChangeRegistrar registrar; - registrar.Init(service()); - - EXPECT_CALL(*service(), - AddPrefObserver(Eq(std::string("test.pref.1")), ®istrar)); - EXPECT_CALL(*service(), - AddPrefObserver(Eq(std::string("test.pref.2")), ®istrar)); - registrar.Add("test.pref.1", observer()); - registrar.Add("test.pref.2", observer()); - Mock::VerifyAndClearExpectations(service()); - - EXPECT_CALL(*service(), - RemovePrefObserver(Eq(std::string("test.pref.1")), ®istrar)); - EXPECT_CALL(*service(), - RemovePrefObserver(Eq(std::string("test.pref.2")), ®istrar)); - registrar.RemoveAll(); - EXPECT_TRUE(registrar.IsEmpty()); - - // Explicitly check the expectations now to make sure that the RemoveAll - // worked (rather than the registrar destructor doing the work). - Mock::VerifyAndClearExpectations(service()); -} - -class ObserveSetOfPreferencesTest : public testing::Test { - public: - virtual void SetUp() { - pref_service_.reset(new TestingPrefServiceSimple); - PrefRegistrySimple* registry = pref_service_->registry(); - registry->RegisterStringPref(kHomePage, "http://google.com"); - registry->RegisterBooleanPref(kHomePageIsNewTabPage, false); - registry->RegisterStringPref(kApplicationLocale, std::string()); - } - - PrefChangeRegistrar* CreatePrefChangeRegistrar() { - PrefChangeRegistrar* pref_set = new PrefChangeRegistrar(); - base::Closure callback = base::Bind(&base::DoNothing); - pref_set->Init(pref_service_.get()); - pref_set->Add(kHomePage, callback); - pref_set->Add(kHomePageIsNewTabPage, callback); - return pref_set; - } - - MOCK_METHOD1(OnPreferenceChanged, void(const std::string&)); - - scoped_ptr pref_service_; -}; - -TEST_F(ObserveSetOfPreferencesTest, IsObserved) { - scoped_ptr pref_set(CreatePrefChangeRegistrar()); - EXPECT_TRUE(pref_set->IsObserved(kHomePage)); - EXPECT_TRUE(pref_set->IsObserved(kHomePageIsNewTabPage)); - EXPECT_FALSE(pref_set->IsObserved(kApplicationLocale)); -} - -TEST_F(ObserveSetOfPreferencesTest, IsManaged) { - scoped_ptr pref_set(CreatePrefChangeRegistrar()); - EXPECT_FALSE(pref_set->IsManaged()); - pref_service_->SetManagedPref(kHomePage, - new StringValue("http://crbug.com")); - EXPECT_TRUE(pref_set->IsManaged()); - pref_service_->SetManagedPref(kHomePageIsNewTabPage, - new FundamentalValue(true)); - EXPECT_TRUE(pref_set->IsManaged()); - pref_service_->RemoveManagedPref(kHomePage); - EXPECT_TRUE(pref_set->IsManaged()); - pref_service_->RemoveManagedPref(kHomePageIsNewTabPage); - EXPECT_FALSE(pref_set->IsManaged()); -} - -TEST_F(ObserveSetOfPreferencesTest, Observe) { - using testing::_; - using testing::Mock; - - PrefChangeRegistrar pref_set; - PrefChangeRegistrar::NamedChangeCallback callback = base::Bind( - &ObserveSetOfPreferencesTest::OnPreferenceChanged, - base::Unretained(this)); - pref_set.Init(pref_service_.get()); - pref_set.Add(kHomePage, callback); - pref_set.Add(kHomePageIsNewTabPage, callback); - - EXPECT_CALL(*this, OnPreferenceChanged(kHomePage)); - pref_service_->SetUserPref(kHomePage, new StringValue("http://crbug.com")); - Mock::VerifyAndClearExpectations(this); - - EXPECT_CALL(*this, OnPreferenceChanged(kHomePageIsNewTabPage)); - pref_service_->SetUserPref(kHomePageIsNewTabPage, - new FundamentalValue(true)); - Mock::VerifyAndClearExpectations(this); - - EXPECT_CALL(*this, OnPreferenceChanged(_)).Times(0); - pref_service_->SetUserPref(kApplicationLocale, new StringValue("en_US.utf8")); - Mock::VerifyAndClearExpectations(this); -} - -} // namespace base diff --git a/base/prefs/pref_member.cc b/base/prefs/pref_member.cc deleted file mode 100644 index ca6e3bed44..0000000000 --- a/base/prefs/pref_member.cc +++ /dev/null @@ -1,225 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "base/prefs/pref_member.h" - -#include "base/bind_helpers.h" -#include "base/callback.h" -#include "base/location.h" -#include "base/prefs/pref_service.h" -#include "base/value_conversions.h" - -using base::MessageLoopProxy; - -namespace subtle { - -PrefMemberBase::PrefMemberBase() - : prefs_(NULL), - setting_value_(false) { -} - -PrefMemberBase::~PrefMemberBase() { - Destroy(); -} - -void PrefMemberBase::Init(const char* pref_name, - PrefService* prefs, - const NamedChangeCallback& observer) { - observer_ = observer; - Init(pref_name, prefs); -} - -void PrefMemberBase::Init(const char* pref_name, - PrefService* prefs) { - DCHECK(pref_name); - DCHECK(prefs); - DCHECK(pref_name_.empty()); // Check that Init is only called once. - prefs_ = prefs; - pref_name_ = pref_name; - // Check that the preference is registered. - DCHECK(prefs_->FindPreference(pref_name_.c_str())) - << pref_name << " not registered."; - - // Add ourselves as a pref observer so we can keep our local value in sync. - prefs_->AddPrefObserver(pref_name, this); -} - -void PrefMemberBase::Destroy() { - if (prefs_ && !pref_name_.empty()) { - prefs_->RemovePrefObserver(pref_name_.c_str(), this); - prefs_ = NULL; - } -} - -void PrefMemberBase::MoveToThread( - const scoped_refptr& message_loop) { - VerifyValuePrefName(); - // Load the value from preferences if it hasn't been loaded so far. - if (!internal()) - UpdateValueFromPref(base::Closure()); - internal()->MoveToThread(message_loop); -} - -void PrefMemberBase::OnPreferenceChanged(PrefService* service, - const std::string& pref_name) { - VerifyValuePrefName(); - UpdateValueFromPref((!setting_value_ && !observer_.is_null()) ? - base::Bind(observer_, pref_name) : base::Closure()); -} - -void PrefMemberBase::UpdateValueFromPref(const base::Closure& callback) const { - VerifyValuePrefName(); - const PrefService::Preference* pref = - prefs_->FindPreference(pref_name_.c_str()); - DCHECK(pref); - if (!internal()) - CreateInternal(); - internal()->UpdateValue(pref->GetValue()->DeepCopy(), - pref->IsManaged(), - pref->IsUserModifiable(), - callback); -} - -void PrefMemberBase::VerifyPref() const { - VerifyValuePrefName(); - if (!internal()) - UpdateValueFromPref(base::Closure()); -} - -void PrefMemberBase::InvokeUnnamedCallback(const base::Closure& callback, - const std::string& pref_name) { - callback.Run(); -} - -PrefMemberBase::Internal::Internal() - : thread_loop_(MessageLoopProxy::current()), - is_managed_(false) { -} -PrefMemberBase::Internal::~Internal() { } - -bool PrefMemberBase::Internal::IsOnCorrectThread() const { - // In unit tests, there may not be a message loop. - return thread_loop_.get() == NULL || thread_loop_->BelongsToCurrentThread(); -} - -void PrefMemberBase::Internal::UpdateValue( - base::Value* v, - bool is_managed, - bool is_user_modifiable, - const base::Closure& callback) const { - scoped_ptr value(v); - base::ScopedClosureRunner closure_runner(callback); - if (IsOnCorrectThread()) { - bool rv = UpdateValueInternal(*value); - DCHECK(rv); - is_managed_ = is_managed; - is_user_modifiable_ = is_user_modifiable; - } else { - bool may_run = thread_loop_->PostTask( - FROM_HERE, - base::Bind(&PrefMemberBase::Internal::UpdateValue, this, - value.release(), is_managed, is_user_modifiable, - closure_runner.Release())); - DCHECK(may_run); - } -} - -void PrefMemberBase::Internal::MoveToThread( - const scoped_refptr& message_loop) { - CheckOnCorrectThread(); - thread_loop_ = message_loop; -} - -bool PrefMemberVectorStringUpdate(const base::Value& value, - std::vector* string_vector) { - if (!value.IsType(base::Value::TYPE_LIST)) - return false; - const base::ListValue* list = static_cast(&value); - - std::vector local_vector; - for (base::ListValue::const_iterator it = list->begin(); - it != list->end(); ++it) { - std::string string_value; - if (!(*it)->GetAsString(&string_value)) - return false; - - local_vector.push_back(string_value); - } - - string_vector->swap(local_vector); - return true; -} - -} // namespace subtle - -template <> -void PrefMember::UpdatePref(const bool& value) { - prefs()->SetBoolean(pref_name().c_str(), value); -} - -template <> -bool PrefMember::Internal::UpdateValueInternal( - const base::Value& value) const { - return value.GetAsBoolean(&value_); -} - -template <> -void PrefMember::UpdatePref(const int& value) { - prefs()->SetInteger(pref_name().c_str(), value); -} - -template <> -bool PrefMember::Internal::UpdateValueInternal( - const base::Value& value) const { - return value.GetAsInteger(&value_); -} - -template <> -void PrefMember::UpdatePref(const double& value) { - prefs()->SetDouble(pref_name().c_str(), value); -} - -template <> -bool PrefMember::Internal::UpdateValueInternal(const base::Value& value) - const { - return value.GetAsDouble(&value_); -} - -template <> -void PrefMember::UpdatePref(const std::string& value) { - prefs()->SetString(pref_name().c_str(), value); -} - -template <> -bool PrefMember::Internal::UpdateValueInternal( - const base::Value& value) - const { - return value.GetAsString(&value_); -} - -template <> -void PrefMember::UpdatePref(const base::FilePath& value) { - prefs()->SetFilePath(pref_name().c_str(), value); -} - -template <> -bool PrefMember::Internal::UpdateValueInternal( - const base::Value& value) - const { - return base::GetValueAsFilePath(value, &value_); -} - -template <> -void PrefMember >::UpdatePref( - const std::vector& value) { - base::ListValue list_value; - list_value.AppendStrings(value); - prefs()->Set(pref_name().c_str(), list_value); -} - -template <> -bool PrefMember >::Internal::UpdateValueInternal( - const base::Value& value) const { - return subtle::PrefMemberVectorStringUpdate(value, &value_); -} diff --git a/base/prefs/pref_member.h b/base/prefs/pref_member.h deleted file mode 100644 index 17f5b447eb..0000000000 --- a/base/prefs/pref_member.h +++ /dev/null @@ -1,352 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. -// -// A helper class that stays in sync with a preference (bool, int, real, -// string or filepath). For example: -// -// class MyClass { -// public: -// MyClass(PrefService* prefs) { -// my_string_.Init(prefs::kHomePage, prefs); -// } -// private: -// StringPrefMember my_string_; -// }; -// -// my_string_ should stay in sync with the prefs::kHomePage pref and will -// update if either the pref changes or if my_string_.SetValue is called. -// -// An optional observer can be passed into the Init method which can be used to -// notify MyClass of changes. Note that if you use SetValue(), the observer -// will not be notified. - -#ifndef BASE_PREFS_PREF_MEMBER_H_ -#define BASE_PREFS_PREF_MEMBER_H_ - -#include -#include - -#include "base/basictypes.h" -#include "base/bind.h" -#include "base/callback_forward.h" -#include "base/files/file_path.h" -#include "base/logging.h" -#include "base/memory/ref_counted.h" -#include "base/message_loop/message_loop_proxy.h" -#include "base/prefs/base_prefs_export.h" -#include "base/prefs/pref_observer.h" -#include "base/values.h" - -class PrefService; - -namespace subtle { - -class BASE_PREFS_EXPORT PrefMemberBase : public PrefObserver { - public: - // Type of callback you can register if you need to know the name of - // the pref that is changing. - typedef base::Callback NamedChangeCallback; - - PrefService* prefs() { return prefs_; } - const PrefService* prefs() const { return prefs_; } - - protected: - class BASE_PREFS_EXPORT Internal - : public base::RefCountedThreadSafe { - public: - Internal(); - - // Update the value, either by calling |UpdateValueInternal| directly - // or by dispatching to the right thread. - // Takes ownership of |value|. - void UpdateValue(base::Value* value, - bool is_managed, - bool is_user_modifiable, - const base::Closure& callback) const; - - void MoveToThread( - const scoped_refptr& message_loop); - - // See PrefMember<> for description. - bool IsManaged() const { - return is_managed_; - } - - bool IsUserModifiable() const { - return is_user_modifiable_; - } - - protected: - friend class base::RefCountedThreadSafe; - virtual ~Internal(); - - void CheckOnCorrectThread() const { - DCHECK(IsOnCorrectThread()); - } - - private: - // This method actually updates the value. It should only be called from - // the thread the PrefMember is on. - virtual bool UpdateValueInternal(const base::Value& value) const = 0; - - bool IsOnCorrectThread() const; - - scoped_refptr thread_loop_; - mutable bool is_managed_; - mutable bool is_user_modifiable_; - - DISALLOW_COPY_AND_ASSIGN(Internal); - }; - - PrefMemberBase(); - virtual ~PrefMemberBase(); - - // See PrefMember<> for description. - void Init(const char* pref_name, PrefService* prefs, - const NamedChangeCallback& observer); - void Init(const char* pref_name, PrefService* prefs); - - virtual void CreateInternal() const = 0; - - // See PrefMember<> for description. - void Destroy(); - - void MoveToThread(const scoped_refptr& message_loop); - - // PrefObserver - virtual void OnPreferenceChanged(PrefService* service, - const std::string& pref_name) OVERRIDE; - - void VerifyValuePrefName() const { - DCHECK(!pref_name_.empty()); - } - - // This method is used to do the actual sync with the preference. - // Note: it is logically const, because it doesn't modify the state - // seen by the outside world. It is just doing a lazy load behind the scenes. - void UpdateValueFromPref(const base::Closure& callback) const; - - // Verifies the preference name, and lazily loads the preference value if - // it hasn't been loaded yet. - void VerifyPref() const; - - const std::string& pref_name() const { return pref_name_; } - - virtual Internal* internal() const = 0; - - // Used to allow registering plain base::Closure callbacks. - static void InvokeUnnamedCallback(const base::Closure& callback, - const std::string& pref_name); - - private: - // Ordered the members to compact the class instance. - std::string pref_name_; - NamedChangeCallback observer_; - PrefService* prefs_; - - protected: - bool setting_value_; -}; - -// This function implements StringListPrefMember::UpdateValue(). -// It is exposed here for testing purposes. -bool BASE_PREFS_EXPORT PrefMemberVectorStringUpdate( - const base::Value& value, - std::vector* string_vector); - -} // namespace subtle - -template -class PrefMember : public subtle::PrefMemberBase { - public: - // Defer initialization to an Init method so it's easy to make this class be - // a member variable. - PrefMember() {} - virtual ~PrefMember() {} - - // Do the actual initialization of the class. Use the two-parameter - // version if you don't want any notifications of changes. This - // method should only be called on the UI thread. - void Init(const char* pref_name, PrefService* prefs, - const NamedChangeCallback& observer) { - subtle::PrefMemberBase::Init(pref_name, prefs, observer); - } - void Init(const char* pref_name, PrefService* prefs, - const base::Closure& observer) { - subtle::PrefMemberBase::Init( - pref_name, prefs, - base::Bind(&PrefMemberBase::InvokeUnnamedCallback, observer)); - } - void Init(const char* pref_name, PrefService* prefs) { - subtle::PrefMemberBase::Init(pref_name, prefs); - } - - // Unsubscribes the PrefMember from the PrefService. After calling this - // function, the PrefMember may not be used any more on the UI thread. - // Assuming |MoveToThread| was previously called, |GetValue|, |IsManaged|, - // and |IsUserModifiable| can still be called from the other thread but - // the results will no longer update from the PrefService. - // This method should only be called on the UI thread. - void Destroy() { - subtle::PrefMemberBase::Destroy(); - } - - // Moves the PrefMember to another thread, allowing read accesses from there. - // Changes from the PrefService will be propagated asynchronously - // via PostTask. - // This method should only be used from the thread the PrefMember is currently - // on, which is the UI thread by default. - void MoveToThread(const scoped_refptr& message_loop) { - subtle::PrefMemberBase::MoveToThread(message_loop); - } - - // Check whether the pref is managed, i.e. controlled externally through - // enterprise configuration management (e.g. windows group policy). Returns - // false for unknown prefs. - // This method should only be used from the thread the PrefMember is currently - // on, which is the UI thread unless changed by |MoveToThread|. - bool IsManaged() const { - VerifyPref(); - return internal_->IsManaged(); - } - - // Checks whether the pref can be modified by the user. This returns false - // when the pref is managed by a policy or an extension, and when a command - // line flag overrides the pref. - // This method should only be used from the thread the PrefMember is currently - // on, which is the UI thread unless changed by |MoveToThread|. - bool IsUserModifiable() const { - VerifyPref(); - return internal_->IsUserModifiable(); - } - - // Retrieve the value of the member variable. - // This method should only be used from the thread the PrefMember is currently - // on, which is the UI thread unless changed by |MoveToThread|. - ValueType GetValue() const { - VerifyPref(); - return internal_->value(); - } - - // Provided as a convenience. - ValueType operator*() const { - return GetValue(); - } - - // Set the value of the member variable. - // This method should only be called on the UI thread. - void SetValue(const ValueType& value) { - VerifyValuePrefName(); - setting_value_ = true; - UpdatePref(value); - setting_value_ = false; - } - - // Returns the pref name. - const std::string& GetPrefName() const { - return pref_name(); - } - - private: - class Internal : public subtle::PrefMemberBase::Internal { - public: - Internal() : value_(ValueType()) {} - - ValueType value() { - CheckOnCorrectThread(); - return value_; - } - - protected: - virtual ~Internal() {} - - virtual BASE_PREFS_EXPORT bool UpdateValueInternal( - const base::Value& value) const OVERRIDE; - - // We cache the value of the pref so we don't have to keep walking the pref - // tree. - mutable ValueType value_; - - DISALLOW_COPY_AND_ASSIGN(Internal); - }; - - virtual Internal* internal() const OVERRIDE { return internal_.get(); } - virtual void CreateInternal() const OVERRIDE { internal_ = new Internal(); } - - // This method is used to do the actual sync with pref of the specified type. - void BASE_PREFS_EXPORT UpdatePref(const ValueType& value); - - mutable scoped_refptr internal_; - - DISALLOW_COPY_AND_ASSIGN(PrefMember); -}; - -// Declaration of template specialization need to be repeated here -// specifically for each specialization (rather than just once above) -// or at least one of our compilers won't be happy in all cases. -// Specifically, it was failing on ChromeOS with a complaint about -// PrefMember::UpdateValueInternal not being defined when -// built in a chroot with the following parameters: -// -// FEATURES="noclean nostrip" USE="-chrome_debug -chrome_remoting -// -chrome_internal -chrome_pdf component_build" -// ~/trunk/goma/goma-wrapper cros_chrome_make --board=${BOARD} -// --install --runhooks - -template <> -BASE_PREFS_EXPORT void PrefMember::UpdatePref(const bool& value); - -template <> -BASE_PREFS_EXPORT bool PrefMember::Internal::UpdateValueInternal( - const base::Value& value) const; - -template <> -BASE_PREFS_EXPORT void PrefMember::UpdatePref(const int& value); - -template <> -BASE_PREFS_EXPORT bool PrefMember::Internal::UpdateValueInternal( - const base::Value& value) const; - -template <> -BASE_PREFS_EXPORT void PrefMember::UpdatePref(const double& value); - -template <> -BASE_PREFS_EXPORT bool PrefMember::Internal::UpdateValueInternal( - const base::Value& value) const; - -template <> -BASE_PREFS_EXPORT void PrefMember::UpdatePref( - const std::string& value); - -template <> -BASE_PREFS_EXPORT bool PrefMember::Internal::UpdateValueInternal( - const base::Value& value) const; - -template <> -BASE_PREFS_EXPORT void PrefMember::UpdatePref( - const base::FilePath& value); - -template <> -BASE_PREFS_EXPORT bool -PrefMember::Internal::UpdateValueInternal( - const base::Value& value) const; - -template <> -BASE_PREFS_EXPORT void PrefMember >::UpdatePref( - const std::vector& value); - -template <> -BASE_PREFS_EXPORT bool -PrefMember >::Internal::UpdateValueInternal( - const base::Value& value) const; - -typedef PrefMember BooleanPrefMember; -typedef PrefMember IntegerPrefMember; -typedef PrefMember DoublePrefMember; -typedef PrefMember StringPrefMember; -typedef PrefMember FilePathPrefMember; -// This preference member is expensive for large string arrays. -typedef PrefMember > StringListPrefMember; - -#endif // BASE_PREFS_PREF_MEMBER_H_ diff --git a/base/prefs/pref_member_unittest.cc b/base/prefs/pref_member_unittest.cc deleted file mode 100644 index d4d7e02c97..0000000000 --- a/base/prefs/pref_member_unittest.cc +++ /dev/null @@ -1,321 +0,0 @@ -// Copyright (c) 2011 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "base/prefs/pref_member.h" - -#include "base/bind.h" -#include "base/message_loop/message_loop.h" -#include "base/prefs/pref_registry_simple.h" -#include "base/prefs/testing_pref_service.h" -#include "base/synchronization/waitable_event.h" -#include "base/threading/thread.h" -#include "testing/gtest/include/gtest/gtest.h" - -namespace { - -const char kBoolPref[] = "bool"; -const char kIntPref[] = "int"; -const char kDoublePref[] = "double"; -const char kStringPref[] = "string"; -const char kStringListPref[] = "string_list"; - -void RegisterTestPrefs(PrefRegistrySimple* registry) { - registry->RegisterBooleanPref(kBoolPref, false); - registry->RegisterIntegerPref(kIntPref, 0); - registry->RegisterDoublePref(kDoublePref, 0.0); - registry->RegisterStringPref(kStringPref, "default"); - registry->RegisterListPref(kStringListPref, new base::ListValue()); -} - -class GetPrefValueHelper - : public base::RefCountedThreadSafe { - public: - GetPrefValueHelper() : value_(false), pref_thread_("pref thread") { - pref_thread_.Start(); - } - - void Init(const char* pref_name, PrefService* prefs) { - pref_.Init(pref_name, prefs); - pref_.MoveToThread(pref_thread_.message_loop_proxy()); - } - - void Destroy() { - pref_.Destroy(); - } - - void FetchValue() { - base::WaitableEvent event(true, false); - ASSERT_TRUE( - pref_thread_.message_loop_proxy()->PostTask( - FROM_HERE, - base::Bind(&GetPrefValueHelper::GetPrefValue, this, &event))); - event.Wait(); - } - - // The thread must be stopped on the main thread. GetPrefValueHelper being - // ref-counted, the destructor can be called from any thread. - void StopThread() { - pref_thread_.Stop(); - } - - bool value() { return value_; } - - private: - friend class base::RefCountedThreadSafe; - ~GetPrefValueHelper() {} - - void GetPrefValue(base::WaitableEvent* event) { - value_ = pref_.GetValue(); - event->Signal(); - } - - BooleanPrefMember pref_; - bool value_; - - base::Thread pref_thread_; // The thread |pref_| runs on. -}; - -class PrefMemberTestClass { - public: - explicit PrefMemberTestClass(PrefService* prefs) - : observe_cnt_(0), prefs_(prefs) { - str_.Init(kStringPref, prefs, - base::Bind(&PrefMemberTestClass::OnPreferenceChanged, - base::Unretained(this))); - } - - void OnPreferenceChanged(const std::string& pref_name) { - EXPECT_EQ(pref_name, kStringPref); - EXPECT_EQ(str_.GetValue(), prefs_->GetString(kStringPref)); - ++observe_cnt_; - } - - StringPrefMember str_; - int observe_cnt_; - - private: - PrefService* prefs_; -}; - -} // anonymous namespace - -TEST(PrefMemberTest, BasicGetAndSet) { - TestingPrefServiceSimple prefs; - RegisterTestPrefs(prefs.registry()); - - // Test bool - BooleanPrefMember boolean; - boolean.Init(kBoolPref, &prefs); - - // Check the defaults - EXPECT_FALSE(prefs.GetBoolean(kBoolPref)); - EXPECT_FALSE(boolean.GetValue()); - EXPECT_FALSE(*boolean); - - // Try changing through the member variable. - boolean.SetValue(true); - EXPECT_TRUE(boolean.GetValue()); - EXPECT_TRUE(prefs.GetBoolean(kBoolPref)); - EXPECT_TRUE(*boolean); - - // Try changing back through the pref. - prefs.SetBoolean(kBoolPref, false); - EXPECT_FALSE(prefs.GetBoolean(kBoolPref)); - EXPECT_FALSE(boolean.GetValue()); - EXPECT_FALSE(*boolean); - - // Test int - IntegerPrefMember integer; - integer.Init(kIntPref, &prefs); - - // Check the defaults - EXPECT_EQ(0, prefs.GetInteger(kIntPref)); - EXPECT_EQ(0, integer.GetValue()); - EXPECT_EQ(0, *integer); - - // Try changing through the member variable. - integer.SetValue(5); - EXPECT_EQ(5, integer.GetValue()); - EXPECT_EQ(5, prefs.GetInteger(kIntPref)); - EXPECT_EQ(5, *integer); - - // Try changing back through the pref. - prefs.SetInteger(kIntPref, 2); - EXPECT_EQ(2, prefs.GetInteger(kIntPref)); - EXPECT_EQ(2, integer.GetValue()); - EXPECT_EQ(2, *integer); - - // Test double - DoublePrefMember double_member; - double_member.Init(kDoublePref, &prefs); - - // Check the defaults - EXPECT_EQ(0.0, prefs.GetDouble(kDoublePref)); - EXPECT_EQ(0.0, double_member.GetValue()); - EXPECT_EQ(0.0, *double_member); - - // Try changing through the member variable. - double_member.SetValue(1.0); - EXPECT_EQ(1.0, double_member.GetValue()); - EXPECT_EQ(1.0, prefs.GetDouble(kDoublePref)); - EXPECT_EQ(1.0, *double_member); - - // Try changing back through the pref. - prefs.SetDouble(kDoublePref, 3.0); - EXPECT_EQ(3.0, prefs.GetDouble(kDoublePref)); - EXPECT_EQ(3.0, double_member.GetValue()); - EXPECT_EQ(3.0, *double_member); - - // Test string - StringPrefMember string; - string.Init(kStringPref, &prefs); - - // Check the defaults - EXPECT_EQ("default", prefs.GetString(kStringPref)); - EXPECT_EQ("default", string.GetValue()); - EXPECT_EQ("default", *string); - - // Try changing through the member variable. - string.SetValue("foo"); - EXPECT_EQ("foo", string.GetValue()); - EXPECT_EQ("foo", prefs.GetString(kStringPref)); - EXPECT_EQ("foo", *string); - - // Try changing back through the pref. - prefs.SetString(kStringPref, "bar"); - EXPECT_EQ("bar", prefs.GetString(kStringPref)); - EXPECT_EQ("bar", string.GetValue()); - EXPECT_EQ("bar", *string); - - // Test string list - base::ListValue expected_list; - std::vector expected_vector; - StringListPrefMember string_list; - string_list.Init(kStringListPref, &prefs); - - // Check the defaults - EXPECT_TRUE(expected_list.Equals(prefs.GetList(kStringListPref))); - EXPECT_EQ(expected_vector, string_list.GetValue()); - EXPECT_EQ(expected_vector, *string_list); - - // Try changing through the pref member. - expected_list.AppendString("foo"); - expected_vector.push_back("foo"); - string_list.SetValue(expected_vector); - - EXPECT_TRUE(expected_list.Equals(prefs.GetList(kStringListPref))); - EXPECT_EQ(expected_vector, string_list.GetValue()); - EXPECT_EQ(expected_vector, *string_list); - - // Try adding through the pref. - expected_list.AppendString("bar"); - expected_vector.push_back("bar"); - prefs.Set(kStringListPref, expected_list); - - EXPECT_TRUE(expected_list.Equals(prefs.GetList(kStringListPref))); - EXPECT_EQ(expected_vector, string_list.GetValue()); - EXPECT_EQ(expected_vector, *string_list); - - // Try removing through the pref. - expected_list.Remove(0, NULL); - expected_vector.erase(expected_vector.begin()); - prefs.Set(kStringListPref, expected_list); - - EXPECT_TRUE(expected_list.Equals(prefs.GetList(kStringListPref))); - EXPECT_EQ(expected_vector, string_list.GetValue()); - EXPECT_EQ(expected_vector, *string_list); -} - -TEST(PrefMemberTest, InvalidList) { - // Set the vector to an initial good value. - std::vector expected_vector; - expected_vector.push_back("foo"); - - // Try to add a valid list first. - base::ListValue list; - list.AppendString("foo"); - std::vector vector; - EXPECT_TRUE(subtle::PrefMemberVectorStringUpdate(list, &vector)); - EXPECT_EQ(expected_vector, vector); - - // Now try to add an invalid list. |vector| should not be changed. - list.AppendInteger(0); - EXPECT_FALSE(subtle::PrefMemberVectorStringUpdate(list, &vector)); - EXPECT_EQ(expected_vector, vector); -} - -TEST(PrefMemberTest, TwoPrefs) { - // Make sure two DoublePrefMembers stay in sync. - TestingPrefServiceSimple prefs; - RegisterTestPrefs(prefs.registry()); - - DoublePrefMember pref1; - pref1.Init(kDoublePref, &prefs); - DoublePrefMember pref2; - pref2.Init(kDoublePref, &prefs); - - pref1.SetValue(2.3); - EXPECT_EQ(2.3, *pref2); - - pref2.SetValue(3.5); - EXPECT_EQ(3.5, *pref1); - - prefs.SetDouble(kDoublePref, 4.2); - EXPECT_EQ(4.2, *pref1); - EXPECT_EQ(4.2, *pref2); -} - -TEST(PrefMemberTest, Observer) { - TestingPrefServiceSimple prefs; - RegisterTestPrefs(prefs.registry()); - - PrefMemberTestClass test_obj(&prefs); - EXPECT_EQ("default", *test_obj.str_); - - // Calling SetValue should not fire the observer. - test_obj.str_.SetValue("hello"); - EXPECT_EQ(0, test_obj.observe_cnt_); - EXPECT_EQ("hello", prefs.GetString(kStringPref)); - - // Changing the pref does fire the observer. - prefs.SetString(kStringPref, "world"); - EXPECT_EQ(1, test_obj.observe_cnt_); - EXPECT_EQ("world", *(test_obj.str_)); - - // Not changing the value should not fire the observer. - prefs.SetString(kStringPref, "world"); - EXPECT_EQ(1, test_obj.observe_cnt_); - EXPECT_EQ("world", *(test_obj.str_)); - - prefs.SetString(kStringPref, "hello"); - EXPECT_EQ(2, test_obj.observe_cnt_); - EXPECT_EQ("hello", prefs.GetString(kStringPref)); -} - -TEST(PrefMemberTest, NoInit) { - // Make sure not calling Init on a PrefMember doesn't cause problems. - IntegerPrefMember pref; -} - -TEST(PrefMemberTest, MoveToThread) { - TestingPrefServiceSimple prefs; - scoped_refptr helper(new GetPrefValueHelper()); - RegisterTestPrefs(prefs.registry()); - helper->Init(kBoolPref, &prefs); - - helper->FetchValue(); - EXPECT_FALSE(helper->value()); - - prefs.SetBoolean(kBoolPref, true); - - helper->FetchValue(); - EXPECT_TRUE(helper->value()); - - helper->Destroy(); - - helper->FetchValue(); - EXPECT_TRUE(helper->value()); - - helper->StopThread(); -} diff --git a/base/prefs/pref_notifier.h b/base/prefs/pref_notifier.h deleted file mode 100644 index e0df260c51..0000000000 --- a/base/prefs/pref_notifier.h +++ /dev/null @@ -1,26 +0,0 @@ -// Copyright (c) 2011 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef BASE_PREFS_PREF_NOTIFIER_H_ -#define BASE_PREFS_PREF_NOTIFIER_H_ - -#include - -// Delegate interface used by PrefValueStore to notify its owner about changes -// to the preference values. -// TODO(mnissler, danno): Move this declaration to pref_value_store.h once we've -// cleaned up all public uses of this interface. -class PrefNotifier { - public: - virtual ~PrefNotifier() {} - - // Sends out a change notification for the preference identified by - // |pref_name|. - virtual void OnPreferenceChanged(const std::string& pref_name) = 0; - - // Broadcasts the intialization completed notification. - virtual void OnInitializationCompleted(bool succeeded) = 0; -}; - -#endif // BASE_PREFS_PREF_NOTIFIER_H_ diff --git a/base/prefs/pref_notifier_impl.cc b/base/prefs/pref_notifier_impl.cc deleted file mode 100644 index c02a7b3f5a..0000000000 --- a/base/prefs/pref_notifier_impl.cc +++ /dev/null @@ -1,117 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "base/prefs/pref_notifier_impl.h" - -#include "base/logging.h" -#include "base/prefs/pref_service.h" -#include "base/stl_util.h" - -PrefNotifierImpl::PrefNotifierImpl() - : pref_service_(NULL) { -} - -PrefNotifierImpl::PrefNotifierImpl(PrefService* service) - : pref_service_(service) { -} - -PrefNotifierImpl::~PrefNotifierImpl() { - DCHECK(thread_checker_.CalledOnValidThread()); - - // Verify that there are no pref observers when we shut down. - for (PrefObserverMap::iterator it = pref_observers_.begin(); - it != pref_observers_.end(); ++it) { - PrefObserverList::Iterator obs_iterator(*(it->second)); - if (obs_iterator.GetNext()) { - LOG(WARNING) << "pref observer found at shutdown " << it->first; - } - } - - // Same for initialization observers. - if (!init_observers_.empty()) - LOG(WARNING) << "Init observer found at shutdown."; - - STLDeleteContainerPairSecondPointers(pref_observers_.begin(), - pref_observers_.end()); - pref_observers_.clear(); - init_observers_.clear(); -} - -void PrefNotifierImpl::AddPrefObserver(const char* path, - PrefObserver* obs) { - // Get the pref observer list associated with the path. - PrefObserverList* observer_list = NULL; - const PrefObserverMap::iterator observer_iterator = - pref_observers_.find(path); - if (observer_iterator == pref_observers_.end()) { - observer_list = new PrefObserverList; - pref_observers_[path] = observer_list; - } else { - observer_list = observer_iterator->second; - } - - // Add the pref observer. ObserverList will DCHECK if it already is - // in the list. - observer_list->AddObserver(obs); -} - -void PrefNotifierImpl::RemovePrefObserver(const char* path, - PrefObserver* obs) { - DCHECK(thread_checker_.CalledOnValidThread()); - - const PrefObserverMap::iterator observer_iterator = - pref_observers_.find(path); - if (observer_iterator == pref_observers_.end()) { - return; - } - - PrefObserverList* observer_list = observer_iterator->second; - observer_list->RemoveObserver(obs); -} - -void PrefNotifierImpl::AddInitObserver(base::Callback obs) { - init_observers_.push_back(obs); -} - -void PrefNotifierImpl::OnPreferenceChanged(const std::string& path) { - FireObservers(path); -} - -void PrefNotifierImpl::OnInitializationCompleted(bool succeeded) { - DCHECK(thread_checker_.CalledOnValidThread()); - - // We must make a copy of init_observers_ and clear it before we run - // observers, or we can end up in this method re-entrantly before - // clearing the observers list. - PrefInitObserverList observers(init_observers_); - init_observers_.clear(); - - for (PrefInitObserverList::iterator it = observers.begin(); - it != observers.end(); - ++it) { - it->Run(succeeded); - } -} - -void PrefNotifierImpl::FireObservers(const std::string& path) { - DCHECK(thread_checker_.CalledOnValidThread()); - - // Only send notifications for registered preferences. - if (!pref_service_->FindPreference(path.c_str())) - return; - - const PrefObserverMap::iterator observer_iterator = - pref_observers_.find(path); - if (observer_iterator == pref_observers_.end()) - return; - - FOR_EACH_OBSERVER(PrefObserver, - *(observer_iterator->second), - OnPreferenceChanged(pref_service_, path)); -} - -void PrefNotifierImpl::SetPrefService(PrefService* pref_service) { - DCHECK(pref_service_ == NULL); - pref_service_ = pref_service; -} diff --git a/base/prefs/pref_notifier_impl.h b/base/prefs/pref_notifier_impl.h deleted file mode 100644 index 655203d06d..0000000000 --- a/base/prefs/pref_notifier_impl.h +++ /dev/null @@ -1,73 +0,0 @@ -// Copyright (c) 2011 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef BASE_PREFS_PREF_NOTIFIER_IMPL_H_ -#define BASE_PREFS_PREF_NOTIFIER_IMPL_H_ - -#include -#include - -#include "base/callback.h" -#include "base/compiler_specific.h" -#include "base/containers/hash_tables.h" -#include "base/observer_list.h" -#include "base/prefs/base_prefs_export.h" -#include "base/prefs/pref_notifier.h" -#include "base/prefs/pref_observer.h" -#include "base/threading/thread_checker.h" - -class PrefService; - -// The PrefNotifier implementation used by the PrefService. -class BASE_PREFS_EXPORT PrefNotifierImpl - : public NON_EXPORTED_BASE(PrefNotifier) { - public: - PrefNotifierImpl(); - explicit PrefNotifierImpl(PrefService* pref_service); - virtual ~PrefNotifierImpl(); - - // If the pref at the given path changes, we call the observer's - // OnPreferenceChanged method. - void AddPrefObserver(const char* path, PrefObserver* observer); - void RemovePrefObserver(const char* path, PrefObserver* observer); - - // We run the callback once, when initialization completes. The bool - // parameter will be set to true for successful initialization, - // false for unsuccessful. - void AddInitObserver(base::Callback observer); - - void SetPrefService(PrefService* pref_service); - - protected: - // PrefNotifier overrides. - virtual void OnPreferenceChanged(const std::string& pref_name) OVERRIDE; - virtual void OnInitializationCompleted(bool succeeded) OVERRIDE; - - // A map from pref names to a list of observers. Observers get fired in the - // order they are added. These should only be accessed externally for unit - // testing. - typedef ObserverList PrefObserverList; - typedef base::hash_map PrefObserverMap; - - typedef std::list > PrefInitObserverList; - - const PrefObserverMap* pref_observers() const { return &pref_observers_; } - - private: - // For the given pref_name, fire any observer of the pref. Virtual so it can - // be mocked for unit testing. - virtual void FireObservers(const std::string& path); - - // Weak reference; the notifier is owned by the PrefService. - PrefService* pref_service_; - - PrefObserverMap pref_observers_; - PrefInitObserverList init_observers_; - - base::ThreadChecker thread_checker_; - - DISALLOW_COPY_AND_ASSIGN(PrefNotifierImpl); -}; - -#endif // BASE_PREFS_PREF_NOTIFIER_IMPL_H_ diff --git a/base/prefs/pref_notifier_impl_unittest.cc b/base/prefs/pref_notifier_impl_unittest.cc deleted file mode 100644 index 29ea322e7e..0000000000 --- a/base/prefs/pref_notifier_impl_unittest.cc +++ /dev/null @@ -1,227 +0,0 @@ -// Copyright (c) 2011 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "base/bind.h" -#include "base/callback.h" -#include "base/prefs/mock_pref_change_callback.h" -#include "base/prefs/pref_notifier_impl.h" -#include "base/prefs/pref_observer.h" -#include "base/prefs/pref_registry_simple.h" -#include "base/prefs/pref_service.h" -#include "base/prefs/pref_value_store.h" -#include "base/prefs/testing_pref_service.h" -#include "testing/gmock/include/gmock/gmock.h" -#include "testing/gtest/include/gtest/gtest.h" - -using testing::_; -using testing::Field; -using testing::Invoke; -using testing::Mock; -using testing::Truly; - -namespace { - -const char kChangedPref[] = "changed_pref"; -const char kUnchangedPref[] = "unchanged_pref"; - -class MockPrefInitObserver { - public: - MOCK_METHOD1(OnInitializationCompleted, void(bool)); -}; - -// This is an unmodified PrefNotifierImpl, except we make -// OnPreferenceChanged public for tests. -class TestingPrefNotifierImpl : public PrefNotifierImpl { - public: - explicit TestingPrefNotifierImpl(PrefService* service) - : PrefNotifierImpl(service) { - } - - // Make public for tests. - using PrefNotifierImpl::OnPreferenceChanged; -}; - -// Mock PrefNotifier that allows tracking of observers and notifications. -class MockPrefNotifier : public PrefNotifierImpl { - public: - explicit MockPrefNotifier(PrefService* pref_service) - : PrefNotifierImpl(pref_service) {} - virtual ~MockPrefNotifier() {} - - MOCK_METHOD1(FireObservers, void(const std::string& path)); - - size_t CountObserver(const char* path, PrefObserver* obs) { - PrefObserverMap::const_iterator observer_iterator = - pref_observers()->find(path); - if (observer_iterator == pref_observers()->end()) - return false; - - PrefObserverList* observer_list = observer_iterator->second; - PrefObserverList::Iterator it(*observer_list); - PrefObserver* existing_obs; - size_t count = 0; - while ((existing_obs = it.GetNext()) != NULL) { - if (existing_obs == obs) - count++; - } - - return count; - } - - // Make public for tests below. - using PrefNotifierImpl::OnPreferenceChanged; - using PrefNotifierImpl::OnInitializationCompleted; -}; - -class PrefObserverMock : public PrefObserver { - public: - PrefObserverMock() {} - virtual ~PrefObserverMock() {} - - MOCK_METHOD2(OnPreferenceChanged, void(PrefService*, const std::string&)); - - void Expect(PrefService* prefs, - const std::string& pref_name, - const base::Value* value) { - EXPECT_CALL(*this, OnPreferenceChanged(prefs, pref_name)) - .With(PrefValueMatches(prefs, pref_name, value)); - } -}; - -// Test fixture class. -class PrefNotifierTest : public testing::Test { - protected: - virtual void SetUp() { - pref_service_.registry()->RegisterBooleanPref(kChangedPref, true); - pref_service_.registry()->RegisterBooleanPref(kUnchangedPref, true); - } - - TestingPrefServiceSimple pref_service_; - - PrefObserverMock obs1_; - PrefObserverMock obs2_; -}; - -TEST_F(PrefNotifierTest, OnPreferenceChanged) { - MockPrefNotifier notifier(&pref_service_); - EXPECT_CALL(notifier, FireObservers(kChangedPref)).Times(1); - notifier.OnPreferenceChanged(kChangedPref); -} - -TEST_F(PrefNotifierTest, OnInitializationCompleted) { - MockPrefNotifier notifier(&pref_service_); - MockPrefInitObserver observer; - notifier.AddInitObserver( - base::Bind(&MockPrefInitObserver::OnInitializationCompleted, - base::Unretained(&observer))); - EXPECT_CALL(observer, OnInitializationCompleted(true)); - notifier.OnInitializationCompleted(true); -} - -TEST_F(PrefNotifierTest, AddAndRemovePrefObservers) { - const char pref_name[] = "homepage"; - const char pref_name2[] = "proxy"; - - MockPrefNotifier notifier(&pref_service_); - notifier.AddPrefObserver(pref_name, &obs1_); - ASSERT_EQ(1u, notifier.CountObserver(pref_name, &obs1_)); - ASSERT_EQ(0u, notifier.CountObserver(pref_name2, &obs1_)); - ASSERT_EQ(0u, notifier.CountObserver(pref_name, &obs2_)); - ASSERT_EQ(0u, notifier.CountObserver(pref_name2, &obs2_)); - - // Re-adding the same observer for the same pref doesn't change anything. - // Skip this in debug mode, since it hits a DCHECK and death tests aren't - // thread-safe. -#if defined(NDEBUG) && !defined(DCHECK_ALWAYS_ON) - notifier.AddPrefObserver(pref_name, &obs1_); - ASSERT_EQ(1u, notifier.CountObserver(pref_name, &obs1_)); - ASSERT_EQ(0u, notifier.CountObserver(pref_name2, &obs1_)); - ASSERT_EQ(0u, notifier.CountObserver(pref_name, &obs2_)); - ASSERT_EQ(0u, notifier.CountObserver(pref_name2, &obs2_)); -#endif - - // Ensure that we can add the same observer to a different pref. - notifier.AddPrefObserver(pref_name2, &obs1_); - ASSERT_EQ(1u, notifier.CountObserver(pref_name, &obs1_)); - ASSERT_EQ(1u, notifier.CountObserver(pref_name2, &obs1_)); - ASSERT_EQ(0u, notifier.CountObserver(pref_name, &obs2_)); - ASSERT_EQ(0u, notifier.CountObserver(pref_name2, &obs2_)); - - // Ensure that we can add another observer to the same pref. - notifier.AddPrefObserver(pref_name, &obs2_); - ASSERT_EQ(1u, notifier.CountObserver(pref_name, &obs1_)); - ASSERT_EQ(1u, notifier.CountObserver(pref_name2, &obs1_)); - ASSERT_EQ(1u, notifier.CountObserver(pref_name, &obs2_)); - ASSERT_EQ(0u, notifier.CountObserver(pref_name2, &obs2_)); - - // Ensure that we can remove all observers, and that removing a non-existent - // observer is harmless. - notifier.RemovePrefObserver(pref_name, &obs1_); - ASSERT_EQ(0u, notifier.CountObserver(pref_name, &obs1_)); - ASSERT_EQ(1u, notifier.CountObserver(pref_name2, &obs1_)); - ASSERT_EQ(1u, notifier.CountObserver(pref_name, &obs2_)); - ASSERT_EQ(0u, notifier.CountObserver(pref_name2, &obs2_)); - - notifier.RemovePrefObserver(pref_name, &obs2_); - ASSERT_EQ(0u, notifier.CountObserver(pref_name, &obs1_)); - ASSERT_EQ(1u, notifier.CountObserver(pref_name2, &obs1_)); - ASSERT_EQ(0u, notifier.CountObserver(pref_name, &obs2_)); - ASSERT_EQ(0u, notifier.CountObserver(pref_name2, &obs2_)); - - notifier.RemovePrefObserver(pref_name, &obs1_); - ASSERT_EQ(0u, notifier.CountObserver(pref_name, &obs1_)); - ASSERT_EQ(1u, notifier.CountObserver(pref_name2, &obs1_)); - ASSERT_EQ(0u, notifier.CountObserver(pref_name, &obs2_)); - ASSERT_EQ(0u, notifier.CountObserver(pref_name2, &obs2_)); - - notifier.RemovePrefObserver(pref_name2, &obs1_); - ASSERT_EQ(0u, notifier.CountObserver(pref_name, &obs1_)); - ASSERT_EQ(0u, notifier.CountObserver(pref_name2, &obs1_)); - ASSERT_EQ(0u, notifier.CountObserver(pref_name, &obs2_)); - ASSERT_EQ(0u, notifier.CountObserver(pref_name2, &obs2_)); -} - -TEST_F(PrefNotifierTest, FireObservers) { - TestingPrefNotifierImpl notifier(&pref_service_); - notifier.AddPrefObserver(kChangedPref, &obs1_); - notifier.AddPrefObserver(kUnchangedPref, &obs1_); - - EXPECT_CALL(obs1_, OnPreferenceChanged(&pref_service_, kChangedPref)); - EXPECT_CALL(obs2_, OnPreferenceChanged(_, _)).Times(0); - notifier.OnPreferenceChanged(kChangedPref); - Mock::VerifyAndClearExpectations(&obs1_); - Mock::VerifyAndClearExpectations(&obs2_); - - notifier.AddPrefObserver(kChangedPref, &obs2_); - notifier.AddPrefObserver(kUnchangedPref, &obs2_); - - EXPECT_CALL(obs1_, OnPreferenceChanged(&pref_service_, kChangedPref)); - EXPECT_CALL(obs2_, OnPreferenceChanged(&pref_service_, kChangedPref)); - notifier.OnPreferenceChanged(kChangedPref); - Mock::VerifyAndClearExpectations(&obs1_); - Mock::VerifyAndClearExpectations(&obs2_); - - // Make sure removing an observer from one pref doesn't affect anything else. - notifier.RemovePrefObserver(kChangedPref, &obs1_); - - EXPECT_CALL(obs1_, OnPreferenceChanged(_, _)).Times(0); - EXPECT_CALL(obs2_, OnPreferenceChanged(&pref_service_, kChangedPref)); - notifier.OnPreferenceChanged(kChangedPref); - Mock::VerifyAndClearExpectations(&obs1_); - Mock::VerifyAndClearExpectations(&obs2_); - - // Make sure removing an observer entirely doesn't affect anything else. - notifier.RemovePrefObserver(kUnchangedPref, &obs1_); - - EXPECT_CALL(obs1_, OnPreferenceChanged(_, _)).Times(0); - EXPECT_CALL(obs2_, OnPreferenceChanged(&pref_service_, kChangedPref)); - notifier.OnPreferenceChanged(kChangedPref); - Mock::VerifyAndClearExpectations(&obs1_); - Mock::VerifyAndClearExpectations(&obs2_); - - notifier.RemovePrefObserver(kChangedPref, &obs2_); - notifier.RemovePrefObserver(kUnchangedPref, &obs2_); -} - -} // namespace diff --git a/base/prefs/pref_observer.h b/base/prefs/pref_observer.h deleted file mode 100644 index 5d8f5b63dc..0000000000 --- a/base/prefs/pref_observer.h +++ /dev/null @@ -1,21 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef BASE_PREFS_PREF_OBSERVER_H_ -#define BASE_PREFS_PREF_OBSERVER_H_ - -#include - -class PrefService; - -// Used internally to the Prefs subsystem to pass preference change -// notifications between PrefService, PrefNotifierImpl and -// PrefChangeRegistrar. -class PrefObserver { - public: - virtual void OnPreferenceChanged(PrefService* service, - const std::string& pref_name) = 0; -}; - -#endif // BASE_PREFS_PREF_OBSERVER_H_ diff --git a/base/prefs/pref_registry.cc b/base/prefs/pref_registry.cc deleted file mode 100644 index 31d788d2f3..0000000000 --- a/base/prefs/pref_registry.cc +++ /dev/null @@ -1,63 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "base/prefs/pref_registry.h" - -#include "base/logging.h" -#include "base/prefs/default_pref_store.h" -#include "base/prefs/pref_store.h" -#include "base/values.h" - -PrefRegistry::PrefRegistry() - : defaults_(new DefaultPrefStore()) { -} - -PrefRegistry::~PrefRegistry() { -} - -scoped_refptr PrefRegistry::defaults() { - return defaults_.get(); -} - -PrefRegistry::const_iterator PrefRegistry::begin() const { - return defaults_->begin(); -} - -PrefRegistry::const_iterator PrefRegistry::end() const { - return defaults_->end(); -} - -void PrefRegistry::SetDefaultPrefValue(const char* pref_name, - base::Value* value) { - DCHECK(value); - if (DCHECK_IS_ON()) { - const base::Value* current_value = NULL; - DCHECK(defaults_->GetValue(pref_name, ¤t_value)) - << "Setting default for unregistered pref: " << pref_name; - DCHECK(value->IsType(current_value->GetType())) - << "Wrong type for new default: " << pref_name; - } - - defaults_->ReplaceDefaultValue(pref_name, make_scoped_ptr(value)); -} - -void PrefRegistry::SetRegistrationCallback( - const RegistrationCallback& callback) { - registration_callback_ = callback; -} - -void PrefRegistry::RegisterPreference(const char* path, - base::Value* default_value) { - base::Value::Type orig_type = default_value->GetType(); - DCHECK(orig_type != base::Value::TYPE_NULL && - orig_type != base::Value::TYPE_BINARY) << - "invalid preference type: " << orig_type; - DCHECK(!defaults_->GetValue(path, NULL)) << - "Trying to register a previously registered pref: " << path; - - defaults_->SetDefaultValue(path, make_scoped_ptr(default_value)); - - if (!registration_callback_.is_null()) - registration_callback_.Run(path, default_value); -} diff --git a/base/prefs/pref_registry.h b/base/prefs/pref_registry.h deleted file mode 100644 index 6c7eac9f59..0000000000 --- a/base/prefs/pref_registry.h +++ /dev/null @@ -1,72 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef BASE_PREFS_PREF_REGISTRY_H_ -#define BASE_PREFS_PREF_REGISTRY_H_ - -#include "base/callback.h" -#include "base/memory/ref_counted.h" -#include "base/prefs/base_prefs_export.h" -#include "base/prefs/pref_value_map.h" - -namespace base { -class Value; -} - -class DefaultPrefStore; -class PrefStore; - -// Preferences need to be registered with a type and default value -// before they are used. -// -// The way you use a PrefRegistry is that you register all required -// preferences on it (via one of its subclasses), then pass it as a -// construction parameter to PrefService. -// -// Currently, registrations after constructing the PrefService will -// also work, but this is being deprecated. -class BASE_PREFS_EXPORT PrefRegistry : public base::RefCounted { - public: - typedef PrefValueMap::const_iterator const_iterator; - typedef base::Callback RegistrationCallback; - - PrefRegistry(); - - // Gets the registered defaults. - scoped_refptr defaults(); - - // Allows iteration over defaults. - const_iterator begin() const; - const_iterator end() const; - - // Changes the default value for a preference. Takes ownership of |value|. - // - // |pref_name| must be a previously registered preference. - void SetDefaultPrefValue(const char* pref_name, base::Value* value); - - // Exactly one callback can be set for registration. The callback - // will be invoked each time registration has been performed on this - // object. - // - // Calling this method after a callback has already been set will - // make the object forget the previous callback and use the new one - // instead. - void SetRegistrationCallback(const RegistrationCallback& callback); - - protected: - friend class base::RefCounted; - virtual ~PrefRegistry(); - - // Used by subclasses to register a default value for a preference. - void RegisterPreference(const char* path, base::Value* default_value); - - scoped_refptr defaults_; - - private: - RegistrationCallback registration_callback_; - - DISALLOW_COPY_AND_ASSIGN(PrefRegistry); -}; - -#endif // BASE_PREFS_PREF_REGISTRY_H_ diff --git a/base/prefs/pref_registry_simple.cc b/base/prefs/pref_registry_simple.cc deleted file mode 100644 index c068b4ba43..0000000000 --- a/base/prefs/pref_registry_simple.cc +++ /dev/null @@ -1,67 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "base/prefs/pref_registry_simple.h" - -#include "base/files/file_path.h" -#include "base/strings/string_number_conversions.h" -#include "base/values.h" - -PrefRegistrySimple::PrefRegistrySimple() { -} - -PrefRegistrySimple::~PrefRegistrySimple() { -} - -void PrefRegistrySimple::RegisterBooleanPref(const char* path, - bool default_value) { - RegisterPreference(path, base::Value::CreateBooleanValue(default_value)); -} - -void PrefRegistrySimple::RegisterIntegerPref(const char* path, - int default_value) { - RegisterPreference(path, base::Value::CreateIntegerValue(default_value)); -} - -void PrefRegistrySimple::RegisterDoublePref(const char* path, - double default_value) { - RegisterPreference(path, base::Value::CreateDoubleValue(default_value)); -} - -void PrefRegistrySimple::RegisterStringPref(const char* path, - const std::string& default_value) { - RegisterPreference(path, base::Value::CreateStringValue(default_value)); -} - -void PrefRegistrySimple::RegisterFilePathPref( - const char* path, - const base::FilePath& default_value) { - RegisterPreference(path, - base::Value::CreateStringValue(default_value.value())); -} - -void PrefRegistrySimple::RegisterListPref(const char* path) { - RegisterPreference(path, new base::ListValue()); -} - -void PrefRegistrySimple::RegisterListPref(const char* path, - base::ListValue* default_value) { - RegisterPreference(path, default_value); -} - -void PrefRegistrySimple::RegisterDictionaryPref(const char* path) { - RegisterPreference(path, new base::DictionaryValue()); -} - -void PrefRegistrySimple::RegisterDictionaryPref( - const char* path, - base::DictionaryValue* default_value) { - RegisterPreference(path, default_value); -} - -void PrefRegistrySimple::RegisterInt64Pref(const char* path, - int64 default_value) { - RegisterPreference( - path, base::Value::CreateStringValue(base::Int64ToString(default_value))); -} diff --git a/base/prefs/pref_registry_simple.h b/base/prefs/pref_registry_simple.h deleted file mode 100644 index 50b646711f..0000000000 --- a/base/prefs/pref_registry_simple.h +++ /dev/null @@ -1,44 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef BASE_PREFS_PREF_REGISTRY_SIMPLE_H_ -#define BASE_PREFS_PREF_REGISTRY_SIMPLE_H_ - -#include - -#include "base/prefs/base_prefs_export.h" -#include "base/prefs/pref_registry.h" - -namespace base { -class DictionaryValue; -class FilePath; -class ListValue; -} - -// A simple implementation of PrefRegistry. -class BASE_PREFS_EXPORT PrefRegistrySimple : public PrefRegistry { - public: - PrefRegistrySimple(); - - void RegisterBooleanPref(const char* path, bool default_value); - void RegisterIntegerPref(const char* path, int default_value); - void RegisterDoublePref(const char* path, double default_value); - void RegisterStringPref(const char* path, const std::string& default_value); - void RegisterFilePathPref(const char* path, - const base::FilePath& default_value); - void RegisterListPref(const char* path); - void RegisterDictionaryPref(const char* path); - void RegisterListPref(const char* path, base::ListValue* default_value); - void RegisterDictionaryPref(const char* path, - base::DictionaryValue* default_value); - void RegisterInt64Pref(const char* path, - int64 default_value); - - private: - virtual ~PrefRegistrySimple(); - - DISALLOW_COPY_AND_ASSIGN(PrefRegistrySimple); -}; - -#endif // BASE_PREFS_PREF_REGISTRY_SIMPLE_H_ diff --git a/base/prefs/pref_service.cc b/base/prefs/pref_service.cc deleted file mode 100644 index 046af915b3..0000000000 --- a/base/prefs/pref_service.cc +++ /dev/null @@ -1,591 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "base/prefs/pref_service.h" - -#include - -#include "base/bind.h" -#include "base/files/file_path.h" -#include "base/logging.h" -#include "base/message_loop/message_loop.h" -#include "base/metrics/histogram.h" -#include "base/prefs/default_pref_store.h" -#include "base/prefs/pref_notifier_impl.h" -#include "base/prefs/pref_registry.h" -#include "base/prefs/pref_value_store.h" -#include "base/stl_util.h" -#include "base/strings/string_number_conversions.h" -#include "base/strings/string_util.h" -#include "base/value_conversions.h" -#include "build/build_config.h" - -namespace { - -class ReadErrorHandler : public PersistentPrefStore::ReadErrorDelegate { - public: - ReadErrorHandler(base::Callback cb) - : callback_(cb) {} - - virtual void OnError(PersistentPrefStore::PrefReadError error) OVERRIDE { - callback_.Run(error); - } - - private: - base::Callback callback_; -}; - -} // namespace - -PrefService::PrefService( - PrefNotifierImpl* pref_notifier, - PrefValueStore* pref_value_store, - PersistentPrefStore* user_prefs, - PrefRegistry* pref_registry, - base::Callback - read_error_callback, - bool async) - : pref_notifier_(pref_notifier), - pref_value_store_(pref_value_store), - pref_registry_(pref_registry), - user_pref_store_(user_prefs), - read_error_callback_(read_error_callback) { - pref_notifier_->SetPrefService(this); - - pref_registry_->SetRegistrationCallback( - base::Bind(&PrefService::AddRegisteredPreference, - base::Unretained(this))); - AddInitialPreferences(); - - InitFromStorage(async); -} - -PrefService::~PrefService() { - DCHECK(CalledOnValidThread()); - - // Remove our callback, setting a NULL one. - pref_registry_->SetRegistrationCallback(PrefRegistry::RegistrationCallback()); - - // Reset pointers so accesses after destruction reliably crash. - pref_value_store_.reset(); - pref_registry_ = NULL; - user_pref_store_ = NULL; - pref_notifier_.reset(); -} - -void PrefService::InitFromStorage(bool async) { - if (!async) { - read_error_callback_.Run(user_pref_store_->ReadPrefs()); - } else { - // Guarantee that initialization happens after this function returned. - base::MessageLoop::current()->PostTask( - FROM_HERE, - base::Bind(&PersistentPrefStore::ReadPrefsAsync, - user_pref_store_.get(), - new ReadErrorHandler(read_error_callback_))); - } -} - -bool PrefService::ReloadPersistentPrefs() { - return user_pref_store_->ReadPrefs() == - PersistentPrefStore::PREF_READ_ERROR_NONE; -} - -void PrefService::CommitPendingWrite() { - DCHECK(CalledOnValidThread()); - user_pref_store_->CommitPendingWrite(); -} - -bool PrefService::GetBoolean(const char* path) const { - DCHECK(CalledOnValidThread()); - - bool result = false; - - const base::Value* value = GetPreferenceValue(path); - if (!value) { - NOTREACHED() << "Trying to read an unregistered pref: " << path; - return result; - } - bool rv = value->GetAsBoolean(&result); - DCHECK(rv); - return result; -} - -int PrefService::GetInteger(const char* path) const { - DCHECK(CalledOnValidThread()); - - int result = 0; - - const base::Value* value = GetPreferenceValue(path); - if (!value) { - NOTREACHED() << "Trying to read an unregistered pref: " << path; - return result; - } - bool rv = value->GetAsInteger(&result); - DCHECK(rv); - return result; -} - -double PrefService::GetDouble(const char* path) const { - DCHECK(CalledOnValidThread()); - - double result = 0.0; - - const base::Value* value = GetPreferenceValue(path); - if (!value) { - NOTREACHED() << "Trying to read an unregistered pref: " << path; - return result; - } - bool rv = value->GetAsDouble(&result); - DCHECK(rv); - return result; -} - -std::string PrefService::GetString(const char* path) const { - DCHECK(CalledOnValidThread()); - - std::string result; - - const base::Value* value = GetPreferenceValue(path); - if (!value) { - NOTREACHED() << "Trying to read an unregistered pref: " << path; - return result; - } - bool rv = value->GetAsString(&result); - DCHECK(rv); - return result; -} - -base::FilePath PrefService::GetFilePath(const char* path) const { - DCHECK(CalledOnValidThread()); - - base::FilePath result; - - const base::Value* value = GetPreferenceValue(path); - if (!value) { - NOTREACHED() << "Trying to read an unregistered pref: " << path; - return base::FilePath(result); - } - bool rv = base::GetValueAsFilePath(*value, &result); - DCHECK(rv); - return result; -} - -bool PrefService::HasPrefPath(const char* path) const { - const Preference* pref = FindPreference(path); - return pref && !pref->IsDefaultValue(); -} - -base::DictionaryValue* PrefService::GetPreferenceValues() const { - DCHECK(CalledOnValidThread()); - base::DictionaryValue* out = new base::DictionaryValue; - PrefRegistry::const_iterator i = pref_registry_->begin(); - for (; i != pref_registry_->end(); ++i) { - const base::Value* value = GetPreferenceValue(i->first); - DCHECK(value); - out->Set(i->first, value->DeepCopy()); - } - return out; -} - -const PrefService::Preference* PrefService::FindPreference( - const char* pref_name) const { - DCHECK(CalledOnValidThread()); - PreferenceMap::iterator it = prefs_map_.find(pref_name); - if (it != prefs_map_.end()) - return &(it->second); - const base::Value* default_value = NULL; - if (!pref_registry_->defaults()->GetValue(pref_name, &default_value)) - return NULL; - it = prefs_map_.insert( - std::make_pair(pref_name, Preference( - this, pref_name, default_value->GetType()))).first; - return &(it->second); -} - -bool PrefService::ReadOnly() const { - return user_pref_store_->ReadOnly(); -} - -PrefService::PrefInitializationStatus PrefService::GetInitializationStatus() - const { - if (!user_pref_store_->IsInitializationComplete()) - return INITIALIZATION_STATUS_WAITING; - - switch (user_pref_store_->GetReadError()) { - case PersistentPrefStore::PREF_READ_ERROR_NONE: - return INITIALIZATION_STATUS_SUCCESS; - case PersistentPrefStore::PREF_READ_ERROR_NO_FILE: - return INITIALIZATION_STATUS_CREATED_NEW_PREF_STORE; - default: - return INITIALIZATION_STATUS_ERROR; - } -} - -bool PrefService::IsManagedPreference(const char* pref_name) const { - const Preference* pref = FindPreference(pref_name); - return pref && pref->IsManaged(); -} - -bool PrefService::IsUserModifiablePreference(const char* pref_name) const { - const Preference* pref = FindPreference(pref_name); - return pref && pref->IsUserModifiable(); -} - -const base::DictionaryValue* PrefService::GetDictionary( - const char* path) const { - DCHECK(CalledOnValidThread()); - - const base::Value* value = GetPreferenceValue(path); - if (!value) { - NOTREACHED() << "Trying to read an unregistered pref: " << path; - return NULL; - } - if (value->GetType() != base::Value::TYPE_DICTIONARY) { - NOTREACHED(); - return NULL; - } - return static_cast(value); -} - -const base::Value* PrefService::GetUserPrefValue(const char* path) const { - DCHECK(CalledOnValidThread()); - - const Preference* pref = FindPreference(path); - if (!pref) { - NOTREACHED() << "Trying to get an unregistered pref: " << path; - return NULL; - } - - // Look for an existing preference in the user store. If it doesn't - // exist, return NULL. - base::Value* value = NULL; - if (!user_pref_store_->GetMutableValue(path, &value)) - return NULL; - - if (!value->IsType(pref->GetType())) { - NOTREACHED() << "Pref value type doesn't match registered type."; - return NULL; - } - - return value; -} - -void PrefService::SetDefaultPrefValue(const char* path, - base::Value* value) { - DCHECK(CalledOnValidThread()); - pref_registry_->SetDefaultPrefValue(path, value); -} - -const base::Value* PrefService::GetDefaultPrefValue(const char* path) const { - DCHECK(CalledOnValidThread()); - // Lookup the preference in the default store. - const base::Value* value = NULL; - if (!pref_registry_->defaults()->GetValue(path, &value)) { - NOTREACHED() << "Default value missing for pref: " << path; - return NULL; - } - return value; -} - -const base::ListValue* PrefService::GetList(const char* path) const { - DCHECK(CalledOnValidThread()); - - const base::Value* value = GetPreferenceValue(path); - if (!value) { - NOTREACHED() << "Trying to read an unregistered pref: " << path; - return NULL; - } - if (value->GetType() != base::Value::TYPE_LIST) { - NOTREACHED(); - return NULL; - } - return static_cast(value); -} - -void PrefService::AddPrefObserver(const char* path, PrefObserver* obs) { - pref_notifier_->AddPrefObserver(path, obs); -} - -void PrefService::RemovePrefObserver(const char* path, PrefObserver* obs) { - pref_notifier_->RemovePrefObserver(path, obs); -} - -void PrefService::AddPrefInitObserver(base::Callback obs) { - pref_notifier_->AddInitObserver(obs); -} - -PrefRegistry* PrefService::DeprecatedGetPrefRegistry() { - return pref_registry_.get(); -} - -void PrefService::AddInitialPreferences() { - for (PrefRegistry::const_iterator it = pref_registry_->begin(); - it != pref_registry_->end(); - ++it) { - AddRegisteredPreference(it->first.c_str(), it->second); - } -} - -// TODO(joi): Once MarkNeedsEmptyValue is gone, we can probably -// completely get rid of this method. There will be one difference in -// semantics; currently all registered preferences are stored right -// away in the prefs_map_, if we remove this they would be stored only -// opportunistically. -void PrefService::AddRegisteredPreference(const char* path, - base::Value* default_value) { - DCHECK(CalledOnValidThread()); - - // For ListValue and DictionaryValue with non empty default, empty value - // for |path| needs to be persisted in |user_pref_store_|. So that - // non empty default is not used when user sets an empty ListValue or - // DictionaryValue. - bool needs_empty_value = false; - base::Value::Type orig_type = default_value->GetType(); - if (orig_type == base::Value::TYPE_LIST) { - const base::ListValue* list = NULL; - if (default_value->GetAsList(&list) && !list->empty()) - needs_empty_value = true; - } else if (orig_type == base::Value::TYPE_DICTIONARY) { - const base::DictionaryValue* dict = NULL; - if (default_value->GetAsDictionary(&dict) && !dict->empty()) - needs_empty_value = true; - } - if (needs_empty_value) - user_pref_store_->MarkNeedsEmptyValue(path); -} - -void PrefService::ClearPref(const char* path) { - DCHECK(CalledOnValidThread()); - - const Preference* pref = FindPreference(path); - if (!pref) { - NOTREACHED() << "Trying to clear an unregistered pref: " << path; - return; - } - user_pref_store_->RemoveValue(path); -} - -void PrefService::Set(const char* path, const base::Value& value) { - SetUserPrefValue(path, value.DeepCopy()); -} - -void PrefService::SetBoolean(const char* path, bool value) { - SetUserPrefValue(path, base::Value::CreateBooleanValue(value)); -} - -void PrefService::SetInteger(const char* path, int value) { - SetUserPrefValue(path, base::Value::CreateIntegerValue(value)); -} - -void PrefService::SetDouble(const char* path, double value) { - SetUserPrefValue(path, base::Value::CreateDoubleValue(value)); -} - -void PrefService::SetString(const char* path, const std::string& value) { - SetUserPrefValue(path, base::Value::CreateStringValue(value)); -} - -void PrefService::SetFilePath(const char* path, const base::FilePath& value) { - SetUserPrefValue(path, base::CreateFilePathValue(value)); -} - -void PrefService::SetInt64(const char* path, int64 value) { - SetUserPrefValue(path, - base::Value::CreateStringValue(base::Int64ToString(value))); -} - -int64 PrefService::GetInt64(const char* path) const { - DCHECK(CalledOnValidThread()); - - const base::Value* value = GetPreferenceValue(path); - if (!value) { - NOTREACHED() << "Trying to read an unregistered pref: " << path; - return 0; - } - std::string result("0"); - bool rv = value->GetAsString(&result); - DCHECK(rv); - - int64 val; - base::StringToInt64(result, &val); - return val; -} - -void PrefService::SetUint64(const char* path, uint64 value) { - SetUserPrefValue(path, - base::Value::CreateStringValue(base::Uint64ToString(value))); -} - -uint64 PrefService::GetUint64(const char* path) const { - DCHECK(CalledOnValidThread()); - - const base::Value* value = GetPreferenceValue(path); - if (!value) { - NOTREACHED() << "Trying to read an unregistered pref: " << path; - return 0; - } - std::string result("0"); - bool rv = value->GetAsString(&result); - DCHECK(rv); - - uint64 val; - base::StringToUint64(result, &val); - return val; -} - -base::Value* PrefService::GetMutableUserPref(const char* path, - base::Value::Type type) { - CHECK(type == base::Value::TYPE_DICTIONARY || type == base::Value::TYPE_LIST); - DCHECK(CalledOnValidThread()); - - const Preference* pref = FindPreference(path); - if (!pref) { - NOTREACHED() << "Trying to get an unregistered pref: " << path; - return NULL; - } - if (pref->GetType() != type) { - NOTREACHED() << "Wrong type for GetMutableValue: " << path; - return NULL; - } - - // Look for an existing preference in the user store. If it doesn't - // exist or isn't the correct type, create a new user preference. - base::Value* value = NULL; - if (!user_pref_store_->GetMutableValue(path, &value) || - !value->IsType(type)) { - if (type == base::Value::TYPE_DICTIONARY) { - value = new base::DictionaryValue; - } else if (type == base::Value::TYPE_LIST) { - value = new base::ListValue; - } else { - NOTREACHED(); - } - user_pref_store_->SetValueSilently(path, value); - } - return value; -} - -void PrefService::ReportUserPrefChanged(const std::string& key) { - user_pref_store_->ReportValueChanged(key); -} - -void PrefService::SetUserPrefValue(const char* path, base::Value* new_value) { - scoped_ptr owned_value(new_value); - DCHECK(CalledOnValidThread()); - - const Preference* pref = FindPreference(path); - if (!pref) { - NOTREACHED() << "Trying to write an unregistered pref: " << path; - return; - } - if (pref->GetType() != new_value->GetType()) { - NOTREACHED() << "Trying to set pref " << path - << " of type " << pref->GetType() - << " to value of type " << new_value->GetType(); - return; - } - - user_pref_store_->SetValue(path, owned_value.release()); -} - -void PrefService::UpdateCommandLinePrefStore(PrefStore* command_line_store) { - pref_value_store_->UpdateCommandLinePrefStore(command_line_store); -} - -/////////////////////////////////////////////////////////////////////////////// -// PrefService::Preference - -PrefService::Preference::Preference(const PrefService* service, - const char* name, - base::Value::Type type) - : name_(name), - type_(type), - pref_service_(service) { - DCHECK(name); - DCHECK(service); -} - -const std::string PrefService::Preference::name() const { - return name_; -} - -base::Value::Type PrefService::Preference::GetType() const { - return type_; -} - -const base::Value* PrefService::Preference::GetValue() const { - const base::Value* result= pref_service_->GetPreferenceValue(name_); - DCHECK(result) << "Must register pref before getting its value"; - return result; -} - -const base::Value* PrefService::Preference::GetRecommendedValue() const { - DCHECK(pref_service_->FindPreference(name_.c_str())) << - "Must register pref before getting its value"; - - const base::Value* found_value = NULL; - if (pref_value_store()->GetRecommendedValue(name_, type_, &found_value)) { - DCHECK(found_value->IsType(type_)); - return found_value; - } - - // The pref has no recommended value. - return NULL; -} - -bool PrefService::Preference::IsManaged() const { - return pref_value_store()->PrefValueInManagedStore(name_.c_str()); -} - -bool PrefService::Preference::IsRecommended() const { - return pref_value_store()->PrefValueFromRecommendedStore(name_.c_str()); -} - -bool PrefService::Preference::HasExtensionSetting() const { - return pref_value_store()->PrefValueInExtensionStore(name_.c_str()); -} - -bool PrefService::Preference::HasUserSetting() const { - return pref_value_store()->PrefValueInUserStore(name_.c_str()); -} - -bool PrefService::Preference::IsExtensionControlled() const { - return pref_value_store()->PrefValueFromExtensionStore(name_.c_str()); -} - -bool PrefService::Preference::IsUserControlled() const { - return pref_value_store()->PrefValueFromUserStore(name_.c_str()); -} - -bool PrefService::Preference::IsDefaultValue() const { - return pref_value_store()->PrefValueFromDefaultStore(name_.c_str()); -} - -bool PrefService::Preference::IsUserModifiable() const { - return pref_value_store()->PrefValueUserModifiable(name_.c_str()); -} - -bool PrefService::Preference::IsExtensionModifiable() const { - return pref_value_store()->PrefValueExtensionModifiable(name_.c_str()); -} - -const base::Value* PrefService::GetPreferenceValue( - const std::string& path) const { - DCHECK(CalledOnValidThread()); - const base::Value* default_value = NULL; - if (pref_registry_->defaults()->GetValue(path, &default_value)) { - const base::Value* found_value = NULL; - base::Value::Type default_type = default_value->GetType(); - if (pref_value_store_->GetValue(path, default_type, &found_value)) { - DCHECK(found_value->IsType(default_type)); - return found_value; - } else { - // Every registered preference has at least a default value. - NOTREACHED() << "no valid value found for registered pref " << path; - } - } - - return NULL; -} diff --git a/base/prefs/pref_service.h b/base/prefs/pref_service.h deleted file mode 100644 index 8af042f40b..0000000000 --- a/base/prefs/pref_service.h +++ /dev/null @@ -1,354 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -// This provides a way to access the application's current preferences. - -// Chromium settings and storage represent user-selected preferences and -// information and MUST not be extracted, overwritten or modified except -// through Chromium defined APIs. - -#ifndef BASE_PREFS_PREF_SERVICE_H_ -#define BASE_PREFS_PREF_SERVICE_H_ - -#include -#include - -#include "base/callback.h" -#include "base/compiler_specific.h" -#include "base/containers/hash_tables.h" -#include "base/memory/ref_counted.h" -#include "base/memory/scoped_ptr.h" -#include "base/observer_list.h" -#include "base/prefs/base_prefs_export.h" -#include "base/prefs/persistent_pref_store.h" -#include "base/threading/non_thread_safe.h" -#include "base/values.h" - -class PrefNotifier; -class PrefNotifierImpl; -class PrefObserver; -class PrefRegistry; -class PrefValueStore; -class PrefStore; - -namespace base { -class FilePath; -} - -namespace subtle { -class PrefMemberBase; -class ScopedUserPrefUpdateBase; -} - -// Base class for PrefServices. You can use the base class to read and -// interact with preferences, but not to register new preferences; for -// that see e.g. PrefRegistrySimple. -// -// Settings and storage accessed through this class represent -// user-selected preferences and information and MUST not be -// extracted, overwritten or modified except through the defined APIs. -class BASE_PREFS_EXPORT PrefService : public base::NonThreadSafe { - public: - enum PrefInitializationStatus { - INITIALIZATION_STATUS_WAITING, - INITIALIZATION_STATUS_SUCCESS, - INITIALIZATION_STATUS_CREATED_NEW_PREF_STORE, - INITIALIZATION_STATUS_ERROR - }; - - // A helper class to store all the information associated with a preference. - class BASE_PREFS_EXPORT Preference { - public: - // The type of the preference is determined by the type with which it is - // registered. This type needs to be a boolean, integer, double, string, - // dictionary (a branch), or list. You shouldn't need to construct this on - // your own; use the PrefService::Register*Pref methods instead. - Preference(const PrefService* service, - const char* name, - base::Value::Type type); - ~Preference() {} - - // Returns the name of the Preference (i.e., the key, e.g., - // browser.window_placement). - const std::string name() const; - - // Returns the registered type of the preference. - base::Value::Type GetType() const; - - // Returns the value of the Preference, falling back to the registered - // default value if no other has been set. - const base::Value* GetValue() const; - - // Returns the value recommended by the admin, if any. - const base::Value* GetRecommendedValue() const; - - // Returns true if the Preference is managed, i.e. set by an admin policy. - // Since managed prefs have the highest priority, this also indicates - // whether the pref is actually being controlled by the policy setting. - bool IsManaged() const; - - // Returns true if the Preference is recommended, i.e. set by an admin - // policy but the user is allowed to change it. - bool IsRecommended() const; - - // Returns true if the Preference has a value set by an extension, even if - // that value is being overridden by a higher-priority source. - bool HasExtensionSetting() const; - - // Returns true if the Preference has a user setting, even if that value is - // being overridden by a higher-priority source. - bool HasUserSetting() const; - - // Returns true if the Preference value is currently being controlled by an - // extension, and not by any higher-priority source. - bool IsExtensionControlled() const; - - // Returns true if the Preference value is currently being controlled by a - // user setting, and not by any higher-priority source. - bool IsUserControlled() const; - - // Returns true if the Preference is currently using its default value, - // and has not been set by any higher-priority source (even with the same - // value). - bool IsDefaultValue() const; - - // Returns true if the user can change the Preference value, which is the - // case if no higher-priority source than the user store controls the - // Preference. - bool IsUserModifiable() const; - - // Returns true if an extension can change the Preference value, which is - // the case if no higher-priority source than the extension store controls - // the Preference. - bool IsExtensionModifiable() const; - - private: - friend class PrefService; - - PrefValueStore* pref_value_store() const { - return pref_service_->pref_value_store_.get(); - } - - const std::string name_; - - const base::Value::Type type_; - - // Reference to the PrefService in which this pref was created. - const PrefService* pref_service_; - }; - - // You may wish to use PrefServiceBuilder or one of its subclasses - // for simplified construction. - PrefService( - PrefNotifierImpl* pref_notifier, - PrefValueStore* pref_value_store, - PersistentPrefStore* user_prefs, - PrefRegistry* pref_registry, - base::Callback - read_error_callback, - bool async); - virtual ~PrefService(); - - // Reloads the data from file. This should only be called when the importer - // is running during first run, and the main process may not change pref - // values while the importer process is running. Returns true on success. - bool ReloadPersistentPrefs(); - - // Lands pending writes to disk. This should only be used if we need to save - // immediately (basically, during shutdown). - void CommitPendingWrite(); - - // Returns true if the preference for the given preference name is available - // and is managed. - bool IsManagedPreference(const char* pref_name) const; - - // Returns |true| if a preference with the given name is available and its - // value can be changed by the user. - bool IsUserModifiablePreference(const char* pref_name) const; - - // Look up a preference. Returns NULL if the preference is not - // registered. - const PrefService::Preference* FindPreference(const char* path) const; - - // If the path is valid and the value at the end of the path matches the type - // specified, it will return the specified value. Otherwise, the default - // value (set when the pref was registered) will be returned. - bool GetBoolean(const char* path) const; - int GetInteger(const char* path) const; - double GetDouble(const char* path) const; - std::string GetString(const char* path) const; - base::FilePath GetFilePath(const char* path) const; - - // Returns the branch if it exists, or the registered default value otherwise. - // Note that |path| must point to a registered preference. In that case, these - // functions will never return NULL. - const base::DictionaryValue* GetDictionary( - const char* path) const; - const base::ListValue* GetList(const char* path) const; - - // Removes a user pref and restores the pref to its default value. - void ClearPref(const char* path); - - // If the path is valid (i.e., registered), update the pref value in the user - // prefs. - // To set the value of dictionary or list values in the pref tree use - // Set(), but to modify the value of a dictionary or list use either - // ListPrefUpdate or DictionaryPrefUpdate from scoped_user_pref_update.h. - void Set(const char* path, const base::Value& value); - void SetBoolean(const char* path, bool value); - void SetInteger(const char* path, int value); - void SetDouble(const char* path, double value); - void SetString(const char* path, const std::string& value); - void SetFilePath(const char* path, const base::FilePath& value); - - // Int64 helper methods that actually store the given value as a string. - // Note that if obtaining the named value via GetDictionary or GetList, the - // Value type will be TYPE_STRING. - void SetInt64(const char* path, int64 value); - int64 GetInt64(const char* path) const; - - // As above, but for unsigned values. - void SetUint64(const char* path, uint64 value); - uint64 GetUint64(const char* path) const; - - // Returns the value of the given preference, from the user pref store. If - // the preference is not set in the user pref store, returns NULL. - const base::Value* GetUserPrefValue(const char* path) const; - - // Changes the default value for a preference. Takes ownership of |value|. - // - // Will cause a pref change notification to be fired if this causes - // the effective value to change. - void SetDefaultPrefValue(const char* path, base::Value* value); - - // Returns the default value of the given preference. |path| must point to a - // registered preference. In that case, will never return NULL. - const base::Value* GetDefaultPrefValue(const char* path) const; - - // Returns true if a value has been set for the specified path. - // NOTE: this is NOT the same as FindPreference. In particular - // FindPreference returns whether RegisterXXX has been invoked, where as - // this checks if a value exists for the path. - bool HasPrefPath(const char* path) const; - - // Returns a dictionary with effective preference values. The ownership - // is passed to the caller. - base::DictionaryValue* GetPreferenceValues() const; - - bool ReadOnly() const; - - PrefInitializationStatus GetInitializationStatus() const; - - // Tell our PrefValueStore to update itself to |command_line_store|. - // Takes ownership of the store. - virtual void UpdateCommandLinePrefStore(PrefStore* command_line_store); - - // We run the callback once, when initialization completes. The bool - // parameter will be set to true for successful initialization, - // false for unsuccessful. - void AddPrefInitObserver(base::Callback callback); - - // Returns the PrefRegistry object for this service. You should not - // use this; the intent is for no registrations to take place after - // PrefService has been constructed. - PrefRegistry* DeprecatedGetPrefRegistry(); - - protected: - // Adds the registered preferences from the PrefRegistry instance - // passed to us at construction time. - void AddInitialPreferences(); - - // Updates local caches for a preference registered at |path|. The - // |default_value| must not be NULL as it determines the preference - // value's type. AddRegisteredPreference must not be called twice - // for the same path. - void AddRegisteredPreference(const char* path, - base::Value* default_value); - - // The PrefNotifier handles registering and notifying preference observers. - // It is created and owned by this PrefService. Subclasses may access it for - // unit testing. - scoped_ptr pref_notifier_; - - // The PrefValueStore provides prioritized preference values. It is owned by - // this PrefService. Subclasses may access it for unit testing. - scoped_ptr pref_value_store_; - - scoped_refptr pref_registry_; - - // Pref Stores and profile that we passed to the PrefValueStore. - scoped_refptr user_pref_store_; - - // Callback to call when a read error occurs. - base::Callback read_error_callback_; - - private: - // Hash map expected to be fastest here since it minimises expensive - // string comparisons. Order is unimportant, and deletions are rare. - // Confirmed on Android where this speeded Chrome startup by roughly 50ms - // vs. std::map, and by roughly 180ms vs. std::set of Preference pointers. - typedef base::hash_map PreferenceMap; - - // Give access to ReportUserPrefChanged() and GetMutableUserPref(). - friend class subtle::ScopedUserPrefUpdateBase; - - // Registration of pref change observers must be done using the - // PrefChangeRegistrar, which is declared as a friend here to grant it - // access to the otherwise protected members Add/RemovePrefObserver. - // PrefMember registers for preferences changes notification directly to - // avoid the storage overhead of the registrar, so its base class must be - // declared as a friend, too. - friend class PrefChangeRegistrar; - friend class subtle::PrefMemberBase; - - // These are protected so they can only be accessed by the friend - // classes listed above. - // - // If the pref at the given path changes, we call the observer's - // OnPreferenceChanged method. Note that observers should not call - // these methods directly but rather use a PrefChangeRegistrar to - // make sure the observer gets cleaned up properly. - // - // Virtual for testing. - virtual void AddPrefObserver(const char* path, PrefObserver* obs); - virtual void RemovePrefObserver(const char* path, PrefObserver* obs); - - // Sends notification of a changed preference. This needs to be called by - // a ScopedUserPrefUpdate if a DictionaryValue or ListValue is changed. - void ReportUserPrefChanged(const std::string& key); - - // Sets the value for this pref path in the user pref store and informs the - // PrefNotifier of the change. - void SetUserPrefValue(const char* path, base::Value* new_value); - - // Load preferences from storage, attempting to diagnose and handle errors. - // This should only be called from the constructor. - void InitFromStorage(bool async); - - // Used to set the value of dictionary or list values in the user pref store. - // This will create a dictionary or list if one does not exist in the user - // pref store. This method returns NULL only if you're requesting an - // unregistered pref or a non-dict/non-list pref. - // |type| may only be Values::TYPE_DICTIONARY or Values::TYPE_LIST and - // |path| must point to a registered preference of type |type|. - // Ownership of the returned value remains at the user pref store. - base::Value* GetMutableUserPref(const char* path, - base::Value::Type type); - - // GetPreferenceValue is the equivalent of FindPreference(path)->GetValue(), - // it has been added for performance. If is faster because it does - // not need to find or create a Preference object to get the - // value (GetValue() calls back though the preference service to - // actually get the value.). - const base::Value* GetPreferenceValue(const std::string& path) const; - - // Local cache of registered Preference objects. The pref_registry_ - // is authoritative with respect to what the types and default values - // of registered preferences are. - mutable PreferenceMap prefs_map_; - - DISALLOW_COPY_AND_ASSIGN(PrefService); -}; - -#endif // BASE_PREFS_PREF_SERVICE_H_ diff --git a/base/prefs/pref_service_builder.cc b/base/prefs/pref_service_builder.cc deleted file mode 100644 index b3d3533603..0000000000 --- a/base/prefs/pref_service_builder.cc +++ /dev/null @@ -1,102 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "base/prefs/pref_service_builder.h" - -#include "base/bind.h" -#include "base/prefs/default_pref_store.h" -#include "base/prefs/json_pref_store.h" -#include "base/prefs/pref_notifier_impl.h" -#include "base/prefs/pref_service.h" - -#include "base/prefs/pref_value_store.h" - -namespace { - -// Do-nothing default implementation. -void DoNothingHandleReadError(PersistentPrefStore::PrefReadError error) { -} - -} // namespace - -PrefServiceBuilder::PrefServiceBuilder() { - ResetDefaultState(); -} - -PrefServiceBuilder::~PrefServiceBuilder() { -} - -PrefServiceBuilder& PrefServiceBuilder::WithManagedPrefs(PrefStore* store) { - managed_prefs_ = store; - return *this; -} - -PrefServiceBuilder& PrefServiceBuilder::WithExtensionPrefs(PrefStore* store) { - extension_prefs_ = store; - return *this; -} - -PrefServiceBuilder& PrefServiceBuilder::WithCommandLinePrefs(PrefStore* store) { - command_line_prefs_ = store; - return *this; -} - -PrefServiceBuilder& PrefServiceBuilder::WithUserPrefs( - PersistentPrefStore* store) { - user_prefs_ = store; - return *this; -} - -PrefServiceBuilder& PrefServiceBuilder::WithRecommendedPrefs(PrefStore* store) { - recommended_prefs_ = store; - return *this; -} - -PrefServiceBuilder& PrefServiceBuilder::WithReadErrorCallback( - const base::Callback& - read_error_callback) { - read_error_callback_ = read_error_callback; - return *this; -} - -PrefServiceBuilder& PrefServiceBuilder::WithUserFilePrefs( - const base::FilePath& prefs_file, - base::SequencedTaskRunner* task_runner) { - user_prefs_ = new JsonPrefStore(prefs_file, task_runner); - return *this; -} - -PrefServiceBuilder& PrefServiceBuilder::WithAsync(bool async) { - async_ = async; - return *this; -} - -PrefService* PrefServiceBuilder::Create(PrefRegistry* pref_registry) { - PrefNotifierImpl* pref_notifier = new PrefNotifierImpl(); - PrefService* pref_service = - new PrefService(pref_notifier, - new PrefValueStore(managed_prefs_.get(), - extension_prefs_.get(), - command_line_prefs_.get(), - user_prefs_.get(), - recommended_prefs_.get(), - pref_registry->defaults().get(), - pref_notifier), - user_prefs_.get(), - pref_registry, - read_error_callback_, - async_); - ResetDefaultState(); - return pref_service; -} - -void PrefServiceBuilder::ResetDefaultState() { - managed_prefs_ = NULL; - extension_prefs_ = NULL; - command_line_prefs_ = NULL; - user_prefs_ = NULL; - recommended_prefs_ = NULL; - read_error_callback_ = base::Bind(&DoNothingHandleReadError); - async_ = false; -} diff --git a/base/prefs/pref_service_builder.h b/base/prefs/pref_service_builder.h deleted file mode 100644 index 4bd4fde7dd..0000000000 --- a/base/prefs/pref_service_builder.h +++ /dev/null @@ -1,72 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef BASE_PREFS_PREF_SERVICE_BUILDER_H_ -#define BASE_PREFS_PREF_SERVICE_BUILDER_H_ - -#include "base/basictypes.h" -#include "base/callback.h" -#include "base/memory/ref_counted.h" -#include "base/prefs/base_prefs_export.h" -#include "base/prefs/persistent_pref_store.h" -#include "base/prefs/pref_registry.h" -#include "base/prefs/pref_store.h" - -class PrefService; - -namespace base { -class FilePath; -class SequencedTaskRunner; -} - -// A class that allows convenient building of PrefService. -class BASE_PREFS_EXPORT PrefServiceBuilder { - public: - PrefServiceBuilder(); - virtual ~PrefServiceBuilder(); - - // Functions for setting the various parameters of the PrefService to build. - // These take ownership of the |store| parameter. - PrefServiceBuilder& WithManagedPrefs(PrefStore* store); - PrefServiceBuilder& WithExtensionPrefs(PrefStore* store); - PrefServiceBuilder& WithCommandLinePrefs(PrefStore* store); - PrefServiceBuilder& WithUserPrefs(PersistentPrefStore* store); - PrefServiceBuilder& WithRecommendedPrefs(PrefStore* store); - - // Sets up error callback for the PrefService. A do-nothing default - // is provided if this is not called. - PrefServiceBuilder& WithReadErrorCallback( - const base::Callback& - read_error_callback); - - // Specifies to use an actual file-backed user pref store. - PrefServiceBuilder& WithUserFilePrefs( - const base::FilePath& prefs_file, - base::SequencedTaskRunner* task_runner); - - PrefServiceBuilder& WithAsync(bool async); - - // Creates a PrefService object initialized with the parameters from - // this builder. - virtual PrefService* Create(PrefRegistry* registry); - - protected: - virtual void ResetDefaultState(); - - scoped_refptr managed_prefs_; - scoped_refptr extension_prefs_; - scoped_refptr command_line_prefs_; - scoped_refptr user_prefs_; - scoped_refptr recommended_prefs_; - - base::Callback read_error_callback_; - - // Defaults to false. - bool async_; - - private: - DISALLOW_COPY_AND_ASSIGN(PrefServiceBuilder); -}; - -#endif // BASE_PREFS_PREF_SERVICE_BUILDER_H_ diff --git a/base/prefs/pref_service_unittest.cc b/base/prefs/pref_service_unittest.cc deleted file mode 100644 index ff6bb2f2de..0000000000 --- a/base/prefs/pref_service_unittest.cc +++ /dev/null @@ -1,318 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include - -#include "base/prefs/json_pref_store.h" -#include "base/prefs/mock_pref_change_callback.h" -#include "base/prefs/pref_change_registrar.h" -#include "base/prefs/pref_registry_simple.h" -#include "base/prefs/pref_value_store.h" -#include "base/prefs/testing_pref_service.h" -#include "base/prefs/testing_pref_store.h" -#include "base/values.h" -#include "testing/gmock/include/gmock/gmock.h" -#include "testing/gtest/include/gtest/gtest.h" - -using testing::_; -using testing::Mock; - -const char kPrefName[] = "pref.name"; - -TEST(PrefServiceTest, NoObserverFire) { - TestingPrefServiceSimple prefs; - - const char pref_name[] = "homepage"; - prefs.registry()->RegisterStringPref(pref_name, std::string()); - - const char new_pref_value[] = "http://www.google.com/"; - MockPrefChangeCallback obs(&prefs); - PrefChangeRegistrar registrar; - registrar.Init(&prefs); - registrar.Add(pref_name, obs.GetCallback()); - - // This should fire the checks in MockPrefChangeCallback::OnPreferenceChanged. - const base::StringValue expected_value(new_pref_value); - obs.Expect(pref_name, &expected_value); - prefs.SetString(pref_name, new_pref_value); - Mock::VerifyAndClearExpectations(&obs); - - // Setting the pref to the same value should not set the pref value a second - // time. - EXPECT_CALL(obs, OnPreferenceChanged(_)).Times(0); - prefs.SetString(pref_name, new_pref_value); - Mock::VerifyAndClearExpectations(&obs); - - // Clearing the pref should cause the pref to fire. - const base::StringValue expected_default_value((std::string())); - obs.Expect(pref_name, &expected_default_value); - prefs.ClearPref(pref_name); - Mock::VerifyAndClearExpectations(&obs); - - // Clearing the pref again should not cause the pref to fire. - EXPECT_CALL(obs, OnPreferenceChanged(_)).Times(0); - prefs.ClearPref(pref_name); - Mock::VerifyAndClearExpectations(&obs); -} - -TEST(PrefServiceTest, HasPrefPath) { - TestingPrefServiceSimple prefs; - - const char path[] = "fake.path"; - - // Shouldn't initially have a path. - EXPECT_FALSE(prefs.HasPrefPath(path)); - - // Register the path. This doesn't set a value, so the path still shouldn't - // exist. - prefs.registry()->RegisterStringPref(path, std::string()); - EXPECT_FALSE(prefs.HasPrefPath(path)); - - // Set a value and make sure we have a path. - prefs.SetString(path, "blah"); - EXPECT_TRUE(prefs.HasPrefPath(path)); -} - -TEST(PrefServiceTest, Observers) { - const char pref_name[] = "homepage"; - - TestingPrefServiceSimple prefs; - prefs.SetUserPref(pref_name, - base::Value::CreateStringValue("http://www.cnn.com")); - prefs.registry()->RegisterStringPref(pref_name, std::string()); - - const char new_pref_value[] = "http://www.google.com/"; - const base::StringValue expected_new_pref_value(new_pref_value); - MockPrefChangeCallback obs(&prefs); - PrefChangeRegistrar registrar; - registrar.Init(&prefs); - registrar.Add(pref_name, obs.GetCallback()); - - PrefChangeRegistrar registrar_two; - registrar_two.Init(&prefs); - - // This should fire the checks in MockPrefChangeCallback::OnPreferenceChanged. - obs.Expect(pref_name, &expected_new_pref_value); - prefs.SetString(pref_name, new_pref_value); - Mock::VerifyAndClearExpectations(&obs); - - // Now try adding a second pref observer. - const char new_pref_value2[] = "http://www.youtube.com/"; - const base::StringValue expected_new_pref_value2(new_pref_value2); - MockPrefChangeCallback obs2(&prefs); - obs.Expect(pref_name, &expected_new_pref_value2); - obs2.Expect(pref_name, &expected_new_pref_value2); - registrar_two.Add(pref_name, obs2.GetCallback()); - // This should fire the checks in obs and obs2. - prefs.SetString(pref_name, new_pref_value2); - Mock::VerifyAndClearExpectations(&obs); - Mock::VerifyAndClearExpectations(&obs2); - - // Set a recommended value. - const base::StringValue recommended_pref_value("http://www.gmail.com/"); - obs.Expect(pref_name, &expected_new_pref_value2); - obs2.Expect(pref_name, &expected_new_pref_value2); - // This should fire the checks in obs and obs2 but with an unchanged value - // as the recommended value is being overridden by the user-set value. - prefs.SetRecommendedPref(pref_name, recommended_pref_value.DeepCopy()); - Mock::VerifyAndClearExpectations(&obs); - Mock::VerifyAndClearExpectations(&obs2); - - // Make sure obs2 still works after removing obs. - registrar.Remove(pref_name); - EXPECT_CALL(obs, OnPreferenceChanged(_)).Times(0); - obs2.Expect(pref_name, &expected_new_pref_value); - // This should only fire the observer in obs2. - prefs.SetString(pref_name, new_pref_value); - Mock::VerifyAndClearExpectations(&obs); - Mock::VerifyAndClearExpectations(&obs2); -} - -// Make sure that if a preference changes type, so the wrong type is stored in -// the user pref file, it uses the correct fallback value instead. -TEST(PrefServiceTest, GetValueChangedType) { - const int kTestValue = 10; - TestingPrefServiceSimple prefs; - prefs.registry()->RegisterIntegerPref(kPrefName, kTestValue); - - // Check falling back to a recommended value. - prefs.SetUserPref(kPrefName, - base::Value::CreateStringValue("not an integer")); - const PrefService::Preference* pref = prefs.FindPreference(kPrefName); - ASSERT_TRUE(pref); - const base::Value* value = pref->GetValue(); - ASSERT_TRUE(value); - EXPECT_EQ(base::Value::TYPE_INTEGER, value->GetType()); - int actual_int_value = -1; - EXPECT_TRUE(value->GetAsInteger(&actual_int_value)); - EXPECT_EQ(kTestValue, actual_int_value); -} - -TEST(PrefServiceTest, GetValueAndGetRecommendedValue) { - const int kDefaultValue = 5; - const int kUserValue = 10; - const int kRecommendedValue = 15; - TestingPrefServiceSimple prefs; - prefs.registry()->RegisterIntegerPref(kPrefName, kDefaultValue); - - // Create pref with a default value only. - const PrefService::Preference* pref = prefs.FindPreference(kPrefName); - ASSERT_TRUE(pref); - - // Check that GetValue() returns the default value. - const base::Value* value = pref->GetValue(); - ASSERT_TRUE(value); - EXPECT_EQ(base::Value::TYPE_INTEGER, value->GetType()); - int actual_int_value = -1; - EXPECT_TRUE(value->GetAsInteger(&actual_int_value)); - EXPECT_EQ(kDefaultValue, actual_int_value); - - // Check that GetRecommendedValue() returns no value. - value = pref->GetRecommendedValue(); - ASSERT_FALSE(value); - - // Set a user-set value. - prefs.SetUserPref(kPrefName, base::Value::CreateIntegerValue(kUserValue)); - - // Check that GetValue() returns the user-set value. - value = pref->GetValue(); - ASSERT_TRUE(value); - EXPECT_EQ(base::Value::TYPE_INTEGER, value->GetType()); - actual_int_value = -1; - EXPECT_TRUE(value->GetAsInteger(&actual_int_value)); - EXPECT_EQ(kUserValue, actual_int_value); - - // Check that GetRecommendedValue() returns no value. - value = pref->GetRecommendedValue(); - ASSERT_FALSE(value); - - // Set a recommended value. - prefs.SetRecommendedPref(kPrefName, - base::Value::CreateIntegerValue(kRecommendedValue)); - - // Check that GetValue() returns the user-set value. - value = pref->GetValue(); - ASSERT_TRUE(value); - EXPECT_EQ(base::Value::TYPE_INTEGER, value->GetType()); - actual_int_value = -1; - EXPECT_TRUE(value->GetAsInteger(&actual_int_value)); - EXPECT_EQ(kUserValue, actual_int_value); - - // Check that GetRecommendedValue() returns the recommended value. - value = pref->GetRecommendedValue(); - ASSERT_TRUE(value); - EXPECT_EQ(base::Value::TYPE_INTEGER, value->GetType()); - actual_int_value = -1; - EXPECT_TRUE(value->GetAsInteger(&actual_int_value)); - EXPECT_EQ(kRecommendedValue, actual_int_value); - - // Remove the user-set value. - prefs.RemoveUserPref(kPrefName); - - // Check that GetValue() returns the recommended value. - value = pref->GetValue(); - ASSERT_TRUE(value); - EXPECT_EQ(base::Value::TYPE_INTEGER, value->GetType()); - actual_int_value = -1; - EXPECT_TRUE(value->GetAsInteger(&actual_int_value)); - EXPECT_EQ(kRecommendedValue, actual_int_value); - - // Check that GetRecommendedValue() returns the recommended value. - value = pref->GetRecommendedValue(); - ASSERT_TRUE(value); - EXPECT_EQ(base::Value::TYPE_INTEGER, value->GetType()); - actual_int_value = -1; - EXPECT_TRUE(value->GetAsInteger(&actual_int_value)); - EXPECT_EQ(kRecommendedValue, actual_int_value); -} - -class PrefServiceSetValueTest : public testing::Test { - protected: - static const char kName[]; - static const char kValue[]; - - PrefServiceSetValueTest() : observer_(&prefs_) {} - - TestingPrefServiceSimple prefs_; - MockPrefChangeCallback observer_; -}; - -const char PrefServiceSetValueTest::kName[] = "name"; -const char PrefServiceSetValueTest::kValue[] = "value"; - -TEST_F(PrefServiceSetValueTest, SetStringValue) { - const char default_string[] = "default"; - const base::StringValue default_value(default_string); - prefs_.registry()->RegisterStringPref(kName, default_string); - - PrefChangeRegistrar registrar; - registrar.Init(&prefs_); - registrar.Add(kName, observer_.GetCallback()); - - // Changing the controlling store from default to user triggers notification. - observer_.Expect(kName, &default_value); - prefs_.Set(kName, default_value); - Mock::VerifyAndClearExpectations(&observer_); - - EXPECT_CALL(observer_, OnPreferenceChanged(_)).Times(0); - prefs_.Set(kName, default_value); - Mock::VerifyAndClearExpectations(&observer_); - - base::StringValue new_value(kValue); - observer_.Expect(kName, &new_value); - prefs_.Set(kName, new_value); - Mock::VerifyAndClearExpectations(&observer_); -} - -TEST_F(PrefServiceSetValueTest, SetDictionaryValue) { - prefs_.registry()->RegisterDictionaryPref(kName); - PrefChangeRegistrar registrar; - registrar.Init(&prefs_); - registrar.Add(kName, observer_.GetCallback()); - - EXPECT_CALL(observer_, OnPreferenceChanged(_)).Times(0); - prefs_.RemoveUserPref(kName); - Mock::VerifyAndClearExpectations(&observer_); - - base::DictionaryValue new_value; - new_value.SetString(kName, kValue); - observer_.Expect(kName, &new_value); - prefs_.Set(kName, new_value); - Mock::VerifyAndClearExpectations(&observer_); - - EXPECT_CALL(observer_, OnPreferenceChanged(_)).Times(0); - prefs_.Set(kName, new_value); - Mock::VerifyAndClearExpectations(&observer_); - - base::DictionaryValue empty; - observer_.Expect(kName, &empty); - prefs_.Set(kName, empty); - Mock::VerifyAndClearExpectations(&observer_); -} - -TEST_F(PrefServiceSetValueTest, SetListValue) { - prefs_.registry()->RegisterListPref(kName); - PrefChangeRegistrar registrar; - registrar.Init(&prefs_); - registrar.Add(kName, observer_.GetCallback()); - - EXPECT_CALL(observer_, OnPreferenceChanged(_)).Times(0); - prefs_.RemoveUserPref(kName); - Mock::VerifyAndClearExpectations(&observer_); - - base::ListValue new_value; - new_value.Append(base::Value::CreateStringValue(kValue)); - observer_.Expect(kName, &new_value); - prefs_.Set(kName, new_value); - Mock::VerifyAndClearExpectations(&observer_); - - EXPECT_CALL(observer_, OnPreferenceChanged(_)).Times(0); - prefs_.Set(kName, new_value); - Mock::VerifyAndClearExpectations(&observer_); - - base::ListValue empty; - observer_.Expect(kName, &empty); - prefs_.Set(kName, empty); - Mock::VerifyAndClearExpectations(&observer_); -} diff --git a/base/prefs/pref_store.cc b/base/prefs/pref_store.cc deleted file mode 100644 index 0521654129..0000000000 --- a/base/prefs/pref_store.cc +++ /dev/null @@ -1,13 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "base/prefs/pref_store.h" - -size_t PrefStore::NumberOfObservers() const { - return 0; -} - -bool PrefStore::IsInitializationComplete() const { - return true; -} diff --git a/base/prefs/pref_store.h b/base/prefs/pref_store.h deleted file mode 100644 index 22395288d1..0000000000 --- a/base/prefs/pref_store.h +++ /dev/null @@ -1,63 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef BASE_PREFS_PREF_STORE_H_ -#define BASE_PREFS_PREF_STORE_H_ - -#include - -#include "base/basictypes.h" -#include "base/memory/ref_counted.h" -#include "base/prefs/base_prefs_export.h" - -namespace base { -class Value; -} - -// This is an abstract interface for reading and writing from/to a persistent -// preference store, used by PrefService. An implementation using a JSON file -// can be found in JsonPrefStore, while an implementation without any backing -// store for testing can be found in TestingPrefStore. Furthermore, there is -// CommandLinePrefStore, which bridges command line options to preferences and -// ConfigurationPolicyPrefStore, which is used for hooking up configuration -// policy with the preference subsystem. -class BASE_PREFS_EXPORT PrefStore : public base::RefCounted { - public: - // Observer interface for monitoring PrefStore. - class BASE_PREFS_EXPORT Observer { - public: - // Called when the value for the given |key| in the store changes. - virtual void OnPrefValueChanged(const std::string& key) = 0; - // Notification about the PrefStore being fully initialized. - virtual void OnInitializationCompleted(bool succeeded) = 0; - - protected: - virtual ~Observer() {} - }; - - PrefStore() {} - - // Add and remove observers. - virtual void AddObserver(Observer* observer) {} - virtual void RemoveObserver(Observer* observer) {} - virtual size_t NumberOfObservers() const; - - // Whether the store has completed all asynchronous initialization. - virtual bool IsInitializationComplete() const; - - // Get the value for a given preference |key| and stores it in |*result|. - // |*result| is only modified if the return value is true and if |result| - // is not NULL. Ownership of the |*result| value remains with the PrefStore. - virtual bool GetValue(const std::string& key, - const base::Value** result) const = 0; - - protected: - friend class base::RefCounted; - virtual ~PrefStore() {} - - private: - DISALLOW_COPY_AND_ASSIGN(PrefStore); -}; - -#endif // BASE_PREFS_PREF_STORE_H_ diff --git a/base/prefs/pref_store_observer_mock.cc b/base/prefs/pref_store_observer_mock.cc deleted file mode 100644 index 0970e6310d..0000000000 --- a/base/prefs/pref_store_observer_mock.cc +++ /dev/null @@ -1,9 +0,0 @@ -// Copyright (c) 2011 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "base/prefs/pref_store_observer_mock.h" - -PrefStoreObserverMock::PrefStoreObserverMock() {} - -PrefStoreObserverMock::~PrefStoreObserverMock() {} diff --git a/base/prefs/pref_store_observer_mock.h b/base/prefs/pref_store_observer_mock.h deleted file mode 100644 index 8252c3b359..0000000000 --- a/base/prefs/pref_store_observer_mock.h +++ /dev/null @@ -1,25 +0,0 @@ -// Copyright (c) 2011 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef BASE_PREFS_PREF_STORE_OBSERVER_MOCK_H_ -#define BASE_PREFS_PREF_STORE_OBSERVER_MOCK_H_ - -#include "base/basictypes.h" -#include "base/prefs/pref_store.h" -#include "testing/gmock/include/gmock/gmock.h" - -// A gmock-ified implementation of PrefStore::Observer. -class PrefStoreObserverMock : public PrefStore::Observer { - public: - PrefStoreObserverMock(); - virtual ~PrefStoreObserverMock(); - - MOCK_METHOD1(OnPrefValueChanged, void(const std::string&)); - MOCK_METHOD1(OnInitializationCompleted, void(bool)); - - private: - DISALLOW_COPY_AND_ASSIGN(PrefStoreObserverMock); -}; - -#endif // BASE_PREFS_PREF_STORE_OBSERVER_MOCK_H_ diff --git a/base/prefs/pref_value_map.cc b/base/prefs/pref_value_map.cc deleted file mode 100644 index eeda272217..0000000000 --- a/base/prefs/pref_value_map.cc +++ /dev/null @@ -1,152 +0,0 @@ -// Copyright (c) 2011 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "base/prefs/pref_value_map.h" - -#include "base/logging.h" -#include "base/memory/scoped_ptr.h" -#include "base/stl_util.h" -#include "base/values.h" - -PrefValueMap::PrefValueMap() {} - -PrefValueMap::~PrefValueMap() { - Clear(); -} - -bool PrefValueMap::GetValue(const std::string& key, - const base::Value** value) const { - const Map::const_iterator entry = prefs_.find(key); - if (entry != prefs_.end()) { - if (value) - *value = entry->second; - return true; - } - - return false; -} - -bool PrefValueMap::GetValue(const std::string& key, base::Value** value) { - const Map::const_iterator entry = prefs_.find(key); - if (entry != prefs_.end()) { - if (value) - *value = entry->second; - return true; - } - - return false; -} - -bool PrefValueMap::SetValue(const std::string& key, base::Value* value) { - DCHECK(value); - scoped_ptr value_ptr(value); - const Map::iterator entry = prefs_.find(key); - if (entry != prefs_.end()) { - if (base::Value::Equals(entry->second, value)) - return false; - delete entry->second; - entry->second = value_ptr.release(); - } else { - prefs_[key] = value_ptr.release(); - } - - return true; -} - -bool PrefValueMap::RemoveValue(const std::string& key) { - const Map::iterator entry = prefs_.find(key); - if (entry != prefs_.end()) { - delete entry->second; - prefs_.erase(entry); - return true; - } - - return false; -} - -void PrefValueMap::Clear() { - STLDeleteValues(&prefs_); - prefs_.clear(); -} - -void PrefValueMap::Swap(PrefValueMap* other) { - prefs_.swap(other->prefs_); -} - -PrefValueMap::iterator PrefValueMap::begin() { - return prefs_.begin(); -} - -PrefValueMap::iterator PrefValueMap::end() { - return prefs_.end(); -} - -PrefValueMap::const_iterator PrefValueMap::begin() const { - return prefs_.begin(); -} - -PrefValueMap::const_iterator PrefValueMap::end() const { - return prefs_.end(); -} - -bool PrefValueMap::GetBoolean(const std::string& key, - bool* value) const { - const base::Value* stored_value = NULL; - return GetValue(key, &stored_value) && stored_value->GetAsBoolean(value); -} - -void PrefValueMap::SetBoolean(const std::string& key, bool value) { - SetValue(key, new base::FundamentalValue(value)); -} - -bool PrefValueMap::GetString(const std::string& key, - std::string* value) const { - const base::Value* stored_value = NULL; - return GetValue(key, &stored_value) && stored_value->GetAsString(value); -} - -void PrefValueMap::SetString(const std::string& key, - const std::string& value) { - SetValue(key, new base::StringValue(value)); -} - -bool PrefValueMap::GetInteger(const std::string& key, int* value) const { - const base::Value* stored_value = NULL; - return GetValue(key, &stored_value) && stored_value->GetAsInteger(value); -} - -void PrefValueMap::SetInteger(const std::string& key, const int value) { - SetValue(key, new base::FundamentalValue(value)); -} - -void PrefValueMap::GetDifferingKeys( - const PrefValueMap* other, - std::vector* differing_keys) const { - differing_keys->clear(); - - // Walk over the maps in lockstep, adding everything that is different. - Map::const_iterator this_pref(prefs_.begin()); - Map::const_iterator other_pref(other->prefs_.begin()); - while (this_pref != prefs_.end() && other_pref != other->prefs_.end()) { - const int diff = this_pref->first.compare(other_pref->first); - if (diff == 0) { - if (!this_pref->second->Equals(other_pref->second)) - differing_keys->push_back(this_pref->first); - ++this_pref; - ++other_pref; - } else if (diff < 0) { - differing_keys->push_back(this_pref->first); - ++this_pref; - } else if (diff > 0) { - differing_keys->push_back(other_pref->first); - ++other_pref; - } - } - - // Add the remaining entries. - for ( ; this_pref != prefs_.end(); ++this_pref) - differing_keys->push_back(this_pref->first); - for ( ; other_pref != other->prefs_.end(); ++other_pref) - differing_keys->push_back(other_pref->first); -} diff --git a/base/prefs/pref_value_map.h b/base/prefs/pref_value_map.h deleted file mode 100644 index 1d79127719..0000000000 --- a/base/prefs/pref_value_map.h +++ /dev/null @@ -1,88 +0,0 @@ -// Copyright (c) 2011 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef BASE_PREFS_PREF_VALUE_MAP_H_ -#define BASE_PREFS_PREF_VALUE_MAP_H_ - -#include -#include -#include - -#include "base/basictypes.h" -#include "base/prefs/base_prefs_export.h" - -namespace base { -class Value; -} - -// A generic string to value map used by the PrefStore implementations. -class BASE_PREFS_EXPORT PrefValueMap { - public: - typedef std::map::iterator iterator; - typedef std::map::const_iterator const_iterator; - - PrefValueMap(); - virtual ~PrefValueMap(); - - // Gets the value for |key| and stores it in |value|. Ownership remains with - // the map. Returns true if a value is present. If not, |value| is not - // touched. - bool GetValue(const std::string& key, const base::Value** value) const; - bool GetValue(const std::string& key, base::Value** value); - - // Sets a new |value| for |key|. Takes ownership of |value|, which must be - // non-NULL. Returns true if the value changed. - bool SetValue(const std::string& key, base::Value* value); - - // Removes the value for |key| from the map. Returns true if a value was - // removed. - bool RemoveValue(const std::string& key); - - // Clears the map. - void Clear(); - - // Swaps the contents of two maps. - void Swap(PrefValueMap* other); - - iterator begin(); - iterator end(); - const_iterator begin() const; - const_iterator end() const; - - // Gets a boolean value for |key| and stores it in |value|. Returns true if - // the value was found and of the proper type. - bool GetBoolean(const std::string& key, bool* value) const; - - // Sets the value for |key| to the boolean |value|. - void SetBoolean(const std::string& key, bool value); - - // Gets a string value for |key| and stores it in |value|. Returns true if - // the value was found and of the proper type. - bool GetString(const std::string& key, std::string* value) const; - - // Sets the value for |key| to the string |value|. - void SetString(const std::string& key, const std::string& value); - - // Gets an int value for |key| and stores it in |value|. Returns true if - // the value was found and of the proper type. - bool GetInteger(const std::string& key, int* value) const; - - // Sets the value for |key| to the int |value|. - void SetInteger(const std::string& key, const int value); - - // Compares this value map against |other| and stores all key names that have - // different values in |differing_keys|. This includes keys that are present - // only in one of the maps. - void GetDifferingKeys(const PrefValueMap* other, - std::vector* differing_keys) const; - - private: - typedef std::map Map; - - Map prefs_; - - DISALLOW_COPY_AND_ASSIGN(PrefValueMap); -}; - -#endif // BASE_PREFS_PREF_VALUE_MAP_H_ diff --git a/base/prefs/pref_value_map_unittest.cc b/base/prefs/pref_value_map_unittest.cc deleted file mode 100644 index 8cc51ad02c..0000000000 --- a/base/prefs/pref_value_map_unittest.cc +++ /dev/null @@ -1,115 +0,0 @@ -// Copyright (c) 2011 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "base/prefs/pref_value_map.h" - -#include "base/values.h" -#include "testing/gtest/include/gtest/gtest.h" - -namespace base { -namespace { - -TEST(PrefValueMapTest, SetValue) { - PrefValueMap map; - const Value* result = NULL; - EXPECT_FALSE(map.GetValue("key", &result)); - EXPECT_FALSE(result); - - EXPECT_TRUE(map.SetValue("key", new StringValue("test"))); - EXPECT_FALSE(map.SetValue("key", new StringValue("test"))); - EXPECT_TRUE(map.SetValue("key", new StringValue("hi mom!"))); - - EXPECT_TRUE(map.GetValue("key", &result)); - EXPECT_TRUE(StringValue("hi mom!").Equals(result)); -} - -TEST(PrefValueMapTest, GetAndSetIntegerValue) { - PrefValueMap map; - ASSERT_TRUE(map.SetValue("key", new FundamentalValue(5))); - - int int_value = 0; - EXPECT_TRUE(map.GetInteger("key", &int_value)); - EXPECT_EQ(5, int_value); - - map.SetInteger("key", -14); - EXPECT_TRUE(map.GetInteger("key", &int_value)); - EXPECT_EQ(-14, int_value); -} - -TEST(PrefValueMapTest, RemoveValue) { - PrefValueMap map; - EXPECT_FALSE(map.RemoveValue("key")); - - EXPECT_TRUE(map.SetValue("key", new StringValue("test"))); - EXPECT_TRUE(map.GetValue("key", NULL)); - - EXPECT_TRUE(map.RemoveValue("key")); - EXPECT_FALSE(map.GetValue("key", NULL)); - - EXPECT_FALSE(map.RemoveValue("key")); -} - -TEST(PrefValueMapTest, Clear) { - PrefValueMap map; - EXPECT_TRUE(map.SetValue("key", new StringValue("test"))); - EXPECT_TRUE(map.GetValue("key", NULL)); - - map.Clear(); - - EXPECT_FALSE(map.GetValue("key", NULL)); -} - -TEST(PrefValueMapTest, GetDifferingKeys) { - PrefValueMap reference; - EXPECT_TRUE(reference.SetValue("b", new StringValue("test"))); - EXPECT_TRUE(reference.SetValue("c", new StringValue("test"))); - EXPECT_TRUE(reference.SetValue("e", new StringValue("test"))); - - PrefValueMap check; - std::vector differing_paths; - std::vector expected_differing_paths; - - reference.GetDifferingKeys(&check, &differing_paths); - expected_differing_paths.push_back("b"); - expected_differing_paths.push_back("c"); - expected_differing_paths.push_back("e"); - EXPECT_EQ(expected_differing_paths, differing_paths); - - EXPECT_TRUE(check.SetValue("a", new StringValue("test"))); - EXPECT_TRUE(check.SetValue("c", new StringValue("test"))); - EXPECT_TRUE(check.SetValue("d", new StringValue("test"))); - - reference.GetDifferingKeys(&check, &differing_paths); - expected_differing_paths.clear(); - expected_differing_paths.push_back("a"); - expected_differing_paths.push_back("b"); - expected_differing_paths.push_back("d"); - expected_differing_paths.push_back("e"); - EXPECT_EQ(expected_differing_paths, differing_paths); -} - -TEST(PrefValueMapTest, SwapTwoMaps) { - PrefValueMap first_map; - EXPECT_TRUE(first_map.SetValue("a", new StringValue("test"))); - EXPECT_TRUE(first_map.SetValue("b", new StringValue("test"))); - EXPECT_TRUE(first_map.SetValue("c", new StringValue("test"))); - - PrefValueMap second_map; - EXPECT_TRUE(second_map.SetValue("d", new StringValue("test"))); - EXPECT_TRUE(second_map.SetValue("e", new StringValue("test"))); - EXPECT_TRUE(second_map.SetValue("f", new StringValue("test"))); - - first_map.Swap(&second_map); - - EXPECT_TRUE(first_map.GetValue("d", NULL)); - EXPECT_TRUE(first_map.GetValue("e", NULL)); - EXPECT_TRUE(first_map.GetValue("f", NULL)); - - EXPECT_TRUE(second_map.GetValue("a", NULL)); - EXPECT_TRUE(second_map.GetValue("b", NULL)); - EXPECT_TRUE(second_map.GetValue("c", NULL)); -} - -} // namespace -} // namespace base diff --git a/base/prefs/pref_value_store.cc b/base/prefs/pref_value_store.cc deleted file mode 100644 index 7d54f09f35..0000000000 --- a/base/prefs/pref_value_store.cc +++ /dev/null @@ -1,277 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "base/prefs/pref_value_store.h" - -#include "base/logging.h" -#include "base/prefs/pref_notifier.h" -#include "base/prefs/pref_observer.h" - -PrefValueStore::PrefStoreKeeper::PrefStoreKeeper() - : pref_value_store_(NULL), - type_(PrefValueStore::INVALID_STORE) { -} - -PrefValueStore::PrefStoreKeeper::~PrefStoreKeeper() { - if (pref_store_.get()) { - pref_store_->RemoveObserver(this); - pref_store_ = NULL; - } - pref_value_store_ = NULL; -} - -void PrefValueStore::PrefStoreKeeper::Initialize( - PrefValueStore* store, - PrefStore* pref_store, - PrefValueStore::PrefStoreType type) { - if (pref_store_.get()) { - pref_store_->RemoveObserver(this); - DCHECK_EQ(0U, pref_store_->NumberOfObservers()); - } - type_ = type; - pref_value_store_ = store; - pref_store_ = pref_store; - if (pref_store_.get()) - pref_store_->AddObserver(this); -} - -void PrefValueStore::PrefStoreKeeper::OnPrefValueChanged( - const std::string& key) { - pref_value_store_->OnPrefValueChanged(type_, key); -} - -void PrefValueStore::PrefStoreKeeper::OnInitializationCompleted( - bool succeeded) { - pref_value_store_->OnInitializationCompleted(type_, succeeded); -} - -PrefValueStore::PrefValueStore(PrefStore* managed_prefs, - PrefStore* extension_prefs, - PrefStore* command_line_prefs, - PrefStore* user_prefs, - PrefStore* recommended_prefs, - PrefStore* default_prefs, - PrefNotifier* pref_notifier) - : pref_notifier_(pref_notifier), - initialization_failed_(false) { - InitPrefStore(MANAGED_STORE, managed_prefs); - InitPrefStore(EXTENSION_STORE, extension_prefs); - InitPrefStore(COMMAND_LINE_STORE, command_line_prefs); - InitPrefStore(USER_STORE, user_prefs); - InitPrefStore(RECOMMENDED_STORE, recommended_prefs); - InitPrefStore(DEFAULT_STORE, default_prefs); - - CheckInitializationCompleted(); -} - -PrefValueStore::~PrefValueStore() {} - -PrefValueStore* PrefValueStore::CloneAndSpecialize( - PrefStore* managed_prefs, - PrefStore* extension_prefs, - PrefStore* command_line_prefs, - PrefStore* user_prefs, - PrefStore* recommended_prefs, - PrefStore* default_prefs, - PrefNotifier* pref_notifier) { - DCHECK(pref_notifier); - if (!managed_prefs) - managed_prefs = GetPrefStore(MANAGED_STORE); - if (!extension_prefs) - extension_prefs = GetPrefStore(EXTENSION_STORE); - if (!command_line_prefs) - command_line_prefs = GetPrefStore(COMMAND_LINE_STORE); - if (!user_prefs) - user_prefs = GetPrefStore(USER_STORE); - if (!recommended_prefs) - recommended_prefs = GetPrefStore(RECOMMENDED_STORE); - if (!default_prefs) - default_prefs = GetPrefStore(DEFAULT_STORE); - - return new PrefValueStore( - managed_prefs, extension_prefs, command_line_prefs, user_prefs, - recommended_prefs, default_prefs, pref_notifier); -} - -void PrefValueStore::set_callback(const PrefChangedCallback& callback) { - pref_changed_callback_ = callback; -} - -bool PrefValueStore::GetValue(const std::string& name, - base::Value::Type type, - const base::Value** out_value) const { - // Check the |PrefStore|s in order of their priority from highest to lowest, - // looking for the first preference value with the given |name| and |type|. - for (size_t i = 0; i <= PREF_STORE_TYPE_MAX; ++i) { - if (GetValueFromStoreWithType(name.c_str(), type, - static_cast(i), out_value)) - return true; - } - return false; -} - -bool PrefValueStore::GetRecommendedValue(const std::string& name, - base::Value::Type type, - const base::Value** out_value) const { - return GetValueFromStoreWithType(name.c_str(), type, RECOMMENDED_STORE, - out_value); -} - -void PrefValueStore::NotifyPrefChanged( - const char* path, - PrefValueStore::PrefStoreType new_store) { - DCHECK(new_store != INVALID_STORE); - // A notification is sent when the pref value in any store changes. If this - // store is currently being overridden by a higher-priority store, the - // effective value of the pref will not have changed. - pref_notifier_->OnPreferenceChanged(path); - if (!pref_changed_callback_.is_null()) - pref_changed_callback_.Run(path); -} - -bool PrefValueStore::PrefValueInManagedStore(const char* name) const { - return PrefValueInStore(name, MANAGED_STORE); -} - -bool PrefValueStore::PrefValueInExtensionStore(const char* name) const { - return PrefValueInStore(name, EXTENSION_STORE); -} - -bool PrefValueStore::PrefValueInUserStore(const char* name) const { - return PrefValueInStore(name, USER_STORE); -} - -bool PrefValueStore::PrefValueFromExtensionStore(const char* name) const { - return ControllingPrefStoreForPref(name) == EXTENSION_STORE; -} - -bool PrefValueStore::PrefValueFromUserStore(const char* name) const { - return ControllingPrefStoreForPref(name) == USER_STORE; -} - -bool PrefValueStore::PrefValueFromRecommendedStore(const char* name) const { - return ControllingPrefStoreForPref(name) == RECOMMENDED_STORE; -} - -bool PrefValueStore::PrefValueFromDefaultStore(const char* name) const { - return ControllingPrefStoreForPref(name) == DEFAULT_STORE; -} - -bool PrefValueStore::PrefValueUserModifiable(const char* name) const { - PrefStoreType effective_store = ControllingPrefStoreForPref(name); - return effective_store >= USER_STORE || - effective_store == INVALID_STORE; -} - -bool PrefValueStore::PrefValueExtensionModifiable(const char* name) const { - PrefStoreType effective_store = ControllingPrefStoreForPref(name); - return effective_store >= EXTENSION_STORE || - effective_store == INVALID_STORE; -} - -void PrefValueStore::UpdateCommandLinePrefStore(PrefStore* command_line_prefs) { - InitPrefStore(COMMAND_LINE_STORE, command_line_prefs); -} - -bool PrefValueStore::PrefValueInStore( - const char* name, - PrefValueStore::PrefStoreType store) const { - // Declare a temp Value* and call GetValueFromStore, - // ignoring the output value. - const base::Value* tmp_value = NULL; - return GetValueFromStore(name, store, &tmp_value); -} - -bool PrefValueStore::PrefValueInStoreRange( - const char* name, - PrefValueStore::PrefStoreType first_checked_store, - PrefValueStore::PrefStoreType last_checked_store) const { - if (first_checked_store > last_checked_store) { - NOTREACHED(); - return false; - } - - for (size_t i = first_checked_store; - i <= static_cast(last_checked_store); ++i) { - if (PrefValueInStore(name, static_cast(i))) - return true; - } - return false; -} - -PrefValueStore::PrefStoreType PrefValueStore::ControllingPrefStoreForPref( - const char* name) const { - for (size_t i = 0; i <= PREF_STORE_TYPE_MAX; ++i) { - if (PrefValueInStore(name, static_cast(i))) - return static_cast(i); - } - return INVALID_STORE; -} - -bool PrefValueStore::GetValueFromStore(const char* name, - PrefValueStore::PrefStoreType store_type, - const base::Value** out_value) const { - // Only return true if we find a value and it is the correct type, so stale - // values with the incorrect type will be ignored. - const PrefStore* store = GetPrefStore(static_cast(store_type)); - if (store && store->GetValue(name, out_value)) - return true; - - // No valid value found for the given preference name: set the return value - // to false. - *out_value = NULL; - return false; -} - -bool PrefValueStore::GetValueFromStoreWithType( - const char* name, - base::Value::Type type, - PrefStoreType store, - const base::Value** out_value) const { - if (GetValueFromStore(name, store, out_value)) { - if ((*out_value)->IsType(type)) - return true; - - LOG(WARNING) << "Expected type for " << name << " is " << type - << " but got " << (*out_value)->GetType() - << " in store " << store; - } - - *out_value = NULL; - return false; -} - -void PrefValueStore::OnPrefValueChanged(PrefValueStore::PrefStoreType type, - const std::string& key) { - NotifyPrefChanged(key.c_str(), type); -} - -void PrefValueStore::OnInitializationCompleted( - PrefValueStore::PrefStoreType type, bool succeeded) { - if (initialization_failed_) - return; - if (!succeeded) { - initialization_failed_ = true; - pref_notifier_->OnInitializationCompleted(false); - return; - } - CheckInitializationCompleted(); -} - -void PrefValueStore::InitPrefStore(PrefValueStore::PrefStoreType type, - PrefStore* pref_store) { - pref_stores_[type].Initialize(this, pref_store, type); -} - -void PrefValueStore::CheckInitializationCompleted() { - if (initialization_failed_) - return; - for (size_t i = 0; i <= PREF_STORE_TYPE_MAX; ++i) { - scoped_refptr store = - GetPrefStore(static_cast(i)); - if (store.get() && !store->IsInitializationComplete()) - return; - } - pref_notifier_->OnInitializationCompleted(true); -} diff --git a/base/prefs/pref_value_store.h b/base/prefs/pref_value_store.h deleted file mode 100644 index 4036e40ac8..0000000000 --- a/base/prefs/pref_value_store.h +++ /dev/null @@ -1,260 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef BASE_PREFS_PREF_VALUE_STORE_H_ -#define BASE_PREFS_PREF_VALUE_STORE_H_ - -#include -#include -#include - -#include "base/basictypes.h" -#include "base/callback.h" -#include "base/gtest_prod_util.h" -#include "base/memory/ref_counted.h" -#include "base/prefs/base_prefs_export.h" -#include "base/prefs/pref_store.h" -#include "base/values.h" - -class PrefNotifier; -class PrefStore; - -// The PrefValueStore manages various sources of values for Preferences -// (e.g., configuration policies, extensions, and user settings). It returns -// the value of a Preference from the source with the highest priority, and -// allows setting user-defined values for preferences that are not managed. -// -// Unless otherwise explicitly noted, all of the methods of this class must -// be called on the UI thread. -class BASE_PREFS_EXPORT PrefValueStore { - public: - typedef base::Callback PrefChangedCallback; - - // In decreasing order of precedence: - // |managed_prefs| contains all preferences from mandatory policies. - // |extension_prefs| contains preference values set by extensions. - // |command_line_prefs| contains preference values set by command-line - // switches. - // |user_prefs| contains all user-set preference values. - // |recommended_prefs| contains all preferences from recommended policies. - // |default_prefs| contains application-default preference values. It must - // be non-null if any preferences are to be registered. - // - // |pref_notifier| facilitates broadcasting preference change notifications - // to the world. - PrefValueStore(PrefStore* managed_prefs, - PrefStore* extension_prefs, - PrefStore* command_line_prefs, - PrefStore* user_prefs, - PrefStore* recommended_prefs, - PrefStore* default_prefs, - PrefNotifier* pref_notifier); - virtual ~PrefValueStore(); - - // Creates a clone of this PrefValueStore with PrefStores overwritten - // by the parameters passed, if unequal NULL. - PrefValueStore* CloneAndSpecialize(PrefStore* managed_prefs, - PrefStore* extension_prefs, - PrefStore* command_line_prefs, - PrefStore* user_prefs, - PrefStore* recommended_prefs, - PrefStore* default_prefs, - PrefNotifier* pref_notifier); - - // A PrefValueStore can have exactly one callback that is directly - // notified of preferences changing in the store. This does not - // filter through the PrefNotifier mechanism, which may not forward - // certain changes (e.g. unregistered prefs). - void set_callback(const PrefChangedCallback& callback); - - // Gets the value for the given preference name that has the specified value - // type. Values stored in a PrefStore that have the matching |name| but - // a non-matching |type| are silently skipped. Returns true if a valid value - // was found in any of the available PrefStores. Most callers should use - // Preference::GetValue() instead of calling this method directly. - bool GetValue(const std::string& name, - base::Value::Type type, - const base::Value** out_value) const; - - // Gets the recommended value for the given preference name that has the - // specified value type. A value stored in the recommended PrefStore that has - // the matching |name| but a non-matching |type| is silently ignored. Returns - // true if a valid value was found. Most callers should use - // Preference::GetRecommendedValue() instead of calling this method directly. - bool GetRecommendedValue(const std::string& name, - base::Value::Type type, - const base::Value** out_value) const; - - // These methods return true if a preference with the given name is in the - // indicated pref store, even if that value is currently being overridden by - // a higher-priority source. - bool PrefValueInManagedStore(const char* name) const; - bool PrefValueInExtensionStore(const char* name) const; - bool PrefValueInUserStore(const char* name) const; - - // These methods return true if a preference with the given name is actually - // being controlled by the indicated pref store and not being overridden by - // a higher-priority source. - bool PrefValueFromExtensionStore(const char* name) const; - bool PrefValueFromUserStore(const char* name) const; - bool PrefValueFromRecommendedStore(const char* name) const; - bool PrefValueFromDefaultStore(const char* name) const; - - // Check whether a Preference value is modifiable by the user, i.e. whether - // there is no higher-priority source controlling it. - bool PrefValueUserModifiable(const char* name) const; - - // Check whether a Preference value is modifiable by an extension, i.e. - // whether there is no higher-priority source controlling it. - bool PrefValueExtensionModifiable(const char* name) const; - - // Update the command line PrefStore with |command_line_prefs|. - void UpdateCommandLinePrefStore(PrefStore* command_line_prefs); - - private: - // PrefStores must be listed here in order from highest to lowest priority. - // MANAGED contains all managed preference values that are provided by - // mandatory policies (e.g. Windows Group Policy or cloud policy). - // EXTENSION contains preference values set by extensions. - // COMMAND_LINE contains preference values set by command-line switches. - // USER contains all user-set preference values. - // RECOMMENDED contains all preferences that are provided by recommended - // policies. - // DEFAULT contains all application default preference values. - enum PrefStoreType { - // INVALID_STORE is not associated with an actual PrefStore but used as - // an invalid marker, e.g. as a return value. - INVALID_STORE = -1, - MANAGED_STORE = 0, - EXTENSION_STORE, - COMMAND_LINE_STORE, - USER_STORE, - RECOMMENDED_STORE, - DEFAULT_STORE, - PREF_STORE_TYPE_MAX = DEFAULT_STORE - }; - - // Keeps a PrefStore reference on behalf of the PrefValueStore and monitors - // the PrefStore for changes, forwarding notifications to PrefValueStore. This - // indirection is here for the sake of disambiguating notifications from the - // individual PrefStores. - class PrefStoreKeeper : public PrefStore::Observer { - public: - PrefStoreKeeper(); - virtual ~PrefStoreKeeper(); - - // Takes ownership of |pref_store|. - void Initialize(PrefValueStore* store, - PrefStore* pref_store, - PrefStoreType type); - - PrefStore* store() { return pref_store_.get(); } - const PrefStore* store() const { return pref_store_.get(); } - - private: - // PrefStore::Observer implementation. - virtual void OnPrefValueChanged(const std::string& key) OVERRIDE; - virtual void OnInitializationCompleted(bool succeeded) OVERRIDE; - - // PrefValueStore this keeper is part of. - PrefValueStore* pref_value_store_; - - // The PrefStore managed by this keeper. - scoped_refptr pref_store_; - - // Type of the pref store. - PrefStoreType type_; - - DISALLOW_COPY_AND_ASSIGN(PrefStoreKeeper); - }; - - typedef std::map PrefTypeMap; - - friend class PrefValueStorePolicyRefreshTest; - FRIEND_TEST_ALL_PREFIXES(PrefValueStorePolicyRefreshTest, TestPolicyRefresh); - FRIEND_TEST_ALL_PREFIXES(PrefValueStorePolicyRefreshTest, - TestRefreshPolicyPrefsCompletion); - FRIEND_TEST_ALL_PREFIXES(PrefValueStorePolicyRefreshTest, - TestConcurrentPolicyRefresh); - - // Returns true if the preference with the given name has a value in the - // given PrefStoreType, of the same value type as the preference was - // registered with. - bool PrefValueInStore(const char* name, PrefStoreType store) const; - - // Returns true if a preference has an explicit value in any of the - // stores in the range specified by |first_checked_store| and - // |last_checked_store|, even if that value is currently being - // overridden by a higher-priority store. - bool PrefValueInStoreRange(const char* name, - PrefStoreType first_checked_store, - PrefStoreType last_checked_store) const; - - // Returns the pref store type identifying the source that controls the - // Preference identified by |name|. If none of the sources has a value, - // INVALID_STORE is returned. In practice, the default PrefStore - // should always have a value for any registered preferencem, so INVALID_STORE - // indicates an error. - PrefStoreType ControllingPrefStoreForPref(const char* name) const; - - // Get a value from the specified |store|. - bool GetValueFromStore(const char* name, - PrefStoreType store, - const base::Value** out_value) const; - - // Get a value from the specified |store| if its |type| matches. - bool GetValueFromStoreWithType(const char* name, - base::Value::Type type, - PrefStoreType store, - const base::Value** out_value) const; - - // Called upon changes in individual pref stores in order to determine whether - // the user-visible pref value has changed. Triggers the change notification - // if the effective value of the preference has changed, or if the store - // controlling the pref has changed. - void NotifyPrefChanged(const char* path, PrefStoreType new_store); - - // Called from the PrefStoreKeeper implementation when a pref value for |key| - // changed in the pref store for |type|. - void OnPrefValueChanged(PrefStoreType type, const std::string& key); - - // Handle the event that the store for |type| has completed initialization. - void OnInitializationCompleted(PrefStoreType type, bool succeeded); - - // Initializes a pref store keeper. Sets up a PrefStoreKeeper that will take - // ownership of the passed |pref_store|. - void InitPrefStore(PrefStoreType type, PrefStore* pref_store); - - // Checks whether initialization is completed and tells the notifier if that - // is the case. - void CheckInitializationCompleted(); - - // Get the PrefStore pointer for the given type. May return NULL if there is - // no PrefStore for that type. - PrefStore* GetPrefStore(PrefStoreType type) { - return pref_stores_[type].store(); - } - const PrefStore* GetPrefStore(PrefStoreType type) const { - return pref_stores_[type].store(); - } - - // Keeps the PrefStore references in order of precedence. - PrefStoreKeeper pref_stores_[PREF_STORE_TYPE_MAX + 1]; - - PrefChangedCallback pref_changed_callback_; - - // Used for generating notifications. This is a weak reference, - // since the notifier is owned by the corresponding PrefService. - PrefNotifier* pref_notifier_; - - // A mapping of preference names to their registered types. - PrefTypeMap pref_types_; - - // True if not all of the PrefStores were initialized successfully. - bool initialization_failed_; - - DISALLOW_COPY_AND_ASSIGN(PrefValueStore); -}; - -#endif // BASE_PREFS_PREF_VALUE_STORE_H_ diff --git a/base/prefs/pref_value_store_unittest.cc b/base/prefs/pref_value_store_unittest.cc deleted file mode 100644 index b38c4acef1..0000000000 --- a/base/prefs/pref_value_store_unittest.cc +++ /dev/null @@ -1,592 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include - -#include "base/bind.h" -#include "base/memory/ref_counted.h" -#include "base/memory/scoped_ptr.h" -#include "base/prefs/pref_notifier.h" -#include "base/prefs/pref_value_store.h" -#include "base/prefs/testing_pref_store.h" -#include "base/values.h" -#include "testing/gmock/include/gmock/gmock.h" -#include "testing/gtest/include/gtest/gtest.h" - -using testing::Mock; -using testing::_; - -namespace { - -// Allows to capture pref notifications through gmock. -class MockPrefNotifier : public PrefNotifier { - public: - MOCK_METHOD1(OnPreferenceChanged, void(const std::string&)); - MOCK_METHOD1(OnInitializationCompleted, void(bool)); -}; - -// Allows to capture sync model associator interaction. -class MockPrefModelAssociator { - public: - MOCK_METHOD1(ProcessPrefChange, void(const std::string&)); -}; - -} // namespace - -// Names of the preferences used in this test. -namespace prefs { -const char kManagedPref[] = "this.pref.managed"; -const char kCommandLinePref[] = "this.pref.command_line"; -const char kExtensionPref[] = "this.pref.extension"; -const char kUserPref[] = "this.pref.user"; -const char kRecommendedPref[] = "this.pref.recommended"; -const char kDefaultPref[] = "this.pref.default"; -const char kMissingPref[] = "this.pref.does_not_exist"; -} - -// Potentially expected values of all preferences used in this test program. -namespace managed_pref { -const char kManagedValue[] = "managed:managed"; -} - -namespace extension_pref { -const char kManagedValue[] = "extension:managed"; -const char kExtensionValue[] = "extension:extension"; -} - -namespace command_line_pref { -const char kManagedValue[] = "command_line:managed"; -const char kExtensionValue[] = "command_line:extension"; -const char kCommandLineValue[] = "command_line:command_line"; -} - -namespace user_pref { -const char kManagedValue[] = "user:managed"; -const char kExtensionValue[] = "user:extension"; -const char kCommandLineValue[] = "user:command_line"; -const char kUserValue[] = "user:user"; -} - -namespace recommended_pref { -const char kManagedValue[] = "recommended:managed"; -const char kExtensionValue[] = "recommended:extension"; -const char kCommandLineValue[] = "recommended:command_line"; -const char kUserValue[] = "recommended:user"; -const char kRecommendedValue[] = "recommended:recommended"; -} - -namespace default_pref { -const char kManagedValue[] = "default:managed"; -const char kExtensionValue[] = "default:extension"; -const char kCommandLineValue[] = "default:command_line"; -const char kUserValue[] = "default:user"; -const char kRecommendedValue[] = "default:recommended"; -const char kDefaultValue[] = "default:default"; -} - -class PrefValueStoreTest : public testing::Test { - protected: - virtual void SetUp() { - // Create TestingPrefStores. - CreateManagedPrefs(); - CreateExtensionPrefs(); - CreateCommandLinePrefs(); - CreateUserPrefs(); - CreateRecommendedPrefs(); - CreateDefaultPrefs(); - sync_associator_.reset(new MockPrefModelAssociator()); - - // Create a fresh PrefValueStore. - pref_value_store_.reset(new PrefValueStore(managed_pref_store_.get(), - extension_pref_store_.get(), - command_line_pref_store_.get(), - user_pref_store_.get(), - recommended_pref_store_.get(), - default_pref_store_.get(), - &pref_notifier_)); - - pref_value_store_->set_callback( - base::Bind(&MockPrefModelAssociator::ProcessPrefChange, - base::Unretained(sync_associator_.get()))); - } - - void CreateManagedPrefs() { - managed_pref_store_ = new TestingPrefStore; - managed_pref_store_->SetString( - prefs::kManagedPref, - managed_pref::kManagedValue); - } - - void CreateExtensionPrefs() { - extension_pref_store_ = new TestingPrefStore; - extension_pref_store_->SetString( - prefs::kManagedPref, - extension_pref::kManagedValue); - extension_pref_store_->SetString( - prefs::kExtensionPref, - extension_pref::kExtensionValue); - } - - void CreateCommandLinePrefs() { - command_line_pref_store_ = new TestingPrefStore; - command_line_pref_store_->SetString( - prefs::kManagedPref, - command_line_pref::kManagedValue); - command_line_pref_store_->SetString( - prefs::kExtensionPref, - command_line_pref::kExtensionValue); - command_line_pref_store_->SetString( - prefs::kCommandLinePref, - command_line_pref::kCommandLineValue); - } - - void CreateUserPrefs() { - user_pref_store_ = new TestingPrefStore; - user_pref_store_->SetString( - prefs::kManagedPref, - user_pref::kManagedValue); - user_pref_store_->SetString( - prefs::kCommandLinePref, - user_pref::kCommandLineValue); - user_pref_store_->SetString( - prefs::kExtensionPref, - user_pref::kExtensionValue); - user_pref_store_->SetString( - prefs::kUserPref, - user_pref::kUserValue); - } - - void CreateRecommendedPrefs() { - recommended_pref_store_ = new TestingPrefStore; - recommended_pref_store_->SetString( - prefs::kManagedPref, - recommended_pref::kManagedValue); - recommended_pref_store_->SetString( - prefs::kCommandLinePref, - recommended_pref::kCommandLineValue); - recommended_pref_store_->SetString( - prefs::kExtensionPref, - recommended_pref::kExtensionValue); - recommended_pref_store_->SetString( - prefs::kUserPref, - recommended_pref::kUserValue); - recommended_pref_store_->SetString( - prefs::kRecommendedPref, - recommended_pref::kRecommendedValue); - } - - void CreateDefaultPrefs() { - default_pref_store_ = new TestingPrefStore; - default_pref_store_->SetString( - prefs::kManagedPref, - default_pref::kManagedValue); - default_pref_store_->SetString( - prefs::kCommandLinePref, - default_pref::kCommandLineValue); - default_pref_store_->SetString( - prefs::kExtensionPref, - default_pref::kExtensionValue); - default_pref_store_->SetString( - prefs::kUserPref, - default_pref::kUserValue); - default_pref_store_->SetString( - prefs::kRecommendedPref, - default_pref::kRecommendedValue); - default_pref_store_->SetString( - prefs::kDefaultPref, - default_pref::kDefaultValue); - } - - void ExpectValueChangeNotifications(const char* name) { - EXPECT_CALL(pref_notifier_, OnPreferenceChanged(name)); - EXPECT_CALL(*sync_associator_, ProcessPrefChange(name)); - } - - void CheckAndClearValueChangeNotifications() { - Mock::VerifyAndClearExpectations(&pref_notifier_); - Mock::VerifyAndClearExpectations(sync_associator_.get()); - } - - MockPrefNotifier pref_notifier_; - scoped_ptr sync_associator_; - scoped_ptr pref_value_store_; - - scoped_refptr managed_pref_store_; - scoped_refptr extension_pref_store_; - scoped_refptr command_line_pref_store_; - scoped_refptr user_pref_store_; - scoped_refptr recommended_pref_store_; - scoped_refptr default_pref_store_; -}; - -TEST_F(PrefValueStoreTest, GetValue) { - const base::Value* value; - - // The following tests read a value from the PrefService. The preferences are - // set in a way such that all lower-priority stores have a value and we can - // test whether overrides work correctly. - - // Test getting a managed value. - value = NULL; - ASSERT_TRUE(pref_value_store_->GetValue(prefs::kManagedPref, - base::Value::TYPE_STRING, &value)); - std::string actual_str_value; - EXPECT_TRUE(value->GetAsString(&actual_str_value)); - EXPECT_EQ(managed_pref::kManagedValue, actual_str_value); - - // Test getting an extension value. - value = NULL; - ASSERT_TRUE(pref_value_store_->GetValue(prefs::kExtensionPref, - base::Value::TYPE_STRING, &value)); - EXPECT_TRUE(value->GetAsString(&actual_str_value)); - EXPECT_EQ(extension_pref::kExtensionValue, actual_str_value); - - // Test getting a command-line value. - value = NULL; - ASSERT_TRUE(pref_value_store_->GetValue(prefs::kCommandLinePref, - base::Value::TYPE_STRING, &value)); - EXPECT_TRUE(value->GetAsString(&actual_str_value)); - EXPECT_EQ(command_line_pref::kCommandLineValue, actual_str_value); - - // Test getting a user-set value. - value = NULL; - ASSERT_TRUE(pref_value_store_->GetValue(prefs::kUserPref, - base::Value::TYPE_STRING, &value)); - EXPECT_TRUE(value->GetAsString(&actual_str_value)); - EXPECT_EQ(user_pref::kUserValue, actual_str_value); - - // Test getting a user set value overwriting a recommended value. - value = NULL; - ASSERT_TRUE(pref_value_store_->GetValue(prefs::kRecommendedPref, - base::Value::TYPE_STRING, &value)); - EXPECT_TRUE(value->GetAsString(&actual_str_value)); - EXPECT_EQ(recommended_pref::kRecommendedValue, - actual_str_value); - - // Test getting a default value. - value = NULL; - ASSERT_TRUE(pref_value_store_->GetValue(prefs::kDefaultPref, - base::Value::TYPE_STRING, &value)); - EXPECT_TRUE(value->GetAsString(&actual_str_value)); - EXPECT_EQ(default_pref::kDefaultValue, actual_str_value); - - // Test getting a preference value that the |PrefValueStore| - // does not contain. - base::FundamentalValue tmp_dummy_value(true); - value = &tmp_dummy_value; - ASSERT_FALSE(pref_value_store_->GetValue(prefs::kMissingPref, - base::Value::TYPE_STRING, &value)); - ASSERT_FALSE(value); -} - -TEST_F(PrefValueStoreTest, GetRecommendedValue) { - const base::Value* value; - - // The following tests read a value from the PrefService. The preferences are - // set in a way such that all lower-priority stores have a value and we can - // test whether overrides do not clutter the recommended value. - - // Test getting recommended value when a managed value is present. - value = NULL; - ASSERT_TRUE(pref_value_store_->GetRecommendedValue( - prefs::kManagedPref, - base::Value::TYPE_STRING, &value)); - std::string actual_str_value; - EXPECT_TRUE(value->GetAsString(&actual_str_value)); - EXPECT_EQ(recommended_pref::kManagedValue, actual_str_value); - - // Test getting recommended value when an extension value is present. - value = NULL; - ASSERT_TRUE(pref_value_store_->GetRecommendedValue( - prefs::kExtensionPref, - base::Value::TYPE_STRING, &value)); - EXPECT_TRUE(value->GetAsString(&actual_str_value)); - EXPECT_EQ(recommended_pref::kExtensionValue, actual_str_value); - - // Test getting recommended value when a command-line value is present. - value = NULL; - ASSERT_TRUE(pref_value_store_->GetRecommendedValue( - prefs::kCommandLinePref, - base::Value::TYPE_STRING, &value)); - EXPECT_TRUE(value->GetAsString(&actual_str_value)); - EXPECT_EQ(recommended_pref::kCommandLineValue, actual_str_value); - - // Test getting recommended value when a user-set value is present. - value = NULL; - ASSERT_TRUE(pref_value_store_->GetRecommendedValue( - prefs::kUserPref, - base::Value::TYPE_STRING, &value)); - EXPECT_TRUE(value->GetAsString(&actual_str_value)); - EXPECT_EQ(recommended_pref::kUserValue, actual_str_value); - - // Test getting recommended value when no higher-priority value is present. - value = NULL; - ASSERT_TRUE(pref_value_store_->GetRecommendedValue( - prefs::kRecommendedPref, - base::Value::TYPE_STRING, &value)); - EXPECT_TRUE(value->GetAsString(&actual_str_value)); - EXPECT_EQ(recommended_pref::kRecommendedValue, - actual_str_value); - - // Test getting recommended value when no recommended value is present. - base::FundamentalValue tmp_dummy_value(true); - value = &tmp_dummy_value; - ASSERT_FALSE(pref_value_store_->GetRecommendedValue( - prefs::kDefaultPref, - base::Value::TYPE_STRING, &value)); - ASSERT_FALSE(value); - - // Test getting a preference value that the |PrefValueStore| - // does not contain. - value = &tmp_dummy_value; - ASSERT_FALSE(pref_value_store_->GetRecommendedValue( - prefs::kMissingPref, - base::Value::TYPE_STRING, &value)); - ASSERT_FALSE(value); -} - -TEST_F(PrefValueStoreTest, PrefChanges) { - // Check pref controlled by highest-priority store. - ExpectValueChangeNotifications(prefs::kManagedPref); - managed_pref_store_->NotifyPrefValueChanged(prefs::kManagedPref); - CheckAndClearValueChangeNotifications(); - - ExpectValueChangeNotifications(prefs::kManagedPref); - extension_pref_store_->NotifyPrefValueChanged(prefs::kManagedPref); - CheckAndClearValueChangeNotifications(); - - ExpectValueChangeNotifications(prefs::kManagedPref); - command_line_pref_store_->NotifyPrefValueChanged(prefs::kManagedPref); - CheckAndClearValueChangeNotifications(); - - ExpectValueChangeNotifications(prefs::kManagedPref); - user_pref_store_->NotifyPrefValueChanged(prefs::kManagedPref); - CheckAndClearValueChangeNotifications(); - - ExpectValueChangeNotifications(prefs::kManagedPref); - recommended_pref_store_->NotifyPrefValueChanged(prefs::kManagedPref); - CheckAndClearValueChangeNotifications(); - - ExpectValueChangeNotifications(prefs::kManagedPref); - default_pref_store_->NotifyPrefValueChanged(prefs::kManagedPref); - CheckAndClearValueChangeNotifications(); - - // Check pref controlled by user store. - ExpectValueChangeNotifications(prefs::kUserPref); - managed_pref_store_->NotifyPrefValueChanged(prefs::kUserPref); - CheckAndClearValueChangeNotifications(); - - ExpectValueChangeNotifications(prefs::kUserPref); - extension_pref_store_->NotifyPrefValueChanged(prefs::kUserPref); - CheckAndClearValueChangeNotifications(); - - ExpectValueChangeNotifications(prefs::kUserPref); - command_line_pref_store_->NotifyPrefValueChanged(prefs::kUserPref); - CheckAndClearValueChangeNotifications(); - - ExpectValueChangeNotifications(prefs::kUserPref); - user_pref_store_->NotifyPrefValueChanged(prefs::kUserPref); - CheckAndClearValueChangeNotifications(); - - ExpectValueChangeNotifications(prefs::kUserPref); - recommended_pref_store_->NotifyPrefValueChanged(prefs::kUserPref); - CheckAndClearValueChangeNotifications(); - - ExpectValueChangeNotifications(prefs::kUserPref); - default_pref_store_->NotifyPrefValueChanged(prefs::kUserPref); - CheckAndClearValueChangeNotifications(); - - // Check pref controlled by default-pref store. - ExpectValueChangeNotifications(prefs::kDefaultPref); - managed_pref_store_->NotifyPrefValueChanged(prefs::kDefaultPref); - CheckAndClearValueChangeNotifications(); - - ExpectValueChangeNotifications(prefs::kDefaultPref); - extension_pref_store_->NotifyPrefValueChanged(prefs::kDefaultPref); - CheckAndClearValueChangeNotifications(); - - ExpectValueChangeNotifications(prefs::kDefaultPref); - command_line_pref_store_->NotifyPrefValueChanged(prefs::kDefaultPref); - CheckAndClearValueChangeNotifications(); - - ExpectValueChangeNotifications(prefs::kDefaultPref); - user_pref_store_->NotifyPrefValueChanged(prefs::kDefaultPref); - CheckAndClearValueChangeNotifications(); - - ExpectValueChangeNotifications(prefs::kDefaultPref); - recommended_pref_store_->NotifyPrefValueChanged(prefs::kDefaultPref); - CheckAndClearValueChangeNotifications(); - - ExpectValueChangeNotifications(prefs::kDefaultPref); - default_pref_store_->NotifyPrefValueChanged(prefs::kDefaultPref); - CheckAndClearValueChangeNotifications(); -} - -TEST_F(PrefValueStoreTest, OnInitializationCompleted) { - EXPECT_CALL(pref_notifier_, OnInitializationCompleted(true)).Times(0); - managed_pref_store_->SetInitializationCompleted(); - extension_pref_store_->SetInitializationCompleted(); - command_line_pref_store_->SetInitializationCompleted(); - recommended_pref_store_->SetInitializationCompleted(); - default_pref_store_->SetInitializationCompleted(); - Mock::VerifyAndClearExpectations(&pref_notifier_); - - // The notification should only be triggered after the last store is done. - EXPECT_CALL(pref_notifier_, OnInitializationCompleted(true)).Times(1); - user_pref_store_->SetInitializationCompleted(); - Mock::VerifyAndClearExpectations(&pref_notifier_); -} - -TEST_F(PrefValueStoreTest, PrefValueInManagedStore) { - EXPECT_TRUE(pref_value_store_->PrefValueInManagedStore( - prefs::kManagedPref)); - EXPECT_FALSE(pref_value_store_->PrefValueInManagedStore( - prefs::kExtensionPref)); - EXPECT_FALSE(pref_value_store_->PrefValueInManagedStore( - prefs::kCommandLinePref)); - EXPECT_FALSE(pref_value_store_->PrefValueInManagedStore( - prefs::kUserPref)); - EXPECT_FALSE(pref_value_store_->PrefValueInManagedStore( - prefs::kRecommendedPref)); - EXPECT_FALSE(pref_value_store_->PrefValueInManagedStore( - prefs::kDefaultPref)); - EXPECT_FALSE(pref_value_store_->PrefValueInManagedStore( - prefs::kMissingPref)); -} - -TEST_F(PrefValueStoreTest, PrefValueInExtensionStore) { - EXPECT_TRUE(pref_value_store_->PrefValueInExtensionStore( - prefs::kManagedPref)); - EXPECT_TRUE(pref_value_store_->PrefValueInExtensionStore( - prefs::kExtensionPref)); - EXPECT_FALSE(pref_value_store_->PrefValueInExtensionStore( - prefs::kCommandLinePref)); - EXPECT_FALSE(pref_value_store_->PrefValueInExtensionStore( - prefs::kUserPref)); - EXPECT_FALSE(pref_value_store_->PrefValueInExtensionStore( - prefs::kRecommendedPref)); - EXPECT_FALSE(pref_value_store_->PrefValueInExtensionStore( - prefs::kDefaultPref)); - EXPECT_FALSE(pref_value_store_->PrefValueInExtensionStore( - prefs::kMissingPref)); -} - -TEST_F(PrefValueStoreTest, PrefValueInUserStore) { - EXPECT_TRUE(pref_value_store_->PrefValueInUserStore( - prefs::kManagedPref)); - EXPECT_TRUE(pref_value_store_->PrefValueInUserStore( - prefs::kExtensionPref)); - EXPECT_TRUE(pref_value_store_->PrefValueInUserStore( - prefs::kCommandLinePref)); - EXPECT_TRUE(pref_value_store_->PrefValueInUserStore( - prefs::kUserPref)); - EXPECT_FALSE(pref_value_store_->PrefValueInUserStore( - prefs::kRecommendedPref)); - EXPECT_FALSE(pref_value_store_->PrefValueInUserStore( - prefs::kDefaultPref)); - EXPECT_FALSE(pref_value_store_->PrefValueInUserStore( - prefs::kMissingPref)); -} - -TEST_F(PrefValueStoreTest, PrefValueFromExtensionStore) { - EXPECT_FALSE(pref_value_store_->PrefValueFromExtensionStore( - prefs::kManagedPref)); - EXPECT_TRUE(pref_value_store_->PrefValueFromExtensionStore( - prefs::kExtensionPref)); - EXPECT_FALSE(pref_value_store_->PrefValueFromExtensionStore( - prefs::kCommandLinePref)); - EXPECT_FALSE(pref_value_store_->PrefValueFromExtensionStore( - prefs::kUserPref)); - EXPECT_FALSE(pref_value_store_->PrefValueFromExtensionStore( - prefs::kRecommendedPref)); - EXPECT_FALSE(pref_value_store_->PrefValueFromExtensionStore( - prefs::kDefaultPref)); - EXPECT_FALSE(pref_value_store_->PrefValueFromExtensionStore( - prefs::kMissingPref)); -} - -TEST_F(PrefValueStoreTest, PrefValueFromUserStore) { - EXPECT_FALSE(pref_value_store_->PrefValueFromUserStore( - prefs::kManagedPref)); - EXPECT_FALSE(pref_value_store_->PrefValueFromUserStore( - prefs::kExtensionPref)); - EXPECT_FALSE(pref_value_store_->PrefValueFromUserStore( - prefs::kCommandLinePref)); - EXPECT_TRUE(pref_value_store_->PrefValueFromUserStore( - prefs::kUserPref)); - EXPECT_FALSE(pref_value_store_->PrefValueFromUserStore( - prefs::kRecommendedPref)); - EXPECT_FALSE(pref_value_store_->PrefValueFromUserStore( - prefs::kDefaultPref)); - EXPECT_FALSE(pref_value_store_->PrefValueFromUserStore( - prefs::kMissingPref)); -} - -TEST_F(PrefValueStoreTest, PrefValueFromRecommendedStore) { - EXPECT_FALSE(pref_value_store_->PrefValueFromRecommendedStore( - prefs::kManagedPref)); - EXPECT_FALSE(pref_value_store_->PrefValueFromRecommendedStore( - prefs::kExtensionPref)); - EXPECT_FALSE(pref_value_store_->PrefValueFromRecommendedStore( - prefs::kCommandLinePref)); - EXPECT_FALSE(pref_value_store_->PrefValueFromRecommendedStore( - prefs::kUserPref)); - EXPECT_TRUE(pref_value_store_->PrefValueFromRecommendedStore( - prefs::kRecommendedPref)); - EXPECT_FALSE(pref_value_store_->PrefValueFromRecommendedStore( - prefs::kDefaultPref)); - EXPECT_FALSE(pref_value_store_->PrefValueFromRecommendedStore( - prefs::kMissingPref)); -} - -TEST_F(PrefValueStoreTest, PrefValueFromDefaultStore) { - EXPECT_FALSE(pref_value_store_->PrefValueFromDefaultStore( - prefs::kManagedPref)); - EXPECT_FALSE(pref_value_store_->PrefValueFromDefaultStore( - prefs::kExtensionPref)); - EXPECT_FALSE(pref_value_store_->PrefValueFromDefaultStore( - prefs::kCommandLinePref)); - EXPECT_FALSE(pref_value_store_->PrefValueFromDefaultStore( - prefs::kUserPref)); - EXPECT_FALSE(pref_value_store_->PrefValueFromDefaultStore( - prefs::kRecommendedPref)); - EXPECT_TRUE(pref_value_store_->PrefValueFromDefaultStore( - prefs::kDefaultPref)); - EXPECT_FALSE(pref_value_store_->PrefValueFromDefaultStore( - prefs::kMissingPref)); -} - -TEST_F(PrefValueStoreTest, PrefValueUserModifiable) { - EXPECT_FALSE(pref_value_store_->PrefValueUserModifiable( - prefs::kManagedPref)); - EXPECT_FALSE(pref_value_store_->PrefValueUserModifiable( - prefs::kExtensionPref)); - EXPECT_FALSE(pref_value_store_->PrefValueUserModifiable( - prefs::kCommandLinePref)); - EXPECT_TRUE(pref_value_store_->PrefValueUserModifiable( - prefs::kUserPref)); - EXPECT_TRUE(pref_value_store_->PrefValueUserModifiable( - prefs::kRecommendedPref)); - EXPECT_TRUE(pref_value_store_->PrefValueUserModifiable( - prefs::kDefaultPref)); - EXPECT_TRUE(pref_value_store_->PrefValueUserModifiable( - prefs::kMissingPref)); -} - -TEST_F(PrefValueStoreTest, PrefValueExtensionModifiable) { - EXPECT_FALSE(pref_value_store_->PrefValueExtensionModifiable( - prefs::kManagedPref)); - EXPECT_TRUE(pref_value_store_->PrefValueExtensionModifiable( - prefs::kExtensionPref)); - EXPECT_TRUE(pref_value_store_->PrefValueExtensionModifiable( - prefs::kCommandLinePref)); - EXPECT_TRUE(pref_value_store_->PrefValueExtensionModifiable( - prefs::kUserPref)); - EXPECT_TRUE(pref_value_store_->PrefValueExtensionModifiable( - prefs::kRecommendedPref)); - EXPECT_TRUE(pref_value_store_->PrefValueExtensionModifiable( - prefs::kDefaultPref)); - EXPECT_TRUE(pref_value_store_->PrefValueExtensionModifiable( - prefs::kMissingPref)); -} diff --git a/base/prefs/testing_pref_service.cc b/base/prefs/testing_pref_service.cc deleted file mode 100644 index b96268a1ce..0000000000 --- a/base/prefs/testing_pref_service.cc +++ /dev/null @@ -1,54 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "base/prefs/testing_pref_service.h" - -#include "base/bind.h" -#include "base/compiler_specific.h" -#include "base/prefs/default_pref_store.h" -#include "base/prefs/pref_notifier_impl.h" -#include "base/prefs/pref_registry_simple.h" -#include "base/prefs/pref_value_store.h" -#include "testing/gtest/include/gtest/gtest.h" - -template <> -TestingPrefServiceBase::TestingPrefServiceBase( - TestingPrefStore* managed_prefs, - TestingPrefStore* user_prefs, - TestingPrefStore* recommended_prefs, - PrefRegistry* pref_registry, - PrefNotifierImpl* pref_notifier) - : PrefService( - pref_notifier, - new PrefValueStore(managed_prefs, - NULL, - NULL, - user_prefs, - recommended_prefs, - pref_registry->defaults().get(), - pref_notifier), - user_prefs, - pref_registry, - base::Bind(&TestingPrefServiceBase::HandleReadError), - false), - managed_prefs_(managed_prefs), - user_prefs_(user_prefs), - recommended_prefs_(recommended_prefs) {} - -TestingPrefServiceSimple::TestingPrefServiceSimple() - : TestingPrefServiceBase( - new TestingPrefStore(), - new TestingPrefStore(), - new TestingPrefStore(), - new PrefRegistrySimple(), - new PrefNotifierImpl()) { -} - -TestingPrefServiceSimple::~TestingPrefServiceSimple() { -} - -PrefRegistrySimple* TestingPrefServiceSimple::registry() { - return static_cast(DeprecatedGetPrefRegistry()); -} diff --git a/base/prefs/testing_pref_service.h b/base/prefs/testing_pref_service.h deleted file mode 100644 index 1af4ba6d1e..0000000000 --- a/base/prefs/testing_pref_service.h +++ /dev/null @@ -1,198 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef BASE_PREFS_TESTING_PREF_SERVICE_H_ -#define BASE_PREFS_TESTING_PREF_SERVICE_H_ - -#include "base/memory/ref_counted.h" -#include "base/memory/scoped_ptr.h" -#include "base/prefs/pref_registry.h" -#include "base/prefs/pref_service.h" -#include "base/prefs/testing_pref_store.h" - -class PrefNotifierImpl; -class PrefRegistrySimple; -class TestingPrefStore; - -// A PrefService subclass for testing. It operates totally in memory and -// provides additional API for manipulating preferences at the different levels -// (managed, extension, user) conveniently. -// -// Use this via its specializations, e.g. TestingPrefServiceSimple. -template -class TestingPrefServiceBase : public SuperPrefService { - public: - virtual ~TestingPrefServiceBase(); - - // Read the value of a preference from the managed layer. Returns NULL if the - // preference is not defined at the managed layer. - const base::Value* GetManagedPref(const char* path) const; - - // Set a preference on the managed layer and fire observers if the preference - // changed. Assumes ownership of |value|. - void SetManagedPref(const char* path, base::Value* value); - - // Clear the preference on the managed layer and fire observers if the - // preference has been defined previously. - void RemoveManagedPref(const char* path); - - // Similar to the above, but for user preferences. - const base::Value* GetUserPref(const char* path) const; - void SetUserPref(const char* path, base::Value* value); - void RemoveUserPref(const char* path); - - // Similar to the above, but for recommended policy preferences. - const base::Value* GetRecommendedPref(const char* path) const; - void SetRecommendedPref(const char* path, base::Value* value); - void RemoveRecommendedPref(const char* path); - - // Do-nothing implementation for TestingPrefService. - static void HandleReadError(PersistentPrefStore::PrefReadError error) {} - - protected: - TestingPrefServiceBase( - TestingPrefStore* managed_prefs, - TestingPrefStore* user_prefs, - TestingPrefStore* recommended_prefs, - ConstructionPrefRegistry* pref_registry, - PrefNotifierImpl* pref_notifier); - - private: - // Reads the value of the preference indicated by |path| from |pref_store|. - // Returns NULL if the preference was not found. - const base::Value* GetPref(TestingPrefStore* pref_store, - const char* path) const; - - // Sets the value for |path| in |pref_store|. - void SetPref(TestingPrefStore* pref_store, const char* path, - base::Value* value); - - // Removes the preference identified by |path| from |pref_store|. - void RemovePref(TestingPrefStore* pref_store, const char* path); - - // Pointers to the pref stores our value store uses. - scoped_refptr managed_prefs_; - scoped_refptr user_prefs_; - scoped_refptr recommended_prefs_; - - DISALLOW_COPY_AND_ASSIGN(TestingPrefServiceBase); -}; - -// Test version of PrefService. -class TestingPrefServiceSimple - : public TestingPrefServiceBase { - public: - TestingPrefServiceSimple(); - virtual ~TestingPrefServiceSimple(); - - // This is provided as a convenience for registering preferences on - // an existing TestingPrefServiceSimple instance. On a production - // PrefService you would do all registrations before constructing - // it, passing it a PrefRegistry via its constructor (or via - // e.g. PrefServiceBuilder). - PrefRegistrySimple* registry(); - - private: - DISALLOW_COPY_AND_ASSIGN(TestingPrefServiceSimple); -}; - -template<> -TestingPrefServiceBase::TestingPrefServiceBase( - TestingPrefStore* managed_prefs, - TestingPrefStore* user_prefs, - TestingPrefStore* recommended_prefs, - PrefRegistry* pref_registry, - PrefNotifierImpl* pref_notifier); - -template -TestingPrefServiceBase< - SuperPrefService, ConstructionPrefRegistry>::~TestingPrefServiceBase() { -} - -template -const base::Value* TestingPrefServiceBase< - SuperPrefService, ConstructionPrefRegistry>::GetManagedPref( - const char* path) const { - return GetPref(managed_prefs_.get(), path); -} - -template -void TestingPrefServiceBase< - SuperPrefService, ConstructionPrefRegistry>::SetManagedPref( - const char* path, base::Value* value) { - SetPref(managed_prefs_.get(), path, value); -} - -template -void TestingPrefServiceBase< - SuperPrefService, ConstructionPrefRegistry>::RemoveManagedPref( - const char* path) { - RemovePref(managed_prefs_.get(), path); -} - -template -const base::Value* TestingPrefServiceBase< - SuperPrefService, ConstructionPrefRegistry>::GetUserPref( - const char* path) const { - return GetPref(user_prefs_.get(), path); -} - -template -void TestingPrefServiceBase< - SuperPrefService, ConstructionPrefRegistry>::SetUserPref( - const char* path, base::Value* value) { - SetPref(user_prefs_.get(), path, value); -} - -template -void TestingPrefServiceBase< - SuperPrefService, ConstructionPrefRegistry>::RemoveUserPref( - const char* path) { - RemovePref(user_prefs_.get(), path); -} - -template -const base::Value* TestingPrefServiceBase< - SuperPrefService, ConstructionPrefRegistry>::GetRecommendedPref( - const char* path) const { - return GetPref(recommended_prefs_, path); -} - -template -void TestingPrefServiceBase< - SuperPrefService, ConstructionPrefRegistry>::SetRecommendedPref( - const char* path, base::Value* value) { - SetPref(recommended_prefs_.get(), path, value); -} - -template -void TestingPrefServiceBase< - SuperPrefService, ConstructionPrefRegistry>::RemoveRecommendedPref( - const char* path) { - RemovePref(recommended_prefs_.get(), path); -} - -template -const base::Value* TestingPrefServiceBase< - SuperPrefService, ConstructionPrefRegistry>::GetPref( - TestingPrefStore* pref_store, const char* path) const { - const base::Value* res; - return pref_store->GetValue(path, &res) ? res : NULL; -} - -template -void TestingPrefServiceBase< - SuperPrefService, ConstructionPrefRegistry>::SetPref( - TestingPrefStore* pref_store, const char* path, base::Value* value) { - pref_store->SetValue(path, value); -} - -template -void TestingPrefServiceBase< - SuperPrefService, ConstructionPrefRegistry>::RemovePref( - TestingPrefStore* pref_store, const char* path) { - pref_store->RemoveValue(path); -} - -#endif // BASE_PREFS_TESTING_PREF_SERVICE_H_ diff --git a/base/prefs/testing_pref_store.cc b/base/prefs/testing_pref_store.cc deleted file mode 100644 index fcb48cee2e..0000000000 --- a/base/prefs/testing_pref_store.cc +++ /dev/null @@ -1,136 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "base/prefs/testing_pref_store.h" - -#include "base/memory/scoped_ptr.h" -#include "base/values.h" - -TestingPrefStore::TestingPrefStore() - : read_only_(true), - init_complete_(false) { -} - -bool TestingPrefStore::GetValue(const std::string& key, - const base::Value** value) const { - return prefs_.GetValue(key, value); -} - -bool TestingPrefStore::GetMutableValue(const std::string& key, - base::Value** value) { - return prefs_.GetValue(key, value); -} - -void TestingPrefStore::AddObserver(PrefStore::Observer* observer) { - observers_.AddObserver(observer); -} - -void TestingPrefStore::RemoveObserver(PrefStore::Observer* observer) { - observers_.RemoveObserver(observer); -} - -size_t TestingPrefStore::NumberOfObservers() const { - return observers_.size(); -} - -bool TestingPrefStore::IsInitializationComplete() const { - return init_complete_; -} - -void TestingPrefStore::SetValue(const std::string& key, base::Value* value) { - if (prefs_.SetValue(key, value)) - NotifyPrefValueChanged(key); -} - -void TestingPrefStore::SetValueSilently(const std::string& key, - base::Value* value) { - prefs_.SetValue(key, value); -} - -void TestingPrefStore::RemoveValue(const std::string& key) { - if (prefs_.RemoveValue(key)) - NotifyPrefValueChanged(key); -} - -void TestingPrefStore::MarkNeedsEmptyValue(const std::string& key) { -} - -bool TestingPrefStore::ReadOnly() const { - return read_only_; -} - -PersistentPrefStore::PrefReadError TestingPrefStore::GetReadError() const { - return PersistentPrefStore::PREF_READ_ERROR_NONE; -} - -PersistentPrefStore::PrefReadError TestingPrefStore::ReadPrefs() { - NotifyInitializationCompleted(); - return PersistentPrefStore::PREF_READ_ERROR_NONE; -} - -void TestingPrefStore::ReadPrefsAsync(ReadErrorDelegate* error_delegate_raw) { - scoped_ptr error_delegate(error_delegate_raw); - NotifyInitializationCompleted(); -} - -void TestingPrefStore::SetInitializationCompleted() { - init_complete_ = true; - NotifyInitializationCompleted(); -} - -void TestingPrefStore::NotifyPrefValueChanged(const std::string& key) { - FOR_EACH_OBSERVER(Observer, observers_, OnPrefValueChanged(key)); -} - -void TestingPrefStore::NotifyInitializationCompleted() { - FOR_EACH_OBSERVER(Observer, observers_, OnInitializationCompleted(true)); -} - -void TestingPrefStore::ReportValueChanged(const std::string& key) { - FOR_EACH_OBSERVER(Observer, observers_, OnPrefValueChanged(key)); -} - -void TestingPrefStore::SetString(const std::string& key, - const std::string& value) { - SetValue(key, new base::StringValue(value)); -} - -void TestingPrefStore::SetInteger(const std::string& key, int value) { - SetValue(key, new base::FundamentalValue(value)); -} - -void TestingPrefStore::SetBoolean(const std::string& key, bool value) { - SetValue(key, new base::FundamentalValue(value)); -} - -bool TestingPrefStore::GetString(const std::string& key, - std::string* value) const { - const base::Value* stored_value; - if (!prefs_.GetValue(key, &stored_value) || !stored_value) - return false; - - return stored_value->GetAsString(value); -} - -bool TestingPrefStore::GetInteger(const std::string& key, int* value) const { - const base::Value* stored_value; - if (!prefs_.GetValue(key, &stored_value) || !stored_value) - return false; - - return stored_value->GetAsInteger(value); -} - -bool TestingPrefStore::GetBoolean(const std::string& key, bool* value) const { - const base::Value* stored_value; - if (!prefs_.GetValue(key, &stored_value) || !stored_value) - return false; - - return stored_value->GetAsBoolean(value); -} - -void TestingPrefStore::set_read_only(bool read_only) { - read_only_ = read_only; -} - -TestingPrefStore::~TestingPrefStore() {} diff --git a/base/prefs/testing_pref_store.h b/base/prefs/testing_pref_store.h deleted file mode 100644 index a9f1e92253..0000000000 --- a/base/prefs/testing_pref_store.h +++ /dev/null @@ -1,84 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef BASE_PREFS_TESTING_PREF_STORE_H_ -#define BASE_PREFS_TESTING_PREF_STORE_H_ - -#include - -#include "base/basictypes.h" -#include "base/compiler_specific.h" -#include "base/observer_list.h" -#include "base/prefs/persistent_pref_store.h" -#include "base/prefs/pref_value_map.h" - -// |TestingPrefStore| is a preference store implementation that allows tests to -// explicitly manipulate the contents of the store, triggering notifications -// where appropriate. -class TestingPrefStore : public PersistentPrefStore { - public: - TestingPrefStore(); - - // Overriden from PrefStore. - virtual bool GetValue(const std::string& key, - const base::Value** result) const OVERRIDE; - virtual void AddObserver(PrefStore::Observer* observer) OVERRIDE; - virtual void RemoveObserver(PrefStore::Observer* observer) OVERRIDE; - virtual size_t NumberOfObservers() const OVERRIDE; - virtual bool IsInitializationComplete() const OVERRIDE; - - // PersistentPrefStore overrides: - virtual bool GetMutableValue(const std::string& key, - base::Value** result) OVERRIDE; - virtual void ReportValueChanged(const std::string& key) OVERRIDE; - virtual void SetValue(const std::string& key, base::Value* value) OVERRIDE; - virtual void SetValueSilently(const std::string& key, - base::Value* value) OVERRIDE; - virtual void RemoveValue(const std::string& key) OVERRIDE; - virtual void MarkNeedsEmptyValue(const std::string& key) OVERRIDE; - virtual bool ReadOnly() const OVERRIDE; - virtual PrefReadError GetReadError() const OVERRIDE; - virtual PersistentPrefStore::PrefReadError ReadPrefs() OVERRIDE; - virtual void ReadPrefsAsync(ReadErrorDelegate* error_delegate) OVERRIDE; - virtual void CommitPendingWrite() OVERRIDE {} - - // Marks the store as having completed initialization. - void SetInitializationCompleted(); - - // Used for tests to trigger notifications explicitly. - void NotifyPrefValueChanged(const std::string& key); - void NotifyInitializationCompleted(); - - // Some convenience getters/setters. - void SetString(const std::string& key, const std::string& value); - void SetInteger(const std::string& key, int value); - void SetBoolean(const std::string& key, bool value); - - bool GetString(const std::string& key, std::string* value) const; - bool GetInteger(const std::string& key, int* value) const; - bool GetBoolean(const std::string& key, bool* value) const; - - // Getter and Setter methods for setting and getting the state of the - // |TestingPrefStore|. - virtual void set_read_only(bool read_only); - - protected: - virtual ~TestingPrefStore(); - - private: - // Stores the preference values. - PrefValueMap prefs_; - - // Flag that indicates if the PrefStore is read-only - bool read_only_; - - // Whether initialization has been completed. - bool init_complete_; - - ObserverList observers_; - - DISALLOW_COPY_AND_ASSIGN(TestingPrefStore); -}; - -#endif // BASE_PREFS_TESTING_PREF_STORE_H_ diff --git a/base/prefs/value_map_pref_store.cc b/base/prefs/value_map_pref_store.cc deleted file mode 100644 index b4b5751111..0000000000 --- a/base/prefs/value_map_pref_store.cc +++ /dev/null @@ -1,45 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "base/prefs/value_map_pref_store.h" - -#include - -#include "base/stl_util.h" -#include "base/values.h" - -ValueMapPrefStore::ValueMapPrefStore() {} - -bool ValueMapPrefStore::GetValue(const std::string& key, - const base::Value** value) const { - return prefs_.GetValue(key, value); -} - -void ValueMapPrefStore::AddObserver(PrefStore::Observer* observer) { - observers_.AddObserver(observer); -} - -void ValueMapPrefStore::RemoveObserver(PrefStore::Observer* observer) { - observers_.RemoveObserver(observer); -} - -size_t ValueMapPrefStore::NumberOfObservers() const { - return observers_.size(); -} - -ValueMapPrefStore::~ValueMapPrefStore() {} - -void ValueMapPrefStore::SetValue(const std::string& key, base::Value* value) { - if (prefs_.SetValue(key, value)) - FOR_EACH_OBSERVER(Observer, observers_, OnPrefValueChanged(key)); -} - -void ValueMapPrefStore::RemoveValue(const std::string& key) { - if (prefs_.RemoveValue(key)) - FOR_EACH_OBSERVER(Observer, observers_, OnPrefValueChanged(key)); -} - -void ValueMapPrefStore::NotifyInitializationCompleted() { - FOR_EACH_OBSERVER(Observer, observers_, OnInitializationCompleted(true)); -} diff --git a/base/prefs/value_map_pref_store.h b/base/prefs/value_map_pref_store.h deleted file mode 100644 index c9c9b1c905..0000000000 --- a/base/prefs/value_map_pref_store.h +++ /dev/null @@ -1,52 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef BASE_PREFS_VALUE_MAP_PREF_STORE_H_ -#define BASE_PREFS_VALUE_MAP_PREF_STORE_H_ - -#include -#include - -#include "base/basictypes.h" -#include "base/observer_list.h" -#include "base/prefs/base_prefs_export.h" -#include "base/prefs/pref_store.h" -#include "base/prefs/pref_value_map.h" - -// A basic PrefStore implementation that uses a simple name-value map for -// storing the preference values. -class BASE_PREFS_EXPORT ValueMapPrefStore : public PrefStore { - public: - ValueMapPrefStore(); - - // PrefStore overrides: - virtual bool GetValue(const std::string& key, - const base::Value** value) const OVERRIDE; - virtual void AddObserver(PrefStore::Observer* observer) OVERRIDE; - virtual void RemoveObserver(PrefStore::Observer* observer) OVERRIDE; - virtual size_t NumberOfObservers() const OVERRIDE; - - protected: - virtual ~ValueMapPrefStore(); - - // Store a |value| for |key| in the store. Also generates an notification if - // the value changed. Assumes ownership of |value|, which must be non-NULL. - void SetValue(const std::string& key, base::Value* value); - - // Remove the value for |key| from the store. Sends a notification if there - // was a value to be removed. - void RemoveValue(const std::string& key); - - // Notify observers about the initialization completed event. - void NotifyInitializationCompleted(); - - private: - PrefValueMap prefs_; - - ObserverList observers_; - - DISALLOW_COPY_AND_ASSIGN(ValueMapPrefStore); -}; - -#endif // BASE_PREFS_VALUE_MAP_PREF_STORE_H_ diff --git a/base/process/internal_linux.cc b/base/process/internal_linux.cc deleted file mode 100644 index ee1107c179..0000000000 --- a/base/process/internal_linux.cc +++ /dev/null @@ -1,190 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "base/process/internal_linux.h" - -#include - -#include -#include -#include - -#include "base/file_util.h" -#include "base/logging.h" -#include "base/strings/string_number_conversions.h" -#include "base/strings/string_split.h" -#include "base/strings/string_util.h" -#include "base/threading/thread_restrictions.h" -#include "base/time/time.h" - -namespace base { -namespace internal { - -const char kProcDir[] = "/proc"; - -const char kStatFile[] = "stat"; - -base::FilePath GetProcPidDir(pid_t pid) { - return base::FilePath(kProcDir).Append(IntToString(pid)); -} - -pid_t ProcDirSlotToPid(const char* d_name) { - int i; - for (i = 0; i < NAME_MAX && d_name[i]; ++i) { - if (!IsAsciiDigit(d_name[i])) { - return 0; - } - } - if (i == NAME_MAX) - return 0; - - // Read the process's command line. - pid_t pid; - std::string pid_string(d_name); - if (!StringToInt(pid_string, &pid)) { - NOTREACHED(); - return 0; - } - return pid; -} - -bool ReadProcFile(const FilePath& file, std::string* buffer) { - buffer->clear(); - // Synchronously reading files in /proc is safe. - ThreadRestrictions::ScopedAllowIO allow_io; - - if (!file_util::ReadFileToString(file, buffer)) { - DLOG(WARNING) << "Failed to read " << file.MaybeAsASCII(); - return false; - } - return !buffer->empty(); -} - -bool ReadProcStats(pid_t pid, std::string* buffer) { - FilePath stat_file = internal::GetProcPidDir(pid).Append(kStatFile); - return ReadProcFile(stat_file, buffer); -} - -bool ParseProcStats(const std::string& stats_data, - std::vector* proc_stats) { - // |stats_data| may be empty if the process disappeared somehow. - // e.g. http://crbug.com/145811 - if (stats_data.empty()) - return false; - - // The stat file is formatted as: - // pid (process name) data1 data2 .... dataN - // Look for the closing paren by scanning backwards, to avoid being fooled by - // processes with ')' in the name. - size_t open_parens_idx = stats_data.find(" ("); - size_t close_parens_idx = stats_data.rfind(") "); - if (open_parens_idx == std::string::npos || - close_parens_idx == std::string::npos || - open_parens_idx > close_parens_idx) { - DLOG(WARNING) << "Failed to find matched parens in '" << stats_data << "'"; - NOTREACHED(); - return false; - } - open_parens_idx++; - - proc_stats->clear(); - // PID. - proc_stats->push_back(stats_data.substr(0, open_parens_idx)); - // Process name without parentheses. - proc_stats->push_back( - stats_data.substr(open_parens_idx + 1, - close_parens_idx - (open_parens_idx + 1))); - - // Split the rest. - std::vector other_stats; - SplitString(stats_data.substr(close_parens_idx + 2), ' ', &other_stats); - for (size_t i = 0; i < other_stats.size(); ++i) - proc_stats->push_back(other_stats[i]); - return true; -} - -typedef std::map ProcStatMap; -void ParseProcStat(const std::string& contents, ProcStatMap* output) { - typedef std::pair StringPair; - std::vector key_value_pairs; - SplitStringIntoKeyValuePairs(contents, ' ', '\n', &key_value_pairs); - for (size_t i = 0; i < key_value_pairs.size(); ++i) { - const StringPair& key_value_pair = key_value_pairs[i]; - output->insert(key_value_pair); - } -} - -int GetProcStatsFieldAsInt(const std::vector& proc_stats, - ProcStatsFields field_num) { - DCHECK_GE(field_num, VM_PPID); - CHECK_LT(static_cast(field_num), proc_stats.size()); - - int value; - return StringToInt(proc_stats[field_num], &value) ? value : 0; -} - -size_t GetProcStatsFieldAsSizeT(const std::vector& proc_stats, - ProcStatsFields field_num) { - DCHECK_GE(field_num, VM_PPID); - CHECK_LT(static_cast(field_num), proc_stats.size()); - - size_t value; - return StringToSizeT(proc_stats[field_num], &value) ? value : 0; -} - -int ReadProcStatsAndGetFieldAsInt(pid_t pid, - ProcStatsFields field_num) { - std::string stats_data; - if (!ReadProcStats(pid, &stats_data)) - return 0; - std::vector proc_stats; - if (!ParseProcStats(stats_data, &proc_stats)) - return 0; - return GetProcStatsFieldAsInt(proc_stats, field_num); -} - -size_t ReadProcStatsAndGetFieldAsSizeT(pid_t pid, - ProcStatsFields field_num) { - std::string stats_data; - if (!ReadProcStats(pid, &stats_data)) - return 0; - std::vector proc_stats; - if (!ParseProcStats(stats_data, &proc_stats)) - return 0; - return GetProcStatsFieldAsSizeT(proc_stats, field_num); -} - -Time GetBootTime() { - FilePath path("/proc/stat"); - std::string contents; - if (!ReadProcFile(path, &contents)) - return Time(); - ProcStatMap proc_stat; - ParseProcStat(contents, &proc_stat); - ProcStatMap::const_iterator btime_it = proc_stat.find("btime"); - if (btime_it == proc_stat.end()) - return Time(); - int btime; - if (!StringToInt(btime_it->second, &btime)) - return Time(); - return Time::FromTimeT(btime); -} - -TimeDelta ClockTicksToTimeDelta(int clock_ticks) { - // This queries the /proc-specific scaling factor which is - // conceptually the system hertz. To dump this value on another - // system, try - // od -t dL /proc/self/auxv - // and look for the number after 17 in the output; mine is - // 0000040 17 100 3 134512692 - // which means the answer is 100. - // It may be the case that this value is always 100. - static const int kHertz = sysconf(_SC_CLK_TCK); - - return TimeDelta::FromMicroseconds( - Time::kMicrosecondsPerSecond * clock_ticks / kHertz); -} - -} // namespace internal -} // namespace base diff --git a/base/process/internal_linux.h b/base/process/internal_linux.h deleted file mode 100644 index a10cee36e5..0000000000 --- a/base/process/internal_linux.h +++ /dev/null @@ -1,89 +0,0 @@ -// Copyright (c) 2013 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -// This file contains internal routines that are called by other files in -// base/process/. - -#ifndef BASE_PROCESS_LINUX_INTERNAL_H_ -#define BASE_PROCESS_LINUX_INTERNAL_H_ - -#include "base/files/file_path.h" - -namespace base { - -class Time; -class TimeDelta; - -namespace internal { - -// "/proc" -extern const char kProcDir[]; - -// "stat" -extern const char kStatFile[]; - -// Returns a FilePath to "/proc/pid". -base::FilePath GetProcPidDir(pid_t pid); - -// Take a /proc directory entry named |d_name|, and if it is the directory for -// a process, convert it to a pid_t. -// Returns 0 on failure. -// e.g. /proc/self/ will return 0, whereas /proc/1234 will return 1234. -pid_t ProcDirSlotToPid(const char* d_name); - -// Reads /proc//stat into |buffer|. Returns true if the file can be read -// and is non-empty. -bool ReadProcStats(pid_t pid, std::string* buffer); - -// Takes |stats_data| and populates |proc_stats| with the values split by -// spaces. Taking into account the 2nd field may, in itself, contain spaces. -// Returns true if successful. -bool ParseProcStats(const std::string& stats_data, - std::vector* proc_stats); - -// Fields from /proc//stat, 0-based. See man 5 proc. -// If the ordering ever changes, carefully review functions that use these -// values. -enum ProcStatsFields { - VM_COMM = 1, // Filename of executable, without parentheses. - VM_STATE = 2, // Letter indicating the state of the process. - VM_PPID = 3, // PID of the parent. - VM_PGRP = 4, // Process group id. - VM_UTIME = 13, // Time scheduled in user mode in clock ticks. - VM_STIME = 14, // Time scheduled in kernel mode in clock ticks. - VM_NUMTHREADS = 19, // Number of threads. - VM_STARTTIME = 21, // The time the process started in clock ticks. - VM_VSIZE = 22, // Virtual memory size in bytes. - VM_RSS = 23, // Resident Set Size in pages. -}; - -// Reads the |field_num|th field from |proc_stats|. Returns 0 on failure. -// This version does not handle the first 3 values, since the first value is -// simply |pid|, and the next two values are strings. -int GetProcStatsFieldAsInt(const std::vector& proc_stats, - ProcStatsFields field_num); - -// Same as GetProcStatsFieldAsInt(), but for size_t values. -size_t GetProcStatsFieldAsSizeT(const std::vector& proc_stats, - ProcStatsFields field_num); - -// Convenience wrapper around GetProcStatsFieldAsInt(), ParseProcStats() and -// ReadProcStats(). See GetProcStatsFieldAsInt() for details. -int ReadProcStatsAndGetFieldAsInt(pid_t pid, - ProcStatsFields field_num); - -// Same as ReadProcStatsAndGetFieldAsInt() but for size_t values. -size_t ReadProcStatsAndGetFieldAsSizeT(pid_t pid, - ProcStatsFields field_num); - -// Returns the time that the OS started. Clock ticks are relative to this. -Time GetBootTime(); - -// Converts Linux clock ticks to a wall time delta. -TimeDelta ClockTicksToTimeDelta(int clock_ticks); - -} // namespace internal -} // namespace base - -#endif // BASE_PROCESS_LINUX_INTERNAL_H_ diff --git a/base/process/kill.cc b/base/process/kill.cc deleted file mode 100644 index caca3484a1..0000000000 --- a/base/process/kill.cc +++ /dev/null @@ -1,26 +0,0 @@ -// Copyright (c) 2013 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "base/process/kill.h" - -#include "base/process/process_iterator.h" - -namespace base { - -bool KillProcesses(const FilePath::StringType& executable_name, - int exit_code, - const ProcessFilter* filter) { - bool result = true; - NamedProcessIterator iter(executable_name, filter); - while (const ProcessEntry* entry = iter.NextProcessEntry()) { -#if defined(OS_WIN) - result &= KillProcessById(entry->pid(), exit_code, true); -#else - result &= KillProcess(entry->pid(), exit_code, true); -#endif - } - return result; -} - -} // namespace base diff --git a/base/process/kill.h b/base/process/kill.h deleted file mode 100644 index f81ea9090d..0000000000 --- a/base/process/kill.h +++ /dev/null @@ -1,144 +0,0 @@ -// Copyright (c) 2013 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -// This file contains routines to kill processes and get the exit code and -// termination status. - -#ifndef BASE_PROCESS_KILL_H_ -#define BASE_PROCESS_KILL_H_ - -#include "base/files/file_path.h" -#include "base/process/process_handle.h" -#include "base/time/time.h" - -namespace base { - -class ProcessFilter; - -// Return status values from GetTerminationStatus. Don't use these as -// exit code arguments to KillProcess*(), use platform/application -// specific values instead. -enum TerminationStatus { - TERMINATION_STATUS_NORMAL_TERMINATION, // zero exit status - TERMINATION_STATUS_ABNORMAL_TERMINATION, // non-zero exit status - TERMINATION_STATUS_PROCESS_WAS_KILLED, // e.g. SIGKILL or task manager kill - TERMINATION_STATUS_PROCESS_CRASHED, // e.g. Segmentation fault - TERMINATION_STATUS_STILL_RUNNING, // child hasn't exited yet - TERMINATION_STATUS_MAX_ENUM -}; - -// Attempts to kill all the processes on the current machine that were launched -// from the given executable name, ending them with the given exit code. If -// filter is non-null, then only processes selected by the filter are killed. -// Returns true if all processes were able to be killed off, false if at least -// one couldn't be killed. -BASE_EXPORT bool KillProcesses(const FilePath::StringType& executable_name, - int exit_code, - const ProcessFilter* filter); - -// Attempts to kill the process identified by the given process -// entry structure, giving it the specified exit code. If |wait| is true, wait -// for the process to be actually terminated before returning. -// Returns true if this is successful, false otherwise. -BASE_EXPORT bool KillProcess(ProcessHandle process, int exit_code, bool wait); - -#if defined(OS_POSIX) -// Attempts to kill the process group identified by |process_group_id|. Returns -// true on success. -BASE_EXPORT bool KillProcessGroup(ProcessHandle process_group_id); -#endif // defined(OS_POSIX) - -#if defined(OS_WIN) -BASE_EXPORT bool KillProcessById(ProcessId process_id, - int exit_code, - bool wait); -#endif // defined(OS_WIN) - -// Get the termination status of the process by interpreting the -// circumstances of the child process' death. |exit_code| is set to -// the status returned by waitpid() on POSIX, and from -// GetExitCodeProcess() on Windows. |exit_code| may be NULL if the -// caller is not interested in it. Note that on Linux, this function -// will only return a useful result the first time it is called after -// the child exits (because it will reap the child and the information -// will no longer be available). -BASE_EXPORT TerminationStatus GetTerminationStatus(ProcessHandle handle, - int* exit_code); - -#if defined(OS_POSIX) -// Wait for the process to exit and get the termination status. See -// GetTerminationStatus for more information. On POSIX systems, we can't call -// WaitForExitCode and then GetTerminationStatus as the child will be reaped -// when WaitForExitCode return and this information will be lost. -BASE_EXPORT TerminationStatus WaitForTerminationStatus(ProcessHandle handle, - int* exit_code); -#endif // defined(OS_POSIX) - -// Waits for process to exit. On POSIX systems, if the process hasn't been -// signaled then puts the exit code in |exit_code|; otherwise it's considered -// a failure. On Windows |exit_code| is always filled. Returns true on success, -// and closes |handle| in any case. -BASE_EXPORT bool WaitForExitCode(ProcessHandle handle, int* exit_code); - -// Waits for process to exit. If it did exit within |timeout_milliseconds|, -// then puts the exit code in |exit_code|, and returns true. -// In POSIX systems, if the process has been signaled then |exit_code| is set -// to -1. Returns false on failure (the caller is then responsible for closing -// |handle|). -// The caller is always responsible for closing the |handle|. -BASE_EXPORT bool WaitForExitCodeWithTimeout(ProcessHandle handle, - int* exit_code, - base::TimeDelta timeout); - -// Wait for all the processes based on the named executable to exit. If filter -// is non-null, then only processes selected by the filter are waited on. -// Returns after all processes have exited or wait_milliseconds have expired. -// Returns true if all the processes exited, false otherwise. -BASE_EXPORT bool WaitForProcessesToExit( - const FilePath::StringType& executable_name, - base::TimeDelta wait, - const ProcessFilter* filter); - -// Wait for a single process to exit. Return true if it exited cleanly within -// the given time limit. On Linux |handle| must be a child process, however -// on Mac and Windows it can be any process. -BASE_EXPORT bool WaitForSingleProcess(ProcessHandle handle, - base::TimeDelta wait); - -// Waits a certain amount of time (can be 0) for all the processes with a given -// executable name to exit, then kills off any of them that are still around. -// If filter is non-null, then only processes selected by the filter are waited -// on. Killed processes are ended with the given exit code. Returns false if -// any processes needed to be killed, true if they all exited cleanly within -// the wait_milliseconds delay. -BASE_EXPORT bool CleanupProcesses(const FilePath::StringType& executable_name, - base::TimeDelta wait, - int exit_code, - const ProcessFilter* filter); - -// This method ensures that the specified process eventually terminates, and -// then it closes the given process handle. -// -// It assumes that the process has already been signalled to exit, and it -// begins by waiting a small amount of time for it to exit. If the process -// does not appear to have exited, then this function starts to become -// aggressive about ensuring that the process terminates. -// -// On Linux this method does not block the calling thread. -// On OS X this method may block for up to 2 seconds. -// -// NOTE: The process handle must have been opened with the PROCESS_TERMINATE -// and SYNCHRONIZE permissions. -// -BASE_EXPORT void EnsureProcessTerminated(ProcessHandle process_handle); - -#if defined(OS_POSIX) && !defined(OS_MACOSX) -// The nicer version of EnsureProcessTerminated() that is patient and will -// wait for |process_handle| to finish and then reap it. -BASE_EXPORT void EnsureProcessGetsReaped(ProcessHandle process_handle); -#endif - -} // namespace base - -#endif // BASE_PROCESS_KILL_H_ diff --git a/base/process/kill_mac.cc b/base/process/kill_mac.cc deleted file mode 100644 index 5ebca5d007..0000000000 --- a/base/process/kill_mac.cc +++ /dev/null @@ -1,173 +0,0 @@ -// Copyright (c) 2013 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "base/process/kill.h" - -#include -#include -#include -#include - -#include "base/file_util.h" -#include "base/logging.h" -#include "base/posix/eintr_wrapper.h" - -namespace base { - -namespace { - -const int kWaitBeforeKillSeconds = 2; - -// Reap |child| process. This call blocks until completion. -void BlockingReap(pid_t child) { - const pid_t result = HANDLE_EINTR(waitpid(child, NULL, 0)); - if (result == -1) { - DPLOG(ERROR) << "waitpid(" << child << ", NULL, 0)"; - } -} - -// Waits for |timeout| seconds for the given |child| to exit and reap it. If -// the child doesn't exit within the time specified, kills it. -// -// This function takes two approaches: first, it tries to use kqueue to -// observe when the process exits. kevent can monitor a kqueue with a -// timeout, so this method is preferred to wait for a specified period of -// time. Once the kqueue indicates the process has exited, waitpid will reap -// the exited child. If the kqueue doesn't provide an exit event notification, -// before the timeout expires, or if the kqueue fails or misbehaves, the -// process will be mercilessly killed and reaped. -// -// A child process passed to this function may be in one of several states: -// running, terminated and not yet reaped, and (apparently, and unfortunately) -// terminated and already reaped. Normally, a process will at least have been -// asked to exit before this function is called, but this is not required. -// If a process is terminating and unreaped, there may be a window between the -// time that kqueue will no longer recognize it and when it becomes an actual -// zombie that a non-blocking (WNOHANG) waitpid can reap. This condition is -// detected when kqueue indicates that the process is not running and a -// non-blocking waitpid fails to reap the process but indicates that it is -// still running. In this event, a blocking attempt to reap the process -// collects the known-dying child, preventing zombies from congregating. -// -// In the event that the kqueue misbehaves entirely, as it might under a -// EMFILE condition ("too many open files", or out of file descriptors), this -// function will forcibly kill and reap the child without delay. This -// eliminates another potential zombie vector. (If you're out of file -// descriptors, you're probably deep into something else, but that doesn't -// mean that zombies be allowed to kick you while you're down.) -// -// The fact that this function seemingly can be called to wait on a child -// that's not only already terminated but already reaped is a bit of a -// problem: a reaped child's pid can be reclaimed and may refer to a distinct -// process in that case. The fact that this function can seemingly be called -// to wait on a process that's not even a child is also a problem: kqueue will -// work in that case, but waitpid won't, and killing a non-child might not be -// the best approach. -void WaitForChildToDie(pid_t child, int timeout) { - DCHECK(child > 0); - DCHECK(timeout > 0); - - // DON'T ADD ANY EARLY RETURNS TO THIS FUNCTION without ensuring that - // |child| has been reaped. Specifically, even if a kqueue, kevent, or other - // call fails, this function should fall back to the last resort of trying - // to kill and reap the process. Not observing this rule will resurrect - // zombies. - - int result; - - int kq = HANDLE_EINTR(kqueue()); - if (kq == -1) { - DPLOG(ERROR) << "kqueue()"; - } else { - file_util::ScopedFD auto_close_kq(&kq); - - struct kevent change = {0}; - EV_SET(&change, child, EVFILT_PROC, EV_ADD, NOTE_EXIT, 0, NULL); - result = HANDLE_EINTR(kevent(kq, &change, 1, NULL, 0, NULL)); - - if (result == -1) { - if (errno != ESRCH) { - DPLOG(ERROR) << "kevent (setup " << child << ")"; - } else { - // At this point, one of the following has occurred: - // 1. The process has died but has not yet been reaped. - // 2. The process has died and has already been reaped. - // 3. The process is in the process of dying. It's no longer - // kqueueable, but it may not be waitable yet either. Mark calls - // this case the "zombie death race". - - result = HANDLE_EINTR(waitpid(child, NULL, WNOHANG)); - - if (result != 0) { - // A positive result indicates case 1. waitpid succeeded and reaped - // the child. A result of -1 indicates case 2. The child has already - // been reaped. In both of these cases, no further action is - // necessary. - return; - } - - // |result| is 0, indicating case 3. The process will be waitable in - // short order. Fall back out of the kqueue code to kill it (for good - // measure) and reap it. - } - } else { - // Keep track of the elapsed time to be able to restart kevent if it's - // interrupted. - TimeDelta remaining_delta = TimeDelta::FromSeconds(timeout); - TimeTicks deadline = TimeTicks::Now() + remaining_delta; - result = -1; - struct kevent event = {0}; - while (remaining_delta.InMilliseconds() > 0) { - const struct timespec remaining_timespec = remaining_delta.ToTimeSpec(); - result = kevent(kq, NULL, 0, &event, 1, &remaining_timespec); - if (result == -1 && errno == EINTR) { - remaining_delta = deadline - TimeTicks::Now(); - result = 0; - } else { - break; - } - } - - if (result == -1) { - DPLOG(ERROR) << "kevent (wait " << child << ")"; - } else if (result > 1) { - DLOG(ERROR) << "kevent (wait " << child << "): unexpected result " - << result; - } else if (result == 1) { - if ((event.fflags & NOTE_EXIT) && - (event.ident == static_cast(child))) { - // The process is dead or dying. This won't block for long, if at - // all. - BlockingReap(child); - return; - } else { - DLOG(ERROR) << "kevent (wait " << child - << "): unexpected event: fflags=" << event.fflags - << ", ident=" << event.ident; - } - } - } - } - - // The child is still alive, or is very freshly dead. Be sure by sending it - // a signal. This is safe even if it's freshly dead, because it will be a - // zombie (or on the way to zombiedom) and kill will return 0 even if the - // signal is not delivered to a live process. - result = kill(child, SIGKILL); - if (result == -1) { - DPLOG(ERROR) << "kill(" << child << ", SIGKILL)"; - } else { - // The child is definitely on the way out now. BlockingReap won't need to - // wait for long, if at all. - BlockingReap(child); - } -} - -} // namespace - -void EnsureProcessTerminated(ProcessHandle process) { - WaitForChildToDie(process, kWaitBeforeKillSeconds); -} - -} // namespace base diff --git a/base/process/kill_posix.cc b/base/process/kill_posix.cc deleted file mode 100644 index 5938fa5323..0000000000 --- a/base/process/kill_posix.cc +++ /dev/null @@ -1,492 +0,0 @@ -// Copyright (c) 2013 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "base/process/kill.h" - -#include -#include -#include -#include - -#include "base/file_util.h" -#include "base/logging.h" -#include "base/posix/eintr_wrapper.h" -#include "base/process/process_iterator.h" -#include "base/synchronization/waitable_event.h" -#include "base/third_party/dynamic_annotations/dynamic_annotations.h" -#include "base/threading/platform_thread.h" - -namespace base { - -namespace { - -int WaitpidWithTimeout(ProcessHandle handle, - int64 wait_milliseconds, - bool* success) { - // This POSIX version of this function only guarantees that we wait no less - // than |wait_milliseconds| for the process to exit. The child process may - // exit sometime before the timeout has ended but we may still block for up - // to 256 milliseconds after the fact. - // - // waitpid() has no direct support on POSIX for specifying a timeout, you can - // either ask it to block indefinitely or return immediately (WNOHANG). - // When a child process terminates a SIGCHLD signal is sent to the parent. - // Catching this signal would involve installing a signal handler which may - // affect other parts of the application and would be difficult to debug. - // - // Our strategy is to call waitpid() once up front to check if the process - // has already exited, otherwise to loop for wait_milliseconds, sleeping for - // at most 256 milliseconds each time using usleep() and then calling - // waitpid(). The amount of time we sleep starts out at 1 milliseconds, and - // we double it every 4 sleep cycles. - // - // usleep() is speced to exit if a signal is received for which a handler - // has been installed. This means that when a SIGCHLD is sent, it will exit - // depending on behavior external to this function. - // - // This function is used primarily for unit tests, if we want to use it in - // the application itself it would probably be best to examine other routes. - int status = -1; - pid_t ret_pid = HANDLE_EINTR(waitpid(handle, &status, WNOHANG)); - static const int64 kMaxSleepInMicroseconds = 1 << 18; // ~256 milliseconds. - int64 max_sleep_time_usecs = 1 << 10; // ~1 milliseconds. - int64 double_sleep_time = 0; - - // If the process hasn't exited yet, then sleep and try again. - TimeTicks wakeup_time = TimeTicks::Now() + - TimeDelta::FromMilliseconds(wait_milliseconds); - while (ret_pid == 0) { - TimeTicks now = TimeTicks::Now(); - if (now > wakeup_time) - break; - // Guaranteed to be non-negative! - int64 sleep_time_usecs = (wakeup_time - now).InMicroseconds(); - // Sleep for a bit while we wait for the process to finish. - if (sleep_time_usecs > max_sleep_time_usecs) - sleep_time_usecs = max_sleep_time_usecs; - - // usleep() will return 0 and set errno to EINTR on receipt of a signal - // such as SIGCHLD. - usleep(sleep_time_usecs); - ret_pid = HANDLE_EINTR(waitpid(handle, &status, WNOHANG)); - - if ((max_sleep_time_usecs < kMaxSleepInMicroseconds) && - (double_sleep_time++ % 4 == 0)) { - max_sleep_time_usecs *= 2; - } - } - - if (success) - *success = (ret_pid != -1); - - return status; -} - -TerminationStatus GetTerminationStatusImpl(ProcessHandle handle, - bool can_block, - int* exit_code) { - int status = 0; - const pid_t result = HANDLE_EINTR(waitpid(handle, &status, - can_block ? 0 : WNOHANG)); - if (result == -1) { - DPLOG(ERROR) << "waitpid(" << handle << ")"; - if (exit_code) - *exit_code = 0; - return TERMINATION_STATUS_NORMAL_TERMINATION; - } else if (result == 0) { - // the child hasn't exited yet. - if (exit_code) - *exit_code = 0; - return TERMINATION_STATUS_STILL_RUNNING; - } - - if (exit_code) - *exit_code = status; - - if (WIFSIGNALED(status)) { - switch (WTERMSIG(status)) { - case SIGABRT: - case SIGBUS: - case SIGFPE: - case SIGILL: - case SIGSEGV: - return TERMINATION_STATUS_PROCESS_CRASHED; - case SIGINT: - case SIGKILL: - case SIGTERM: - return TERMINATION_STATUS_PROCESS_WAS_KILLED; - default: - break; - } - } - - if (WIFEXITED(status) && WEXITSTATUS(status) != 0) - return TERMINATION_STATUS_ABNORMAL_TERMINATION; - - return TERMINATION_STATUS_NORMAL_TERMINATION; -} - -} // namespace - -// Attempts to kill the process identified by the given process -// entry structure. Ignores specified exit_code; posix can't force that. -// Returns true if this is successful, false otherwise. -bool KillProcess(ProcessHandle process_id, int exit_code, bool wait) { - DCHECK_GT(process_id, 1) << " tried to kill invalid process_id"; - if (process_id <= 1) - return false; - bool result = kill(process_id, SIGTERM) == 0; - if (result && wait) { - int tries = 60; - - if (RunningOnValgrind()) { - // Wait for some extra time when running under Valgrind since the child - // processes may take some time doing leak checking. - tries *= 2; - } - - unsigned sleep_ms = 4; - - // The process may not end immediately due to pending I/O - bool exited = false; - while (tries-- > 0) { - pid_t pid = HANDLE_EINTR(waitpid(process_id, NULL, WNOHANG)); - if (pid == process_id) { - exited = true; - break; - } - if (pid == -1) { - if (errno == ECHILD) { - // The wait may fail with ECHILD if another process also waited for - // the same pid, causing the process state to get cleaned up. - exited = true; - break; - } - DPLOG(ERROR) << "Error waiting for process " << process_id; - } - - usleep(sleep_ms * 1000); - const unsigned kMaxSleepMs = 1000; - if (sleep_ms < kMaxSleepMs) - sleep_ms *= 2; - } - - // If we're waiting and the child hasn't died by now, force it - // with a SIGKILL. - if (!exited) - result = kill(process_id, SIGKILL) == 0; - } - - if (!result) - DPLOG(ERROR) << "Unable to terminate process " << process_id; - - return result; -} - -bool KillProcessGroup(ProcessHandle process_group_id) { - bool result = kill(-1 * process_group_id, SIGKILL) == 0; - if (!result) - DPLOG(ERROR) << "Unable to terminate process group " << process_group_id; - return result; -} - -TerminationStatus GetTerminationStatus(ProcessHandle handle, int* exit_code) { - return GetTerminationStatusImpl(handle, false /* can_block */, exit_code); -} - -TerminationStatus WaitForTerminationStatus(ProcessHandle handle, - int* exit_code) { - return GetTerminationStatusImpl(handle, true /* can_block */, exit_code); -} - -bool WaitForExitCode(ProcessHandle handle, int* exit_code) { - int status; - if (HANDLE_EINTR(waitpid(handle, &status, 0)) == -1) { - NOTREACHED(); - return false; - } - - if (WIFEXITED(status)) { - *exit_code = WEXITSTATUS(status); - return true; - } - - // If it didn't exit cleanly, it must have been signaled. - DCHECK(WIFSIGNALED(status)); - return false; -} - -bool WaitForExitCodeWithTimeout(ProcessHandle handle, - int* exit_code, - base::TimeDelta timeout) { - bool waitpid_success = false; - int status = WaitpidWithTimeout(handle, timeout.InMilliseconds(), - &waitpid_success); - if (status == -1) - return false; - if (!waitpid_success) - return false; - if (WIFSIGNALED(status)) { - *exit_code = -1; - return true; - } - if (WIFEXITED(status)) { - *exit_code = WEXITSTATUS(status); - return true; - } - return false; -} - -bool WaitForProcessesToExit(const FilePath::StringType& executable_name, - base::TimeDelta wait, - const ProcessFilter* filter) { - bool result = false; - - // TODO(port): This is inefficient, but works if there are multiple procs. - // TODO(port): use waitpid to avoid leaving zombies around - - base::TimeTicks end_time = base::TimeTicks::Now() + wait; - do { - NamedProcessIterator iter(executable_name, filter); - if (!iter.NextProcessEntry()) { - result = true; - break; - } - base::PlatformThread::Sleep(base::TimeDelta::FromMilliseconds(100)); - } while ((end_time - base::TimeTicks::Now()) > base::TimeDelta()); - - return result; -} - -#if defined(OS_MACOSX) -// Using kqueue on Mac so that we can wait on non-child processes. -// We can't use kqueues on child processes because we need to reap -// our own children using wait. -static bool WaitForSingleNonChildProcess(ProcessHandle handle, - base::TimeDelta wait) { - DCHECK_GT(handle, 0); - DCHECK(wait.InMilliseconds() == base::kNoTimeout || wait > base::TimeDelta()); - - int kq = kqueue(); - if (kq == -1) { - DPLOG(ERROR) << "kqueue"; - return false; - } - file_util::ScopedFD kq_closer(&kq); - - struct kevent change = {0}; - EV_SET(&change, handle, EVFILT_PROC, EV_ADD, NOTE_EXIT, 0, NULL); - int result = HANDLE_EINTR(kevent(kq, &change, 1, NULL, 0, NULL)); - if (result == -1) { - if (errno == ESRCH) { - // If the process wasn't found, it must be dead. - return true; - } - - DPLOG(ERROR) << "kevent (setup " << handle << ")"; - return false; - } - - // Keep track of the elapsed time to be able to restart kevent if it's - // interrupted. - bool wait_forever = wait.InMilliseconds() == base::kNoTimeout; - base::TimeDelta remaining_delta; - base::TimeTicks deadline; - if (!wait_forever) { - remaining_delta = wait; - deadline = base::TimeTicks::Now() + remaining_delta; - } - - result = -1; - struct kevent event = {0}; - - while (wait_forever || remaining_delta > base::TimeDelta()) { - struct timespec remaining_timespec; - struct timespec* remaining_timespec_ptr; - if (wait_forever) { - remaining_timespec_ptr = NULL; - } else { - remaining_timespec = remaining_delta.ToTimeSpec(); - remaining_timespec_ptr = &remaining_timespec; - } - - result = kevent(kq, NULL, 0, &event, 1, remaining_timespec_ptr); - - if (result == -1 && errno == EINTR) { - if (!wait_forever) { - remaining_delta = deadline - base::TimeTicks::Now(); - } - result = 0; - } else { - break; - } - } - - if (result < 0) { - DPLOG(ERROR) << "kevent (wait " << handle << ")"; - return false; - } else if (result > 1) { - DLOG(ERROR) << "kevent (wait " << handle << "): unexpected result " - << result; - return false; - } else if (result == 0) { - // Timed out. - return false; - } - - DCHECK_EQ(result, 1); - - if (event.filter != EVFILT_PROC || - (event.fflags & NOTE_EXIT) == 0 || - event.ident != static_cast(handle)) { - DLOG(ERROR) << "kevent (wait " << handle - << "): unexpected event: filter=" << event.filter - << ", fflags=" << event.fflags - << ", ident=" << event.ident; - return false; - } - - return true; -} -#endif // OS_MACOSX - -bool WaitForSingleProcess(ProcessHandle handle, base::TimeDelta wait) { - ProcessHandle parent_pid = GetParentProcessId(handle); - ProcessHandle our_pid = Process::Current().handle(); - if (parent_pid != our_pid) { -#if defined(OS_MACOSX) - // On Mac we can wait on non child processes. - return WaitForSingleNonChildProcess(handle, wait); -#else - // Currently on Linux we can't handle non child processes. - NOTIMPLEMENTED(); -#endif // OS_MACOSX - } - - bool waitpid_success; - int status = -1; - if (wait.InMilliseconds() == base::kNoTimeout) { - waitpid_success = (HANDLE_EINTR(waitpid(handle, &status, 0)) != -1); - } else { - status = WaitpidWithTimeout( - handle, wait.InMilliseconds(), &waitpid_success); - } - - if (status != -1) { - DCHECK(waitpid_success); - return WIFEXITED(status); - } else { - return false; - } -} - -bool CleanupProcesses(const FilePath::StringType& executable_name, - base::TimeDelta wait, - int exit_code, - const ProcessFilter* filter) { - bool exited_cleanly = WaitForProcessesToExit(executable_name, wait, filter); - if (!exited_cleanly) - KillProcesses(executable_name, exit_code, filter); - return exited_cleanly; -} - -#if !defined(OS_MACOSX) - -namespace { - -// Return true if the given child is dead. This will also reap the process. -// Doesn't block. -static bool IsChildDead(pid_t child) { - const pid_t result = HANDLE_EINTR(waitpid(child, NULL, WNOHANG)); - if (result == -1) { - DPLOG(ERROR) << "waitpid(" << child << ")"; - NOTREACHED(); - } else if (result > 0) { - // The child has died. - return true; - } - - return false; -} - -// A thread class which waits for the given child to exit and reaps it. -// If the child doesn't exit within a couple of seconds, kill it. -class BackgroundReaper : public PlatformThread::Delegate { - public: - BackgroundReaper(pid_t child, unsigned timeout) - : child_(child), - timeout_(timeout) { - } - - // Overridden from PlatformThread::Delegate: - virtual void ThreadMain() OVERRIDE { - WaitForChildToDie(); - delete this; - } - - void WaitForChildToDie() { - // Wait forever case. - if (timeout_ == 0) { - pid_t r = HANDLE_EINTR(waitpid(child_, NULL, 0)); - if (r != child_) { - DPLOG(ERROR) << "While waiting for " << child_ - << " to terminate, we got the following result: " << r; - } - return; - } - - // There's no good way to wait for a specific child to exit in a timed - // fashion. (No kqueue on Linux), so we just loop and sleep. - - // Wait for 2 * timeout_ 500 milliseconds intervals. - for (unsigned i = 0; i < 2 * timeout_; ++i) { - PlatformThread::Sleep(TimeDelta::FromMilliseconds(500)); - if (IsChildDead(child_)) - return; - } - - if (kill(child_, SIGKILL) == 0) { - // SIGKILL is uncatchable. Since the signal was delivered, we can - // just wait for the process to die now in a blocking manner. - if (HANDLE_EINTR(waitpid(child_, NULL, 0)) < 0) - DPLOG(WARNING) << "waitpid"; - } else { - DLOG(ERROR) << "While waiting for " << child_ << " to terminate we" - << " failed to deliver a SIGKILL signal (" << errno << ")."; - } - } - - private: - const pid_t child_; - // Number of seconds to wait, if 0 then wait forever and do not attempt to - // kill |child_|. - const unsigned timeout_; - - DISALLOW_COPY_AND_ASSIGN(BackgroundReaper); -}; - -} // namespace - -void EnsureProcessTerminated(ProcessHandle process) { - // If the child is already dead, then there's nothing to do. - if (IsChildDead(process)) - return; - - const unsigned timeout = 2; // seconds - BackgroundReaper* reaper = new BackgroundReaper(process, timeout); - PlatformThread::CreateNonJoinable(0, reaper); -} - -void EnsureProcessGetsReaped(ProcessHandle process) { - // If the child is already dead, then there's nothing to do. - if (IsChildDead(process)) - return; - - BackgroundReaper* reaper = new BackgroundReaper(process, 0); - PlatformThread::CreateNonJoinable(0, reaper); -} - -#endif // !defined(OS_MACOSX) - -} // namespace base diff --git a/base/process/kill_win.cc b/base/process/kill_win.cc deleted file mode 100644 index 99a7c66185..0000000000 --- a/base/process/kill_win.cc +++ /dev/null @@ -1,255 +0,0 @@ -// Copyright (c) 2013 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "base/process/kill.h" - -#include -#include - -#include "base/bind.h" -#include "base/bind_helpers.h" -#include "base/logging.h" -#include "base/message_loop/message_loop.h" -#include "base/process/process_iterator.h" -#include "base/win/object_watcher.h" - -namespace base { - -namespace { - -// Exit codes with special meanings on Windows. -const DWORD kNormalTerminationExitCode = 0; -const DWORD kDebuggerInactiveExitCode = 0xC0000354; -const DWORD kKeyboardInterruptExitCode = 0xC000013A; -const DWORD kDebuggerTerminatedExitCode = 0x40010004; - -// This exit code is used by the Windows task manager when it kills a -// process. It's value is obviously not that unique, and it's -// surprising to me that the task manager uses this value, but it -// seems to be common practice on Windows to test for it as an -// indication that the task manager has killed something if the -// process goes away. -const DWORD kProcessKilledExitCode = 1; - -// Maximum amount of time (in milliseconds) to wait for the process to exit. -static const int kWaitInterval = 2000; - -class TimerExpiredTask : public win::ObjectWatcher::Delegate { - public: - explicit TimerExpiredTask(ProcessHandle process); - ~TimerExpiredTask(); - - void TimedOut(); - - // MessageLoop::Watcher ----------------------------------------------------- - virtual void OnObjectSignaled(HANDLE object); - - private: - void KillProcess(); - - // The process that we are watching. - ProcessHandle process_; - - win::ObjectWatcher watcher_; - - DISALLOW_COPY_AND_ASSIGN(TimerExpiredTask); -}; - -TimerExpiredTask::TimerExpiredTask(ProcessHandle process) : process_(process) { - watcher_.StartWatching(process_, this); -} - -TimerExpiredTask::~TimerExpiredTask() { - TimedOut(); - DCHECK(!process_) << "Make sure to close the handle."; -} - -void TimerExpiredTask::TimedOut() { - if (process_) - KillProcess(); -} - -void TimerExpiredTask::OnObjectSignaled(HANDLE object) { - CloseHandle(process_); - process_ = NULL; -} - -void TimerExpiredTask::KillProcess() { - // Stop watching the process handle since we're killing it. - watcher_.StopWatching(); - - // OK, time to get frisky. We don't actually care when the process - // terminates. We just care that it eventually terminates, and that's what - // TerminateProcess should do for us. Don't check for the result code since - // it fails quite often. This should be investigated eventually. - base::KillProcess(process_, kProcessKilledExitCode, false); - - // Now, just cleanup as if the process exited normally. - OnObjectSignaled(process_); -} - -} // namespace - -bool KillProcess(ProcessHandle process, int exit_code, bool wait) { - bool result = (TerminateProcess(process, exit_code) != FALSE); - if (result && wait) { - // The process may not end immediately due to pending I/O - if (WAIT_OBJECT_0 != WaitForSingleObject(process, 60 * 1000)) - DLOG_GETLASTERROR(ERROR) << "Error waiting for process exit"; - } else if (!result) { - DLOG_GETLASTERROR(ERROR) << "Unable to terminate process"; - } - return result; -} - -// Attempts to kill the process identified by the given process -// entry structure, giving it the specified exit code. -// Returns true if this is successful, false otherwise. -bool KillProcessById(ProcessId process_id, int exit_code, bool wait) { - HANDLE process = OpenProcess(PROCESS_TERMINATE | SYNCHRONIZE, - FALSE, // Don't inherit handle - process_id); - if (!process) { - DLOG_GETLASTERROR(ERROR) << "Unable to open process " << process_id; - return false; - } - bool ret = KillProcess(process, exit_code, wait); - CloseHandle(process); - return ret; -} - -TerminationStatus GetTerminationStatus(ProcessHandle handle, int* exit_code) { - DWORD tmp_exit_code = 0; - - if (!::GetExitCodeProcess(handle, &tmp_exit_code)) { - DLOG_GETLASTERROR(FATAL) << "GetExitCodeProcess() failed"; - if (exit_code) { - // This really is a random number. We haven't received any - // information about the exit code, presumably because this - // process doesn't have permission to get the exit code, or - // because of some other cause for GetExitCodeProcess to fail - // (MSDN docs don't give the possible failure error codes for - // this function, so it could be anything). But we don't want - // to leave exit_code uninitialized, since that could cause - // random interpretations of the exit code. So we assume it - // terminated "normally" in this case. - *exit_code = kNormalTerminationExitCode; - } - // Assume the child has exited normally if we can't get the exit - // code. - return TERMINATION_STATUS_NORMAL_TERMINATION; - } - if (tmp_exit_code == STILL_ACTIVE) { - DWORD wait_result = WaitForSingleObject(handle, 0); - if (wait_result == WAIT_TIMEOUT) { - if (exit_code) - *exit_code = wait_result; - return TERMINATION_STATUS_STILL_RUNNING; - } - - if (wait_result == WAIT_FAILED) { - DLOG_GETLASTERROR(ERROR) << "WaitForSingleObject() failed"; - } else { - DCHECK_EQ(WAIT_OBJECT_0, wait_result); - - // Strange, the process used 0x103 (STILL_ACTIVE) as exit code. - NOTREACHED(); - } - - return TERMINATION_STATUS_ABNORMAL_TERMINATION; - } - - if (exit_code) - *exit_code = tmp_exit_code; - - switch (tmp_exit_code) { - case kNormalTerminationExitCode: - return TERMINATION_STATUS_NORMAL_TERMINATION; - case kDebuggerInactiveExitCode: // STATUS_DEBUGGER_INACTIVE. - case kKeyboardInterruptExitCode: // Control-C/end session. - case kDebuggerTerminatedExitCode: // Debugger terminated process. - case kProcessKilledExitCode: // Task manager kill. - return TERMINATION_STATUS_PROCESS_WAS_KILLED; - default: - // All other exit codes indicate crashes. - return TERMINATION_STATUS_PROCESS_CRASHED; - } -} - -bool WaitForExitCode(ProcessHandle handle, int* exit_code) { - bool success = WaitForExitCodeWithTimeout( - handle, exit_code, base::TimeDelta::FromMilliseconds(INFINITE)); - CloseProcessHandle(handle); - return success; -} - -bool WaitForExitCodeWithTimeout(ProcessHandle handle, - int* exit_code, - base::TimeDelta timeout) { - if (::WaitForSingleObject(handle, timeout.InMilliseconds()) != WAIT_OBJECT_0) - return false; - DWORD temp_code; // Don't clobber out-parameters in case of failure. - if (!::GetExitCodeProcess(handle, &temp_code)) - return false; - - *exit_code = temp_code; - return true; -} - -bool WaitForProcessesToExit(const FilePath::StringType& executable_name, - base::TimeDelta wait, - const ProcessFilter* filter) { - const ProcessEntry* entry; - bool result = true; - DWORD start_time = GetTickCount(); - - NamedProcessIterator iter(executable_name, filter); - while ((entry = iter.NextProcessEntry())) { - DWORD remaining_wait = std::max( - 0, wait.InMilliseconds() - (GetTickCount() - start_time)); - HANDLE process = OpenProcess(SYNCHRONIZE, - FALSE, - entry->th32ProcessID); - DWORD wait_result = WaitForSingleObject(process, remaining_wait); - CloseHandle(process); - result = result && (wait_result == WAIT_OBJECT_0); - } - - return result; -} - -bool WaitForSingleProcess(ProcessHandle handle, base::TimeDelta wait) { - int exit_code; - if (!WaitForExitCodeWithTimeout(handle, &exit_code, wait)) - return false; - return exit_code == 0; -} - -bool CleanupProcesses(const FilePath::StringType& executable_name, - base::TimeDelta wait, - int exit_code, - const ProcessFilter* filter) { - bool exited_cleanly = WaitForProcessesToExit(executable_name, wait, filter); - if (!exited_cleanly) - KillProcesses(executable_name, exit_code, filter); - return exited_cleanly; -} - -void EnsureProcessTerminated(ProcessHandle process) { - DCHECK(process != GetCurrentProcess()); - - // If already signaled, then we are done! - if (WaitForSingleObject(process, 0) == WAIT_OBJECT_0) { - CloseHandle(process); - return; - } - - MessageLoop::current()->PostDelayedTask( - FROM_HERE, - base::Bind(&TimerExpiredTask::TimedOut, - base::Owned(new TimerExpiredTask(process))), - base::TimeDelta::FromMilliseconds(kWaitInterval)); -} - -} // namespace base diff --git a/base/process/launch.h b/base/process/launch.h deleted file mode 100644 index 45b10537b8..0000000000 --- a/base/process/launch.h +++ /dev/null @@ -1,258 +0,0 @@ -// Copyright (c) 2013 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -// This file contains functions for launching subprocesses. - -#ifndef BASE_PROCESS_LAUNCH_H_ -#define BASE_PROCESS_LAUNCH_H_ - -#include -#include -#include -#include - -#include "base/base_export.h" -#include "base/basictypes.h" -#include "base/process/process_handle.h" - -#if defined(OS_POSIX) -#include "base/posix/file_descriptor_shuffle.h" -#elif defined(OS_WIN) -#include -#endif - -class CommandLine; - -namespace base { - -typedef std::vector > EnvironmentVector; -typedef std::vector > FileHandleMappingVector; - -// Options for launching a subprocess that are passed to LaunchProcess(). -// The default constructor constructs the object with default options. -struct LaunchOptions { - LaunchOptions() - : wait(false), -#if defined(OS_WIN) - start_hidden(false), - inherit_handles(false), - as_user(NULL), - empty_desktop_name(false), - job_handle(NULL), - stdin_handle(NULL), - stdout_handle(NULL), - stderr_handle(NULL), - force_breakaway_from_job_(false) -#else - environ(NULL), - fds_to_remap(NULL), - maximize_rlimits(NULL), - new_process_group(false) -#if defined(OS_LINUX) - , clone_flags(0) -#endif // OS_LINUX -#if defined(OS_CHROMEOS) - , ctrl_terminal_fd(-1) -#endif // OS_CHROMEOS -#endif // !defined(OS_WIN) - {} - - // If true, wait for the process to complete. - bool wait; - -#if defined(OS_WIN) - bool start_hidden; - - // If true, the new process inherits handles from the parent. In production - // code this flag should be used only when running short-lived, trusted - // binaries, because open handles from other libraries and subsystems will - // leak to the child process, causing errors such as open socket hangs. - bool inherit_handles; - - // If non-NULL, runs as if the user represented by the token had launched it. - // Whether the application is visible on the interactive desktop depends on - // the token belonging to an interactive logon session. - // - // To avoid hard to diagnose problems, when specified this loads the - // environment variables associated with the user and if this operation fails - // the entire call fails as well. - UserTokenHandle as_user; - - // If true, use an empty string for the desktop name. - bool empty_desktop_name; - - // If non-NULL, launches the application in that job object. The process will - // be terminated immediately and LaunchProcess() will fail if assignment to - // the job object fails. - HANDLE job_handle; - - // Handles for the redirection of stdin, stdout and stderr. The handles must - // be inheritable. Caller should either set all three of them or none (i.e. - // there is no way to redirect stderr without redirecting stdin). The - // |inherit_handles| flag must be set to true when redirecting stdio stream. - HANDLE stdin_handle; - HANDLE stdout_handle; - HANDLE stderr_handle; - - // If set to true, ensures that the child process is launched with the - // CREATE_BREAKAWAY_FROM_JOB flag which allows it to breakout of the parent - // job if any. - bool force_breakaway_from_job_; -#else - // If non-NULL, set/unset environment variables. - // See documentation of AlterEnvironment(). - // This pointer is owned by the caller and must live through the - // call to LaunchProcess(). - const EnvironmentVector* environ; - - // If non-NULL, remap file descriptors according to the mapping of - // src fd->dest fd to propagate FDs into the child process. - // This pointer is owned by the caller and must live through the - // call to LaunchProcess(). - const FileHandleMappingVector* fds_to_remap; - - // Each element is an RLIMIT_* constant that should be raised to its - // rlim_max. This pointer is owned by the caller and must live through - // the call to LaunchProcess(). - const std::set* maximize_rlimits; - - // If true, start the process in a new process group, instead of - // inheriting the parent's process group. The pgid of the child process - // will be the same as its pid. - bool new_process_group; - -#if defined(OS_LINUX) - // If non-zero, start the process using clone(), using flags as provided. - int clone_flags; -#endif // defined(OS_LINUX) - -#if defined(OS_CHROMEOS) - // If non-negative, the specified file descriptor will be set as the launched - // process' controlling terminal. - int ctrl_terminal_fd; -#endif // defined(OS_CHROMEOS) - -#endif // !defined(OS_WIN) -}; - -// Launch a process via the command line |cmdline|. -// See the documentation of LaunchOptions for details on |options|. -// -// Returns true upon success. -// -// Upon success, if |process_handle| is non-NULL, it will be filled in with the -// handle of the launched process. NOTE: In this case, the caller is -// responsible for closing the handle so that it doesn't leak! -// Otherwise, the process handle will be implicitly closed. -// -// Unix-specific notes: -// - All file descriptors open in the parent process will be closed in the -// child process except for any preserved by options::fds_to_remap, and -// stdin, stdout, and stderr. If not remapped by options::fds_to_remap, -// stdin is reopened as /dev/null, and the child is allowed to inherit its -// parent's stdout and stderr. -// - If the first argument on the command line does not contain a slash, -// PATH will be searched. (See man execvp.) -BASE_EXPORT bool LaunchProcess(const CommandLine& cmdline, - const LaunchOptions& options, - ProcessHandle* process_handle); - -#if defined(OS_WIN) -// Windows-specific LaunchProcess that takes the command line as a -// string. Useful for situations where you need to control the -// command line arguments directly, but prefer the CommandLine version -// if launching Chrome itself. -// -// The first command line argument should be the path to the process, -// and don't forget to quote it. -// -// Example (including literal quotes) -// cmdline = "c:\windows\explorer.exe" -foo "c:\bar\" -BASE_EXPORT bool LaunchProcess(const string16& cmdline, - const LaunchOptions& options, - ProcessHandle* process_handle); - -#elif defined(OS_POSIX) -// A POSIX-specific version of LaunchProcess that takes an argv array -// instead of a CommandLine. Useful for situations where you need to -// control the command line arguments directly, but prefer the -// CommandLine version if launching Chrome itself. -BASE_EXPORT bool LaunchProcess(const std::vector& argv, - const LaunchOptions& options, - ProcessHandle* process_handle); - -// AlterEnvironment returns a modified environment vector, constructed from the -// given environment and the list of changes given in |changes|. Each key in -// the environment is matched against the first element of the pairs. In the -// event of a match, the value is replaced by the second of the pair, unless -// the second is empty, in which case the key-value is removed. -// -// The returned array is allocated using new[] and must be freed by the caller. -BASE_EXPORT char** AlterEnvironment(const EnvironmentVector& changes, - const char* const* const env); - -// Close all file descriptors, except those which are a destination in the -// given multimap. Only call this function in a child process where you know -// that there aren't any other threads. -BASE_EXPORT void CloseSuperfluousFds(const InjectiveMultimap& saved_map); -#endif // defined(OS_POSIX) - -#if defined(OS_WIN) -// Set JOBOBJECT_EXTENDED_LIMIT_INFORMATION to JobObject |job_object|. -// As its limit_info.BasicLimitInformation.LimitFlags has -// JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE. -// When the provide JobObject |job_object| is closed, the binded process will -// be terminated. -BASE_EXPORT bool SetJobObjectAsKillOnJobClose(HANDLE job_object); - -// Output multi-process printf, cout, cerr, etc to the cmd.exe console that ran -// chrome. This is not thread-safe: only call from main thread. -BASE_EXPORT void RouteStdioToConsole(); -#endif // defined(OS_WIN) - -// Executes the application specified by |cl| and wait for it to exit. Stores -// the output (stdout) in |output|. Redirects stderr to /dev/null. Returns true -// on success (application launched and exited cleanly, with exit code -// indicating success). -BASE_EXPORT bool GetAppOutput(const CommandLine& cl, std::string* output); - -#if defined(OS_POSIX) -// A POSIX-specific version of GetAppOutput that takes an argv array -// instead of a CommandLine. Useful for situations where you need to -// control the command line arguments directly. -BASE_EXPORT bool GetAppOutput(const std::vector& argv, - std::string* output); - -// A restricted version of |GetAppOutput()| which (a) clears the environment, -// and (b) stores at most |max_output| bytes; also, it doesn't search the path -// for the command. -BASE_EXPORT bool GetAppOutputRestricted(const CommandLine& cl, - std::string* output, size_t max_output); - -// A version of |GetAppOutput()| which also returns the exit code of the -// executed command. Returns true if the application runs and exits cleanly. If -// this is the case the exit code of the application is available in -// |*exit_code|. -BASE_EXPORT bool GetAppOutputWithExitCode(const CommandLine& cl, - std::string* output, int* exit_code); -#endif // defined(OS_POSIX) - -// If supported on the platform, and the user has sufficent rights, increase -// the current process's scheduling priority to a high priority. -BASE_EXPORT void RaiseProcessToHighPriority(); - -#if defined(OS_MACOSX) -// Restore the default exception handler, setting it to Apple Crash Reporter -// (ReportCrash). When forking and execing a new process, the child will -// inherit the parent's exception ports, which may be set to the Breakpad -// instance running inside the parent. The parent's Breakpad instance should -// not handle the child's exceptions. Calling RestoreDefaultExceptionHandler -// in the child after forking will restore the standard exception handler. -// See http://crbug.com/20371/ for more details. -void RestoreDefaultExceptionHandler(); -#endif // defined(OS_MACOSX) - -} // namespace base - -#endif // BASE_PROCESS_LAUNCH_H_ diff --git a/base/process/launch_ios.cc b/base/process/launch_ios.cc deleted file mode 100644 index 3c700f8f0a..0000000000 --- a/base/process/launch_ios.cc +++ /dev/null @@ -1,13 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "base/process/launch.h" - -namespace base { - -void RaiseProcessToHighPriority() { - // Impossible on iOS. Do nothing. -} - -} // namespace base diff --git a/base/process/launch_mac.cc b/base/process/launch_mac.cc deleted file mode 100644 index 176edca72e..0000000000 --- a/base/process/launch_mac.cc +++ /dev/null @@ -1,28 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "base/process/launch.h" - -#include - -namespace base { - -void RestoreDefaultExceptionHandler() { - // This function is tailored to remove the Breakpad exception handler. - // exception_mask matches s_exception_mask in - // breakpad/src/client/mac/handler/exception_handler.cc - const exception_mask_t exception_mask = EXC_MASK_BAD_ACCESS | - EXC_MASK_BAD_INSTRUCTION | - EXC_MASK_ARITHMETIC | - EXC_MASK_BREAKPOINT; - - // Setting the exception port to MACH_PORT_NULL may not be entirely - // kosher to restore the default exception handler, but in practice, - // it results in the exception port being set to Apple Crash Reporter, - // the desired behavior. - task_set_exception_ports(mach_task_self(), exception_mask, MACH_PORT_NULL, - EXCEPTION_DEFAULT, THREAD_STATE_NONE); -} - -} // namespace base diff --git a/base/process/launch_posix.cc b/base/process/launch_posix.cc deleted file mode 100644 index 52e149cd8d..0000000000 --- a/base/process/launch_posix.cc +++ /dev/null @@ -1,760 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "base/process/launch.h" - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include - -#include "base/allocator/type_profiler_control.h" -#include "base/command_line.h" -#include "base/compiler_specific.h" -#include "base/debug/debugger.h" -#include "base/debug/stack_trace.h" -#include "base/file_util.h" -#include "base/files/dir_reader_posix.h" -#include "base/logging.h" -#include "base/memory/scoped_ptr.h" -#include "base/posix/eintr_wrapper.h" -#include "base/process/kill.h" -#include "base/process/process_metrics.h" -#include "base/strings/stringprintf.h" -#include "base/synchronization/waitable_event.h" -#include "base/third_party/dynamic_annotations/dynamic_annotations.h" -#include "base/threading/platform_thread.h" -#include "base/threading/thread_restrictions.h" - -#if defined(OS_CHROMEOS) -#include -#endif - -#if defined(OS_FREEBSD) -#include -#include -#endif - -#if defined(OS_MACOSX) -#include -#include -#else -extern char** environ; -#endif - -namespace base { - -namespace { - -// Get the process's "environment" (i.e. the thing that setenv/getenv -// work with). -char** GetEnvironment() { -#if defined(OS_MACOSX) - return *_NSGetEnviron(); -#else - return environ; -#endif -} - -// Set the process's "environment" (i.e. the thing that setenv/getenv -// work with). -void SetEnvironment(char** env) { -#if defined(OS_MACOSX) - *_NSGetEnviron() = env; -#else - environ = env; -#endif -} - -// Set the calling thread's signal mask to new_sigmask and return -// the previous signal mask. -sigset_t SetSignalMask(const sigset_t& new_sigmask) { - sigset_t old_sigmask; -#if defined(OS_ANDROID) - // POSIX says pthread_sigmask() must be used in multi-threaded processes, - // but Android's pthread_sigmask() was broken until 4.1: - // https://code.google.com/p/android/issues/detail?id=15337 - // http://stackoverflow.com/questions/13777109/pthread-sigmask-on-android-not-working - RAW_CHECK(sigprocmask(SIG_SETMASK, &new_sigmask, &old_sigmask) == 0); -#else - RAW_CHECK(pthread_sigmask(SIG_SETMASK, &new_sigmask, &old_sigmask) == 0); -#endif - return old_sigmask; -} - -#if !defined(OS_LINUX) || \ - (!defined(__i386__) && !defined(__x86_64__) && !defined(__arm__)) -void ResetChildSignalHandlersToDefaults() { - // The previous signal handlers are likely to be meaningless in the child's - // context so we reset them to the defaults for now. http://crbug.com/44953 - // These signal handlers are set up at least in browser_main_posix.cc: - // BrowserMainPartsPosix::PreEarlyInitialization and stack_trace_posix.cc: - // EnableInProcessStackDumping. - signal(SIGHUP, SIG_DFL); - signal(SIGINT, SIG_DFL); - signal(SIGILL, SIG_DFL); - signal(SIGABRT, SIG_DFL); - signal(SIGFPE, SIG_DFL); - signal(SIGBUS, SIG_DFL); - signal(SIGSEGV, SIG_DFL); - signal(SIGSYS, SIG_DFL); - signal(SIGTERM, SIG_DFL); -} - -#else - -// TODO(jln): remove the Linux special case once kernels are fixed. - -// Internally the kernel makes sigset_t an array of long large enough to have -// one bit per signal. -typedef uint64_t kernel_sigset_t; - -// This is what struct sigaction looks like to the kernel at least on X86 and -// ARM. MIPS, for instance, is very different. -struct kernel_sigaction { - void* k_sa_handler; // For this usage it only needs to be a generic pointer. - unsigned long k_sa_flags; - void* k_sa_restorer; // For this usage it only needs to be a generic pointer. - kernel_sigset_t k_sa_mask; -}; - -// glibc's sigaction() will prevent access to sa_restorer, so we need to roll -// our own. -int sys_rt_sigaction(int sig, const struct kernel_sigaction* act, - struct kernel_sigaction* oact) { - return syscall(SYS_rt_sigaction, sig, act, oact, sizeof(kernel_sigset_t)); -} - -// This function is intended to be used in between fork() and execve() and will -// reset all signal handlers to the default. -// The motivation for going through all of them is that sa_restorer can leak -// from parents and help defeat ASLR on buggy kernels. We reset it to NULL. -// See crbug.com/177956. -void ResetChildSignalHandlersToDefaults(void) { - for (int signum = 1; ; ++signum) { - struct kernel_sigaction act = {0}; - int sigaction_get_ret = sys_rt_sigaction(signum, NULL, &act); - if (sigaction_get_ret && errno == EINVAL) { -#if !defined(NDEBUG) - // Linux supports 32 real-time signals from 33 to 64. - // If the number of signals in the Linux kernel changes, someone should - // look at this code. - const int kNumberOfSignals = 64; - RAW_CHECK(signum == kNumberOfSignals + 1); -#endif // !defined(NDEBUG) - break; - } - // All other failures are fatal. - if (sigaction_get_ret) { - RAW_LOG(FATAL, "sigaction (get) failed."); - } - - // The kernel won't allow to re-set SIGKILL or SIGSTOP. - if (signum != SIGSTOP && signum != SIGKILL) { - act.k_sa_handler = reinterpret_cast(SIG_DFL); - act.k_sa_restorer = NULL; - if (sys_rt_sigaction(signum, &act, NULL)) { - RAW_LOG(FATAL, "sigaction (set) failed."); - } - } -#if !defined(NDEBUG) - // Now ask the kernel again and check that no restorer will leak. - if (sys_rt_sigaction(signum, NULL, &act) || act.k_sa_restorer) { - RAW_LOG(FATAL, "Cound not fix sa_restorer."); - } -#endif // !defined(NDEBUG) - } -} -#endif // !defined(OS_LINUX) || - // (!defined(__i386__) && !defined(__x86_64__) && !defined(__arm__)) - -} // anonymous namespace - -// A class to handle auto-closing of DIR*'s. -class ScopedDIRClose { - public: - inline void operator()(DIR* x) const { - if (x) { - closedir(x); - } - } -}; -typedef scoped_ptr_malloc ScopedDIR; - -#if defined(OS_LINUX) -static const char kFDDir[] = "/proc/self/fd"; -#elif defined(OS_MACOSX) -static const char kFDDir[] = "/dev/fd"; -#elif defined(OS_SOLARIS) -static const char kFDDir[] = "/dev/fd"; -#elif defined(OS_FREEBSD) -static const char kFDDir[] = "/dev/fd"; -#elif defined(OS_OPENBSD) -static const char kFDDir[] = "/dev/fd"; -#elif defined(OS_ANDROID) -static const char kFDDir[] = "/proc/self/fd"; -#endif - -void CloseSuperfluousFds(const base::InjectiveMultimap& saved_mapping) { - // DANGER: no calls to malloc are allowed from now on: - // http://crbug.com/36678 - - // Get the maximum number of FDs possible. - size_t max_fds = GetMaxFds(); - - DirReaderPosix fd_dir(kFDDir); - if (!fd_dir.IsValid()) { - // Fallback case: Try every possible fd. - for (size_t i = 0; i < max_fds; ++i) { - const int fd = static_cast(i); - if (fd == STDIN_FILENO || fd == STDOUT_FILENO || fd == STDERR_FILENO) - continue; - InjectiveMultimap::const_iterator j; - for (j = saved_mapping.begin(); j != saved_mapping.end(); j++) { - if (fd == j->dest) - break; - } - if (j != saved_mapping.end()) - continue; - - // Since we're just trying to close anything we can find, - // ignore any error return values of close(). - ignore_result(HANDLE_EINTR(close(fd))); - } - return; - } - - const int dir_fd = fd_dir.fd(); - - for ( ; fd_dir.Next(); ) { - // Skip . and .. entries. - if (fd_dir.name()[0] == '.') - continue; - - char *endptr; - errno = 0; - const long int fd = strtol(fd_dir.name(), &endptr, 10); - if (fd_dir.name()[0] == 0 || *endptr || fd < 0 || errno) - continue; - if (fd == STDIN_FILENO || fd == STDOUT_FILENO || fd == STDERR_FILENO) - continue; - InjectiveMultimap::const_iterator i; - for (i = saved_mapping.begin(); i != saved_mapping.end(); i++) { - if (fd == i->dest) - break; - } - if (i != saved_mapping.end()) - continue; - if (fd == dir_fd) - continue; - - // When running under Valgrind, Valgrind opens several FDs for its - // own use and will complain if we try to close them. All of - // these FDs are >= |max_fds|, so we can check against that here - // before closing. See https://bugs.kde.org/show_bug.cgi?id=191758 - if (fd < static_cast(max_fds)) { - int ret = HANDLE_EINTR(close(fd)); - DPCHECK(ret == 0); - } - } -} - -char** AlterEnvironment(const EnvironmentVector& changes, - const char* const* const env) { - unsigned count = 0; - unsigned size = 0; - - // First assume that all of the current environment will be included. - for (unsigned i = 0; env[i]; i++) { - const char *const pair = env[i]; - count++; - size += strlen(pair) + 1 /* terminating NUL */; - } - - for (EnvironmentVector::const_iterator j = changes.begin(); - j != changes.end(); - ++j) { - bool found = false; - const char *pair; - - for (unsigned i = 0; env[i]; i++) { - pair = env[i]; - const char *const equals = strchr(pair, '='); - if (!equals) - continue; - const unsigned keylen = equals - pair; - if (keylen == j->first.size() && - memcmp(pair, j->first.data(), keylen) == 0) { - found = true; - break; - } - } - - // if found, we'll either be deleting or replacing this element. - if (found) { - count--; - size -= strlen(pair) + 1; - if (j->second.size()) - found = false; - } - - // if !found, then we have a new element to add. - if (!found && !j->second.empty()) { - count++; - size += j->first.size() + 1 /* '=' */ + j->second.size() + 1 /* NUL */; - } - } - - count++; // for the final NULL - uint8_t *buffer = new uint8_t[sizeof(char*) * count + size]; - char **const ret = reinterpret_cast(buffer); - unsigned k = 0; - char *scratch = reinterpret_cast(buffer + sizeof(char*) * count); - - for (unsigned i = 0; env[i]; i++) { - const char *const pair = env[i]; - const char *const equals = strchr(pair, '='); - if (!equals) { - const unsigned len = strlen(pair); - ret[k++] = scratch; - memcpy(scratch, pair, len + 1); - scratch += len + 1; - continue; - } - const unsigned keylen = equals - pair; - bool handled = false; - for (EnvironmentVector::const_iterator - j = changes.begin(); j != changes.end(); j++) { - if (j->first.size() == keylen && - memcmp(j->first.data(), pair, keylen) == 0) { - if (!j->second.empty()) { - ret[k++] = scratch; - memcpy(scratch, pair, keylen + 1); - scratch += keylen + 1; - memcpy(scratch, j->second.c_str(), j->second.size() + 1); - scratch += j->second.size() + 1; - } - handled = true; - break; - } - } - - if (!handled) { - const unsigned len = strlen(pair); - ret[k++] = scratch; - memcpy(scratch, pair, len + 1); - scratch += len + 1; - } - } - - // Now handle new elements - for (EnvironmentVector::const_iterator - j = changes.begin(); j != changes.end(); j++) { - if (j->second.empty()) - continue; - - bool found = false; - for (unsigned i = 0; env[i]; i++) { - const char *const pair = env[i]; - const char *const equals = strchr(pair, '='); - if (!equals) - continue; - const unsigned keylen = equals - pair; - if (keylen == j->first.size() && - memcmp(pair, j->first.data(), keylen) == 0) { - found = true; - break; - } - } - - if (!found) { - ret[k++] = scratch; - memcpy(scratch, j->first.data(), j->first.size()); - scratch += j->first.size(); - *scratch++ = '='; - memcpy(scratch, j->second.c_str(), j->second.size() + 1); - scratch += j->second.size() + 1; - } - } - - ret[k] = NULL; - return ret; -} - -bool LaunchProcess(const std::vector& argv, - const LaunchOptions& options, - ProcessHandle* process_handle) { - size_t fd_shuffle_size = 0; - if (options.fds_to_remap) { - fd_shuffle_size = options.fds_to_remap->size(); - } - - InjectiveMultimap fd_shuffle1; - InjectiveMultimap fd_shuffle2; - fd_shuffle1.reserve(fd_shuffle_size); - fd_shuffle2.reserve(fd_shuffle_size); - - scoped_ptr argv_cstr(new char*[argv.size() + 1]); - scoped_ptr new_environ; - if (options.environ) - new_environ.reset(AlterEnvironment(*options.environ, GetEnvironment())); - - sigset_t full_sigset; - sigfillset(&full_sigset); - const sigset_t orig_sigmask = SetSignalMask(full_sigset); - - pid_t pid; -#if defined(OS_LINUX) - if (options.clone_flags) { - // Signal handling in this function assumes the creation of a new - // process, so we check that a thread is not being created by mistake - // and that signal handling follows the process-creation rules. - RAW_CHECK( - !(options.clone_flags & (CLONE_SIGHAND | CLONE_THREAD | CLONE_VM))); - pid = syscall(__NR_clone, options.clone_flags, 0, 0, 0); - } else -#endif - { - pid = fork(); - } - - // Always restore the original signal mask in the parent. - if (pid != 0) { - SetSignalMask(orig_sigmask); - } - - if (pid < 0) { - DPLOG(ERROR) << "fork"; - return false; - } else if (pid == 0) { - // Child process - - // DANGER: fork() rule: in the child, if you don't end up doing exec*(), - // you call _exit() instead of exit(). This is because _exit() does not - // call any previously-registered (in the parent) exit handlers, which - // might do things like block waiting for threads that don't even exist - // in the child. - - // If a child process uses the readline library, the process block forever. - // In BSD like OSes including OS X it is safe to assign /dev/null as stdin. - // See http://crbug.com/56596. - int null_fd = HANDLE_EINTR(open("/dev/null", O_RDONLY)); - if (null_fd < 0) { - RAW_LOG(ERROR, "Failed to open /dev/null"); - _exit(127); - } - - file_util::ScopedFD null_fd_closer(&null_fd); - int new_fd = HANDLE_EINTR(dup2(null_fd, STDIN_FILENO)); - if (new_fd != STDIN_FILENO) { - RAW_LOG(ERROR, "Failed to dup /dev/null for stdin"); - _exit(127); - } - - if (options.new_process_group) { - // Instead of inheriting the process group ID of the parent, the child - // starts off a new process group with pgid equal to its process ID. - if (setpgid(0, 0) < 0) { - RAW_LOG(ERROR, "setpgid failed"); - _exit(127); - } - } - - // Stop type-profiler. - // The profiler should be stopped between fork and exec since it inserts - // locks at new/delete expressions. See http://crbug.com/36678. - base::type_profiler::Controller::Stop(); - - if (options.maximize_rlimits) { - // Some resource limits need to be maximal in this child. - std::set::const_iterator resource; - for (resource = options.maximize_rlimits->begin(); - resource != options.maximize_rlimits->end(); - ++resource) { - struct rlimit limit; - if (getrlimit(*resource, &limit) < 0) { - RAW_LOG(WARNING, "getrlimit failed"); - } else if (limit.rlim_cur < limit.rlim_max) { - limit.rlim_cur = limit.rlim_max; - if (setrlimit(*resource, &limit) < 0) { - RAW_LOG(WARNING, "setrlimit failed"); - } - } - } - } - -#if defined(OS_MACOSX) - RestoreDefaultExceptionHandler(); -#endif // defined(OS_MACOSX) - - ResetChildSignalHandlersToDefaults(); - SetSignalMask(orig_sigmask); - -#if 0 - // When debugging it can be helpful to check that we really aren't making - // any hidden calls to malloc. - void *malloc_thunk = - reinterpret_cast(reinterpret_cast(malloc) & ~4095); - mprotect(malloc_thunk, 4096, PROT_READ | PROT_WRITE | PROT_EXEC); - memset(reinterpret_cast(malloc), 0xff, 8); -#endif // 0 - - // DANGER: no calls to malloc are allowed from now on: - // http://crbug.com/36678 - -#if defined(OS_CHROMEOS) - if (options.ctrl_terminal_fd >= 0) { - // Set process' controlling terminal. - if (HANDLE_EINTR(setsid()) != -1) { - if (HANDLE_EINTR( - ioctl(options.ctrl_terminal_fd, TIOCSCTTY, NULL)) == -1) { - RAW_LOG(WARNING, "ioctl(TIOCSCTTY), ctrl terminal not set"); - } - } else { - RAW_LOG(WARNING, "setsid failed, ctrl terminal not set"); - } - } -#endif // defined(OS_CHROMEOS) - - if (options.fds_to_remap) { - for (FileHandleMappingVector::const_iterator - it = options.fds_to_remap->begin(); - it != options.fds_to_remap->end(); ++it) { - fd_shuffle1.push_back(InjectionArc(it->first, it->second, false)); - fd_shuffle2.push_back(InjectionArc(it->first, it->second, false)); - } - } - - if (options.environ) - SetEnvironment(new_environ.get()); - - // fd_shuffle1 is mutated by this call because it cannot malloc. - if (!ShuffleFileDescriptors(&fd_shuffle1)) - _exit(127); - - CloseSuperfluousFds(fd_shuffle2); - - for (size_t i = 0; i < argv.size(); i++) - argv_cstr[i] = const_cast(argv[i].c_str()); - argv_cstr[argv.size()] = NULL; - execvp(argv_cstr[0], argv_cstr.get()); - - RAW_LOG(ERROR, "LaunchProcess: failed to execvp:"); - RAW_LOG(ERROR, argv_cstr[0]); - _exit(127); - } else { - // Parent process - if (options.wait) { - // While this isn't strictly disk IO, waiting for another process to - // finish is the sort of thing ThreadRestrictions is trying to prevent. - base::ThreadRestrictions::AssertIOAllowed(); - pid_t ret = HANDLE_EINTR(waitpid(pid, 0, 0)); - DPCHECK(ret > 0); - } - - if (process_handle) - *process_handle = pid; - } - - return true; -} - - -bool LaunchProcess(const CommandLine& cmdline, - const LaunchOptions& options, - ProcessHandle* process_handle) { - return LaunchProcess(cmdline.argv(), options, process_handle); -} - -void RaiseProcessToHighPriority() { - // On POSIX, we don't actually do anything here. We could try to nice() or - // setpriority() or sched_getscheduler, but these all require extra rights. -} - -// Return value used by GetAppOutputInternal to encapsulate the various exit -// scenarios from the function. -enum GetAppOutputInternalResult { - EXECUTE_FAILURE, - EXECUTE_SUCCESS, - GOT_MAX_OUTPUT, -}; - -// Executes the application specified by |argv| and wait for it to exit. Stores -// the output (stdout) in |output|. If |do_search_path| is set, it searches the -// path for the application; in that case, |envp| must be null, and it will use -// the current environment. If |do_search_path| is false, |argv[0]| should fully -// specify the path of the application, and |envp| will be used as the -// environment. Redirects stderr to /dev/null. -// If we successfully start the application and get all requested output, we -// return GOT_MAX_OUTPUT, or if there is a problem starting or exiting -// the application we return RUN_FAILURE. Otherwise we return EXECUTE_SUCCESS. -// The GOT_MAX_OUTPUT return value exists so a caller that asks for limited -// output can treat this as a success, despite having an exit code of SIG_PIPE -// due to us closing the output pipe. -// In the case of EXECUTE_SUCCESS, the application exit code will be returned -// in |*exit_code|, which should be checked to determine if the application -// ran successfully. -static GetAppOutputInternalResult GetAppOutputInternal( - const std::vector& argv, - char* const envp[], - std::string* output, - size_t max_output, - bool do_search_path, - int* exit_code) { - // Doing a blocking wait for another command to finish counts as IO. - base::ThreadRestrictions::AssertIOAllowed(); - // exit_code must be supplied so calling function can determine success. - DCHECK(exit_code); - *exit_code = EXIT_FAILURE; - - int pipe_fd[2]; - pid_t pid; - InjectiveMultimap fd_shuffle1, fd_shuffle2; - scoped_ptr argv_cstr(new char*[argv.size() + 1]); - - fd_shuffle1.reserve(3); - fd_shuffle2.reserve(3); - - // Either |do_search_path| should be false or |envp| should be null, but not - // both. - DCHECK(!do_search_path ^ !envp); - - if (pipe(pipe_fd) < 0) - return EXECUTE_FAILURE; - - switch (pid = fork()) { - case -1: // error - close(pipe_fd[0]); - close(pipe_fd[1]); - return EXECUTE_FAILURE; - case 0: // child - { -#if defined(OS_MACOSX) - RestoreDefaultExceptionHandler(); -#endif - // DANGER: no calls to malloc are allowed from now on: - // http://crbug.com/36678 - - // Obscure fork() rule: in the child, if you don't end up doing exec*(), - // you call _exit() instead of exit(). This is because _exit() does not - // call any previously-registered (in the parent) exit handlers, which - // might do things like block waiting for threads that don't even exist - // in the child. - int dev_null = open("/dev/null", O_WRONLY); - if (dev_null < 0) - _exit(127); - - // Stop type-profiler. - // The profiler should be stopped between fork and exec since it inserts - // locks at new/delete expressions. See http://crbug.com/36678. - base::type_profiler::Controller::Stop(); - - fd_shuffle1.push_back(InjectionArc(pipe_fd[1], STDOUT_FILENO, true)); - fd_shuffle1.push_back(InjectionArc(dev_null, STDERR_FILENO, true)); - fd_shuffle1.push_back(InjectionArc(dev_null, STDIN_FILENO, true)); - // Adding another element here? Remeber to increase the argument to - // reserve(), above. - - std::copy(fd_shuffle1.begin(), fd_shuffle1.end(), - std::back_inserter(fd_shuffle2)); - - if (!ShuffleFileDescriptors(&fd_shuffle1)) - _exit(127); - - CloseSuperfluousFds(fd_shuffle2); - - for (size_t i = 0; i < argv.size(); i++) - argv_cstr[i] = const_cast(argv[i].c_str()); - argv_cstr[argv.size()] = NULL; - if (do_search_path) - execvp(argv_cstr[0], argv_cstr.get()); - else - execve(argv_cstr[0], argv_cstr.get(), envp); - _exit(127); - } - default: // parent - { - // Close our writing end of pipe now. Otherwise later read would not - // be able to detect end of child's output (in theory we could still - // write to the pipe). - close(pipe_fd[1]); - - output->clear(); - char buffer[256]; - size_t output_buf_left = max_output; - ssize_t bytes_read = 1; // A lie to properly handle |max_output == 0| - // case in the logic below. - - while (output_buf_left > 0) { - bytes_read = HANDLE_EINTR(read(pipe_fd[0], buffer, - std::min(output_buf_left, sizeof(buffer)))); - if (bytes_read <= 0) - break; - output->append(buffer, bytes_read); - output_buf_left -= static_cast(bytes_read); - } - close(pipe_fd[0]); - - // Always wait for exit code (even if we know we'll declare - // GOT_MAX_OUTPUT). - bool success = WaitForExitCode(pid, exit_code); - - // If we stopped because we read as much as we wanted, we return - // GOT_MAX_OUTPUT (because the child may exit due to |SIGPIPE|). - if (!output_buf_left && bytes_read > 0) - return GOT_MAX_OUTPUT; - else if (success) - return EXECUTE_SUCCESS; - return EXECUTE_FAILURE; - } - } -} - -bool GetAppOutput(const CommandLine& cl, std::string* output) { - return GetAppOutput(cl.argv(), output); -} - -bool GetAppOutput(const std::vector& argv, std::string* output) { - // Run |execve()| with the current environment and store "unlimited" data. - int exit_code; - GetAppOutputInternalResult result = GetAppOutputInternal( - argv, NULL, output, std::numeric_limits::max(), true, - &exit_code); - return result == EXECUTE_SUCCESS && exit_code == EXIT_SUCCESS; -} - -// TODO(viettrungluu): Conceivably, we should have a timeout as well, so we -// don't hang if what we're calling hangs. -bool GetAppOutputRestricted(const CommandLine& cl, - std::string* output, size_t max_output) { - // Run |execve()| with the empty environment. - char* const empty_environ = NULL; - int exit_code; - GetAppOutputInternalResult result = GetAppOutputInternal( - cl.argv(), &empty_environ, output, max_output, false, &exit_code); - return result == GOT_MAX_OUTPUT || (result == EXECUTE_SUCCESS && - exit_code == EXIT_SUCCESS); -} - -bool GetAppOutputWithExitCode(const CommandLine& cl, - std::string* output, - int* exit_code) { - // Run |execve()| with the current environment and store "unlimited" data. - GetAppOutputInternalResult result = GetAppOutputInternal( - cl.argv(), NULL, output, std::numeric_limits::max(), true, - exit_code); - return result == EXECUTE_SUCCESS; -} - -} // namespace base diff --git a/base/process/launch_win.cc b/base/process/launch_win.cc deleted file mode 100644 index c5126c56fb..0000000000 --- a/base/process/launch_win.cc +++ /dev/null @@ -1,283 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "base/process/launch.h" - -#include -#include -#include -#include -#include - -#include - -#include "base/bind.h" -#include "base/bind_helpers.h" -#include "base/command_line.h" -#include "base/debug/stack_trace.h" -#include "base/logging.h" -#include "base/memory/scoped_ptr.h" -#include "base/message_loop/message_loop.h" -#include "base/metrics/histogram.h" -#include "base/process/kill.h" -#include "base/sys_info.h" -#include "base/win/object_watcher.h" -#include "base/win/scoped_handle.h" -#include "base/win/scoped_process_information.h" -#include "base/win/windows_version.h" - -// userenv.dll is required for CreateEnvironmentBlock(). -#pragma comment(lib, "userenv.lib") - -namespace base { - -namespace { - -// This exit code is used by the Windows task manager when it kills a -// process. It's value is obviously not that unique, and it's -// surprising to me that the task manager uses this value, but it -// seems to be common practice on Windows to test for it as an -// indication that the task manager has killed something if the -// process goes away. -const DWORD kProcessKilledExitCode = 1; - -} // namespace - -void RouteStdioToConsole() { - // Don't change anything if stdout or stderr already point to a - // valid stream. - // - // If we are running under Buildbot or under Cygwin's default - // terminal (mintty), stderr and stderr will be pipe handles. In - // that case, we don't want to open CONOUT$, because its output - // likely does not go anywhere. - // - // We don't use GetStdHandle() to check stdout/stderr here because - // it can return dangling IDs of handles that were never inherited - // by this process. These IDs could have been reused by the time - // this function is called. The CRT checks the validity of - // stdout/stderr on startup (before the handle IDs can be reused). - // _fileno(stdout) will return -2 (_NO_CONSOLE_FILENO) if stdout was - // invalid. - if (_fileno(stdout) >= 0 || _fileno(stderr) >= 0) - return; - - if (!AttachConsole(ATTACH_PARENT_PROCESS)) { - unsigned int result = GetLastError(); - // Was probably already attached. - if (result == ERROR_ACCESS_DENIED) - return; - // Don't bother creating a new console for each child process if the - // parent process is invalid (eg: crashed). - if (result == ERROR_GEN_FAILURE) - return; - // Make a new console if attaching to parent fails with any other error. - // It should be ERROR_INVALID_HANDLE at this point, which means the browser - // was likely not started from a console. - AllocConsole(); - } - - // Arbitrary byte count to use when buffering output lines. More - // means potential waste, less means more risk of interleaved - // log-lines in output. - enum { kOutputBufferSize = 64 * 1024 }; - - if (freopen("CONOUT$", "w", stdout)) { - setvbuf(stdout, NULL, _IOLBF, kOutputBufferSize); - // Overwrite FD 1 for the benefit of any code that uses this FD - // directly. This is safe because the CRT allocates FDs 0, 1 and - // 2 at startup even if they don't have valid underlying Windows - // handles. This means we won't be overwriting an FD created by - // _open() after startup. - _dup2(_fileno(stdout), 1); - } - if (freopen("CONOUT$", "w", stderr)) { - setvbuf(stderr, NULL, _IOLBF, kOutputBufferSize); - _dup2(_fileno(stderr), 2); - } - - // Fix all cout, wcout, cin, wcin, cerr, wcerr, clog and wclog. - std::ios::sync_with_stdio(); -} - -bool LaunchProcess(const string16& cmdline, - const LaunchOptions& options, - ProcessHandle* process_handle) { - STARTUPINFO startup_info = {}; - startup_info.cb = sizeof(startup_info); - if (options.empty_desktop_name) - startup_info.lpDesktop = L""; - startup_info.dwFlags = STARTF_USESHOWWINDOW; - startup_info.wShowWindow = options.start_hidden ? SW_HIDE : SW_SHOW; - - if (options.stdin_handle || options.stdout_handle || options.stderr_handle) { - DCHECK(options.inherit_handles); - DCHECK(options.stdin_handle); - DCHECK(options.stdout_handle); - DCHECK(options.stderr_handle); - startup_info.dwFlags |= STARTF_USESTDHANDLES; - startup_info.hStdInput = options.stdin_handle; - startup_info.hStdOutput = options.stdout_handle; - startup_info.hStdError = options.stderr_handle; - } - - DWORD flags = 0; - - if (options.job_handle) { - flags |= CREATE_SUSPENDED; - - // If this code is run under a debugger, the launched process is - // automatically associated with a job object created by the debugger. - // The CREATE_BREAKAWAY_FROM_JOB flag is used to prevent this. - flags |= CREATE_BREAKAWAY_FROM_JOB; - } - - if (options.force_breakaway_from_job_) - flags |= CREATE_BREAKAWAY_FROM_JOB; - - base::win::ScopedProcessInformation process_info; - - if (options.as_user) { - flags |= CREATE_UNICODE_ENVIRONMENT; - void* enviroment_block = NULL; - - if (!CreateEnvironmentBlock(&enviroment_block, options.as_user, FALSE)) { - DPLOG(ERROR); - return false; - } - - BOOL launched = - CreateProcessAsUser(options.as_user, NULL, - const_cast(cmdline.c_str()), - NULL, NULL, options.inherit_handles, flags, - enviroment_block, NULL, &startup_info, - process_info.Receive()); - DestroyEnvironmentBlock(enviroment_block); - if (!launched) { - DPLOG(ERROR); - return false; - } - } else { - if (!CreateProcess(NULL, - const_cast(cmdline.c_str()), NULL, NULL, - options.inherit_handles, flags, NULL, NULL, - &startup_info, process_info.Receive())) { - DPLOG(ERROR); - return false; - } - } - - if (options.job_handle) { - if (0 == AssignProcessToJobObject(options.job_handle, - process_info.process_handle())) { - DLOG(ERROR) << "Could not AssignProcessToObject."; - KillProcess(process_info.process_handle(), kProcessKilledExitCode, true); - return false; - } - - ResumeThread(process_info.thread_handle()); - } - - if (options.wait) - WaitForSingleObject(process_info.process_handle(), INFINITE); - - // If the caller wants the process handle, we won't close it. - if (process_handle) - *process_handle = process_info.TakeProcessHandle(); - - return true; -} - -bool LaunchProcess(const CommandLine& cmdline, - const LaunchOptions& options, - ProcessHandle* process_handle) { - return LaunchProcess(cmdline.GetCommandLineString(), options, process_handle); -} - -bool SetJobObjectAsKillOnJobClose(HANDLE job_object) { - JOBOBJECT_EXTENDED_LIMIT_INFORMATION limit_info = {0}; - limit_info.BasicLimitInformation.LimitFlags = - JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE; - return 0 != SetInformationJobObject( - job_object, - JobObjectExtendedLimitInformation, - &limit_info, - sizeof(limit_info)); -} - -bool GetAppOutput(const CommandLine& cl, std::string* output) { - HANDLE out_read = NULL; - HANDLE out_write = NULL; - - SECURITY_ATTRIBUTES sa_attr; - // Set the bInheritHandle flag so pipe handles are inherited. - sa_attr.nLength = sizeof(SECURITY_ATTRIBUTES); - sa_attr.bInheritHandle = TRUE; - sa_attr.lpSecurityDescriptor = NULL; - - // Create the pipe for the child process's STDOUT. - if (!CreatePipe(&out_read, &out_write, &sa_attr, 0)) { - NOTREACHED() << "Failed to create pipe"; - return false; - } - - // Ensure we don't leak the handles. - win::ScopedHandle scoped_out_read(out_read); - win::ScopedHandle scoped_out_write(out_write); - - // Ensure the read handle to the pipe for STDOUT is not inherited. - if (!SetHandleInformation(out_read, HANDLE_FLAG_INHERIT, 0)) { - NOTREACHED() << "Failed to disabled pipe inheritance"; - return false; - } - - FilePath::StringType writable_command_line_string(cl.GetCommandLineString()); - - base::win::ScopedProcessInformation proc_info; - STARTUPINFO start_info = { 0 }; - - start_info.cb = sizeof(STARTUPINFO); - start_info.hStdOutput = out_write; - // Keep the normal stdin and stderr. - start_info.hStdInput = GetStdHandle(STD_INPUT_HANDLE); - start_info.hStdError = GetStdHandle(STD_ERROR_HANDLE); - start_info.dwFlags |= STARTF_USESTDHANDLES; - - // Create the child process. - if (!CreateProcess(NULL, - &writable_command_line_string[0], - NULL, NULL, - TRUE, // Handles are inherited. - 0, NULL, NULL, &start_info, proc_info.Receive())) { - NOTREACHED() << "Failed to start process"; - return false; - } - - // Close our writing end of pipe now. Otherwise later read would not be able - // to detect end of child's output. - scoped_out_write.Close(); - - // Read output from the child process's pipe for STDOUT - const int kBufferSize = 1024; - char buffer[kBufferSize]; - - for (;;) { - DWORD bytes_read = 0; - BOOL success = ReadFile(out_read, buffer, kBufferSize, &bytes_read, NULL); - if (!success || bytes_read == 0) - break; - output->append(buffer, bytes_read); - } - - // Let's wait for the process to finish. - WaitForSingleObject(proc_info.process_handle(), INFINITE); - - return true; -} - -void RaiseProcessToHighPriority() { - SetPriorityClass(GetCurrentProcess(), HIGH_PRIORITY_CLASS); -} - -} // namespace base diff --git a/base/process/memory.h b/base/process/memory.h deleted file mode 100644 index de79477e95..0000000000 --- a/base/process/memory.h +++ /dev/null @@ -1,69 +0,0 @@ -// Copyright (c) 2013 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef BASE_PROCESS_MEMORY_H_ -#define BASE_PROCESS_MEMORY_H_ - -#include "base/base_export.h" -#include "base/basictypes.h" -#include "base/process/process_handle.h" -#include "build/build_config.h" - -#if defined(OS_WIN) -#include -#endif - -namespace base { - -// Enables low fragmentation heap (LFH) for every heaps of this process. This -// won't have any effect on heaps created after this function call. It will not -// modify data allocated in the heaps before calling this function. So it is -// better to call this function early in initialization and again before -// entering the main loop. -// Note: Returns true on Windows 2000 without doing anything. -BASE_EXPORT bool EnableLowFragmentationHeap(); - -// Enables 'terminate on heap corruption' flag. Helps protect against heap -// overflow. Has no effect if the OS doesn't provide the necessary facility. -BASE_EXPORT void EnableTerminationOnHeapCorruption(); - -// Turns on process termination if memory runs out. -BASE_EXPORT void EnableTerminationOnOutOfMemory(); - -#if defined(OS_WIN) -// Returns the module handle to which an address belongs. The reference count -// of the module is not incremented. -BASE_EXPORT HMODULE GetModuleFromAddress(void* address); -#endif - -#if defined(OS_LINUX) || defined(OS_ANDROID) -BASE_EXPORT extern size_t g_oom_size; - -// The maximum allowed value for the OOM score. -const int kMaxOomScore = 1000; - -// This adjusts /proc//oom_score_adj so the Linux OOM killer will -// prefer to kill certain process types over others. The range for the -// adjustment is [-1000, 1000], with [0, 1000] being user accessible. -// If the Linux system doesn't support the newer oom_score_adj range -// of [0, 1000], then we revert to using the older oom_adj, and -// translate the given value into [0, 15]. Some aliasing of values -// may occur in that case, of course. -BASE_EXPORT bool AdjustOOMScore(ProcessId process, int score); -#endif - -#if defined(OS_MACOSX) -// Very large images or svg canvases can cause huge mallocs. Skia -// does tricks on tcmalloc-based systems to allow malloc to fail with -// a NULL rather than hit the oom crasher. This replicates that for -// OSX. -// -// IF YOU USE THIS WITHOUT CONSULTING YOUR FRIENDLY OSX DEVELOPER, -// YOUR CODE IS LIKELY TO BE REVERTED. THANK YOU. -BASE_EXPORT void* UncheckedMalloc(size_t size); -#endif // defined(OS_MACOSX) - -} // namespace base - -#endif // BASE_PROCESS_MEMORY_H_ diff --git a/base/process/memory_linux.cc b/base/process/memory_linux.cc deleted file mode 100644 index f81429b2ac..0000000000 --- a/base/process/memory_linux.cc +++ /dev/null @@ -1,183 +0,0 @@ -// Copyright (c) 2013 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "base/process/memory.h" - -#include - -#include "base/file_util.h" -#include "base/files/file_path.h" -#include "base/logging.h" -#include "base/process/internal_linux.h" -#include "base/strings/string_number_conversions.h" - -namespace base { - -size_t g_oom_size = 0U; - -namespace { - -void OnNoMemorySize(size_t size) { - g_oom_size = size; - - if (size != 0) - LOG(FATAL) << "Out of memory, size = " << size; - LOG(FATAL) << "Out of memory."; -} - -void OnNoMemory() { - OnNoMemorySize(0); -} - -} // namespace - -#if !defined(ADDRESS_SANITIZER) && !defined(MEMORY_SANITIZER) && \ - !defined(THREAD_SANITIZER) && !defined(LEAK_SANITIZER) - -#if defined(LIBC_GLIBC) && !defined(USE_TCMALLOC) - -extern "C" { -void* __libc_malloc(size_t size); -void* __libc_realloc(void* ptr, size_t size); -void* __libc_calloc(size_t nmemb, size_t size); -void* __libc_valloc(size_t size); -void* __libc_pvalloc(size_t size); -void* __libc_memalign(size_t alignment, size_t size); - -// Overriding the system memory allocation functions: -// -// For security reasons, we want malloc failures to be fatal. Too much code -// doesn't check for a NULL return value from malloc and unconditionally uses -// the resulting pointer. If the first offset that they try to access is -// attacker controlled, then the attacker can direct the code to access any -// part of memory. -// -// Thus, we define all the standard malloc functions here and mark them as -// visibility 'default'. This means that they replace the malloc functions for -// all Chromium code and also for all code in shared libraries. There are tests -// for this in process_util_unittest.cc. -// -// If we are using tcmalloc, then the problem is moot since tcmalloc handles -// this for us. Thus this code is in a !defined(USE_TCMALLOC) block. -// -// If we are testing the binary with AddressSanitizer, we should not -// redefine malloc and let AddressSanitizer do it instead. -// -// We call the real libc functions in this code by using __libc_malloc etc. -// Previously we tried using dlsym(RTLD_NEXT, ...) but that failed depending on -// the link order. Since ld.so needs calloc during symbol resolution, it -// defines its own versions of several of these functions in dl-minimal.c. -// Depending on the runtime library order, dlsym ended up giving us those -// functions and bad things happened. See crbug.com/31809 -// -// This means that any code which calls __libc_* gets the raw libc versions of -// these functions. - -#define DIE_ON_OOM_1(function_name) \ - void* function_name(size_t) __attribute__ ((visibility("default"))); \ - \ - void* function_name(size_t size) { \ - void* ret = __libc_##function_name(size); \ - if (ret == NULL && size != 0) \ - OnNoMemorySize(size); \ - return ret; \ - } - -#define DIE_ON_OOM_2(function_name, arg1_type) \ - void* function_name(arg1_type, size_t) \ - __attribute__ ((visibility("default"))); \ - \ - void* function_name(arg1_type arg1, size_t size) { \ - void* ret = __libc_##function_name(arg1, size); \ - if (ret == NULL && size != 0) \ - OnNoMemorySize(size); \ - return ret; \ - } - -DIE_ON_OOM_1(malloc) -DIE_ON_OOM_1(valloc) -DIE_ON_OOM_1(pvalloc) - -DIE_ON_OOM_2(calloc, size_t) -DIE_ON_OOM_2(realloc, void*) -DIE_ON_OOM_2(memalign, size_t) - -// posix_memalign has a unique signature and doesn't have a __libc_ variant. -int posix_memalign(void** ptr, size_t alignment, size_t size) - __attribute__ ((visibility("default"))); - -int posix_memalign(void** ptr, size_t alignment, size_t size) { - // This will use the safe version of memalign, above. - *ptr = memalign(alignment, size); - return 0; -} - -} // extern C - -#else - -// TODO(mostynb@opera.com): dlsym dance - -#endif // LIBC_GLIBC && !USE_TCMALLOC - -#endif // !*_SANITIZER - -void EnableTerminationOnHeapCorruption() { - // On Linux, there nothing to do AFAIK. -} - -void EnableTerminationOnOutOfMemory() { -#if defined(OS_ANDROID) - // Android doesn't support setting a new handler. - DLOG(WARNING) << "Not feasible."; -#else - // Set the new-out of memory handler. - std::set_new_handler(&OnNoMemory); - // If we're using glibc's allocator, the above functions will override - // malloc and friends and make them die on out of memory. -#endif -} - -// NOTE: This is not the only version of this function in the source: -// the setuid sandbox (in process_util_linux.c, in the sandbox source) -// also has its own C version. -bool AdjustOOMScore(ProcessId process, int score) { - if (score < 0 || score > kMaxOomScore) - return false; - - FilePath oom_path(internal::GetProcPidDir(process)); - - // Attempt to write the newer oom_score_adj file first. - FilePath oom_file = oom_path.AppendASCII("oom_score_adj"); - if (PathExists(oom_file)) { - std::string score_str = IntToString(score); - DVLOG(1) << "Adjusting oom_score_adj of " << process << " to " - << score_str; - int score_len = static_cast(score_str.length()); - return (score_len == file_util::WriteFile(oom_file, - score_str.c_str(), - score_len)); - } - - // If the oom_score_adj file doesn't exist, then we write the old - // style file and translate the oom_adj score to the range 0-15. - oom_file = oom_path.AppendASCII("oom_adj"); - if (PathExists(oom_file)) { - // Max score for the old oom_adj range. Used for conversion of new - // values to old values. - const int kMaxOldOomScore = 15; - - int converted_score = score * kMaxOldOomScore / kMaxOomScore; - std::string score_str = IntToString(converted_score); - DVLOG(1) << "Adjusting oom_adj of " << process << " to " << score_str; - int score_len = static_cast(score_str.length()); - return (score_len == file_util::WriteFile(oom_file, - score_str.c_str(), - score_len)); - } - - return false; -} - -} // namespace base diff --git a/base/process/memory_mac.mm b/base/process/memory_mac.mm deleted file mode 100644 index dd30e704c8..0000000000 --- a/base/process/memory_mac.mm +++ /dev/null @@ -1,704 +0,0 @@ -// Copyright (c) 2013 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "base/process/memory.h" - -#include -#include -#include -#include -#include -#import - -#include - -#include "base/lazy_instance.h" -#include "base/logging.h" -#include "base/mac/mac_util.h" -#include "base/scoped_clear_errno.h" -#include "third_party/apple_apsl/CFBase.h" -#include "third_party/apple_apsl/malloc.h" - -#if ARCH_CPU_32_BITS -#include -#include - -#include "base/threading/thread_local.h" -#include "third_party/mach_override/mach_override.h" -#endif // ARCH_CPU_32_BITS - -namespace base { - -// These are helpers for EnableTerminationOnHeapCorruption, which is a no-op -// on 64 bit Macs. -#if ARCH_CPU_32_BITS -namespace { - -// Finds the library path for malloc() and thus the libC part of libSystem, -// which in Lion is in a separate image. -const char* LookUpLibCPath() { - const void* addr = reinterpret_cast(&malloc); - - Dl_info info; - if (dladdr(addr, &info)) - return info.dli_fname; - - DLOG(WARNING) << "Could not find image path for malloc()"; - return NULL; -} - -typedef void(*malloc_error_break_t)(void); -malloc_error_break_t g_original_malloc_error_break = NULL; - -// Returns the function pointer for malloc_error_break. This symbol is declared -// as __private_extern__ and cannot be dlsym()ed. Instead, use nlist() to -// get it. -malloc_error_break_t LookUpMallocErrorBreak() { - const char* lib_c_path = LookUpLibCPath(); - if (!lib_c_path) - return NULL; - - // Only need to look up two symbols, but nlist() requires a NULL-terminated - // array and takes no count. - struct nlist nl[3]; - bzero(&nl, sizeof(nl)); - - // The symbol to find. - nl[0].n_un.n_name = const_cast("_malloc_error_break"); - - // A reference symbol by which the address of the desired symbol will be - // calculated. - nl[1].n_un.n_name = const_cast("_malloc"); - - int rv = nlist(lib_c_path, nl); - if (rv != 0 || nl[0].n_type == N_UNDF || nl[1].n_type == N_UNDF) { - return NULL; - } - - // nlist() returns addresses as offsets in the image, not the instruction - // pointer in memory. Use the known in-memory address of malloc() - // to compute the offset for malloc_error_break(). - uintptr_t reference_addr = reinterpret_cast(&malloc); - reference_addr -= nl[1].n_value; - reference_addr += nl[0].n_value; - - return reinterpret_cast(reference_addr); -} - -// Combines ThreadLocalBoolean with AutoReset. It would be convenient -// to compose ThreadLocalPointer with base::AutoReset, but that -// would require allocating some storage for the bool. -class ThreadLocalBooleanAutoReset { - public: - ThreadLocalBooleanAutoReset(ThreadLocalBoolean* tlb, bool new_value) - : scoped_tlb_(tlb), - original_value_(tlb->Get()) { - scoped_tlb_->Set(new_value); - } - ~ThreadLocalBooleanAutoReset() { - scoped_tlb_->Set(original_value_); - } - - private: - ThreadLocalBoolean* scoped_tlb_; - bool original_value_; - - DISALLOW_COPY_AND_ASSIGN(ThreadLocalBooleanAutoReset); -}; - -base::LazyInstance::Leaky - g_unchecked_malloc = LAZY_INSTANCE_INITIALIZER; - -// NOTE(shess): This is called when the malloc library noticed that the heap -// is fubar. Avoid calls which will re-enter the malloc library. -void CrMallocErrorBreak() { - g_original_malloc_error_break(); - - // Out of memory is certainly not heap corruption, and not necessarily - // something for which the process should be terminated. Leave that decision - // to the OOM killer. The EBADF case comes up because the malloc library - // attempts to log to ASL (syslog) before calling this code, which fails - // accessing a Unix-domain socket because of sandboxing. - if (errno == ENOMEM || (errno == EBADF && g_unchecked_malloc.Get().Get())) - return; - - // A unit test checks this error message, so it needs to be in release builds. - char buf[1024] = - "Terminating process due to a potential for future heap corruption: " - "errno="; - char errnobuf[] = { - '0' + ((errno / 100) % 10), - '0' + ((errno / 10) % 10), - '0' + (errno % 10), - '\000' - }; - COMPILE_ASSERT(ELAST <= 999, errno_too_large_to_encode); - strlcat(buf, errnobuf, sizeof(buf)); - RAW_LOG(ERROR, buf); - - // Crash by writing to NULL+errno to allow analyzing errno from - // crash dump info (setting a breakpad key would re-enter the malloc - // library). Max documented errno in intro(2) is actually 102, but - // it really just needs to be "small" to stay on the right vm page. - const int kMaxErrno = 256; - char* volatile death_ptr = NULL; - death_ptr += std::min(errno, kMaxErrno); - *death_ptr = '!'; -} - -} // namespace -#endif // ARCH_CPU_32_BITS - -void EnableTerminationOnHeapCorruption() { -#if defined(ADDRESS_SANITIZER) || ARCH_CPU_64_BITS - // AddressSanitizer handles heap corruption, and on 64 bit Macs, the malloc - // system automatically abort()s on heap corruption. - return; -#else - // Only override once, otherwise CrMallocErrorBreak() will recurse - // to itself. - if (g_original_malloc_error_break) - return; - - malloc_error_break_t malloc_error_break = LookUpMallocErrorBreak(); - if (!malloc_error_break) { - DLOG(WARNING) << "Could not find malloc_error_break"; - return; - } - - mach_error_t err = mach_override_ptr( - (void*)malloc_error_break, - (void*)&CrMallocErrorBreak, - (void**)&g_original_malloc_error_break); - - if (err != err_none) - DLOG(WARNING) << "Could not override malloc_error_break; error = " << err; -#endif // defined(ADDRESS_SANITIZER) || ARCH_CPU_64_BITS -} - -// ------------------------------------------------------------------------ - -namespace { - -bool g_oom_killer_enabled; - -// Starting with Mac OS X 10.7, the zone allocators set up by the system are -// read-only, to prevent them from being overwritten in an attack. However, -// blindly unprotecting and reprotecting the zone allocators fails with -// GuardMalloc because GuardMalloc sets up its zone allocator using a block of -// memory in its bss. Explicit saving/restoring of the protection is required. -// -// This function takes a pointer to a malloc zone, de-protects it if necessary, -// and returns (in the out parameters) a region of memory (if any) to be -// re-protected when modifications are complete. This approach assumes that -// there is no contention for the protection of this memory. -void DeprotectMallocZone(ChromeMallocZone* default_zone, - mach_vm_address_t* reprotection_start, - mach_vm_size_t* reprotection_length, - vm_prot_t* reprotection_value) { - mach_port_t unused; - *reprotection_start = reinterpret_cast(default_zone); - struct vm_region_basic_info_64 info; - mach_msg_type_number_t count = VM_REGION_BASIC_INFO_COUNT_64; - kern_return_t result = - mach_vm_region(mach_task_self(), - reprotection_start, - reprotection_length, - VM_REGION_BASIC_INFO_64, - reinterpret_cast(&info), - &count, - &unused); - CHECK(result == KERN_SUCCESS); - - result = mach_port_deallocate(mach_task_self(), unused); - CHECK(result == KERN_SUCCESS); - - // Does the region fully enclose the zone pointers? Possibly unwarranted - // simplification used: using the size of a full version 8 malloc zone rather - // than the actual smaller size if the passed-in zone is not version 8. - CHECK(*reprotection_start <= - reinterpret_cast(default_zone)); - mach_vm_size_t zone_offset = reinterpret_cast(default_zone) - - reinterpret_cast(*reprotection_start); - CHECK(zone_offset + sizeof(ChromeMallocZone) <= *reprotection_length); - - if (info.protection & VM_PROT_WRITE) { - // No change needed; the zone is already writable. - *reprotection_start = 0; - *reprotection_length = 0; - *reprotection_value = VM_PROT_NONE; - } else { - *reprotection_value = info.protection; - result = mach_vm_protect(mach_task_self(), - *reprotection_start, - *reprotection_length, - false, - info.protection | VM_PROT_WRITE); - CHECK(result == KERN_SUCCESS); - } -} - -// === C malloc/calloc/valloc/realloc/posix_memalign === - -typedef void* (*malloc_type)(struct _malloc_zone_t* zone, - size_t size); -typedef void* (*calloc_type)(struct _malloc_zone_t* zone, - size_t num_items, - size_t size); -typedef void* (*valloc_type)(struct _malloc_zone_t* zone, - size_t size); -typedef void (*free_type)(struct _malloc_zone_t* zone, - void* ptr); -typedef void* (*realloc_type)(struct _malloc_zone_t* zone, - void* ptr, - size_t size); -typedef void* (*memalign_type)(struct _malloc_zone_t* zone, - size_t alignment, - size_t size); - -malloc_type g_old_malloc; -calloc_type g_old_calloc; -valloc_type g_old_valloc; -free_type g_old_free; -realloc_type g_old_realloc; -memalign_type g_old_memalign; - -malloc_type g_old_malloc_purgeable; -calloc_type g_old_calloc_purgeable; -valloc_type g_old_valloc_purgeable; -free_type g_old_free_purgeable; -realloc_type g_old_realloc_purgeable; -memalign_type g_old_memalign_purgeable; - -void* oom_killer_malloc(struct _malloc_zone_t* zone, - size_t size) { -#if ARCH_CPU_32_BITS - ScopedClearErrno clear_errno; -#endif // ARCH_CPU_32_BITS - void* result = g_old_malloc(zone, size); - if (!result && size) - debug::BreakDebugger(); - return result; -} - -void* oom_killer_calloc(struct _malloc_zone_t* zone, - size_t num_items, - size_t size) { -#if ARCH_CPU_32_BITS - ScopedClearErrno clear_errno; -#endif // ARCH_CPU_32_BITS - void* result = g_old_calloc(zone, num_items, size); - if (!result && num_items && size) - debug::BreakDebugger(); - return result; -} - -void* oom_killer_valloc(struct _malloc_zone_t* zone, - size_t size) { -#if ARCH_CPU_32_BITS - ScopedClearErrno clear_errno; -#endif // ARCH_CPU_32_BITS - void* result = g_old_valloc(zone, size); - if (!result && size) - debug::BreakDebugger(); - return result; -} - -void oom_killer_free(struct _malloc_zone_t* zone, - void* ptr) { -#if ARCH_CPU_32_BITS - ScopedClearErrno clear_errno; -#endif // ARCH_CPU_32_BITS - g_old_free(zone, ptr); -} - -void* oom_killer_realloc(struct _malloc_zone_t* zone, - void* ptr, - size_t size) { -#if ARCH_CPU_32_BITS - ScopedClearErrno clear_errno; -#endif // ARCH_CPU_32_BITS - void* result = g_old_realloc(zone, ptr, size); - if (!result && size) - debug::BreakDebugger(); - return result; -} - -void* oom_killer_memalign(struct _malloc_zone_t* zone, - size_t alignment, - size_t size) { -#if ARCH_CPU_32_BITS - ScopedClearErrno clear_errno; -#endif // ARCH_CPU_32_BITS - void* result = g_old_memalign(zone, alignment, size); - // Only die if posix_memalign would have returned ENOMEM, since there are - // other reasons why NULL might be returned (see - // http://opensource.apple.com/source/Libc/Libc-583/gen/malloc.c ). - if (!result && size && alignment >= sizeof(void*) - && (alignment & (alignment - 1)) == 0) { - debug::BreakDebugger(); - } - return result; -} - -void* oom_killer_malloc_purgeable(struct _malloc_zone_t* zone, - size_t size) { -#if ARCH_CPU_32_BITS - ScopedClearErrno clear_errno; -#endif // ARCH_CPU_32_BITS - void* result = g_old_malloc_purgeable(zone, size); - if (!result && size) - debug::BreakDebugger(); - return result; -} - -void* oom_killer_calloc_purgeable(struct _malloc_zone_t* zone, - size_t num_items, - size_t size) { -#if ARCH_CPU_32_BITS - ScopedClearErrno clear_errno; -#endif // ARCH_CPU_32_BITS - void* result = g_old_calloc_purgeable(zone, num_items, size); - if (!result && num_items && size) - debug::BreakDebugger(); - return result; -} - -void* oom_killer_valloc_purgeable(struct _malloc_zone_t* zone, - size_t size) { -#if ARCH_CPU_32_BITS - ScopedClearErrno clear_errno; -#endif // ARCH_CPU_32_BITS - void* result = g_old_valloc_purgeable(zone, size); - if (!result && size) - debug::BreakDebugger(); - return result; -} - -void oom_killer_free_purgeable(struct _malloc_zone_t* zone, - void* ptr) { -#if ARCH_CPU_32_BITS - ScopedClearErrno clear_errno; -#endif // ARCH_CPU_32_BITS - g_old_free_purgeable(zone, ptr); -} - -void* oom_killer_realloc_purgeable(struct _malloc_zone_t* zone, - void* ptr, - size_t size) { -#if ARCH_CPU_32_BITS - ScopedClearErrno clear_errno; -#endif // ARCH_CPU_32_BITS - void* result = g_old_realloc_purgeable(zone, ptr, size); - if (!result && size) - debug::BreakDebugger(); - return result; -} - -void* oom_killer_memalign_purgeable(struct _malloc_zone_t* zone, - size_t alignment, - size_t size) { -#if ARCH_CPU_32_BITS - ScopedClearErrno clear_errno; -#endif // ARCH_CPU_32_BITS - void* result = g_old_memalign_purgeable(zone, alignment, size); - // Only die if posix_memalign would have returned ENOMEM, since there are - // other reasons why NULL might be returned (see - // http://opensource.apple.com/source/Libc/Libc-583/gen/malloc.c ). - if (!result && size && alignment >= sizeof(void*) - && (alignment & (alignment - 1)) == 0) { - debug::BreakDebugger(); - } - return result; -} - -// === C++ operator new === - -void oom_killer_new() { - debug::BreakDebugger(); -} - -// === Core Foundation CFAllocators === - -bool CanGetContextForCFAllocator() { - return !base::mac::IsOSLaterThanMountainLion_DontCallThis(); -} - -CFAllocatorContext* ContextForCFAllocator(CFAllocatorRef allocator) { - if (base::mac::IsOSSnowLeopard()) { - ChromeCFAllocatorLeopards* our_allocator = - const_cast( - reinterpret_cast(allocator)); - return &our_allocator->_context; - } else if (base::mac::IsOSLion() || base::mac::IsOSMountainLion()) { - ChromeCFAllocatorLions* our_allocator = - const_cast( - reinterpret_cast(allocator)); - return &our_allocator->_context; - } else { - return NULL; - } -} - -CFAllocatorAllocateCallBack g_old_cfallocator_system_default; -CFAllocatorAllocateCallBack g_old_cfallocator_malloc; -CFAllocatorAllocateCallBack g_old_cfallocator_malloc_zone; - -void* oom_killer_cfallocator_system_default(CFIndex alloc_size, - CFOptionFlags hint, - void* info) { - void* result = g_old_cfallocator_system_default(alloc_size, hint, info); - if (!result) - debug::BreakDebugger(); - return result; -} - -void* oom_killer_cfallocator_malloc(CFIndex alloc_size, - CFOptionFlags hint, - void* info) { - void* result = g_old_cfallocator_malloc(alloc_size, hint, info); - if (!result) - debug::BreakDebugger(); - return result; -} - -void* oom_killer_cfallocator_malloc_zone(CFIndex alloc_size, - CFOptionFlags hint, - void* info) { - void* result = g_old_cfallocator_malloc_zone(alloc_size, hint, info); - if (!result) - debug::BreakDebugger(); - return result; -} - -// === Cocoa NSObject allocation === - -typedef id (*allocWithZone_t)(id, SEL, NSZone*); -allocWithZone_t g_old_allocWithZone; - -id oom_killer_allocWithZone(id self, SEL _cmd, NSZone* zone) -{ - id result = g_old_allocWithZone(self, _cmd, zone); - if (!result) - debug::BreakDebugger(); - return result; -} - -} // namespace - -void* UncheckedMalloc(size_t size) { - if (g_old_malloc) { -#if ARCH_CPU_32_BITS - ScopedClearErrno clear_errno; - ThreadLocalBooleanAutoReset flag(g_unchecked_malloc.Pointer(), true); -#endif // ARCH_CPU_32_BITS - return g_old_malloc(malloc_default_zone(), size); - } - return malloc(size); -} - -void EnableTerminationOnOutOfMemory() { - if (g_oom_killer_enabled) - return; - - g_oom_killer_enabled = true; - - // === C malloc/calloc/valloc/realloc/posix_memalign === - - // This approach is not perfect, as requests for amounts of memory larger than - // MALLOC_ABSOLUTE_MAX_SIZE (currently SIZE_T_MAX - (2 * PAGE_SIZE)) will - // still fail with a NULL rather than dying (see - // http://opensource.apple.com/source/Libc/Libc-583/gen/malloc.c for details). - // Unfortunately, it's the best we can do. Also note that this does not affect - // allocations from non-default zones. - - CHECK(!g_old_malloc && !g_old_calloc && !g_old_valloc && !g_old_realloc && - !g_old_memalign) << "Old allocators unexpectedly non-null"; - - CHECK(!g_old_malloc_purgeable && !g_old_calloc_purgeable && - !g_old_valloc_purgeable && !g_old_realloc_purgeable && - !g_old_memalign_purgeable) << "Old allocators unexpectedly non-null"; - -#if !defined(ADDRESS_SANITIZER) - // Don't do anything special on OOM for the malloc zones replaced by - // AddressSanitizer, as modifying or protecting them may not work correctly. - - ChromeMallocZone* default_zone = - reinterpret_cast(malloc_default_zone()); - ChromeMallocZone* purgeable_zone = - reinterpret_cast(malloc_default_purgeable_zone()); - - mach_vm_address_t default_reprotection_start = 0; - mach_vm_size_t default_reprotection_length = 0; - vm_prot_t default_reprotection_value = VM_PROT_NONE; - DeprotectMallocZone(default_zone, - &default_reprotection_start, - &default_reprotection_length, - &default_reprotection_value); - - mach_vm_address_t purgeable_reprotection_start = 0; - mach_vm_size_t purgeable_reprotection_length = 0; - vm_prot_t purgeable_reprotection_value = VM_PROT_NONE; - if (purgeable_zone) { - DeprotectMallocZone(purgeable_zone, - &purgeable_reprotection_start, - &purgeable_reprotection_length, - &purgeable_reprotection_value); - } - - // Default zone - - g_old_malloc = default_zone->malloc; - g_old_calloc = default_zone->calloc; - g_old_valloc = default_zone->valloc; - g_old_free = default_zone->free; - g_old_realloc = default_zone->realloc; - CHECK(g_old_malloc && g_old_calloc && g_old_valloc && g_old_free && - g_old_realloc) - << "Failed to get system allocation functions."; - - default_zone->malloc = oom_killer_malloc; - default_zone->calloc = oom_killer_calloc; - default_zone->valloc = oom_killer_valloc; - default_zone->free = oom_killer_free; - default_zone->realloc = oom_killer_realloc; - - if (default_zone->version >= 5) { - g_old_memalign = default_zone->memalign; - if (g_old_memalign) - default_zone->memalign = oom_killer_memalign; - } - - // Purgeable zone (if it exists) - - if (purgeable_zone) { - g_old_malloc_purgeable = purgeable_zone->malloc; - g_old_calloc_purgeable = purgeable_zone->calloc; - g_old_valloc_purgeable = purgeable_zone->valloc; - g_old_free_purgeable = purgeable_zone->free; - g_old_realloc_purgeable = purgeable_zone->realloc; - CHECK(g_old_malloc_purgeable && g_old_calloc_purgeable && - g_old_valloc_purgeable && g_old_free_purgeable && - g_old_realloc_purgeable) - << "Failed to get system allocation functions."; - - purgeable_zone->malloc = oom_killer_malloc_purgeable; - purgeable_zone->calloc = oom_killer_calloc_purgeable; - purgeable_zone->valloc = oom_killer_valloc_purgeable; - purgeable_zone->free = oom_killer_free_purgeable; - purgeable_zone->realloc = oom_killer_realloc_purgeable; - - if (purgeable_zone->version >= 5) { - g_old_memalign_purgeable = purgeable_zone->memalign; - if (g_old_memalign_purgeable) - purgeable_zone->memalign = oom_killer_memalign_purgeable; - } - } - - // Restore protection if it was active. - - if (default_reprotection_start) { - kern_return_t result = mach_vm_protect(mach_task_self(), - default_reprotection_start, - default_reprotection_length, - false, - default_reprotection_value); - CHECK(result == KERN_SUCCESS); - } - - if (purgeable_reprotection_start) { - kern_return_t result = mach_vm_protect(mach_task_self(), - purgeable_reprotection_start, - purgeable_reprotection_length, - false, - purgeable_reprotection_value); - CHECK(result == KERN_SUCCESS); - } -#endif - - // === C malloc_zone_batch_malloc === - - // batch_malloc is omitted because the default malloc zone's implementation - // only supports batch_malloc for "tiny" allocations from the free list. It - // will fail for allocations larger than "tiny", and will only allocate as - // many blocks as it's able to from the free list. These factors mean that it - // can return less than the requested memory even in a non-out-of-memory - // situation. There's no good way to detect whether a batch_malloc failure is - // due to these other factors, or due to genuine memory or address space - // exhaustion. The fact that it only allocates space from the "tiny" free list - // means that it's likely that a failure will not be due to memory exhaustion. - // Similarly, these constraints on batch_malloc mean that callers must always - // be expecting to receive less memory than was requested, even in situations - // where memory pressure is not a concern. Finally, the only public interface - // to batch_malloc is malloc_zone_batch_malloc, which is specific to the - // system's malloc implementation. It's unlikely that anyone's even heard of - // it. - - // === C++ operator new === - - // Yes, operator new does call through to malloc, but this will catch failures - // that our imperfect handling of malloc cannot. - - std::set_new_handler(oom_killer_new); - -#ifndef ADDRESS_SANITIZER - // === Core Foundation CFAllocators === - - // This will not catch allocation done by custom allocators, but will catch - // all allocation done by system-provided ones. - - CHECK(!g_old_cfallocator_system_default && !g_old_cfallocator_malloc && - !g_old_cfallocator_malloc_zone) - << "Old allocators unexpectedly non-null"; - - bool cf_allocator_internals_known = CanGetContextForCFAllocator(); - - if (cf_allocator_internals_known) { - CFAllocatorContext* context = - ContextForCFAllocator(kCFAllocatorSystemDefault); - CHECK(context) << "Failed to get context for kCFAllocatorSystemDefault."; - g_old_cfallocator_system_default = context->allocate; - CHECK(g_old_cfallocator_system_default) - << "Failed to get kCFAllocatorSystemDefault allocation function."; - context->allocate = oom_killer_cfallocator_system_default; - - context = ContextForCFAllocator(kCFAllocatorMalloc); - CHECK(context) << "Failed to get context for kCFAllocatorMalloc."; - g_old_cfallocator_malloc = context->allocate; - CHECK(g_old_cfallocator_malloc) - << "Failed to get kCFAllocatorMalloc allocation function."; - context->allocate = oom_killer_cfallocator_malloc; - - context = ContextForCFAllocator(kCFAllocatorMallocZone); - CHECK(context) << "Failed to get context for kCFAllocatorMallocZone."; - g_old_cfallocator_malloc_zone = context->allocate; - CHECK(g_old_cfallocator_malloc_zone) - << "Failed to get kCFAllocatorMallocZone allocation function."; - context->allocate = oom_killer_cfallocator_malloc_zone; - } else { - NSLog(@"Internals of CFAllocator not known; out-of-memory failures via " - "CFAllocator will not result in termination. http://crbug.com/45650"); - } -#endif - - // === Cocoa NSObject allocation === - - // Note that both +[NSObject new] and +[NSObject alloc] call through to - // +[NSObject allocWithZone:]. - - CHECK(!g_old_allocWithZone) - << "Old allocator unexpectedly non-null"; - - Class nsobject_class = [NSObject class]; - Method orig_method = class_getClassMethod(nsobject_class, - @selector(allocWithZone:)); - g_old_allocWithZone = reinterpret_cast( - method_getImplementation(orig_method)); - CHECK(g_old_allocWithZone) - << "Failed to get allocWithZone allocation function."; - method_setImplementation(orig_method, - reinterpret_cast(oom_killer_allocWithZone)); -} - -} // namespace base diff --git a/base/process/memory_stubs.cc b/base/process/memory_stubs.cc deleted file mode 100644 index b06c7d5f2b..0000000000 --- a/base/process/memory_stubs.cc +++ /dev/null @@ -1,19 +0,0 @@ -// Copyright (c) 2013 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "base/process/memory.h" - -namespace base { - -void EnableTerminationOnOutOfMemory() { -} - -void EnableTerminationOnHeapCorruption() { -} - -bool AdjustOOMScore(ProcessId process, int score) { - return false; -} - -} // namespace base diff --git a/base/process/memory_unittest.cc b/base/process/memory_unittest.cc deleted file mode 100644 index a1f30526aa..0000000000 --- a/base/process/memory_unittest.cc +++ /dev/null @@ -1,379 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#define _CRT_SECURE_NO_WARNINGS - -#include "base/process/memory.h" - -#include - -#include "base/compiler_specific.h" -#include "base/debug/alias.h" -#include "testing/gtest/include/gtest/gtest.h" - -#if defined(OS_WIN) -#include -#endif -#if defined(OS_POSIX) -#include -#endif -#if defined(OS_MACOSX) -#include -#include "base/process/memory_unittest_mac.h" -#endif -#if defined(OS_LINUX) -#include -#include -#endif - -#if defined(OS_WIN) -// HeapQueryInformation function pointer. -typedef BOOL (WINAPI* HeapQueryFn) \ - (HANDLE, HEAP_INFORMATION_CLASS, PVOID, SIZE_T, PSIZE_T); - -const int kConstantInModule = 42; - -TEST(ProcessMemoryTest, GetModuleFromAddress) { - // Since the unit tests are their own EXE, this should be - // equivalent to the EXE's HINSTANCE. - // - // kConstantInModule is a constant in this file and - // therefore within the unit test EXE. - EXPECT_EQ(::GetModuleHandle(NULL), - base::GetModuleFromAddress( - const_cast(&kConstantInModule))); - - // Any address within the kernel32 module should return - // kernel32's HMODULE. Our only assumption here is that - // kernel32 is larger than 4 bytes. - HMODULE kernel32 = ::GetModuleHandle(L"kernel32.dll"); - HMODULE kernel32_from_address = - base::GetModuleFromAddress(reinterpret_cast(kernel32) + 1); - EXPECT_EQ(kernel32, kernel32_from_address); -} - -TEST(ProcessMemoryTest, EnableLFH) { - ASSERT_TRUE(base::EnableLowFragmentationHeap()); - if (IsDebuggerPresent()) { - // Under these conditions, LFH can't be enabled. There's no point to test - // anything. - const char* no_debug_env = getenv("_NO_DEBUG_HEAP"); - if (!no_debug_env || strcmp(no_debug_env, "1")) - return; - } - HMODULE kernel32 = GetModuleHandle(L"kernel32.dll"); - ASSERT_TRUE(kernel32 != NULL); - HeapQueryFn heap_query = reinterpret_cast(GetProcAddress( - kernel32, - "HeapQueryInformation")); - - // On Windows 2000, the function is not exported. This is not a reason to - // fail but we won't be able to retrieves information about the heap, so we - // should stop here. - if (heap_query == NULL) - return; - - HANDLE heaps[1024] = { 0 }; - unsigned number_heaps = GetProcessHeaps(1024, heaps); - EXPECT_GT(number_heaps, 0u); - for (unsigned i = 0; i < number_heaps; ++i) { - ULONG flag = 0; - SIZE_T length; - ASSERT_NE(0, heap_query(heaps[i], - HeapCompatibilityInformation, - &flag, - sizeof(flag), - &length)); - // If flag is 0, the heap is a standard heap that does not support - // look-asides. If flag is 1, the heap supports look-asides. If flag is 2, - // the heap is a low-fragmentation heap (LFH). Note that look-asides are not - // supported on the LFH. - - // We don't have any documented way of querying the HEAP_NO_SERIALIZE flag. - EXPECT_LE(flag, 2u); - EXPECT_NE(flag, 1u); - } -} -#endif // defined(OS_WIN) - -#if defined(OS_MACOSX) - -// For the following Mac tests: -// Note that base::EnableTerminationOnHeapCorruption() is called as part of -// test suite setup and does not need to be done again, else mach_override -// will fail. - -#if !defined(ADDRESS_SANITIZER) -// The following code tests the system implementation of malloc() thus no need -// to test it under AddressSanitizer. -TEST(ProcessMemoryTest, MacMallocFailureDoesNotTerminate) { - // Test that ENOMEM doesn't crash via CrMallocErrorBreak two ways: the exit - // code and lack of the error string. The number of bytes is one less than - // MALLOC_ABSOLUTE_MAX_SIZE, more than which the system early-returns NULL and - // does not call through malloc_error_break(). See the comment at - // EnableTerminationOnOutOfMemory() for more information. - void* buf = NULL; - ASSERT_EXIT( - { - base::EnableTerminationOnOutOfMemory(); - - buf = malloc(std::numeric_limits::max() - (2 * PAGE_SIZE) - 1); - }, - testing::KilledBySignal(SIGTRAP), - "\\*\\*\\* error: can't allocate region.*" - "(Terminating process due to a potential for future heap " - "corruption){0}"); - - base::debug::Alias(buf); -} -#endif // !defined(ADDRESS_SANITIZER) - -TEST(ProcessMemoryTest, MacTerminateOnHeapCorruption) { - // Assert that freeing an unallocated pointer will crash the process. - char buf[9]; - asm("" : "=r" (buf)); // Prevent clang from being too smart. -#if ARCH_CPU_64_BITS - // On 64 bit Macs, the malloc system automatically abort()s on heap corruption - // but does not output anything. - ASSERT_DEATH(free(buf), ""); -#elif defined(ADDRESS_SANITIZER) - // AddressSanitizer replaces malloc() and prints a different error message on - // heap corruption. - ASSERT_DEATH(free(buf), "attempting free on address which " - "was not malloc\\(\\)-ed"); -#else - ASSERT_DEATH(free(buf), "being freed.*" - "\\*\\*\\* set a breakpoint in malloc_error_break to debug.*" - "Terminating process due to a potential for future heap corruption"); -#endif // ARCH_CPU_64_BITS || defined(ADDRESS_SANITIZER) -} - -#endif // defined(OS_MACOSX) - -// Android doesn't implement set_new_handler, so we can't use the -// OutOfMemoryTest cases. -// OpenBSD does not support these tests either. -// AddressSanitizer and ThreadSanitizer define the malloc()/free()/etc. -// functions so that they don't crash if the program is out of memory, so the -// OOM tests aren't supposed to work. -// TODO(vandebo) make this work on Windows too. -#if !defined(OS_ANDROID) && !defined(OS_OPENBSD) && \ - !defined(OS_WIN) && \ - !defined(ADDRESS_SANITIZER) && !defined(THREAD_SANITIZER) - -#if defined(USE_TCMALLOC) -extern "C" { -int tc_set_new_mode(int mode); -} -#endif // defined(USE_TCMALLOC) - -class OutOfMemoryDeathTest : public testing::Test { - public: - OutOfMemoryDeathTest() - : value_(NULL), - // Make test size as large as possible minus a few pages so - // that alignment or other rounding doesn't make it wrap. - test_size_(std::numeric_limits::max() - 12 * 1024), - signed_test_size_(std::numeric_limits::max()) { - } - -#if defined(USE_TCMALLOC) - virtual void SetUp() OVERRIDE { - tc_set_new_mode(1); - } - - virtual void TearDown() OVERRIDE { - tc_set_new_mode(0); - } -#endif // defined(USE_TCMALLOC) - - void SetUpInDeathAssert() { - // Must call EnableTerminationOnOutOfMemory() because that is called from - // chrome's main function and therefore hasn't been called yet. - // Since this call may result in another thread being created and death - // tests shouldn't be started in a multithread environment, this call - // should be done inside of the ASSERT_DEATH. - base::EnableTerminationOnOutOfMemory(); - } - - void* value_; - size_t test_size_; - ssize_t signed_test_size_; -}; - -TEST_F(OutOfMemoryDeathTest, New) { - ASSERT_DEATH({ - SetUpInDeathAssert(); - value_ = operator new(test_size_); - }, ""); -} - -TEST_F(OutOfMemoryDeathTest, NewArray) { - ASSERT_DEATH({ - SetUpInDeathAssert(); - value_ = new char[test_size_]; - }, ""); -} - -TEST_F(OutOfMemoryDeathTest, Malloc) { - ASSERT_DEATH({ - SetUpInDeathAssert(); - value_ = malloc(test_size_); - }, ""); -} - -TEST_F(OutOfMemoryDeathTest, Realloc) { - ASSERT_DEATH({ - SetUpInDeathAssert(); - value_ = realloc(NULL, test_size_); - }, ""); -} - -TEST_F(OutOfMemoryDeathTest, Calloc) { - ASSERT_DEATH({ - SetUpInDeathAssert(); - value_ = calloc(1024, test_size_ / 1024L); - }, ""); -} - -TEST_F(OutOfMemoryDeathTest, Valloc) { - ASSERT_DEATH({ - SetUpInDeathAssert(); - value_ = valloc(test_size_); - }, ""); -} - -#if defined(OS_LINUX) -TEST_F(OutOfMemoryDeathTest, Pvalloc) { - ASSERT_DEATH({ - SetUpInDeathAssert(); - value_ = pvalloc(test_size_); - }, ""); -} - -TEST_F(OutOfMemoryDeathTest, Memalign) { - ASSERT_DEATH({ - SetUpInDeathAssert(); - value_ = memalign(4, test_size_); - }, ""); -} - -TEST_F(OutOfMemoryDeathTest, ViaSharedLibraries) { - // g_try_malloc is documented to return NULL on failure. (g_malloc is the - // 'safe' default that crashes if allocation fails). However, since we have - // hopefully overridden malloc, even g_try_malloc should fail. This tests - // that the run-time symbol resolution is overriding malloc for shared - // libraries as well as for our code. - ASSERT_DEATH({ - SetUpInDeathAssert(); - value_ = g_try_malloc(test_size_); - }, ""); -} -#endif // OS_LINUX - -// Android doesn't implement posix_memalign(). -#if defined(OS_POSIX) && !defined(OS_ANDROID) -TEST_F(OutOfMemoryDeathTest, Posix_memalign) { - // Grab the return value of posix_memalign to silence a compiler warning - // about unused return values. We don't actually care about the return - // value, since we're asserting death. - ASSERT_DEATH({ - SetUpInDeathAssert(); - EXPECT_EQ(ENOMEM, posix_memalign(&value_, 8, test_size_)); - }, ""); -} -#endif // defined(OS_POSIX) && !defined(OS_ANDROID) - -#if defined(OS_MACOSX) - -// Purgeable zone tests - -TEST_F(OutOfMemoryDeathTest, MallocPurgeable) { - malloc_zone_t* zone = malloc_default_purgeable_zone(); - ASSERT_DEATH({ - SetUpInDeathAssert(); - value_ = malloc_zone_malloc(zone, test_size_); - }, ""); -} - -TEST_F(OutOfMemoryDeathTest, ReallocPurgeable) { - malloc_zone_t* zone = malloc_default_purgeable_zone(); - ASSERT_DEATH({ - SetUpInDeathAssert(); - value_ = malloc_zone_realloc(zone, NULL, test_size_); - }, ""); -} - -TEST_F(OutOfMemoryDeathTest, CallocPurgeable) { - malloc_zone_t* zone = malloc_default_purgeable_zone(); - ASSERT_DEATH({ - SetUpInDeathAssert(); - value_ = malloc_zone_calloc(zone, 1024, test_size_ / 1024L); - }, ""); -} - -TEST_F(OutOfMemoryDeathTest, VallocPurgeable) { - malloc_zone_t* zone = malloc_default_purgeable_zone(); - ASSERT_DEATH({ - SetUpInDeathAssert(); - value_ = malloc_zone_valloc(zone, test_size_); - }, ""); -} - -TEST_F(OutOfMemoryDeathTest, PosixMemalignPurgeable) { - malloc_zone_t* zone = malloc_default_purgeable_zone(); - ASSERT_DEATH({ - SetUpInDeathAssert(); - value_ = malloc_zone_memalign(zone, 8, test_size_); - }, ""); -} - -// Since these allocation functions take a signed size, it's possible that -// calling them just once won't be enough to exhaust memory. In the 32-bit -// environment, it's likely that these allocation attempts will fail because -// not enough contiguous address space is available. In the 64-bit environment, -// it's likely that they'll fail because they would require a preposterous -// amount of (virtual) memory. - -TEST_F(OutOfMemoryDeathTest, CFAllocatorSystemDefault) { - ASSERT_DEATH({ - SetUpInDeathAssert(); - while ((value_ = - base::AllocateViaCFAllocatorSystemDefault(signed_test_size_))) {} - }, ""); -} - -TEST_F(OutOfMemoryDeathTest, CFAllocatorMalloc) { - ASSERT_DEATH({ - SetUpInDeathAssert(); - while ((value_ = - base::AllocateViaCFAllocatorMalloc(signed_test_size_))) {} - }, ""); -} - -TEST_F(OutOfMemoryDeathTest, CFAllocatorMallocZone) { - ASSERT_DEATH({ - SetUpInDeathAssert(); - while ((value_ = - base::AllocateViaCFAllocatorMallocZone(signed_test_size_))) {} - }, ""); -} - -#if !defined(ARCH_CPU_64_BITS) - -// See process_util_unittest_mac.mm for an explanation of why this test isn't -// run in the 64-bit environment. - -TEST_F(OutOfMemoryDeathTest, PsychoticallyBigObjCObject) { - ASSERT_DEATH({ - SetUpInDeathAssert(); - while ((value_ = base::AllocatePsychoticallyBigObjCObject())) {} - }, ""); -} - -#endif // !ARCH_CPU_64_BITS -#endif // OS_MACOSX - -#endif // !defined(OS_ANDROID) && !defined(OS_OPENBSD) && - // !defined(OS_WIN) && !defined(ADDRESS_SANITIZER) diff --git a/base/process/memory_unittest_mac.h b/base/process/memory_unittest_mac.h deleted file mode 100644 index 472d2c5962..0000000000 --- a/base/process/memory_unittest_mac.h +++ /dev/null @@ -1,32 +0,0 @@ -// Copyright (c) 2010 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -// This file contains helpers for the process_util_unittest to allow it to fully -// test the Mac code. - -#ifndef BASE_PROCESS_MEMORY_UNITTEST_MAC_H_ -#define BASE_PROCESS_MEMORY_UNITTEST_MAC_H_ - -#include "base/basictypes.h" - -namespace base { - -// Allocates memory via system allocators. Alas, they take a _signed_ size for -// allocation. -void* AllocateViaCFAllocatorSystemDefault(ssize_t size); -void* AllocateViaCFAllocatorMalloc(ssize_t size); -void* AllocateViaCFAllocatorMallocZone(ssize_t size); - -#if !defined(ARCH_CPU_64_BITS) -// See process_util_unittest_mac.mm for an explanation of why this function -// isn't implemented for the 64-bit environment. - -// Allocates a huge Objective C object. -void* AllocatePsychoticallyBigObjCObject(); - -#endif // !ARCH_CPU_64_BITS - -} // namespace base - -#endif // BASE_PROCESS_MEMORY_UNITTEST_MAC_H_ diff --git a/base/process/memory_unittest_mac.mm b/base/process/memory_unittest_mac.mm deleted file mode 100644 index bc4bf65347..0000000000 --- a/base/process/memory_unittest_mac.mm +++ /dev/null @@ -1,59 +0,0 @@ -// Copyright (c) 2010 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "base/process/memory_unittest_mac.h" - -#import -#include - -#if !defined(ARCH_CPU_64_BITS) - -// In the 64-bit environment, the Objective-C 2.0 Runtime Reference states -// that sizeof(anInstance) is constrained to 32 bits. That's not necessarily -// "psychotically big" and in fact a 64-bit program is expected to be able to -// successfully allocate an object that large, likely reserving a good deal of -// swap space. The only way to test the behavior of memory exhaustion for -// Objective-C allocation in this environment would be to loop over allocation -// of these large objects, but that would slowly consume all available memory -// and cause swap file proliferation. That's bad, so this behavior isn't -// tested in the 64-bit environment. - -@interface PsychoticallyBigObjCObject : NSObject -{ - // In the 32-bit environment, the compiler limits Objective-C objects to - // < 2GB in size. - int justUnder2Gigs_[(2U * 1024 * 1024 * 1024 - 1) / sizeof(int)]; -} - -@end - -@implementation PsychoticallyBigObjCObject - -@end - -namespace base { - -void* AllocatePsychoticallyBigObjCObject() { - return [[PsychoticallyBigObjCObject alloc] init]; -} - -} // namespace base - -#endif // ARCH_CPU_64_BITS - -namespace base { - -void* AllocateViaCFAllocatorSystemDefault(ssize_t size) { - return CFAllocatorAllocate(kCFAllocatorSystemDefault, size, 0); -} - -void* AllocateViaCFAllocatorMalloc(ssize_t size) { - return CFAllocatorAllocate(kCFAllocatorMalloc, size, 0); -} - -void* AllocateViaCFAllocatorMallocZone(ssize_t size) { - return CFAllocatorAllocate(kCFAllocatorMallocZone, size, 0); -} - -} // namespace base diff --git a/base/process/memory_win.cc b/base/process/memory_win.cc deleted file mode 100644 index c53a1be539..0000000000 --- a/base/process/memory_win.cc +++ /dev/null @@ -1,85 +0,0 @@ -// Copyright (c) 2013 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "base/process/memory.h" - -#include - -#include "base/logging.h" -#include "base/memory/scoped_ptr.h" - -namespace base { - -namespace { - -void OnNoMemory() { - // Kill the process. This is important for security, since WebKit doesn't - // NULL-check many memory allocations. If a malloc fails, returns NULL, and - // the buffer is then used, it provides a handy mapping of memory starting at - // address 0 for an attacker to utilize. - __debugbreak(); - _exit(1); -} - -// HeapSetInformation function pointer. -typedef BOOL (WINAPI* HeapSetFn)(HANDLE, HEAP_INFORMATION_CLASS, PVOID, SIZE_T); - -} // namespace - -bool EnableLowFragmentationHeap() { - HMODULE kernel32 = GetModuleHandle(L"kernel32.dll"); - HeapSetFn heap_set = reinterpret_cast(GetProcAddress( - kernel32, - "HeapSetInformation")); - - // On Windows 2000, the function is not exported. This is not a reason to - // fail. - if (!heap_set) - return true; - - unsigned number_heaps = GetProcessHeaps(0, NULL); - if (!number_heaps) - return false; - - // Gives us some extra space in the array in case a thread is creating heaps - // at the same time we're querying them. - static const int MARGIN = 8; - scoped_ptr heaps(new HANDLE[number_heaps + MARGIN]); - number_heaps = GetProcessHeaps(number_heaps + MARGIN, heaps.get()); - if (!number_heaps) - return false; - - for (unsigned i = 0; i < number_heaps; ++i) { - ULONG lfh_flag = 2; - // Don't bother with the result code. It may fails on heaps that have the - // HEAP_NO_SERIALIZE flag. This is expected and not a problem at all. - heap_set(heaps[i], - HeapCompatibilityInformation, - &lfh_flag, - sizeof(lfh_flag)); - } - return true; -} - -void EnableTerminationOnHeapCorruption() { - // Ignore the result code. Supported on XP SP3 and Vista. - HeapSetInformation(NULL, HeapEnableTerminationOnCorruption, NULL, 0); -} - -void EnableTerminationOnOutOfMemory() { - std::set_new_handler(&OnNoMemory); -} - -HMODULE GetModuleFromAddress(void* address) { - HMODULE instance = NULL; - if (!::GetModuleHandleExA(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS | - GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT, - static_cast(address), - &instance)) { - NOTREACHED(); - } - return instance; -} - -} // namespace base diff --git a/base/process/process.h b/base/process/process.h deleted file mode 100644 index 20e8884b97..0000000000 --- a/base/process/process.h +++ /dev/null @@ -1,70 +0,0 @@ -// Copyright (c) 2011 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef BASE_PROCESS_PROCESS_PROCESS_H_ -#define BASE_PROCESS_PROCESS_PROCESS_H_ - -#include "base/base_export.h" -#include "base/basictypes.h" -#include "base/process/process_handle.h" -#include "build/build_config.h" - -namespace base { - -class BASE_EXPORT Process { - public: - Process() : process_(kNullProcessHandle) { - } - - explicit Process(ProcessHandle handle) : process_(handle) { - } - - // A handle to the current process. - static Process Current(); - - static bool CanBackgroundProcesses(); - - // Get/Set the handle for this process. The handle will be 0 if the process - // is no longer running. - ProcessHandle handle() const { return process_; } - void set_handle(ProcessHandle handle) { - process_ = handle; - } - - // Get the PID for this process. - ProcessId pid() const; - - // Is the this process the current process. - bool is_current() const; - - // Close the process handle. This will not terminate the process. - void Close(); - - // Terminates the process with extreme prejudice. The given result code will - // be the exit code of the process. If the process has already exited, this - // will do nothing. - void Terminate(int result_code); - - // A process is backgrounded when it's priority is lower than normal. - // Return true if this process is backgrounded, false otherwise. - bool IsProcessBackgrounded() const; - - // Set a process as backgrounded. If value is true, the priority - // of the process will be lowered. If value is false, the priority - // of the process will be made "normal" - equivalent to default - // process priority. - // Returns true if the priority was changed, false otherwise. - bool SetProcessBackgrounded(bool value); - - // Returns an integer representing the priority of a process. The meaning - // of this value is OS dependent. - int GetPriority() const; - - private: - ProcessHandle process_; -}; - -} // namespace base - -#endif // BASE_PROCESS_PROCESS_PROCESS_H_ diff --git a/base/process/process_handle.h b/base/process/process_handle.h deleted file mode 100644 index a37784275e..0000000000 --- a/base/process/process_handle.h +++ /dev/null @@ -1,96 +0,0 @@ -// Copyright (c) 2013 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef BASE_PROCESS_PROCESS_HANDLE_H_ -#define BASE_PROCESS_PROCESS_HANDLE_H_ - -#include "base/base_export.h" -#include "base/basictypes.h" -#include "base/files/file_path.h" -#include "build/build_config.h" - -#include -#if defined(OS_WIN) -#include -#endif - -namespace base { - -// ProcessHandle is a platform specific type which represents the underlying OS -// handle to a process. -// ProcessId is a number which identifies the process in the OS. -#if defined(OS_WIN) -typedef HANDLE ProcessHandle; -typedef DWORD ProcessId; -typedef HANDLE UserTokenHandle; -const ProcessHandle kNullProcessHandle = NULL; -const ProcessId kNullProcessId = 0; -#elif defined(OS_POSIX) -// On POSIX, our ProcessHandle will just be the PID. -typedef pid_t ProcessHandle; -typedef pid_t ProcessId; -const ProcessHandle kNullProcessHandle = 0; -const ProcessId kNullProcessId = 0; -#endif // defined(OS_WIN) - -// Returns the id of the current process. -BASE_EXPORT ProcessId GetCurrentProcId(); - -// Returns the ProcessHandle of the current process. -BASE_EXPORT ProcessHandle GetCurrentProcessHandle(); - -// Converts a PID to a process handle. This handle must be closed by -// CloseProcessHandle when you are done with it. Returns true on success. -BASE_EXPORT bool OpenProcessHandle(ProcessId pid, ProcessHandle* handle); - -// Converts a PID to a process handle. On Windows the handle is opened -// with more access rights and must only be used by trusted code. -// You have to close returned handle using CloseProcessHandle. Returns true -// on success. -// TODO(sanjeevr): Replace all calls to OpenPrivilegedProcessHandle with the -// more specific OpenProcessHandleWithAccess method and delete this. -BASE_EXPORT bool OpenPrivilegedProcessHandle(ProcessId pid, - ProcessHandle* handle); - -// Converts a PID to a process handle using the desired access flags. Use a -// combination of the kProcessAccess* flags defined above for |access_flags|. -BASE_EXPORT bool OpenProcessHandleWithAccess(ProcessId pid, - uint32 access_flags, - ProcessHandle* handle); - -// Closes the process handle opened by OpenProcessHandle. -BASE_EXPORT void CloseProcessHandle(ProcessHandle process); - -// Returns the unique ID for the specified process. This is functionally the -// same as Windows' GetProcessId(), but works on versions of Windows before -// Win XP SP1 as well. -BASE_EXPORT ProcessId GetProcId(ProcessHandle process); - -#if defined(OS_WIN) -enum IntegrityLevel { - INTEGRITY_UNKNOWN, - LOW_INTEGRITY, - MEDIUM_INTEGRITY, - HIGH_INTEGRITY, -}; -// Determine the integrity level of the specified process. Returns false -// if the system does not support integrity levels (pre-Vista) or in the case -// of an underlying system failure. -BASE_EXPORT bool GetProcessIntegrityLevel(ProcessHandle process, - IntegrityLevel* level); -#endif - -#if defined(OS_LINUX) || defined(OS_ANDROID) || defined(OS_BSD) -// Returns the path to the executable of the given process. -BASE_EXPORT FilePath GetProcessExecutablePath(ProcessHandle process); -#endif - -#if defined(OS_POSIX) -// Returns the ID for the parent of the given process. -BASE_EXPORT ProcessId GetParentProcessId(ProcessHandle process); -#endif - -} // namespace base - -#endif // BASE_PROCESS_PROCESS_HANDLE_H_ diff --git a/base/process/process_handle_freebsd.cc b/base/process/process_handle_freebsd.cc deleted file mode 100644 index 8a0e9de8f2..0000000000 --- a/base/process/process_handle_freebsd.cc +++ /dev/null @@ -1,39 +0,0 @@ -// Copyright (c) 2011 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "base/process/process_handle.h" - -#include -#include -#include - -namespace base { - -ProcessId GetParentProcessId(ProcessHandle process) { - struct kinfo_proc info; - size_t length; - int mib[] = { CTL_KERN, KERN_PROC, KERN_PROC_PID, process }; - - if (sysctl(mib, arraysize(mib), &info, &length, NULL, 0) < 0) - return -1; - - return info.ki_ppid; -} - -FilePath GetProcessExecutablePath(ProcessHandle process) { - char pathname[PATH_MAX]; - size_t length; - int mib[] = { CTL_KERN, KERN_PROC, KERN_PROC_PATHNAME, process }; - - length = sizeof(pathname); - - if (sysctl(mib, arraysize(mib), pathname, &length, NULL, 0) < 0 || - length == 0) { - return FilePath(); - } - - return FilePath(std::string(pathname)); -} - -} // namespace base diff --git a/base/process/process_handle_linux.cc b/base/process/process_handle_linux.cc deleted file mode 100644 index 91441f7b38..0000000000 --- a/base/process/process_handle_linux.cc +++ /dev/null @@ -1,30 +0,0 @@ -// Copyright (c) 2013 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "base/process/process_handle.h" - -#include "base/file_util.h" -#include "base/process/internal_linux.h" - -namespace base { - -ProcessId GetParentProcessId(ProcessHandle process) { - ProcessId pid = - internal::ReadProcStatsAndGetFieldAsInt(process, internal::VM_PPID); - if (pid) - return pid; - return -1; -} - -FilePath GetProcessExecutablePath(ProcessHandle process) { - FilePath stat_file = internal::GetProcPidDir(process).Append("exe"); - FilePath exe_name; - if (!file_util::ReadSymbolicLink(stat_file, &exe_name)) { - // No such process. Happens frequently in e.g. TerminateAllChromeProcesses - return FilePath(); - } - return exe_name; -} - -} // namespace base diff --git a/base/process/process_handle_mac.cc b/base/process/process_handle_mac.cc deleted file mode 100644 index 6cb8d686e4..0000000000 --- a/base/process/process_handle_mac.cc +++ /dev/null @@ -1,27 +0,0 @@ -// Copyright (c) 2013 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "base/process/process_handle.h" - -#include -#include - -#include "base/logging.h" - -namespace base { - -ProcessId GetParentProcessId(ProcessHandle process) { - struct kinfo_proc info; - size_t length = sizeof(struct kinfo_proc); - int mib[4] = { CTL_KERN, KERN_PROC, KERN_PROC_PID, process }; - if (sysctl(mib, 4, &info, &length, NULL, 0) < 0) { - DPLOG(ERROR) << "sysctl"; - return -1; - } - if (length == 0) - return -1; - return info.kp_eproc.e_ppid; -} - -} // namespace base diff --git a/base/process/process_handle_openbsd.cc b/base/process/process_handle_openbsd.cc deleted file mode 100644 index 3508ccb04c..0000000000 --- a/base/process/process_handle_openbsd.cc +++ /dev/null @@ -1,49 +0,0 @@ -// Copyright (c) 2011 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "base/process/process_handle.h" - -#include -#include -#include - -namespace base { - -ProcessId GetParentProcessId(ProcessHandle process) { - struct kinfo_proc info; - size_t length; - int mib[] = { CTL_KERN, KERN_PROC, KERN_PROC_PID, process, - sizeof(struct kinfo_proc), 0 }; - - if (sysctl(mib, arraysize(mib), NULL, &length, NULL, 0) < 0) - return -1; - - mib[5] = (length / sizeof(struct kinfo_proc)); - - if (sysctl(mib, arraysize(mib), &info, &length, NULL, 0) < 0) - return -1; - - return info.p_ppid; -} - -FilePath GetProcessExecutablePath(ProcessHandle process) { - struct kinfo_proc kp; - size_t len; - int mib[] = { CTL_KERN, KERN_PROC, KERN_PROC_PID, process, - sizeof(struct kinfo_proc), 0 }; - - if (sysctl(mib, arraysize(mib), NULL, &len, NULL, 0) == -1) - return FilePath(); - mib[5] = (len / sizeof(struct kinfo_proc)); - if (sysctl(mib, arraysize(mib), &kp, &len, NULL, 0) < 0) - return FilePath(); - if ((kp.p_flag & P_SYSTEM) != 0) - return FilePath(); - if (strcmp(kp.p_comm, "chrome") == 0) - return FilePath(kp.p_comm); - - return FilePath(); -} - -} // namespace base diff --git a/base/process/process_handle_posix.cc b/base/process/process_handle_posix.cc deleted file mode 100644 index 4013254a5c..0000000000 --- a/base/process/process_handle_posix.cc +++ /dev/null @@ -1,49 +0,0 @@ -// Copyright (c) 2013 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "base/process/process_handle.h" - -#include - -namespace base { - -ProcessId GetCurrentProcId() { - return getpid(); -} - -ProcessHandle GetCurrentProcessHandle() { - return GetCurrentProcId(); -} - -bool OpenProcessHandle(ProcessId pid, ProcessHandle* handle) { - // On Posix platforms, process handles are the same as PIDs, so we - // don't need to do anything. - *handle = pid; - return true; -} - -bool OpenPrivilegedProcessHandle(ProcessId pid, ProcessHandle* handle) { - // On POSIX permissions are checked for each operation on process, - // not when opening a "handle". - return OpenProcessHandle(pid, handle); -} - -bool OpenProcessHandleWithAccess(ProcessId pid, - uint32 access_flags, - ProcessHandle* handle) { - // On POSIX permissions are checked for each operation on process, - // not when opening a "handle". - return OpenProcessHandle(pid, handle); -} - -void CloseProcessHandle(ProcessHandle process) { - // See OpenProcessHandle, nothing to do. - return; -} - -ProcessId GetProcId(ProcessHandle process) { - return process; -} - -} // namespace base diff --git a/base/process/process_handle_win.cc b/base/process/process_handle_win.cc deleted file mode 100644 index 3bc3a125e0..0000000000 --- a/base/process/process_handle_win.cc +++ /dev/null @@ -1,126 +0,0 @@ -// Copyright (c) 2013 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "base/process/process_handle.h" - -#include - -#include "base/memory/scoped_ptr.h" -#include "base/win/scoped_handle.h" -#include "base/win/windows_version.h" - -namespace base { - -ProcessId GetCurrentProcId() { - return ::GetCurrentProcessId(); -} - -ProcessHandle GetCurrentProcessHandle() { - return ::GetCurrentProcess(); -} - -bool OpenProcessHandle(ProcessId pid, ProcessHandle* handle) { - // We try to limit privileges granted to the handle. If you need this - // for test code, consider using OpenPrivilegedProcessHandle instead of - // adding more privileges here. - ProcessHandle result = OpenProcess(PROCESS_TERMINATE | - PROCESS_QUERY_INFORMATION | - SYNCHRONIZE, - FALSE, pid); - - if (result == NULL) - return false; - - *handle = result; - return true; -} - -bool OpenPrivilegedProcessHandle(ProcessId pid, ProcessHandle* handle) { - ProcessHandle result = OpenProcess(PROCESS_DUP_HANDLE | - PROCESS_TERMINATE | - PROCESS_QUERY_INFORMATION | - PROCESS_VM_READ | - SYNCHRONIZE, - FALSE, pid); - - if (result == NULL) - return false; - - *handle = result; - return true; -} - -bool OpenProcessHandleWithAccess(ProcessId pid, - uint32 access_flags, - ProcessHandle* handle) { - ProcessHandle result = OpenProcess(access_flags, FALSE, pid); - - if (result == NULL) - return false; - - *handle = result; - return true; -} - -void CloseProcessHandle(ProcessHandle process) { - CloseHandle(process); -} - -ProcessId GetProcId(ProcessHandle process) { - // This returns 0 if we have insufficient rights to query the process handle. - return GetProcessId(process); -} - -bool GetProcessIntegrityLevel(ProcessHandle process, IntegrityLevel *level) { - if (!level) - return false; - - if (win::GetVersion() < base::win::VERSION_VISTA) - return false; - - HANDLE process_token; - if (!OpenProcessToken(process, TOKEN_QUERY | TOKEN_QUERY_SOURCE, - &process_token)) - return false; - - win::ScopedHandle scoped_process_token(process_token); - - DWORD token_info_length = 0; - if (GetTokenInformation(process_token, TokenIntegrityLevel, NULL, 0, - &token_info_length) || - GetLastError() != ERROR_INSUFFICIENT_BUFFER) - return false; - - scoped_ptr token_label_bytes(new char[token_info_length]); - if (!token_label_bytes.get()) - return false; - - TOKEN_MANDATORY_LABEL* token_label = - reinterpret_cast(token_label_bytes.get()); - if (!token_label) - return false; - - if (!GetTokenInformation(process_token, TokenIntegrityLevel, token_label, - token_info_length, &token_info_length)) - return false; - - DWORD integrity_level = *GetSidSubAuthority(token_label->Label.Sid, - (DWORD)(UCHAR)(*GetSidSubAuthorityCount(token_label->Label.Sid)-1)); - - if (integrity_level < SECURITY_MANDATORY_MEDIUM_RID) { - *level = LOW_INTEGRITY; - } else if (integrity_level >= SECURITY_MANDATORY_MEDIUM_RID && - integrity_level < SECURITY_MANDATORY_HIGH_RID) { - *level = MEDIUM_INTEGRITY; - } else if (integrity_level >= SECURITY_MANDATORY_HIGH_RID) { - *level = HIGH_INTEGRITY; - } else { - NOTREACHED(); - return false; - } - - return true; -} - -} // namespace base diff --git a/base/process/process_info.h b/base/process/process_info.h deleted file mode 100644 index e9e7b4e815..0000000000 --- a/base/process/process_info.h +++ /dev/null @@ -1,25 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef BASE_PROCESS_PROCESS_PROCESS_INFO_H_ -#define BASE_PROCESS_PROCESS_PROCESS_INFO_H_ - -#include "base/base_export.h" -#include "base/basictypes.h" - -namespace base { - -class Time; - -// Vends information about the current process. -class BASE_EXPORT CurrentProcessInfo { - public: - // Returns the time at which the process was launched. May be empty if an - // error occurred retrieving the information. - static const Time CreationTime(); -}; - -} // namespace base - -#endif // BASE_PROCESS_PROCESS_PROCESS_INFO_H_ diff --git a/base/process/process_info_linux.cc b/base/process/process_info_linux.cc deleted file mode 100644 index da34c180e8..0000000000 --- a/base/process/process_info_linux.cc +++ /dev/null @@ -1,27 +0,0 @@ -// Copyright 2013 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "base/process/process_info.h" - -#include "base/basictypes.h" -#include "base/logging.h" -#include "base/process/internal_linux.h" -#include "base/process/process_handle.h" -#include "base/time/time.h" - -namespace base { - -//static -const Time CurrentProcessInfo::CreationTime() { - ProcessHandle pid = GetCurrentProcessHandle(); - int start_ticks = internal::ReadProcStatsAndGetFieldAsInt( - pid, internal::VM_STARTTIME); - DCHECK(start_ticks); - TimeDelta start_offset = internal::ClockTicksToTimeDelta(start_ticks); - Time boot_time = internal::GetBootTime(); - DCHECK(!boot_time.is_null()); - return Time(boot_time + start_offset); -} - -} // namespace base diff --git a/base/process/process_info_mac.cc b/base/process/process_info_mac.cc deleted file mode 100644 index ab8394b891..0000000000 --- a/base/process/process_info_mac.cc +++ /dev/null @@ -1,31 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "base/process/process_info.h" - -#include -#include -#include - -#include "base/basictypes.h" -#include "base/memory/scoped_ptr.h" -#include "base/time/time.h" - -namespace base { - -//static -const Time CurrentProcessInfo::CreationTime() { - int mib[] = { CTL_KERN, KERN_PROC, KERN_PROC_PID, getpid() }; - size_t len = 0; - if (sysctl(mib, arraysize(mib), NULL, &len, NULL, 0) < 0) - return Time(); - - scoped_ptr_malloc - proc(static_cast(malloc(len))); - if (sysctl(mib, arraysize(mib), proc.get(), &len, NULL, 0) < 0) - return Time(); - return Time::FromTimeVal(proc->kp_proc.p_un.__p_starttime); -} - -} // namespace base diff --git a/base/process/process_info_win.cc b/base/process/process_info_win.cc deleted file mode 100644 index b930ae6dd8..0000000000 --- a/base/process/process_info_win.cc +++ /dev/null @@ -1,25 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "base/process/process_info.h" - -#include - -#include "base/basictypes.h" -#include "base/time/time.h" - -namespace base { - -//static -const Time CurrentProcessInfo::CreationTime() { - FILETIME creation_time = {}; - FILETIME ignore = {}; - if (::GetProcessTimes(::GetCurrentProcess(), &creation_time, &ignore, - &ignore, &ignore) == false) - return Time(); - - return Time::FromFileTime(creation_time); -} - -} // namespace base diff --git a/base/process/process_iterator.cc b/base/process/process_iterator.cc deleted file mode 100644 index b9ef047732..0000000000 --- a/base/process/process_iterator.cc +++ /dev/null @@ -1,65 +0,0 @@ -// Copyright (c) 2013 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "base/process/process_iterator.h" - -namespace base { - -#if defined(OS_POSIX) -ProcessEntry::ProcessEntry() : pid_(0), ppid_(0), gid_(0) {} -ProcessEntry::~ProcessEntry() {} -#endif - -const ProcessEntry* ProcessIterator::NextProcessEntry() { - bool result = false; - do { - result = CheckForNextProcess(); - } while (result && !IncludeEntry()); - if (result) - return &entry_; - return NULL; -} - -ProcessIterator::ProcessEntries ProcessIterator::Snapshot() { - ProcessEntries found; - while (const ProcessEntry* process_entry = NextProcessEntry()) { - found.push_back(*process_entry); - } - return found; -} - -bool ProcessIterator::IncludeEntry() { - return !filter_ || filter_->Includes(entry_); -} - -NamedProcessIterator::NamedProcessIterator( - const FilePath::StringType& executable_name, - const ProcessFilter* filter) : ProcessIterator(filter), - executable_name_(executable_name) { -#if defined(OS_ANDROID) - // On Android, the process name contains only the last 15 characters, which - // is in file /proc//stat, the string between open parenthesis and close - // parenthesis. Please See ProcessIterator::CheckForNextProcess for details. - // Now if the length of input process name is greater than 15, only save the - // last 15 characters. - if (executable_name_.size() > 15) { - executable_name_ = FilePath::StringType(executable_name_, - executable_name_.size() - 15, 15); - } -#endif -} - -NamedProcessIterator::~NamedProcessIterator() { -} - -int GetProcessCount(const FilePath::StringType& executable_name, - const ProcessFilter* filter) { - int count = 0; - NamedProcessIterator iter(executable_name, filter); - while (iter.NextProcessEntry()) - ++count; - return count; -} - -} // namespace base diff --git a/base/process/process_iterator.h b/base/process/process_iterator.h deleted file mode 100644 index aa8ba74aba..0000000000 --- a/base/process/process_iterator.h +++ /dev/null @@ -1,183 +0,0 @@ -// Copyright (c) 2013 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -// This file contains methods to iterate over processes on the system. - -#ifndef BASE_PROCESS_PROCESS_ITERATOR_H_ -#define BASE_PROCESS_PROCESS_ITERATOR_H_ - -#include -#include -#include - -#include "base/base_export.h" -#include "base/basictypes.h" -#include "base/files/file_path.h" -#include "base/process/process.h" -#include "build/build_config.h" - -#if defined(OS_WIN) -#include -#include -#elif defined(OS_MACOSX) || defined(OS_BSD) -#include -#elif defined(OS_POSIX) -#include -#endif - -namespace base { - -#if defined(OS_WIN) -struct ProcessEntry : public PROCESSENTRY32 { - ProcessId pid() const { return th32ProcessID; } - ProcessId parent_pid() const { return th32ParentProcessID; } - const wchar_t* exe_file() const { return szExeFile; } -}; - -// Process access masks. These constants provide platform-independent -// definitions for the standard Windows access masks. -// See http://msdn.microsoft.com/en-us/library/ms684880(VS.85).aspx for -// the specific semantics of each mask value. -const uint32 kProcessAccessTerminate = PROCESS_TERMINATE; -const uint32 kProcessAccessCreateThread = PROCESS_CREATE_THREAD; -const uint32 kProcessAccessSetSessionId = PROCESS_SET_SESSIONID; -const uint32 kProcessAccessVMOperation = PROCESS_VM_OPERATION; -const uint32 kProcessAccessVMRead = PROCESS_VM_READ; -const uint32 kProcessAccessVMWrite = PROCESS_VM_WRITE; -const uint32 kProcessAccessDuplicateHandle = PROCESS_DUP_HANDLE; -const uint32 kProcessAccessCreateProcess = PROCESS_CREATE_PROCESS; -const uint32 kProcessAccessSetQuota = PROCESS_SET_QUOTA; -const uint32 kProcessAccessSetInformation = PROCESS_SET_INFORMATION; -const uint32 kProcessAccessQueryInformation = PROCESS_QUERY_INFORMATION; -const uint32 kProcessAccessSuspendResume = PROCESS_SUSPEND_RESUME; -const uint32 kProcessAccessQueryLimitedInfomation = - PROCESS_QUERY_LIMITED_INFORMATION; -const uint32 kProcessAccessWaitForTermination = SYNCHRONIZE; -#elif defined(OS_POSIX) -struct BASE_EXPORT ProcessEntry { - ProcessEntry(); - ~ProcessEntry(); - - ProcessId pid() const { return pid_; } - ProcessId parent_pid() const { return ppid_; } - ProcessId gid() const { return gid_; } - const char* exe_file() const { return exe_file_.c_str(); } - const std::vector& cmd_line_args() const { - return cmd_line_args_; - } - - ProcessId pid_; - ProcessId ppid_; - ProcessId gid_; - std::string exe_file_; - std::vector cmd_line_args_; -}; - -// Process access masks. They are not used on Posix because access checking -// does not happen during handle creation. -const uint32 kProcessAccessTerminate = 0; -const uint32 kProcessAccessCreateThread = 0; -const uint32 kProcessAccessSetSessionId = 0; -const uint32 kProcessAccessVMOperation = 0; -const uint32 kProcessAccessVMRead = 0; -const uint32 kProcessAccessVMWrite = 0; -const uint32 kProcessAccessDuplicateHandle = 0; -const uint32 kProcessAccessCreateProcess = 0; -const uint32 kProcessAccessSetQuota = 0; -const uint32 kProcessAccessSetInformation = 0; -const uint32 kProcessAccessQueryInformation = 0; -const uint32 kProcessAccessSuspendResume = 0; -const uint32 kProcessAccessQueryLimitedInfomation = 0; -const uint32 kProcessAccessWaitForTermination = 0; -#endif // defined(OS_POSIX) - -// Used to filter processes by process ID. -class ProcessFilter { - public: - // Returns true to indicate set-inclusion and false otherwise. This method - // should not have side-effects and should be idempotent. - virtual bool Includes(const ProcessEntry& entry) const = 0; - - protected: - virtual ~ProcessFilter() {} -}; - -// This class provides a way to iterate through a list of processes on the -// current machine with a specified filter. -// To use, create an instance and then call NextProcessEntry() until it returns -// false. -class BASE_EXPORT ProcessIterator { - public: - typedef std::list ProcessEntries; - - explicit ProcessIterator(const ProcessFilter* filter); - virtual ~ProcessIterator(); - - // If there's another process that matches the given executable name, - // returns a const pointer to the corresponding PROCESSENTRY32. - // If there are no more matching processes, returns NULL. - // The returned pointer will remain valid until NextProcessEntry() - // is called again or this NamedProcessIterator goes out of scope. - const ProcessEntry* NextProcessEntry(); - - // Takes a snapshot of all the ProcessEntry found. - ProcessEntries Snapshot(); - - protected: - virtual bool IncludeEntry(); - const ProcessEntry& entry() { return entry_; } - - private: - // Determines whether there's another process (regardless of executable) - // left in the list of all processes. Returns true and sets entry_ to - // that process's info if there is one, false otherwise. - bool CheckForNextProcess(); - - // Initializes a PROCESSENTRY32 data structure so that it's ready for - // use with Process32First/Process32Next. - void InitProcessEntry(ProcessEntry* entry); - -#if defined(OS_WIN) - HANDLE snapshot_; - bool started_iteration_; -#elif defined(OS_MACOSX) || defined(OS_BSD) - std::vector kinfo_procs_; - size_t index_of_kinfo_proc_; -#elif defined(OS_POSIX) - DIR* procfs_dir_; -#endif - ProcessEntry entry_; - const ProcessFilter* filter_; - - DISALLOW_COPY_AND_ASSIGN(ProcessIterator); -}; - -// This class provides a way to iterate through the list of processes -// on the current machine that were started from the given executable -// name. To use, create an instance and then call NextProcessEntry() -// until it returns false. -class BASE_EXPORT NamedProcessIterator : public ProcessIterator { - public: - NamedProcessIterator(const FilePath::StringType& executable_name, - const ProcessFilter* filter); - virtual ~NamedProcessIterator(); - - protected: - virtual bool IncludeEntry() OVERRIDE; - - private: - FilePath::StringType executable_name_; - - DISALLOW_COPY_AND_ASSIGN(NamedProcessIterator); -}; - -// Returns the number of processes on the machine that are running from the -// given executable name. If filter is non-null, then only processes selected -// by the filter will be counted. -BASE_EXPORT int GetProcessCount(const FilePath::StringType& executable_name, - const ProcessFilter* filter); - -} // namespace base - -#endif // BASE_PROCESS_PROCESS_ITERATOR_H_ diff --git a/base/process/process_iterator_freebsd.cc b/base/process/process_iterator_freebsd.cc deleted file mode 100644 index e8225b0054..0000000000 --- a/base/process/process_iterator_freebsd.cc +++ /dev/null @@ -1,124 +0,0 @@ -// Copyright (c) 2013 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "base/process/process_iterator.h" - -#include - -#include "base/logging.h" -#include "base/strings/string_util.h" - -namespace base { - -ProcessIterator::ProcessIterator(const ProcessFilter* filter) - : index_of_kinfo_proc_(), - filter_(filter) { - - int mib[] = { CTL_KERN, KERN_PROC, KERN_PROC_UID, getuid() }; - - bool done = false; - int try_num = 1; - const int max_tries = 10; - - do { - size_t len = 0; - if (sysctl(mib, arraysize(mib), NULL, &len, NULL, 0) < 0) { - LOG(ERROR) << "failed to get the size needed for the process list"; - kinfo_procs_.resize(0); - done = true; - } else { - size_t num_of_kinfo_proc = len / sizeof(struct kinfo_proc); - // Leave some spare room for process table growth (more could show up - // between when we check and now) - num_of_kinfo_proc += 16; - kinfo_procs_.resize(num_of_kinfo_proc); - len = num_of_kinfo_proc * sizeof(struct kinfo_proc); - if (sysctl(mib, arraysize(mib), &kinfo_procs_[0], &len, NULL, 0) <0) { - // If we get a mem error, it just means we need a bigger buffer, so - // loop around again. Anything else is a real error and give up. - if (errno != ENOMEM) { - LOG(ERROR) << "failed to get the process list"; - kinfo_procs_.resize(0); - done = true; - } - } else { - // Got the list, just make sure we're sized exactly right - size_t num_of_kinfo_proc = len / sizeof(struct kinfo_proc); - kinfo_procs_.resize(num_of_kinfo_proc); - done = true; - } - } - } while (!done && (try_num++ < max_tries)); - - if (!done) { - LOG(ERROR) << "failed to collect the process list in a few tries"; - kinfo_procs_.resize(0); - } -} - -ProcessIterator::~ProcessIterator() { -} - -bool ProcessIterator::CheckForNextProcess() { - std::string data; - - for (; index_of_kinfo_proc_ < kinfo_procs_.size(); ++index_of_kinfo_proc_) { - size_t length; - struct kinfo_proc kinfo = kinfo_procs_[index_of_kinfo_proc_]; - int mib[] = { CTL_KERN, KERN_PROC_ARGS, kinfo.ki_pid }; - - if ((kinfo.ki_pid > 0) && (kinfo.ki_stat == SZOMB)) - continue; - - length = 0; - if (sysctl(mib, arraysize(mib), NULL, &length, NULL, 0) < 0) { - LOG(ERROR) << "failed to figure out the buffer size for a command line"; - continue; - } - - data.resize(length); - - if (sysctl(mib, arraysize(mib), &data[0], &length, NULL, 0) < 0) { - LOG(ERROR) << "failed to fetch a commandline"; - continue; - } - - std::string delimiters; - delimiters.push_back('\0'); - Tokenize(data, delimiters, &entry_.cmd_line_args_); - - size_t exec_name_end = data.find('\0'); - if (exec_name_end == std::string::npos) { - LOG(ERROR) << "command line data didn't match expected format"; - continue; - } - - entry_.pid_ = kinfo.ki_pid; - entry_.ppid_ = kinfo.ki_ppid; - entry_.gid_ = kinfo.ki_pgid; - - size_t last_slash = data.rfind('/', exec_name_end); - if (last_slash == std::string::npos) { - entry_.exe_file_.assign(data, 0, exec_name_end); - } else { - entry_.exe_file_.assign(data, last_slash + 1, - exec_name_end - last_slash - 1); - } - - // Start w/ the next entry next time through - ++index_of_kinfo_proc_; - - return true; - } - return false; -} - -bool NamedProcessIterator::IncludeEntry() { - if (executable_name_ != entry().exe_file()) - return false; - - return ProcessIterator::IncludeEntry(); -} - -} // namespace base diff --git a/base/process/process_iterator_linux.cc b/base/process/process_iterator_linux.cc deleted file mode 100644 index 6da51ca3b5..0000000000 --- a/base/process/process_iterator_linux.cc +++ /dev/null @@ -1,137 +0,0 @@ -// Copyright (c) 2013 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "base/process/process_iterator.h" - -#include "base/file_util.h" -#include "base/logging.h" -#include "base/process/internal_linux.h" -#include "base/strings/string_util.h" -#include "base/threading/thread_restrictions.h" - -namespace base { - -namespace { - -// Reads the |field_num|th field from |proc_stats|. -// Returns an empty string on failure. -// This version only handles VM_COMM and VM_STATE, which are the only fields -// that are strings. -std::string GetProcStatsFieldAsString( - const std::vector& proc_stats, - internal::ProcStatsFields field_num) { - if (field_num < internal::VM_COMM || field_num > internal::VM_STATE) { - NOTREACHED(); - return std::string(); - } - - if (proc_stats.size() > static_cast(field_num)) - return proc_stats[field_num]; - - NOTREACHED(); - return 0; -} - -// Reads /proc//cmdline and populates |proc_cmd_line_args| with the command -// line arguments. Returns true if successful. -// Note: /proc//cmdline contains command line arguments separated by single -// null characters. We tokenize it into a vector of strings using '\0' as a -// delimiter. -bool GetProcCmdline(pid_t pid, std::vector* proc_cmd_line_args) { - // Synchronously reading files in /proc is safe. - ThreadRestrictions::ScopedAllowIO allow_io; - - FilePath cmd_line_file = internal::GetProcPidDir(pid).Append("cmdline"); - std::string cmd_line; - if (!file_util::ReadFileToString(cmd_line_file, &cmd_line)) - return false; - std::string delimiters; - delimiters.push_back('\0'); - Tokenize(cmd_line, delimiters, proc_cmd_line_args); - return true; -} - -} // namespace - -ProcessIterator::ProcessIterator(const ProcessFilter* filter) - : filter_(filter) { - procfs_dir_ = opendir(internal::kProcDir); -} - -ProcessIterator::~ProcessIterator() { - if (procfs_dir_) { - closedir(procfs_dir_); - procfs_dir_ = NULL; - } -} - -bool ProcessIterator::CheckForNextProcess() { - // TODO(port): skip processes owned by different UID - - pid_t pid = kNullProcessId; - std::vector cmd_line_args; - std::string stats_data; - std::vector proc_stats; - - // Arbitrarily guess that there will never be more than 200 non-process - // files in /proc. Hardy has 53 and Lucid has 61. - int skipped = 0; - const int kSkipLimit = 200; - while (skipped < kSkipLimit) { - dirent* slot = readdir(procfs_dir_); - // all done looking through /proc? - if (!slot) - return false; - - // If not a process, keep looking for one. - pid = internal::ProcDirSlotToPid(slot->d_name); - if (!pid) { - skipped++; - continue; - } - - if (!GetProcCmdline(pid, &cmd_line_args)) - continue; - - if (!internal::ReadProcStats(pid, &stats_data)) - continue; - if (!internal::ParseProcStats(stats_data, &proc_stats)) - continue; - - std::string runstate = - GetProcStatsFieldAsString(proc_stats, internal::VM_STATE); - if (runstate.size() != 1) { - NOTREACHED(); - continue; - } - - // Is the process in 'Zombie' state, i.e. dead but waiting to be reaped? - // Allowed values: D R S T Z - if (runstate[0] != 'Z') - break; - - // Nope, it's a zombie; somebody isn't cleaning up after their children. - // (e.g. WaitForProcessesToExit doesn't clean up after dead children yet.) - // There could be a lot of zombies, can't really decrement i here. - } - if (skipped >= kSkipLimit) { - NOTREACHED(); - return false; - } - - entry_.pid_ = pid; - entry_.ppid_ = GetProcStatsFieldAsInt(proc_stats, internal::VM_PPID); - entry_.gid_ = GetProcStatsFieldAsInt(proc_stats, internal::VM_PGRP); - entry_.cmd_line_args_.assign(cmd_line_args.begin(), cmd_line_args.end()); - entry_.exe_file_ = GetProcessExecutablePath(pid).BaseName().value(); - return true; -} - -bool NamedProcessIterator::IncludeEntry() { - if (executable_name_ != entry().exe_file()) - return false; - return ProcessIterator::IncludeEntry(); -} - -} // namespace base diff --git a/base/process/process_iterator_mac.cc b/base/process/process_iterator_mac.cc deleted file mode 100644 index 29daa2d489..0000000000 --- a/base/process/process_iterator_mac.cc +++ /dev/null @@ -1,134 +0,0 @@ -// Copyright (c) 2013 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "base/process/process_iterator.h" - -#include -#include -#include - -#include "base/logging.h" -#include "base/strings/string_util.h" - -namespace base { - -ProcessIterator::ProcessIterator(const ProcessFilter* filter) - : index_of_kinfo_proc_(0), - filter_(filter) { - // Get a snapshot of all of my processes (yes, as we loop it can go stale, but - // but trying to find where we were in a constantly changing list is basically - // impossible. - - int mib[] = { CTL_KERN, KERN_PROC, KERN_PROC_UID, geteuid() }; - - // Since more processes could start between when we get the size and when - // we get the list, we do a loop to keep trying until we get it. - bool done = false; - int try_num = 1; - const int max_tries = 10; - do { - // Get the size of the buffer - size_t len = 0; - if (sysctl(mib, arraysize(mib), NULL, &len, NULL, 0) < 0) { - DLOG(ERROR) << "failed to get the size needed for the process list"; - kinfo_procs_.resize(0); - done = true; - } else { - size_t num_of_kinfo_proc = len / sizeof(struct kinfo_proc); - // Leave some spare room for process table growth (more could show up - // between when we check and now) - num_of_kinfo_proc += 16; - kinfo_procs_.resize(num_of_kinfo_proc); - len = num_of_kinfo_proc * sizeof(struct kinfo_proc); - // Load the list of processes - if (sysctl(mib, arraysize(mib), &kinfo_procs_[0], &len, NULL, 0) < 0) { - // If we get a mem error, it just means we need a bigger buffer, so - // loop around again. Anything else is a real error and give up. - if (errno != ENOMEM) { - DLOG(ERROR) << "failed to get the process list"; - kinfo_procs_.resize(0); - done = true; - } - } else { - // Got the list, just make sure we're sized exactly right - size_t num_of_kinfo_proc = len / sizeof(struct kinfo_proc); - kinfo_procs_.resize(num_of_kinfo_proc); - done = true; - } - } - } while (!done && (try_num++ < max_tries)); - - if (!done) { - DLOG(ERROR) << "failed to collect the process list in a few tries"; - kinfo_procs_.resize(0); - } -} - -ProcessIterator::~ProcessIterator() { -} - -bool ProcessIterator::CheckForNextProcess() { - std::string data; - for (; index_of_kinfo_proc_ < kinfo_procs_.size(); ++index_of_kinfo_proc_) { - kinfo_proc& kinfo = kinfo_procs_[index_of_kinfo_proc_]; - - // Skip processes just awaiting collection - if ((kinfo.kp_proc.p_pid > 0) && (kinfo.kp_proc.p_stat == SZOMB)) - continue; - - int mib[] = { CTL_KERN, KERN_PROCARGS, kinfo.kp_proc.p_pid }; - - // Find out what size buffer we need. - size_t data_len = 0; - if (sysctl(mib, arraysize(mib), NULL, &data_len, NULL, 0) < 0) { - DVPLOG(1) << "failed to figure out the buffer size for a commandline"; - continue; - } - - data.resize(data_len); - if (sysctl(mib, arraysize(mib), &data[0], &data_len, NULL, 0) < 0) { - DVPLOG(1) << "failed to fetch a commandline"; - continue; - } - - // |data| contains all the command line parameters of the process, separated - // by blocks of one or more null characters. We tokenize |data| into a - // vector of strings using '\0' as a delimiter and populate - // |entry_.cmd_line_args_|. - std::string delimiters; - delimiters.push_back('\0'); - Tokenize(data, delimiters, &entry_.cmd_line_args_); - - // |data| starts with the full executable path followed by a null character. - // We search for the first instance of '\0' and extract everything before it - // to populate |entry_.exe_file_|. - size_t exec_name_end = data.find('\0'); - if (exec_name_end == std::string::npos) { - DLOG(ERROR) << "command line data didn't match expected format"; - continue; - } - - entry_.pid_ = kinfo.kp_proc.p_pid; - entry_.ppid_ = kinfo.kp_eproc.e_ppid; - entry_.gid_ = kinfo.kp_eproc.e_pgid; - size_t last_slash = data.rfind('/', exec_name_end); - if (last_slash == std::string::npos) - entry_.exe_file_.assign(data, 0, exec_name_end); - else - entry_.exe_file_.assign(data, last_slash + 1, - exec_name_end - last_slash - 1); - // Start w/ the next entry next time through - ++index_of_kinfo_proc_; - // Done - return true; - } - return false; -} - -bool NamedProcessIterator::IncludeEntry() { - return (executable_name_ == entry().exe_file() && - ProcessIterator::IncludeEntry()); -} - -} // namespace base diff --git a/base/process/process_iterator_openbsd.cc b/base/process/process_iterator_openbsd.cc deleted file mode 100644 index 7c44eb118c..0000000000 --- a/base/process/process_iterator_openbsd.cc +++ /dev/null @@ -1,128 +0,0 @@ -// Copyright (c) 2013 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "base/process/process_iterator.h" - -#include -#include - -#include "base/logging.h" -#include "base/strings/string_util.h" - -namespace base { - -ProcessIterator::ProcessIterator(const ProcessFilter* filter) - : index_of_kinfo_proc_(), - filter_(filter) { - - int mib[] = { CTL_KERN, KERN_PROC, KERN_PROC_UID, getuid(), - sizeof(struct kinfo_proc), 0 }; - - bool done = false; - int try_num = 1; - const int max_tries = 10; - - do { - size_t len = 0; - if (sysctl(mib, arraysize(mib), NULL, &len, NULL, 0) < 0) { - DLOG(ERROR) << "failed to get the size needed for the process list"; - kinfo_procs_.resize(0); - done = true; - } else { - size_t num_of_kinfo_proc = len / sizeof(struct kinfo_proc); - // Leave some spare room for process table growth (more could show up - // between when we check and now) - num_of_kinfo_proc += 16; - kinfo_procs_.resize(num_of_kinfo_proc); - len = num_of_kinfo_proc * sizeof(struct kinfo_proc); - if (sysctl(mib, arraysize(mib), &kinfo_procs_[0], &len, NULL, 0) < 0) { - // If we get a mem error, it just means we need a bigger buffer, so - // loop around again. Anything else is a real error and give up. - if (errno != ENOMEM) { - DLOG(ERROR) << "failed to get the process list"; - kinfo_procs_.resize(0); - done = true; - } - } else { - // Got the list, just make sure we're sized exactly right - size_t num_of_kinfo_proc = len / sizeof(struct kinfo_proc); - kinfo_procs_.resize(num_of_kinfo_proc); - done = true; - } - } - } while (!done && (try_num++ < max_tries)); - - if (!done) { - DLOG(ERROR) << "failed to collect the process list in a few tries"; - kinfo_procs_.resize(0); - } -} - -ProcessIterator::~ProcessIterator() { -} - -bool ProcessIterator::CheckForNextProcess() { - std::string data; - for (; index_of_kinfo_proc_ < kinfo_procs_.size(); ++index_of_kinfo_proc_) { - kinfo_proc& kinfo = kinfo_procs_[index_of_kinfo_proc_]; - - // Skip processes just awaiting collection - if ((kinfo.p_pid > 0) && (kinfo.p_stat == SZOMB)) - continue; - - int mib[] = { CTL_KERN, KERN_PROC_ARGS, kinfo.p_pid }; - - // Find out what size buffer we need. - size_t data_len = 0; - if (sysctl(mib, arraysize(mib), NULL, &data_len, NULL, 0) < 0) { - DVPLOG(1) << "failed to figure out the buffer size for a commandline"; - continue; - } - - data.resize(data_len); - if (sysctl(mib, arraysize(mib), &data[0], &data_len, NULL, 0) < 0) { - DVPLOG(1) << "failed to fetch a commandline"; - continue; - } - - // |data| contains all the command line parameters of the process, separated - // by blocks of one or more null characters. We tokenize |data| into a - // vector of strings using '\0' as a delimiter and populate - // |entry_.cmd_line_args_|. - std::string delimiters; - delimiters.push_back('\0'); - Tokenize(data, delimiters, &entry_.cmd_line_args_); - - // |data| starts with the full executable path followed by a null character. - // We search for the first instance of '\0' and extract everything before it - // to populate |entry_.exe_file_|. - size_t exec_name_end = data.find('\0'); - if (exec_name_end == std::string::npos) { - DLOG(ERROR) << "command line data didn't match expected format"; - continue; - } - - entry_.pid_ = kinfo.p_pid; - entry_.ppid_ = kinfo.p_ppid; - entry_.gid_ = kinfo.p__pgid; - size_t last_slash = data.rfind('/', exec_name_end); - if (last_slash == std::string::npos) - entry_.exe_file_.assign(data, 0, exec_name_end); - else - entry_.exe_file_.assign(data, last_slash + 1, - exec_name_end - last_slash - 1); - // Start w/ the next entry next time through - ++index_of_kinfo_proc_; - // Done - return true; - } - return false; -} - -bool NamedProcessIterator::IncludeEntry() { - return (executable_name_ == entry().exe_file() && - ProcessIterator::IncludeEntry()); -} - -} // namespace base diff --git a/base/process/process_iterator_win.cc b/base/process/process_iterator_win.cc deleted file mode 100644 index 9d5a970ef4..0000000000 --- a/base/process/process_iterator_win.cc +++ /dev/null @@ -1,41 +0,0 @@ -// Copyright (c) 2013 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "base/process/process_iterator.h" - -namespace base { - -ProcessIterator::ProcessIterator(const ProcessFilter* filter) - : started_iteration_(false), - filter_(filter) { - snapshot_ = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0); -} - -ProcessIterator::~ProcessIterator() { - CloseHandle(snapshot_); -} - -bool ProcessIterator::CheckForNextProcess() { - InitProcessEntry(&entry_); - - if (!started_iteration_) { - started_iteration_ = true; - return !!Process32First(snapshot_, &entry_); - } - - return !!Process32Next(snapshot_, &entry_); -} - -void ProcessIterator::InitProcessEntry(ProcessEntry* entry) { - memset(entry, 0, sizeof(*entry)); - entry->dwSize = sizeof(*entry); -} - -bool NamedProcessIterator::IncludeEntry() { - // Case insensitive. - return _wcsicmp(executable_name_.c_str(), entry().exe_file()) == 0 && - ProcessIterator::IncludeEntry(); -} - -} // namespace base diff --git a/base/process/process_linux.cc b/base/process/process_linux.cc deleted file mode 100644 index 93006aafe5..0000000000 --- a/base/process/process_linux.cc +++ /dev/null @@ -1,137 +0,0 @@ -// Copyright (c) 2011 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "base/process/process.h" - -#include -#include - -#include "base/file_util.h" -#include "base/lazy_instance.h" -#include "base/logging.h" -#include "base/strings/string_split.h" -#include "base/strings/stringprintf.h" -#include "base/synchronization/lock.h" - -namespace { -const int kForegroundPriority = 0; - -#if defined(OS_CHROMEOS) -// We are more aggressive in our lowering of background process priority -// for chromeos as we have much more control over other processes running -// on the machine. -// -// TODO(davemoore) Refactor this by adding support for higher levels to set -// the foregrounding / backgrounding process so we don't have to keep -// chrome / chromeos specific logic here. -const int kBackgroundPriority = 19; -const char kControlPath[] = "/sys/fs/cgroup/cpu%s/cgroup.procs"; -const char kForeground[] = "/chrome_renderers/foreground"; -const char kBackground[] = "/chrome_renderers/background"; -const char kProcPath[] = "/proc/%d/cgroup"; - -struct CGroups { - // Check for cgroups files. ChromeOS supports these by default. It creates - // a cgroup mount in /sys/fs/cgroup and then configures two cpu task groups, - // one contains at most a single foreground renderer and the other contains - // all background renderers. This allows us to limit the impact of background - // renderers on foreground ones to a greater level than simple renicing. - bool enabled; - base::FilePath foreground_file; - base::FilePath background_file; - - CGroups() { - foreground_file = - base::FilePath(base::StringPrintf(kControlPath, kForeground)); - background_file = - base::FilePath(base::StringPrintf(kControlPath, kBackground)); - file_util::FileSystemType foreground_type; - file_util::FileSystemType background_type; - enabled = - file_util::GetFileSystemType(foreground_file, &foreground_type) && - file_util::GetFileSystemType(background_file, &background_type) && - foreground_type == file_util::FILE_SYSTEM_CGROUP && - background_type == file_util::FILE_SYSTEM_CGROUP; - } -}; - -base::LazyInstance cgroups = LAZY_INSTANCE_INITIALIZER; -#else -const int kBackgroundPriority = 5; -#endif -} - -namespace base { - -bool Process::IsProcessBackgrounded() const { - DCHECK(process_); - -#if defined(OS_CHROMEOS) - if (cgroups.Get().enabled) { - std::string proc; - if (file_util::ReadFileToString( - base::FilePath(StringPrintf(kProcPath, process_)), - &proc)) { - std::vector proc_parts; - base::SplitString(proc, ':', &proc_parts); - DCHECK(proc_parts.size() == 3); - bool ret = proc_parts[2] == std::string(kBackground); - return ret; - } else { - return false; - } - } -#endif - return GetPriority() == kBackgroundPriority; -} - -bool Process::SetProcessBackgrounded(bool background) { - DCHECK(process_); - -#if defined(OS_CHROMEOS) - if (cgroups.Get().enabled) { - std::string pid = StringPrintf("%d", process_); - const base::FilePath file = - background ? - cgroups.Get().background_file : cgroups.Get().foreground_file; - return file_util::WriteFile(file, pid.c_str(), pid.size()) > 0; - } -#endif // OS_CHROMEOS - - if (!CanBackgroundProcesses()) - return false; - - int priority = background ? kBackgroundPriority : kForegroundPriority; - int result = setpriority(PRIO_PROCESS, process_, priority); - DPCHECK(result == 0); - return result == 0; -} - -struct CheckForNicePermission { - CheckForNicePermission() : can_reraise_priority(false) { - // We won't be able to raise the priority if we don't have the right rlimit. - // The limit may be adjusted in /etc/security/limits.conf for PAM systems. - struct rlimit rlim; - if ((getrlimit(RLIMIT_NICE, &rlim) == 0) && - (20 - kForegroundPriority) <= static_cast(rlim.rlim_cur)) { - can_reraise_priority = true; - } - }; - - bool can_reraise_priority; -}; - -// static -bool Process::CanBackgroundProcesses() { -#if defined(OS_CHROMEOS) - if (cgroups.Get().enabled) - return true; -#endif - - static LazyInstance check_for_nice_permission = - LAZY_INSTANCE_INITIALIZER; - return check_for_nice_permission.Get().can_reraise_priority; -} - -} // namespace base diff --git a/base/process/process_metrics.h b/base/process/process_metrics.h deleted file mode 100644 index e329b4ef73..0000000000 --- a/base/process/process_metrics.h +++ /dev/null @@ -1,269 +0,0 @@ -// Copyright (c) 2013 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -// This file contains routines for gathering resource statistics for processes -// running on the system. - -#ifndef BASE_PROCESS_PROCESS_METRICS_H_ -#define BASE_PROCESS_PROCESS_METRICS_H_ - -#include - -#include "base/base_export.h" -#include "base/basictypes.h" -#include "base/process/process_handle.h" -#include "base/time/time.h" - -#if defined(OS_MACOSX) -#include -#endif - -namespace base { - -#if defined(OS_WIN) -struct IoCounters : public IO_COUNTERS { -}; -#elif defined(OS_POSIX) -struct IoCounters { - uint64_t ReadOperationCount; - uint64_t WriteOperationCount; - uint64_t OtherOperationCount; - uint64_t ReadTransferCount; - uint64_t WriteTransferCount; - uint64_t OtherTransferCount; -}; -#endif - -// Working Set (resident) memory usage broken down by -// -// On Windows: -// priv (private): These pages (kbytes) cannot be shared with any other process. -// shareable: These pages (kbytes) can be shared with other processes under -// the right circumstances. -// shared : These pages (kbytes) are currently shared with at least one -// other process. -// -// On Linux: -// priv: Pages mapped only by this process. -// shared: PSS or 0 if the kernel doesn't support this. -// shareable: 0 - -// On ChromeOS: -// priv: Pages mapped only by this process. -// shared: PSS or 0 if the kernel doesn't support this. -// shareable: 0 -// swapped Pages swapped out to zram. -// -// On OS X: TODO(thakis): Revise. -// priv: Memory. -// shared: 0 -// shareable: 0 -// -struct WorkingSetKBytes { - WorkingSetKBytes() : priv(0), shareable(0), shared(0) {} - size_t priv; - size_t shareable; - size_t shared; -#if defined(OS_CHROMEOS) - size_t swapped; -#endif -}; - -// Committed (resident + paged) memory usage broken down by -// private: These pages cannot be shared with any other process. -// mapped: These pages are mapped into the view of a section (backed by -// pagefile.sys) -// image: These pages are mapped into the view of an image section (backed by -// file system) -struct CommittedKBytes { - CommittedKBytes() : priv(0), mapped(0), image(0) {} - size_t priv; - size_t mapped; - size_t image; -}; - -// Free memory (Megabytes marked as free) in the 2G process address space. -// total : total amount in megabytes marked as free. Maximum value is 2048. -// largest : size of the largest contiguous amount of memory found. It is -// always smaller or equal to FreeMBytes::total. -// largest_ptr: starting address of the largest memory block. -struct FreeMBytes { - size_t total; - size_t largest; - void* largest_ptr; -}; - -// Convert a POSIX timeval to microseconds. -BASE_EXPORT int64 TimeValToMicroseconds(const struct timeval& tv); - -// Provides performance metrics for a specified process (CPU usage, memory and -// IO counters). To use it, invoke CreateProcessMetrics() to get an instance -// for a specific process, then access the information with the different get -// methods. -class BASE_EXPORT ProcessMetrics { - public: - ~ProcessMetrics(); - - // Creates a ProcessMetrics for the specified process. - // The caller owns the returned object. -#if !defined(OS_MACOSX) || defined(OS_IOS) - static ProcessMetrics* CreateProcessMetrics(ProcessHandle process); -#else - class PortProvider { - public: - virtual ~PortProvider() {} - - // Should return the mach task for |process| if possible, or else - // |MACH_PORT_NULL|. Only processes that this returns tasks for will have - // metrics on OS X (except for the current process, which always gets - // metrics). - virtual mach_port_t TaskForPid(ProcessHandle process) const = 0; - }; - - // The port provider needs to outlive the ProcessMetrics object returned by - // this function. If NULL is passed as provider, the returned object - // only returns valid metrics if |process| is the current process. - static ProcessMetrics* CreateProcessMetrics(ProcessHandle process, - PortProvider* port_provider); -#endif // !defined(OS_MACOSX) || defined(OS_IOS) - - // Returns the current space allocated for the pagefile, in bytes (these pages - // may or may not be in memory). On Linux, this returns the total virtual - // memory size. - size_t GetPagefileUsage() const; - // Returns the peak space allocated for the pagefile, in bytes. - size_t GetPeakPagefileUsage() const; - // Returns the current working set size, in bytes. On Linux, this returns - // the resident set size. - size_t GetWorkingSetSize() const; - // Returns the peak working set size, in bytes. - size_t GetPeakWorkingSetSize() const; - // Returns private and sharedusage, in bytes. Private bytes is the amount of - // memory currently allocated to a process that cannot be shared. Returns - // false on platform specific error conditions. Note: |private_bytes| - // returns 0 on unsupported OSes: prior to XP SP2. - bool GetMemoryBytes(size_t* private_bytes, - size_t* shared_bytes); - // Fills a CommittedKBytes with both resident and paged - // memory usage as per definition of CommittedBytes. - void GetCommittedKBytes(CommittedKBytes* usage) const; - // Fills a WorkingSetKBytes containing resident private and shared memory - // usage in bytes, as per definition of WorkingSetBytes. - bool GetWorkingSetKBytes(WorkingSetKBytes* ws_usage) const; - - // Computes the current process available memory for allocation. - // It does a linear scan of the address space querying each memory region - // for its free (unallocated) status. It is useful for estimating the memory - // load and fragmentation. - bool CalculateFreeMemory(FreeMBytes* free) const; - - // Returns the CPU usage in percent since the last time this method was - // called. The first time this method is called it returns 0 and will return - // the actual CPU info on subsequent calls. - // On Windows, the CPU usage value is for all CPUs. So if you have 2 CPUs and - // your process is using all the cycles of 1 CPU and not the other CPU, this - // method returns 50. - double GetCPUUsage(); - - // Retrieves accounting information for all I/O operations performed by the - // process. - // If IO information is retrieved successfully, the function returns true - // and fills in the IO_COUNTERS passed in. The function returns false - // otherwise. - bool GetIOCounters(IoCounters* io_counters) const; - - private: -#if !defined(OS_MACOSX) || defined(OS_IOS) - explicit ProcessMetrics(ProcessHandle process); -#else - ProcessMetrics(ProcessHandle process, PortProvider* port_provider); -#endif // !defined(OS_MACOSX) || defined(OS_IOS) - -#if defined(OS_LINUX) || defined(OS_ANDROID) - bool GetWorkingSetKBytesStatm(WorkingSetKBytes* ws_usage) const; -#endif - -#if defined(OS_CHROMEOS) - bool GetWorkingSetKBytesTotmaps(WorkingSetKBytes *ws_usage) const; -#endif - - ProcessHandle process_; - - int processor_count_; - - // Used to store the previous times and CPU usage counts so we can - // compute the CPU usage between calls. - int64 last_time_; - int64 last_system_time_; - -#if !defined(OS_IOS) -#if defined(OS_MACOSX) - // Queries the port provider if it's set. - mach_port_t TaskForPid(ProcessHandle process) const; - - PortProvider* port_provider_; -#elif defined(OS_POSIX) - // Jiffie count at the last_time_ we updated. - int last_cpu_; -#endif // defined(OS_POSIX) -#endif // !defined(OS_IOS) - - DISALLOW_COPY_AND_ASSIGN(ProcessMetrics); -}; - -// Returns the memory committed by the system in KBytes. -// Returns 0 if it can't compute the commit charge. -BASE_EXPORT size_t GetSystemCommitCharge(); - -#if defined(OS_LINUX) || defined(OS_ANDROID) -// Parse the data found in /proc//stat and return the sum of the -// CPU-related ticks. Returns -1 on parse error. -// Exposed for testing. -BASE_EXPORT int ParseProcStatCPU(const std::string& input); - -// Data from /proc/meminfo about system-wide memory consumption. -// Values are in KB. -struct BASE_EXPORT SystemMemoryInfoKB { - SystemMemoryInfoKB(); - - int total; - int free; - int buffers; - int cached; - int active_anon; - int inactive_anon; - int active_file; - int inactive_file; - int shmem; - - // Gem data will be -1 if not supported. - int gem_objects; - long long gem_size; -}; -// Retrieves data from /proc/meminfo about system-wide memory consumption. -// Fills in the provided |meminfo| structure. Returns true on success. -// Exposed for memory debugging widget. -BASE_EXPORT bool GetSystemMemoryInfo(SystemMemoryInfoKB* meminfo); -#endif // defined(OS_LINUX) || defined(OS_ANDROID) - -#if defined(OS_LINUX) || defined(OS_ANDROID) -// Get the number of threads of |process| as available in /proc//stat. -// This should be used with care as no synchronization with running threads is -// done. This is mostly useful to guarantee being single-threaded. -// Returns 0 on failure. -BASE_EXPORT int GetNumberOfThreads(ProcessHandle process); - -// /proc/self/exe refers to the current executable. -BASE_EXPORT extern const char kProcSelfExe[]; -#endif // defined(OS_LINUX) || defined(OS_ANDROID) - -#if defined(OS_POSIX) -// Returns the maximum number of file descriptors that can be open by a process -// at once. If the number is unavailable, a conservative best guess is returned. -size_t GetMaxFds(); -#endif // defined(OS_POSIX) - -} // namespace base - -#endif // BASE_PROCESS_PROCESS_METRICS_H_ diff --git a/base/process/process_metrics_freebsd.cc b/base/process/process_metrics_freebsd.cc deleted file mode 100644 index 019454cd81..0000000000 --- a/base/process/process_metrics_freebsd.cc +++ /dev/null @@ -1,122 +0,0 @@ -// Copyright (c) 2013 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "base/process/process_metrics.h" - -namespace base { - -ProcessMetrics::ProcessMetrics(ProcessHandle process) - : process_(process), - last_time_(0), - last_system_time_(0), - last_cpu_(0) { - processor_count_ = base::SysInfo::NumberOfProcessors(); -} - -// static -ProcessMetrics* ProcessMetrics::CreateProcessMetrics(ProcessHandle process) { - return new ProcessMetrics(process); -} - -size_t ProcessMetrics::GetPagefileUsage() const { - struct kinfo_proc info; - int mib[] = { CTL_KERN, KERN_PROC, KERN_PROC_PID, process_ }; - size_t length = sizeof(info); - - if (sysctl(mib, arraysize(mib), &info, &length, NULL, 0) < 0) - return 0; - - return info.ki_size; -} - -size_t ProcessMetrics::GetPeakPagefileUsage() const { - return 0; -} - -size_t ProcessMetrics::GetWorkingSetSize() const { - struct kinfo_proc info; - int mib[] = { CTL_KERN, KERN_PROC, KERN_PROC_PID, process_ }; - size_t length = sizeof(info); - - if (sysctl(mib, arraysize(mib), &info, &length, NULL, 0) < 0) - return 0; - - return info.ki_rssize * getpagesize(); -} - -size_t ProcessMetrics::GetPeakWorkingSetSize() const { - return 0; -} - -bool ProcessMetrics::GetMemoryBytes(size_t* private_bytes, - size_t* shared_bytes) { - WorkingSetKBytes ws_usage; - if (!GetWorkingSetKBytes(&ws_usage)) - return false; - - if (private_bytes) - *private_bytes = ws_usage.priv << 10; - - if (shared_bytes) - *shared_bytes = ws_usage.shared * 1024; - - return true; -} - -bool ProcessMetrics::GetWorkingSetKBytes(WorkingSetKBytes* ws_usage) const { -// TODO(bapt) be sure we can't be precise - size_t priv = GetWorkingSetSize(); - if (!priv) - return false; - ws_usage->priv = priv / 1024; - ws_usage->shareable = 0; - ws_usage->shared = 0; - - return true; -} - -double ProcessMetrics::GetCPUUsage() { - struct kinfo_proc info; - int mib[] = { CTL_KERN, KERN_PROC, KERN_PROC_PID, process_ }; - size_t length = sizeof(info); - - struct timeval now; - int retval = gettimeofday(&now, NULL); - if (retval) - return 0; - - if (sysctl(mib, arraysize(mib), &info, &length, NULL, 0) < 0) - return 0; - - return (info.ki_pctcpu / FSCALE) * 100.0; -} - -bool ProcessMetrics::GetIOCounters(IoCounters* io_counters) const { - return false; -} - -size_t GetSystemCommitCharge() { - int mib[2], pagesize; - unsigned long mem_total, mem_free, mem_inactive; - size_t length = sizeof(mem_total); - - if (sysctl(mib, arraysize(mib), &mem_total, &length, NULL, 0) < 0) - return 0; - - length = sizeof(mem_free); - if (sysctlbyname("vm.stats.vm.v_free_count", &mem_free, &length, NULL, 0) < 0) - return 0; - - length = sizeof(mem_inactive); - if (sysctlbyname("vm.stats.vm.v_inactive_count", &mem_inactive, &length, - NULL, 0) < 0) { - return 0; - } - - pagesize = getpagesize(); - - return mem_total - (mem_free*pagesize) - (mem_inactive*pagesize); -} - -} // namespace base diff --git a/base/process/process_metrics_ios.cc b/base/process/process_metrics_ios.cc deleted file mode 100644 index 94c671901b..0000000000 --- a/base/process/process_metrics_ios.cc +++ /dev/null @@ -1,64 +0,0 @@ -// Copyright (c) 2013 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "base/process/process_metrics.h" - -#include - -namespace base { - -namespace { - -bool GetTaskInfo(task_basic_info_64* task_info_data) { - mach_msg_type_number_t count = TASK_BASIC_INFO_64_COUNT; - kern_return_t kr = task_info(mach_task_self(), - TASK_BASIC_INFO_64, - reinterpret_cast(task_info_data), - &count); - return kr == KERN_SUCCESS; -} - -} // namespace - -ProcessMetrics::ProcessMetrics(ProcessHandle process) {} - -ProcessMetrics::~ProcessMetrics() {} - -// static -ProcessMetrics* ProcessMetrics::CreateProcessMetrics(ProcessHandle process) { - return new ProcessMetrics(process); -} - -size_t ProcessMetrics::GetPagefileUsage() const { - task_basic_info_64 task_info_data; - if (!GetTaskInfo(&task_info_data)) - return 0; - return task_info_data.virtual_size; -} - -size_t ProcessMetrics::GetWorkingSetSize() const { - task_basic_info_64 task_info_data; - if (!GetTaskInfo(&task_info_data)) - return 0; - return task_info_data.resident_size; -} - -size_t GetMaxFds() { - static const rlim_t kSystemDefaultMaxFds = 256; - rlim_t max_fds; - struct rlimit nofile; - if (getrlimit(RLIMIT_NOFILE, &nofile)) { - // Error case: Take a best guess. - max_fds = kSystemDefaultMaxFds; - } else { - max_fds = nofile.rlim_cur; - } - - if (max_fds > INT_MAX) - max_fds = INT_MAX; - - return static_cast(max_fds); -} - -} // namespace base diff --git a/base/process/process_metrics_linux.cc b/base/process/process_metrics_linux.cc deleted file mode 100644 index 1c86ee467c..0000000000 --- a/base/process/process_metrics_linux.cc +++ /dev/null @@ -1,516 +0,0 @@ -// Copyright (c) 2013 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "base/process/process_metrics.h" - -#include -#include -#include -#include -#include -#include - -#include "base/file_util.h" -#include "base/logging.h" -#include "base/process/internal_linux.h" -#include "base/strings/string_number_conversions.h" -#include "base/strings/string_split.h" -#include "base/strings/string_tokenizer.h" -#include "base/strings/string_util.h" -#include "base/sys_info.h" -#include "base/threading/thread_restrictions.h" - -namespace base { - -namespace { - -enum ParsingState { - KEY_NAME, - KEY_VALUE -}; - -// Read /proc//status and returns the value for |field|, or 0 on failure. -// Only works for fields in the form of "Field: value kB". -size_t ReadProcStatusAndGetFieldAsSizeT(pid_t pid, const std::string& field) { - FilePath stat_file = internal::GetProcPidDir(pid).Append("status"); - std::string status; - { - // Synchronously reading files in /proc is safe. - ThreadRestrictions::ScopedAllowIO allow_io; - if (!file_util::ReadFileToString(stat_file, &status)) - return 0; - } - - StringTokenizer tokenizer(status, ":\n"); - ParsingState state = KEY_NAME; - StringPiece last_key_name; - while (tokenizer.GetNext()) { - switch (state) { - case KEY_NAME: - last_key_name = tokenizer.token_piece(); - state = KEY_VALUE; - break; - case KEY_VALUE: - DCHECK(!last_key_name.empty()); - if (last_key_name == field) { - std::string value_str; - tokenizer.token_piece().CopyToString(&value_str); - std::string value_str_trimmed; - TrimWhitespaceASCII(value_str, TRIM_ALL, &value_str_trimmed); - std::vector split_value_str; - SplitString(value_str_trimmed, ' ', &split_value_str); - if (split_value_str.size() != 2 || split_value_str[1] != "kB") { - NOTREACHED(); - return 0; - } - size_t value; - if (!StringToSizeT(split_value_str[0], &value)) { - NOTREACHED(); - return 0; - } - return value; - } - state = KEY_NAME; - break; - } - } - NOTREACHED(); - return 0; -} - -// Get the total CPU of a single process. Return value is number of jiffies -// on success or -1 on error. -int GetProcessCPU(pid_t pid) { - // Use /proc//task to find all threads and parse their /stat file. - FilePath task_path = internal::GetProcPidDir(pid).Append("task"); - - DIR* dir = opendir(task_path.value().c_str()); - if (!dir) { - DPLOG(ERROR) << "opendir(" << task_path.value() << ")"; - return -1; - } - - int total_cpu = 0; - while (struct dirent* ent = readdir(dir)) { - pid_t tid = internal::ProcDirSlotToPid(ent->d_name); - if (!tid) - continue; - - // Synchronously reading files in /proc is safe. - ThreadRestrictions::ScopedAllowIO allow_io; - - std::string stat; - FilePath stat_path = - task_path.Append(ent->d_name).Append(internal::kStatFile); - if (file_util::ReadFileToString(stat_path, &stat)) { - int cpu = ParseProcStatCPU(stat); - if (cpu > 0) - total_cpu += cpu; - } - } - closedir(dir); - - return total_cpu; -} - -} // namespace - -// static -ProcessMetrics* ProcessMetrics::CreateProcessMetrics(ProcessHandle process) { - return new ProcessMetrics(process); -} - -// On linux, we return vsize. -size_t ProcessMetrics::GetPagefileUsage() const { - return internal::ReadProcStatsAndGetFieldAsSizeT(process_, - internal::VM_VSIZE); -} - -// On linux, we return the high water mark of vsize. -size_t ProcessMetrics::GetPeakPagefileUsage() const { - return ReadProcStatusAndGetFieldAsSizeT(process_, "VmPeak") * 1024; -} - -// On linux, we return RSS. -size_t ProcessMetrics::GetWorkingSetSize() const { - return internal::ReadProcStatsAndGetFieldAsSizeT(process_, internal::VM_RSS) * - getpagesize(); -} - -// On linux, we return the high water mark of RSS. -size_t ProcessMetrics::GetPeakWorkingSetSize() const { - return ReadProcStatusAndGetFieldAsSizeT(process_, "VmHWM") * 1024; -} - -bool ProcessMetrics::GetMemoryBytes(size_t* private_bytes, - size_t* shared_bytes) { - WorkingSetKBytes ws_usage; - if (!GetWorkingSetKBytes(&ws_usage)) - return false; - - if (private_bytes) - *private_bytes = ws_usage.priv * 1024; - - if (shared_bytes) - *shared_bytes = ws_usage.shared * 1024; - - return true; -} - -bool ProcessMetrics::GetWorkingSetKBytes(WorkingSetKBytes* ws_usage) const { -#if defined(OS_CHROMEOS) - if (GetWorkingSetKBytesTotmaps(ws_usage)) - return true; -#endif - return GetWorkingSetKBytesStatm(ws_usage); -} - -double ProcessMetrics::GetCPUUsage() { - struct timeval now; - int retval = gettimeofday(&now, NULL); - if (retval) - return 0; - int64 time = TimeValToMicroseconds(now); - - if (last_time_ == 0) { - // First call, just set the last values. - last_time_ = time; - last_cpu_ = GetProcessCPU(process_); - return 0; - } - - int64 time_delta = time - last_time_; - DCHECK_NE(time_delta, 0); - if (time_delta == 0) - return 0; - - int cpu = GetProcessCPU(process_); - - // We have the number of jiffies in the time period. Convert to percentage. - // Note this means we will go *over* 100 in the case where multiple threads - // are together adding to more than one CPU's worth. - TimeDelta cpu_time = internal::ClockTicksToTimeDelta(cpu); - TimeDelta last_cpu_time = internal::ClockTicksToTimeDelta(last_cpu_); - int percentage = 100 * (cpu_time - last_cpu_time).InSecondsF() / - TimeDelta::FromMicroseconds(time_delta).InSecondsF(); - - last_time_ = time; - last_cpu_ = cpu; - - return percentage; -} - -// To have /proc/self/io file you must enable CONFIG_TASK_IO_ACCOUNTING -// in your kernel configuration. -bool ProcessMetrics::GetIOCounters(IoCounters* io_counters) const { - // Synchronously reading files in /proc is safe. - ThreadRestrictions::ScopedAllowIO allow_io; - - std::string proc_io_contents; - FilePath io_file = internal::GetProcPidDir(process_).Append("io"); - if (!file_util::ReadFileToString(io_file, &proc_io_contents)) - return false; - - (*io_counters).OtherOperationCount = 0; - (*io_counters).OtherTransferCount = 0; - - StringTokenizer tokenizer(proc_io_contents, ": \n"); - ParsingState state = KEY_NAME; - StringPiece last_key_name; - while (tokenizer.GetNext()) { - switch (state) { - case KEY_NAME: - last_key_name = tokenizer.token_piece(); - state = KEY_VALUE; - break; - case KEY_VALUE: - DCHECK(!last_key_name.empty()); - if (last_key_name == "syscr") { - StringToInt64(tokenizer.token_piece(), - reinterpret_cast(&(*io_counters).ReadOperationCount)); - } else if (last_key_name == "syscw") { - StringToInt64(tokenizer.token_piece(), - reinterpret_cast(&(*io_counters).WriteOperationCount)); - } else if (last_key_name == "rchar") { - StringToInt64(tokenizer.token_piece(), - reinterpret_cast(&(*io_counters).ReadTransferCount)); - } else if (last_key_name == "wchar") { - StringToInt64(tokenizer.token_piece(), - reinterpret_cast(&(*io_counters).WriteTransferCount)); - } - state = KEY_NAME; - break; - } - } - return true; -} - -ProcessMetrics::ProcessMetrics(ProcessHandle process) - : process_(process), - last_time_(0), - last_system_time_(0), - last_cpu_(0) { - processor_count_ = base::SysInfo::NumberOfProcessors(); -} - -#if defined(OS_CHROMEOS) -// Private, Shared and Proportional working set sizes are obtained from -// /proc//totmaps -bool ProcessMetrics::GetWorkingSetKBytesTotmaps(WorkingSetKBytes *ws_usage) - const { - // The format of /proc//totmaps is: - // - // Rss: 6120 kB - // Pss: 3335 kB - // Shared_Clean: 1008 kB - // Shared_Dirty: 4012 kB - // Private_Clean: 4 kB - // Private_Dirty: 1096 kB - // Referenced: XXX kB - // Anonymous: XXX kB - // AnonHugePages: XXX kB - // Swap: XXX kB - // Locked: XXX kB - const size_t kPssIndex = (1 * 3) + 1; - const size_t kPrivate_CleanIndex = (4 * 3) + 1; - const size_t kPrivate_DirtyIndex = (5 * 3) + 1; - const size_t kSwapIndex = (9 * 3) + 1; - - std::string totmaps_data; - { - FilePath totmaps_file = internal::GetProcPidDir(process_).Append("totmaps"); - ThreadRestrictions::ScopedAllowIO allow_io; - bool ret = file_util::ReadFileToString(totmaps_file, &totmaps_data); - if (!ret || totmaps_data.length() == 0) - return false; - } - - std::vector totmaps_fields; - SplitStringAlongWhitespace(totmaps_data, &totmaps_fields); - - DCHECK_EQ("Pss:", totmaps_fields[kPssIndex-1]); - DCHECK_EQ("Private_Clean:", totmaps_fields[kPrivate_CleanIndex - 1]); - DCHECK_EQ("Private_Dirty:", totmaps_fields[kPrivate_DirtyIndex - 1]); - DCHECK_EQ("Swap:", totmaps_fields[kSwapIndex-1]); - - int pss = 0; - int private_clean = 0; - int private_dirty = 0; - int swap = 0; - bool ret = true; - ret &= StringToInt(totmaps_fields[kPssIndex], &pss); - ret &= StringToInt(totmaps_fields[kPrivate_CleanIndex], &private_clean); - ret &= StringToInt(totmaps_fields[kPrivate_DirtyIndex], &private_dirty); - ret &= StringToInt(totmaps_fields[kSwapIndex], &swap); - - // On ChromeOS swap is to zram. We count this as private / shared, as - // increased swap decreases available RAM to user processes, which would - // otherwise create surprising results. - ws_usage->priv = private_clean + private_dirty + swap; - ws_usage->shared = pss + swap; - ws_usage->shareable = 0; - ws_usage->swapped = swap; - return ret; -} -#endif - -// Private and Shared working set sizes are obtained from /proc//statm. -bool ProcessMetrics::GetWorkingSetKBytesStatm(WorkingSetKBytes* ws_usage) - const { - // Use statm instead of smaps because smaps is: - // a) Large and slow to parse. - // b) Unavailable in the SUID sandbox. - - // First we need to get the page size, since everything is measured in pages. - // For details, see: man 5 proc. - const int page_size_kb = getpagesize() / 1024; - if (page_size_kb <= 0) - return false; - - std::string statm; - { - FilePath statm_file = internal::GetProcPidDir(process_).Append("statm"); - // Synchronously reading files in /proc is safe. - ThreadRestrictions::ScopedAllowIO allow_io; - bool ret = file_util::ReadFileToString(statm_file, &statm); - if (!ret || statm.length() == 0) - return false; - } - - std::vector statm_vec; - SplitString(statm, ' ', &statm_vec); - if (statm_vec.size() != 7) - return false; // Not the format we expect. - - int statm_rss, statm_shared; - bool ret = true; - ret &= StringToInt(statm_vec[1], &statm_rss); - ret &= StringToInt(statm_vec[2], &statm_shared); - - ws_usage->priv = (statm_rss - statm_shared) * page_size_kb; - ws_usage->shared = statm_shared * page_size_kb; - - // Sharable is not calculated, as it does not provide interesting data. - ws_usage->shareable = 0; - -#if defined(OS_CHROMEOS) - // Can't get swapped memory from statm. - ws_usage->swapped = 0; -#endif - - return ret; -} - -size_t GetSystemCommitCharge() { - SystemMemoryInfoKB meminfo; - if (!GetSystemMemoryInfo(&meminfo)) - return 0; - return meminfo.total - meminfo.free - meminfo.buffers - meminfo.cached; -} - -// Exposed for testing. -int ParseProcStatCPU(const std::string& input) { - std::vector proc_stats; - if (!internal::ParseProcStats(input, &proc_stats)) - return -1; - - if (proc_stats.size() <= internal::VM_STIME) - return -1; - int utime = GetProcStatsFieldAsInt(proc_stats, internal::VM_UTIME); - int stime = GetProcStatsFieldAsInt(proc_stats, internal::VM_STIME); - return utime + stime; -} - -namespace { - -// The format of /proc/meminfo is: -// -// MemTotal: 8235324 kB -// MemFree: 1628304 kB -// Buffers: 429596 kB -// Cached: 4728232 kB -// ... -const size_t kMemTotalIndex = 1; -const size_t kMemFreeIndex = 4; -const size_t kMemBuffersIndex = 7; -const size_t kMemCachedIndex = 10; -const size_t kMemActiveAnonIndex = 22; -const size_t kMemInactiveAnonIndex = 25; -const size_t kMemActiveFileIndex = 28; -const size_t kMemInactiveFileIndex = 31; - -} // namespace - -SystemMemoryInfoKB::SystemMemoryInfoKB() - : total(0), - free(0), - buffers(0), - cached(0), - active_anon(0), - inactive_anon(0), - active_file(0), - inactive_file(0), - shmem(0), - gem_objects(-1), - gem_size(-1) { -} - -bool GetSystemMemoryInfo(SystemMemoryInfoKB* meminfo) { - // Synchronously reading files in /proc is safe. - ThreadRestrictions::ScopedAllowIO allow_io; - - // Used memory is: total - free - buffers - caches - FilePath meminfo_file("/proc/meminfo"); - std::string meminfo_data; - if (!file_util::ReadFileToString(meminfo_file, &meminfo_data)) { - DLOG(WARNING) << "Failed to open " << meminfo_file.value(); - return false; - } - std::vector meminfo_fields; - SplitStringAlongWhitespace(meminfo_data, &meminfo_fields); - - if (meminfo_fields.size() < kMemCachedIndex) { - DLOG(WARNING) << "Failed to parse " << meminfo_file.value() - << ". Only found " << meminfo_fields.size() << " fields."; - return false; - } - - DCHECK_EQ(meminfo_fields[kMemTotalIndex-1], "MemTotal:"); - DCHECK_EQ(meminfo_fields[kMemFreeIndex-1], "MemFree:"); - DCHECK_EQ(meminfo_fields[kMemBuffersIndex-1], "Buffers:"); - DCHECK_EQ(meminfo_fields[kMemCachedIndex-1], "Cached:"); - DCHECK_EQ(meminfo_fields[kMemActiveAnonIndex-1], "Active(anon):"); - DCHECK_EQ(meminfo_fields[kMemInactiveAnonIndex-1], "Inactive(anon):"); - DCHECK_EQ(meminfo_fields[kMemActiveFileIndex-1], "Active(file):"); - DCHECK_EQ(meminfo_fields[kMemInactiveFileIndex-1], "Inactive(file):"); - - StringToInt(meminfo_fields[kMemTotalIndex], &meminfo->total); - StringToInt(meminfo_fields[kMemFreeIndex], &meminfo->free); - StringToInt(meminfo_fields[kMemBuffersIndex], &meminfo->buffers); - StringToInt(meminfo_fields[kMemCachedIndex], &meminfo->cached); - StringToInt(meminfo_fields[kMemActiveAnonIndex], &meminfo->active_anon); - StringToInt(meminfo_fields[kMemInactiveAnonIndex], - &meminfo->inactive_anon); - StringToInt(meminfo_fields[kMemActiveFileIndex], &meminfo->active_file); - StringToInt(meminfo_fields[kMemInactiveFileIndex], - &meminfo->inactive_file); -#if defined(OS_CHROMEOS) - // Chrome OS has a tweaked kernel that allows us to query Shmem, which is - // usually video memory otherwise invisible to the OS. Unfortunately, the - // meminfo format varies on different hardware so we have to search for the - // string. It always appears after "Cached:". - for (size_t i = kMemCachedIndex+2; i < meminfo_fields.size(); i += 3) { - if (meminfo_fields[i] == "Shmem:") { - StringToInt(meminfo_fields[i+1], &meminfo->shmem); - break; - } - } - - // Report on Chrome OS GEM object graphics memory. /var/run/debugfs_gpu is a - // bind mount into /sys/kernel/debug and synchronously reading the in-memory - // files in /sys is fast. -#if defined(ARCH_CPU_ARM_FAMILY) - FilePath geminfo_file("/var/run/debugfs_gpu/exynos_gem_objects"); -#else - FilePath geminfo_file("/var/run/debugfs_gpu/i915_gem_objects"); -#endif - std::string geminfo_data; - meminfo->gem_objects = -1; - meminfo->gem_size = -1; - if (file_util::ReadFileToString(geminfo_file, &geminfo_data)) { - int gem_objects = -1; - long long gem_size = -1; - int num_res = sscanf(geminfo_data.c_str(), - "%d objects, %lld bytes", - &gem_objects, &gem_size); - if (num_res == 2) { - meminfo->gem_objects = gem_objects; - meminfo->gem_size = gem_size; - } - } - -#if defined(ARCH_CPU_ARM_FAMILY) - // Incorporate Mali graphics memory if present. - FilePath mali_memory_file("/sys/devices/platform/mali.0/memory"); - std::string mali_memory_data; - if (file_util::ReadFileToString(mali_memory_file, &mali_memory_data)) { - long long mali_size = -1; - int num_res = sscanf(mali_memory_data.c_str(), "%lld bytes", &mali_size); - if (num_res == 1) - meminfo->gem_size += mali_size; - } -#endif // defined(ARCH_CPU_ARM_FAMILY) -#endif // defined(OS_CHROMEOS) - - return true; -} - -const char kProcSelfExe[] = "/proc/self/exe"; - -int GetNumberOfThreads(ProcessHandle process) { - return internal::ReadProcStatsAndGetFieldAsInt(process, - internal::VM_NUMTHREADS); -} - -} // namespace base diff --git a/base/process/process_metrics_mac.cc b/base/process/process_metrics_mac.cc deleted file mode 100644 index 048735ed36..0000000000 --- a/base/process/process_metrics_mac.cc +++ /dev/null @@ -1,325 +0,0 @@ -// Copyright (c) 2013 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "base/process/process_metrics.h" - -#include -#include -#include -#include - -#include "base/containers/hash_tables.h" -#include "base/logging.h" -#include "base/mac/scoped_mach_port.h" -#include "base/sys_info.h" - -namespace base { - -namespace { - -bool GetTaskInfo(mach_port_t task, task_basic_info_64* task_info_data) { - if (task == MACH_PORT_NULL) - return false; - mach_msg_type_number_t count = TASK_BASIC_INFO_64_COUNT; - kern_return_t kr = task_info(task, - TASK_BASIC_INFO_64, - reinterpret_cast(task_info_data), - &count); - // Most likely cause for failure: |task| is a zombie. - return kr == KERN_SUCCESS; -} - -bool GetCPUTypeForProcess(pid_t pid, cpu_type_t* cpu_type) { - size_t len = sizeof(*cpu_type); - int result = sysctlbyname("sysctl.proc_cputype", - cpu_type, - &len, - NULL, - 0); - if (result != 0) { - DPLOG(ERROR) << "sysctlbyname(""sysctl.proc_cputype"")"; - return false; - } - - return true; -} - -bool IsAddressInSharedRegion(mach_vm_address_t addr, cpu_type_t type) { - if (type == CPU_TYPE_I386) { - return addr >= SHARED_REGION_BASE_I386 && - addr < (SHARED_REGION_BASE_I386 + SHARED_REGION_SIZE_I386); - } else if (type == CPU_TYPE_X86_64) { - return addr >= SHARED_REGION_BASE_X86_64 && - addr < (SHARED_REGION_BASE_X86_64 + SHARED_REGION_SIZE_X86_64); - } else { - return false; - } -} - -} // namespace - -// Getting a mach task from a pid for another process requires permissions in -// general, so there doesn't really seem to be a way to do these (and spinning -// up ps to fetch each stats seems dangerous to put in a base api for anyone to -// call). Child processes ipc their port, so return something if available, -// otherwise return 0. - -// static -ProcessMetrics* ProcessMetrics::CreateProcessMetrics( - ProcessHandle process, - ProcessMetrics::PortProvider* port_provider) { - return new ProcessMetrics(process, port_provider); -} - -size_t ProcessMetrics::GetPagefileUsage() const { - task_basic_info_64 task_info_data; - if (!GetTaskInfo(TaskForPid(process_), &task_info_data)) - return 0; - return task_info_data.virtual_size; -} - -size_t ProcessMetrics::GetPeakPagefileUsage() const { - return 0; -} - -size_t ProcessMetrics::GetWorkingSetSize() const { - task_basic_info_64 task_info_data; - if (!GetTaskInfo(TaskForPid(process_), &task_info_data)) - return 0; - return task_info_data.resident_size; -} - -size_t ProcessMetrics::GetPeakWorkingSetSize() const { - return 0; -} - -// This is a rough approximation of the algorithm that libtop uses. -// private_bytes is the size of private resident memory. -// shared_bytes is the size of shared resident memory. -bool ProcessMetrics::GetMemoryBytes(size_t* private_bytes, - size_t* shared_bytes) { - kern_return_t kr; - size_t private_pages_count = 0; - size_t shared_pages_count = 0; - - if (!private_bytes && !shared_bytes) - return true; - - mach_port_t task = TaskForPid(process_); - if (task == MACH_PORT_NULL) { - DLOG(ERROR) << "Invalid process"; - return false; - } - - cpu_type_t cpu_type; - if (!GetCPUTypeForProcess(process_, &cpu_type)) - return false; - - // The same region can be referenced multiple times. To avoid double counting - // we need to keep track of which regions we've already counted. - base::hash_set seen_objects; - - // We iterate through each VM region in the task's address map. For shared - // memory we add up all the pages that are marked as shared. Like libtop we - // try to avoid counting pages that are also referenced by other tasks. Since - // we don't have access to the VM regions of other tasks the only hint we have - // is if the address is in the shared region area. - // - // Private memory is much simpler. We simply count the pages that are marked - // as private or copy on write (COW). - // - // See libtop_update_vm_regions in - // http://www.opensource.apple.com/source/top/top-67/libtop.c - mach_vm_size_t size = 0; - for (mach_vm_address_t address = MACH_VM_MIN_ADDRESS;; address += size) { - vm_region_top_info_data_t info; - mach_msg_type_number_t info_count = VM_REGION_TOP_INFO_COUNT; - mach_port_t object_name; - kr = mach_vm_region(task, - &address, - &size, - VM_REGION_TOP_INFO, - (vm_region_info_t)&info, - &info_count, - &object_name); - if (kr == KERN_INVALID_ADDRESS) { - // We're at the end of the address space. - break; - } else if (kr != KERN_SUCCESS) { - DLOG(ERROR) << "Calling mach_vm_region failed with error: " - << mach_error_string(kr); - return false; - } - - if (IsAddressInSharedRegion(address, cpu_type) && - info.share_mode != SM_PRIVATE) - continue; - - if (info.share_mode == SM_COW && info.ref_count == 1) - info.share_mode = SM_PRIVATE; - - switch (info.share_mode) { - case SM_PRIVATE: - private_pages_count += info.private_pages_resident; - private_pages_count += info.shared_pages_resident; - break; - case SM_COW: - private_pages_count += info.private_pages_resident; - // Fall through - case SM_SHARED: - if (seen_objects.count(info.obj_id) == 0) { - // Only count the first reference to this region. - seen_objects.insert(info.obj_id); - shared_pages_count += info.shared_pages_resident; - } - break; - default: - break; - } - } - - vm_size_t page_size; - kr = host_page_size(task, &page_size); - if (kr != KERN_SUCCESS) { - DLOG(ERROR) << "Failed to fetch host page size, error: " - << mach_error_string(kr); - return false; - } - - if (private_bytes) - *private_bytes = private_pages_count * page_size; - if (shared_bytes) - *shared_bytes = shared_pages_count * page_size; - - return true; -} - -void ProcessMetrics::GetCommittedKBytes(CommittedKBytes* usage) const { -} - -bool ProcessMetrics::GetWorkingSetKBytes(WorkingSetKBytes* ws_usage) const { - size_t priv = GetWorkingSetSize(); - if (!priv) - return false; - ws_usage->priv = priv / 1024; - ws_usage->shareable = 0; - ws_usage->shared = 0; - return true; -} - -#define TIME_VALUE_TO_TIMEVAL(a, r) do { \ - (r)->tv_sec = (a)->seconds; \ - (r)->tv_usec = (a)->microseconds; \ -} while (0) - -double ProcessMetrics::GetCPUUsage() { - mach_port_t task = TaskForPid(process_); - if (task == MACH_PORT_NULL) - return 0; - - kern_return_t kr; - - // Libtop explicitly loops over the threads (libtop_pinfo_update_cpu_usage() - // in libtop.c), but this is more concise and gives the same results: - task_thread_times_info thread_info_data; - mach_msg_type_number_t thread_info_count = TASK_THREAD_TIMES_INFO_COUNT; - kr = task_info(task, - TASK_THREAD_TIMES_INFO, - reinterpret_cast(&thread_info_data), - &thread_info_count); - if (kr != KERN_SUCCESS) { - // Most likely cause: |task| is a zombie. - return 0; - } - - task_basic_info_64 task_info_data; - if (!GetTaskInfo(task, &task_info_data)) - return 0; - - /* Set total_time. */ - // thread info contains live time... - struct timeval user_timeval, system_timeval, task_timeval; - TIME_VALUE_TO_TIMEVAL(&thread_info_data.user_time, &user_timeval); - TIME_VALUE_TO_TIMEVAL(&thread_info_data.system_time, &system_timeval); - timeradd(&user_timeval, &system_timeval, &task_timeval); - - // ... task info contains terminated time. - TIME_VALUE_TO_TIMEVAL(&task_info_data.user_time, &user_timeval); - TIME_VALUE_TO_TIMEVAL(&task_info_data.system_time, &system_timeval); - timeradd(&user_timeval, &task_timeval, &task_timeval); - timeradd(&system_timeval, &task_timeval, &task_timeval); - - struct timeval now; - int retval = gettimeofday(&now, NULL); - if (retval) - return 0; - - int64 time = TimeValToMicroseconds(now); - int64 task_time = TimeValToMicroseconds(task_timeval); - - if ((last_system_time_ == 0) || (last_time_ == 0)) { - // First call, just set the last values. - last_system_time_ = task_time; - last_time_ = time; - return 0; - } - - int64 system_time_delta = task_time - last_system_time_; - int64 time_delta = time - last_time_; - DCHECK_NE(0U, time_delta); - if (time_delta == 0) - return 0; - - last_system_time_ = task_time; - last_time_ = time; - - return static_cast(system_time_delta * 100.0) / time_delta; -} - -bool ProcessMetrics::GetIOCounters(IoCounters* io_counters) const { - return false; -} - -ProcessMetrics::ProcessMetrics(ProcessHandle process, - ProcessMetrics::PortProvider* port_provider) - : process_(process), - last_time_(0), - last_system_time_(0), - port_provider_(port_provider) { - processor_count_ = SysInfo::NumberOfProcessors(); -} - -mach_port_t ProcessMetrics::TaskForPid(ProcessHandle process) const { - mach_port_t task = MACH_PORT_NULL; - if (port_provider_) - task = port_provider_->TaskForPid(process_); - if (task == MACH_PORT_NULL && process_ == getpid()) - task = mach_task_self(); - return task; -} - -// Bytes committed by the system. -size_t GetSystemCommitCharge() { - base::mac::ScopedMachPort host(mach_host_self()); - mach_msg_type_number_t count = HOST_VM_INFO_COUNT; - vm_statistics_data_t data; - kern_return_t kr = host_statistics(host, HOST_VM_INFO, - reinterpret_cast(&data), - &count); - if (kr) { - DLOG(WARNING) << "Failed to fetch host statistics."; - return 0; - } - - vm_size_t page_size; - kr = host_page_size(host, &page_size); - if (kr) { - DLOG(ERROR) << "Failed to fetch host page size."; - return 0; - } - - return (data.active_count * page_size) / 1024; -} - -} // namespace base diff --git a/base/process/process_metrics_openbsd.cc b/base/process/process_metrics_openbsd.cc deleted file mode 100644 index 36f607c0a9..0000000000 --- a/base/process/process_metrics_openbsd.cc +++ /dev/null @@ -1,168 +0,0 @@ -// Copyright (c) 2013 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "base/process/process_metrics.h" - -#include -#include - -namespace base { - -// static -ProcessMetrics* ProcessMetrics::CreateProcessMetrics(ProcessHandle process) { - return new ProcessMetrics(process); -} - -size_t ProcessMetrics::GetPagefileUsage() const { - struct kinfo_proc info; - size_t length; - int mib[] = { CTL_KERN, KERN_PROC, KERN_PROC_PID, process_, - sizeof(struct kinfo_proc), 0 }; - - if (sysctl(mib, arraysize(mib), NULL, &length, NULL, 0) < 0) - return -1; - - mib[5] = (length / sizeof(struct kinfo_proc)); - - if (sysctl(mib, arraysize(mib), &info, &length, NULL, 0) < 0) - return -1; - - return (info.p_vm_tsize + info.p_vm_dsize + info.p_vm_ssize); -} - -size_t ProcessMetrics::GetPeakPagefileUsage() const { - return 0; -} - -size_t ProcessMetrics::GetWorkingSetSize() const { - struct kinfo_proc info; - size_t length; - int mib[] = { CTL_KERN, KERN_PROC, KERN_PROC_PID, process_, - sizeof(struct kinfo_proc), 0 }; - - if (sysctl(mib, arraysize(mib), NULL, &length, NULL, 0) < 0) - return -1; - - mib[5] = (length / sizeof(struct kinfo_proc)); - - if (sysctl(mib, arraysize(mib), &info, &length, NULL, 0) < 0) - return -1; - - return info.p_vm_rssize * getpagesize(); -} - -size_t ProcessMetrics::GetPeakWorkingSetSize() const { - return 0; -} - -bool ProcessMetrics::GetMemoryBytes(size_t* private_bytes, - size_t* shared_bytes) { - WorkingSetKBytes ws_usage; - - if (!GetWorkingSetKBytes(&ws_usage)) - return false; - - if (private_bytes) - *private_bytes = ws_usage.priv << 10; - - if (shared_bytes) - *shared_bytes = ws_usage.shared * 1024; - - return true; -} - -bool ProcessMetrics::GetWorkingSetKBytes(WorkingSetKBytes* ws_usage) const { - // TODO(bapt): be sure we can't be precise - size_t priv = GetWorkingSetSize(); - if (!priv) - return false; - ws_usage->priv = priv / 1024; - ws_usage->shareable = 0; - ws_usage->shared = 0; - - return true; -} - -bool ProcessMetrics::GetIOCounters(IoCounters* io_counters) const { - return false; -} - -static int GetProcessCPU(pid_t pid) { - struct kinfo_proc info; - size_t length; - int mib[] = { CTL_KERN, KERN_PROC, KERN_PROC_PID, pid, - sizeof(struct kinfo_proc), 0 }; - - if (sysctl(mib, arraysize(mib), NULL, &length, NULL, 0) < 0) - return -1; - - mib[5] = (length / sizeof(struct kinfo_proc)); - - if (sysctl(mib, arraysize(mib), &info, &length, NULL, 0) < 0) - return 0; - - return info.p_pctcpu; -} - -double ProcessMetrics::GetCPUUsage() { - struct timeval now; - - int retval = gettimeofday(&now, NULL); - if (retval) - return 0; - - int64 time = TimeValToMicroseconds(now); - - if (last_time_ == 0) { - // First call, just set the last values. - last_time_ = time; - last_cpu_ = GetProcessCPU(process_); - return 0; - } - - int64 time_delta = time - last_time_; - DCHECK_NE(time_delta, 0); - - if (time_delta == 0) - return 0; - - int cpu = GetProcessCPU(process_); - - last_time_ = time; - last_cpu_ = cpu; - - double percentage = static_cast((cpu * 100.0) / FSCALE); - - return percentage; -} - -ProcessMetrics::ProcessMetrics(ProcessHandle process) - : process_(process), - last_time_(0), - last_system_time_(0), - last_cpu_(0) { - - processor_count_ = base::SysInfo::NumberOfProcessors(); -} - -size_t GetSystemCommitCharge() { - int mib[] = { CTL_VM, VM_METER }; - int pagesize; - struct vmtotal vmtotal; - unsigned long mem_total, mem_free, mem_inactive; - size_t len = sizeof(vmtotal); - - if (sysctl(mib, arraysize(mib), &vmtotal, &len, NULL, 0) < 0) - return 0; - - mem_total = vmtotal.t_vm; - mem_free = vmtotal.t_free; - mem_inactive = vmtotal.t_vm - vmtotal.t_avm; - - pagesize = getpagesize(); - - return mem_total - (mem_free*pagesize) - (mem_inactive*pagesize); -} - -} // namespace base diff --git a/base/process/process_metrics_posix.cc b/base/process/process_metrics_posix.cc deleted file mode 100644 index 531f6a40d7..0000000000 --- a/base/process/process_metrics_posix.cc +++ /dev/null @@ -1,55 +0,0 @@ -// Copyright (c) 2013 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "base/process/process_metrics.h" - -#include -#include - -#include "base/logging.h" - -namespace base { - -int64 TimeValToMicroseconds(const struct timeval& tv) { - static const int kMicrosecondsPerSecond = 1000000; - int64 ret = tv.tv_sec; // Avoid (int * int) integer overflow. - ret *= kMicrosecondsPerSecond; - ret += tv.tv_usec; - return ret; -} - -ProcessMetrics::~ProcessMetrics() { } - -#if defined(OS_LINUX) -static const rlim_t kSystemDefaultMaxFds = 8192; -#elif defined(OS_MACOSX) -static const rlim_t kSystemDefaultMaxFds = 256; -#elif defined(OS_SOLARIS) -static const rlim_t kSystemDefaultMaxFds = 8192; -#elif defined(OS_FREEBSD) -static const rlim_t kSystemDefaultMaxFds = 8192; -#elif defined(OS_OPENBSD) -static const rlim_t kSystemDefaultMaxFds = 256; -#elif defined(OS_ANDROID) -static const rlim_t kSystemDefaultMaxFds = 1024; -#endif - -size_t GetMaxFds() { - rlim_t max_fds; - struct rlimit nofile; - if (getrlimit(RLIMIT_NOFILE, &nofile)) { - // getrlimit failed. Take a best guess. - max_fds = kSystemDefaultMaxFds; - RAW_LOG(ERROR, "getrlimit(RLIMIT_NOFILE) failed"); - } else { - max_fds = nofile.rlim_cur; - } - - if (max_fds > INT_MAX) - max_fds = INT_MAX; - - return static_cast(max_fds); -} - -} // namespace base diff --git a/base/process/process_metrics_win.cc b/base/process/process_metrics_win.cc deleted file mode 100644 index f42ea86feb..0000000000 --- a/base/process/process_metrics_win.cc +++ /dev/null @@ -1,315 +0,0 @@ -// Copyright (c) 2013 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "base/process/process_metrics.h" - -#include -#include - -#include "base/logging.h" -#include "base/sys_info.h" - -namespace base { - -// System pagesize. This value remains constant on x86/64 architectures. -const int PAGESIZE_KB = 4; - -ProcessMetrics::~ProcessMetrics() { } - -// static -ProcessMetrics* ProcessMetrics::CreateProcessMetrics(ProcessHandle process) { - return new ProcessMetrics(process); -} - -size_t ProcessMetrics::GetPagefileUsage() const { - PROCESS_MEMORY_COUNTERS pmc; - if (GetProcessMemoryInfo(process_, &pmc, sizeof(pmc))) { - return pmc.PagefileUsage; - } - return 0; -} - -// Returns the peak space allocated for the pagefile, in bytes. -size_t ProcessMetrics::GetPeakPagefileUsage() const { - PROCESS_MEMORY_COUNTERS pmc; - if (GetProcessMemoryInfo(process_, &pmc, sizeof(pmc))) { - return pmc.PeakPagefileUsage; - } - return 0; -} - -// Returns the current working set size, in bytes. -size_t ProcessMetrics::GetWorkingSetSize() const { - PROCESS_MEMORY_COUNTERS pmc; - if (GetProcessMemoryInfo(process_, &pmc, sizeof(pmc))) { - return pmc.WorkingSetSize; - } - return 0; -} - -// Returns the peak working set size, in bytes. -size_t ProcessMetrics::GetPeakWorkingSetSize() const { - PROCESS_MEMORY_COUNTERS pmc; - if (GetProcessMemoryInfo(process_, &pmc, sizeof(pmc))) { - return pmc.PeakWorkingSetSize; - } - return 0; -} - -bool ProcessMetrics::GetMemoryBytes(size_t* private_bytes, - size_t* shared_bytes) { - // PROCESS_MEMORY_COUNTERS_EX is not supported until XP SP2. - // GetProcessMemoryInfo() will simply fail on prior OS. So the requested - // information is simply not available. Hence, we will return 0 on unsupported - // OSes. Unlike most Win32 API, we don't need to initialize the "cb" member. - PROCESS_MEMORY_COUNTERS_EX pmcx; - if (private_bytes && - GetProcessMemoryInfo(process_, - reinterpret_cast(&pmcx), - sizeof(pmcx))) { - *private_bytes = pmcx.PrivateUsage; - } - - if (shared_bytes) { - WorkingSetKBytes ws_usage; - if (!GetWorkingSetKBytes(&ws_usage)) - return false; - - *shared_bytes = ws_usage.shared * 1024; - } - - return true; -} - -void ProcessMetrics::GetCommittedKBytes(CommittedKBytes* usage) const { - MEMORY_BASIC_INFORMATION mbi = {0}; - size_t committed_private = 0; - size_t committed_mapped = 0; - size_t committed_image = 0; - void* base_address = NULL; - while (VirtualQueryEx(process_, base_address, &mbi, sizeof(mbi)) == - sizeof(mbi)) { - if (mbi.State == MEM_COMMIT) { - if (mbi.Type == MEM_PRIVATE) { - committed_private += mbi.RegionSize; - } else if (mbi.Type == MEM_MAPPED) { - committed_mapped += mbi.RegionSize; - } else if (mbi.Type == MEM_IMAGE) { - committed_image += mbi.RegionSize; - } else { - NOTREACHED(); - } - } - void* new_base = (static_cast(mbi.BaseAddress)) + mbi.RegionSize; - // Avoid infinite loop by weird MEMORY_BASIC_INFORMATION. - // If we query 64bit processes in a 32bit process, VirtualQueryEx() - // returns such data. - if (new_base <= base_address) { - usage->image = 0; - usage->mapped = 0; - usage->priv = 0; - return; - } - base_address = new_base; - } - usage->image = committed_image / 1024; - usage->mapped = committed_mapped / 1024; - usage->priv = committed_private / 1024; -} - -bool ProcessMetrics::GetWorkingSetKBytes(WorkingSetKBytes* ws_usage) const { - size_t ws_private = 0; - size_t ws_shareable = 0; - size_t ws_shared = 0; - - DCHECK(ws_usage); - memset(ws_usage, 0, sizeof(*ws_usage)); - - DWORD number_of_entries = 4096; // Just a guess. - PSAPI_WORKING_SET_INFORMATION* buffer = NULL; - int retries = 5; - for (;;) { - DWORD buffer_size = sizeof(PSAPI_WORKING_SET_INFORMATION) + - (number_of_entries * sizeof(PSAPI_WORKING_SET_BLOCK)); - - // if we can't expand the buffer, don't leak the previous - // contents or pass a NULL pointer to QueryWorkingSet - PSAPI_WORKING_SET_INFORMATION* new_buffer = - reinterpret_cast( - realloc(buffer, buffer_size)); - if (!new_buffer) { - free(buffer); - return false; - } - buffer = new_buffer; - - // Call the function once to get number of items - if (QueryWorkingSet(process_, buffer, buffer_size)) - break; // Success - - if (GetLastError() != ERROR_BAD_LENGTH) { - free(buffer); - return false; - } - - number_of_entries = static_cast(buffer->NumberOfEntries); - - // Maybe some entries are being added right now. Increase the buffer to - // take that into account. - number_of_entries = static_cast(number_of_entries * 1.25); - - if (--retries == 0) { - free(buffer); // If we're looping, eventually fail. - return false; - } - } - - // On windows 2000 the function returns 1 even when the buffer is too small. - // The number of entries that we are going to parse is the minimum between the - // size we allocated and the real number of entries. - number_of_entries = - std::min(number_of_entries, static_cast(buffer->NumberOfEntries)); - for (unsigned int i = 0; i < number_of_entries; i++) { - if (buffer->WorkingSetInfo[i].Shared) { - ws_shareable++; - if (buffer->WorkingSetInfo[i].ShareCount > 1) - ws_shared++; - } else { - ws_private++; - } - } - - ws_usage->priv = ws_private * PAGESIZE_KB; - ws_usage->shareable = ws_shareable * PAGESIZE_KB; - ws_usage->shared = ws_shared * PAGESIZE_KB; - free(buffer); - return true; -} - -static uint64 FileTimeToUTC(const FILETIME& ftime) { - LARGE_INTEGER li; - li.LowPart = ftime.dwLowDateTime; - li.HighPart = ftime.dwHighDateTime; - return li.QuadPart; -} - -double ProcessMetrics::GetCPUUsage() { - FILETIME now; - FILETIME creation_time; - FILETIME exit_time; - FILETIME kernel_time; - FILETIME user_time; - - GetSystemTimeAsFileTime(&now); - - if (!GetProcessTimes(process_, &creation_time, &exit_time, - &kernel_time, &user_time)) { - // We don't assert here because in some cases (such as in the Task Manager) - // we may call this function on a process that has just exited but we have - // not yet received the notification. - return 0; - } - int64 system_time = (FileTimeToUTC(kernel_time) + FileTimeToUTC(user_time)) / - processor_count_; - int64 time = FileTimeToUTC(now); - - if ((last_system_time_ == 0) || (last_time_ == 0)) { - // First call, just set the last values. - last_system_time_ = system_time; - last_time_ = time; - return 0; - } - - int64 system_time_delta = system_time - last_system_time_; - int64 time_delta = time - last_time_; - DCHECK_NE(0U, time_delta); - if (time_delta == 0) - return 0; - - // We add time_delta / 2 so the result is rounded. - int cpu = static_cast((system_time_delta * 100 + time_delta / 2) / - time_delta); - - last_system_time_ = system_time; - last_time_ = time; - - return cpu; -} - -bool ProcessMetrics::CalculateFreeMemory(FreeMBytes* free) const { - const SIZE_T kTopAddress = 0x7F000000; - const SIZE_T kMegabyte = 1024 * 1024; - SIZE_T accumulated = 0; - - MEMORY_BASIC_INFORMATION largest = {0}; - UINT_PTR scan = 0; - while (scan < kTopAddress) { - MEMORY_BASIC_INFORMATION info; - if (!::VirtualQueryEx(process_, reinterpret_cast(scan), - &info, sizeof(info))) - return false; - if (info.State == MEM_FREE) { - accumulated += info.RegionSize; - if (info.RegionSize > largest.RegionSize) - largest = info; - } - scan += info.RegionSize; - } - free->largest = largest.RegionSize / kMegabyte; - free->largest_ptr = largest.BaseAddress; - free->total = accumulated / kMegabyte; - return true; -} - -bool ProcessMetrics::GetIOCounters(IoCounters* io_counters) const { - return GetProcessIoCounters(process_, io_counters) != FALSE; -} - -ProcessMetrics::ProcessMetrics(ProcessHandle process) - : process_(process), - processor_count_(base::SysInfo::NumberOfProcessors()), - last_time_(0), - last_system_time_(0) { -} - -// GetPerformanceInfo is not available on WIN2K. So we'll -// load it on-the-fly. -const wchar_t kPsapiDllName[] = L"psapi.dll"; -typedef BOOL (WINAPI *GetPerformanceInfoFunction) ( - PPERFORMANCE_INFORMATION pPerformanceInformation, - DWORD cb); - -// Beware of races if called concurrently from multiple threads. -static BOOL InternalGetPerformanceInfo( - PPERFORMANCE_INFORMATION pPerformanceInformation, DWORD cb) { - static GetPerformanceInfoFunction GetPerformanceInfo_func = NULL; - if (!GetPerformanceInfo_func) { - HMODULE psapi_dll = ::GetModuleHandle(kPsapiDllName); - if (psapi_dll) - GetPerformanceInfo_func = reinterpret_cast( - GetProcAddress(psapi_dll, "GetPerformanceInfo")); - - if (!GetPerformanceInfo_func) { - // The function could be loaded! - memset(pPerformanceInformation, 0, cb); - return FALSE; - } - } - return GetPerformanceInfo_func(pPerformanceInformation, cb); -} - -size_t GetSystemCommitCharge() { - // Get the System Page Size. - SYSTEM_INFO system_info; - GetSystemInfo(&system_info); - - PERFORMANCE_INFORMATION info; - if (!InternalGetPerformanceInfo(&info, sizeof(info))) { - DLOG(ERROR) << "Failed to fetch internal performance info."; - return 0; - } - return (info.CommitTotal * system_info.dwPageSize) / 1024; -} - -} // namespace base diff --git a/base/process/process_posix.cc b/base/process/process_posix.cc deleted file mode 100644 index 3d8b31d035..0000000000 --- a/base/process/process_posix.cc +++ /dev/null @@ -1,73 +0,0 @@ -// Copyright (c) 2011 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "base/process/process.h" - -#include -#include -#include - -#include "base/logging.h" -#include "base/process/kill.h" - -namespace base { - -// static -Process Process::Current() { - return Process(GetCurrentProcessHandle()); -} - -ProcessId Process::pid() const { - if (process_ == 0) - return 0; - - return GetProcId(process_); -} - -bool Process::is_current() const { - return process_ == GetCurrentProcessHandle(); -} - -void Process::Close() { - process_ = 0; - // if the process wasn't terminated (so we waited) or the state - // wasn't already collected w/ a wait from process_utils, we're gonna - // end up w/ a zombie when it does finally exit. -} - -void Process::Terminate(int result_code) { - // result_code isn't supportable. - if (!process_) - return; - // We don't wait here. It's the responsibility of other code to reap the - // child. - KillProcess(process_, result_code, false); -} - -#if !defined(OS_LINUX) -bool Process::IsProcessBackgrounded() const { - // See SetProcessBackgrounded(). - return false; -} - -bool Process::SetProcessBackgrounded(bool value) { - // POSIX only allows lowering the priority of a process, so if we - // were to lower it we wouldn't be able to raise it back to its initial - // priority. - return false; -} - -// static -bool Process::CanBackgroundProcesses() { - return false; -} - -#endif - -int Process::GetPriority() const { - DCHECK(process_); - return getpriority(PRIO_PROCESS, process_); -} - -} // namspace base diff --git a/base/process/process_util_unittest.cc b/base/process/process_util_unittest.cc deleted file mode 100644 index 77f058c8f2..0000000000 --- a/base/process/process_util_unittest.cc +++ /dev/null @@ -1,961 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#define _CRT_SECURE_NO_WARNINGS - -#include - -#include "base/command_line.h" -#include "base/debug/alias.h" -#include "base/debug/stack_trace.h" -#include "base/files/file_path.h" -#include "base/logging.h" -#include "base/memory/scoped_ptr.h" -#include "base/path_service.h" -#include "base/posix/eintr_wrapper.h" -#include "base/process/kill.h" -#include "base/process/launch.h" -#include "base/process/memory.h" -#include "base/process/process.h" -#include "base/process/process_metrics.h" -#include "base/strings/utf_string_conversions.h" -#include "base/test/multiprocess_test.h" -#include "base/test/test_timeouts.h" -#include "base/third_party/dynamic_annotations/dynamic_annotations.h" -#include "base/threading/platform_thread.h" -#include "base/threading/thread.h" -#include "testing/gtest/include/gtest/gtest.h" -#include "testing/multiprocess_func_list.h" - -#if defined(OS_LINUX) -#include -#include -#include -#endif -#if defined(OS_POSIX) -#include -#include -#include -#include -#include -#include -#include -#endif -#if defined(OS_WIN) -#include -#endif -#if defined(OS_MACOSX) -#include -#include -#endif - -using base::FilePath; - -namespace { - -#if defined(OS_WIN) -const wchar_t kProcessName[] = L"base_unittests.exe"; -#else -const wchar_t kProcessName[] = L"base_unittests"; -#endif // defined(OS_WIN) - -#if defined(OS_ANDROID) -const char kShellPath[] = "/system/bin/sh"; -const char kPosixShell[] = "sh"; -#else -const char kShellPath[] = "/bin/sh"; -const char kPosixShell[] = "bash"; -#endif - -const char kSignalFileSlow[] = "SlowChildProcess.die"; -const char kSignalFileCrash[] = "CrashingChildProcess.die"; -const char kSignalFileKill[] = "KilledChildProcess.die"; - -#if defined(OS_WIN) -const int kExpectedStillRunningExitCode = 0x102; -const int kExpectedKilledExitCode = 1; -#else -const int kExpectedStillRunningExitCode = 0; -#endif - -// Sleeps until file filename is created. -void WaitToDie(const char* filename) { - FILE* fp; - do { - base::PlatformThread::Sleep(base::TimeDelta::FromMilliseconds(10)); - fp = fopen(filename, "r"); - } while (!fp); - fclose(fp); -} - -// Signals children they should die now. -void SignalChildren(const char* filename) { - FILE* fp = fopen(filename, "w"); - fclose(fp); -} - -// Using a pipe to the child to wait for an event was considered, but -// there were cases in the past where pipes caused problems (other -// libraries closing the fds, child deadlocking). This is a simple -// case, so it's not worth the risk. Using wait loops is discouraged -// in most instances. -base::TerminationStatus WaitForChildTermination(base::ProcessHandle handle, - int* exit_code) { - // Now we wait until the result is something other than STILL_RUNNING. - base::TerminationStatus status = base::TERMINATION_STATUS_STILL_RUNNING; - const base::TimeDelta kInterval = base::TimeDelta::FromMilliseconds(20); - base::TimeDelta waited; - do { - status = base::GetTerminationStatus(handle, exit_code); - base::PlatformThread::Sleep(kInterval); - waited += kInterval; - } while (status == base::TERMINATION_STATUS_STILL_RUNNING && -// Waiting for more time for process termination on android devices. -#if defined(OS_ANDROID) - waited < TestTimeouts::large_test_timeout()); -#else - waited < TestTimeouts::action_max_timeout()); -#endif - - return status; -} - -} // namespace - -class ProcessUtilTest : public base::MultiProcessTest { - public: -#if defined(OS_POSIX) - // Spawn a child process that counts how many file descriptors are open. - int CountOpenFDsInChild(); -#endif - // Converts the filename to a platform specific filepath. - // On Android files can not be created in arbitrary directories. - static std::string GetSignalFilePath(const char* filename); -}; - -std::string ProcessUtilTest::GetSignalFilePath(const char* filename) { -#if !defined(OS_ANDROID) - return filename; -#else - FilePath tmp_dir; - PathService::Get(base::DIR_CACHE, &tmp_dir); - tmp_dir = tmp_dir.Append(filename); - return tmp_dir.value(); -#endif -} - -MULTIPROCESS_TEST_MAIN(SimpleChildProcess) { - return 0; -} - -TEST_F(ProcessUtilTest, SpawnChild) { - base::ProcessHandle handle = this->SpawnChild("SimpleChildProcess", false); - ASSERT_NE(base::kNullProcessHandle, handle); - EXPECT_TRUE(base::WaitForSingleProcess( - handle, TestTimeouts::action_max_timeout())); - base::CloseProcessHandle(handle); -} - -MULTIPROCESS_TEST_MAIN(SlowChildProcess) { - WaitToDie(ProcessUtilTest::GetSignalFilePath(kSignalFileSlow).c_str()); - return 0; -} - -TEST_F(ProcessUtilTest, KillSlowChild) { - const std::string signal_file = - ProcessUtilTest::GetSignalFilePath(kSignalFileSlow); - remove(signal_file.c_str()); - base::ProcessHandle handle = this->SpawnChild("SlowChildProcess", false); - ASSERT_NE(base::kNullProcessHandle, handle); - SignalChildren(signal_file.c_str()); - EXPECT_TRUE(base::WaitForSingleProcess( - handle, TestTimeouts::action_max_timeout())); - base::CloseProcessHandle(handle); - remove(signal_file.c_str()); -} - -// Times out on Linux and Win, flakes on other platforms, http://crbug.com/95058 -TEST_F(ProcessUtilTest, DISABLED_GetTerminationStatusExit) { - const std::string signal_file = - ProcessUtilTest::GetSignalFilePath(kSignalFileSlow); - remove(signal_file.c_str()); - base::ProcessHandle handle = this->SpawnChild("SlowChildProcess", false); - ASSERT_NE(base::kNullProcessHandle, handle); - - int exit_code = 42; - EXPECT_EQ(base::TERMINATION_STATUS_STILL_RUNNING, - base::GetTerminationStatus(handle, &exit_code)); - EXPECT_EQ(kExpectedStillRunningExitCode, exit_code); - - SignalChildren(signal_file.c_str()); - exit_code = 42; - base::TerminationStatus status = - WaitForChildTermination(handle, &exit_code); - EXPECT_EQ(base::TERMINATION_STATUS_NORMAL_TERMINATION, status); - EXPECT_EQ(0, exit_code); - base::CloseProcessHandle(handle); - remove(signal_file.c_str()); -} - -#if defined(OS_WIN) -// TODO(cpu): figure out how to test this in other platforms. -TEST_F(ProcessUtilTest, GetProcId) { - base::ProcessId id1 = base::GetProcId(GetCurrentProcess()); - EXPECT_NE(0ul, id1); - base::ProcessHandle handle = this->SpawnChild("SimpleChildProcess", false); - ASSERT_NE(base::kNullProcessHandle, handle); - base::ProcessId id2 = base::GetProcId(handle); - EXPECT_NE(0ul, id2); - EXPECT_NE(id1, id2); - base::CloseProcessHandle(handle); -} -#endif - -#if !defined(OS_MACOSX) -// This test is disabled on Mac, since it's flaky due to ReportCrash -// taking a variable amount of time to parse and load the debug and -// symbol data for this unit test's executable before firing the -// signal handler. -// -// TODO(gspencer): turn this test process into a very small program -// with no symbols (instead of using the multiprocess testing -// framework) to reduce the ReportCrash overhead. - -MULTIPROCESS_TEST_MAIN(CrashingChildProcess) { - WaitToDie(ProcessUtilTest::GetSignalFilePath(kSignalFileCrash).c_str()); -#if defined(OS_POSIX) - // Have to disable to signal handler for segv so we can get a crash - // instead of an abnormal termination through the crash dump handler. - ::signal(SIGSEGV, SIG_DFL); -#endif - // Make this process have a segmentation fault. - volatile int* oops = NULL; - *oops = 0xDEAD; - return 1; -} - -// This test intentionally crashes, so we don't need to run it under -// AddressSanitizer. -// TODO(jschuh): crbug.com/175753 Fix this in Win64 bots. -#if defined(ADDRESS_SANITIZER) || (defined(OS_WIN) && defined(ARCH_CPU_X86_64)) -#define MAYBE_GetTerminationStatusCrash DISABLED_GetTerminationStatusCrash -#else -#define MAYBE_GetTerminationStatusCrash GetTerminationStatusCrash -#endif -TEST_F(ProcessUtilTest, MAYBE_GetTerminationStatusCrash) { - const std::string signal_file = - ProcessUtilTest::GetSignalFilePath(kSignalFileCrash); - remove(signal_file.c_str()); - base::ProcessHandle handle = this->SpawnChild("CrashingChildProcess", - false); - ASSERT_NE(base::kNullProcessHandle, handle); - - int exit_code = 42; - EXPECT_EQ(base::TERMINATION_STATUS_STILL_RUNNING, - base::GetTerminationStatus(handle, &exit_code)); - EXPECT_EQ(kExpectedStillRunningExitCode, exit_code); - - SignalChildren(signal_file.c_str()); - exit_code = 42; - base::TerminationStatus status = - WaitForChildTermination(handle, &exit_code); - EXPECT_EQ(base::TERMINATION_STATUS_PROCESS_CRASHED, status); - -#if defined(OS_WIN) - EXPECT_EQ(0xc0000005, exit_code); -#elif defined(OS_POSIX) - int signaled = WIFSIGNALED(exit_code); - EXPECT_NE(0, signaled); - int signal = WTERMSIG(exit_code); - EXPECT_EQ(SIGSEGV, signal); -#endif - base::CloseProcessHandle(handle); - - // Reset signal handlers back to "normal". - base::debug::EnableInProcessStackDumping(); - remove(signal_file.c_str()); -} -#endif // !defined(OS_MACOSX) - -MULTIPROCESS_TEST_MAIN(KilledChildProcess) { - WaitToDie(ProcessUtilTest::GetSignalFilePath(kSignalFileKill).c_str()); -#if defined(OS_WIN) - // Kill ourselves. - HANDLE handle = ::OpenProcess(PROCESS_ALL_ACCESS, 0, ::GetCurrentProcessId()); - ::TerminateProcess(handle, kExpectedKilledExitCode); -#elif defined(OS_POSIX) - // Send a SIGKILL to this process, just like the OOM killer would. - ::kill(getpid(), SIGKILL); -#endif - return 1; -} - -TEST_F(ProcessUtilTest, GetTerminationStatusKill) { - const std::string signal_file = - ProcessUtilTest::GetSignalFilePath(kSignalFileKill); - remove(signal_file.c_str()); - base::ProcessHandle handle = this->SpawnChild("KilledChildProcess", - false); - ASSERT_NE(base::kNullProcessHandle, handle); - - int exit_code = 42; - EXPECT_EQ(base::TERMINATION_STATUS_STILL_RUNNING, - base::GetTerminationStatus(handle, &exit_code)); - EXPECT_EQ(kExpectedStillRunningExitCode, exit_code); - - SignalChildren(signal_file.c_str()); - exit_code = 42; - base::TerminationStatus status = - WaitForChildTermination(handle, &exit_code); - EXPECT_EQ(base::TERMINATION_STATUS_PROCESS_WAS_KILLED, status); -#if defined(OS_WIN) - EXPECT_EQ(kExpectedKilledExitCode, exit_code); -#elif defined(OS_POSIX) - int signaled = WIFSIGNALED(exit_code); - EXPECT_NE(0, signaled); - int signal = WTERMSIG(exit_code); - EXPECT_EQ(SIGKILL, signal); -#endif - base::CloseProcessHandle(handle); - remove(signal_file.c_str()); -} - -// Ensure that the priority of a process is restored correctly after -// backgrounding and restoring. -// Note: a platform may not be willing or able to lower the priority of -// a process. The calls to SetProcessBackground should be noops then. -TEST_F(ProcessUtilTest, SetProcessBackgrounded) { - base::ProcessHandle handle = this->SpawnChild("SimpleChildProcess", false); - base::Process process(handle); - int old_priority = process.GetPriority(); -#if defined(OS_WIN) - EXPECT_TRUE(process.SetProcessBackgrounded(true)); - EXPECT_TRUE(process.IsProcessBackgrounded()); - EXPECT_TRUE(process.SetProcessBackgrounded(false)); - EXPECT_FALSE(process.IsProcessBackgrounded()); -#else - process.SetProcessBackgrounded(true); - process.SetProcessBackgrounded(false); -#endif - int new_priority = process.GetPriority(); - EXPECT_EQ(old_priority, new_priority); -} - -// Same as SetProcessBackgrounded but to this very process. It uses -// a different code path at least for Windows. -TEST_F(ProcessUtilTest, SetProcessBackgroundedSelf) { - base::Process process(base::Process::Current().handle()); - int old_priority = process.GetPriority(); -#if defined(OS_WIN) - EXPECT_TRUE(process.SetProcessBackgrounded(true)); - EXPECT_TRUE(process.IsProcessBackgrounded()); - EXPECT_TRUE(process.SetProcessBackgrounded(false)); - EXPECT_FALSE(process.IsProcessBackgrounded()); -#else - process.SetProcessBackgrounded(true); - process.SetProcessBackgrounded(false); -#endif - int new_priority = process.GetPriority(); - EXPECT_EQ(old_priority, new_priority); -} - -#if defined(OS_LINUX) || defined(OS_ANDROID) -TEST_F(ProcessUtilTest, GetSystemMemoryInfo) { - base::SystemMemoryInfoKB info; - EXPECT_TRUE(base::GetSystemMemoryInfo(&info)); - - // Ensure each field received a value. - EXPECT_GT(info.total, 0); - EXPECT_GT(info.free, 0); - EXPECT_GT(info.buffers, 0); - EXPECT_GT(info.cached, 0); - EXPECT_GT(info.active_anon, 0); - EXPECT_GT(info.inactive_anon, 0); - EXPECT_GT(info.active_file, 0); - EXPECT_GT(info.inactive_file, 0); - - // All the values should be less than the total amount of memory. - EXPECT_LT(info.free, info.total); - EXPECT_LT(info.buffers, info.total); - EXPECT_LT(info.cached, info.total); - EXPECT_LT(info.active_anon, info.total); - EXPECT_LT(info.inactive_anon, info.total); - EXPECT_LT(info.active_file, info.total); - EXPECT_LT(info.inactive_file, info.total); - -#if defined(OS_CHROMEOS) - // Chrome OS exposes shmem. - EXPECT_GT(info.shmem, 0); - EXPECT_LT(info.shmem, info.total); - // Chrome unit tests are not run on actual Chrome OS hardware, so gem_objects - // and gem_size cannot be tested here. -#endif -} -#endif // defined(OS_LINUX) || defined(OS_ANDROID) - -// TODO(estade): if possible, port these 2 tests. -#if defined(OS_WIN) -TEST_F(ProcessUtilTest, CalcFreeMemory) { - scoped_ptr metrics( - base::ProcessMetrics::CreateProcessMetrics(::GetCurrentProcess())); - ASSERT_TRUE(NULL != metrics.get()); - - bool using_tcmalloc = false; - - // Detect if we are using tcmalloc -#if !defined(NO_TCMALLOC) - const char* chrome_allocator = getenv("CHROME_ALLOCATOR"); - if (!chrome_allocator || _stricmp(chrome_allocator, "tcmalloc") == 0) - using_tcmalloc = true; -#endif - - // Typical values here is ~1900 for total and ~1000 for largest. Obviously - // it depends in what other tests have done to this process. - base::FreeMBytes free_mem1 = {0}; - EXPECT_TRUE(metrics->CalculateFreeMemory(&free_mem1)); - EXPECT_LT(10u, free_mem1.total); - EXPECT_LT(10u, free_mem1.largest); - EXPECT_GT(2048u, free_mem1.total); - EXPECT_GT(2048u, free_mem1.largest); - EXPECT_GE(free_mem1.total, free_mem1.largest); - EXPECT_TRUE(NULL != free_mem1.largest_ptr); - - // Allocate 20M and check again. It should have gone down. - const int kAllocMB = 20; - scoped_ptr alloc(new char[kAllocMB * 1024 * 1024]); - size_t expected_total = free_mem1.total - kAllocMB; - size_t expected_largest = free_mem1.largest; - - base::FreeMBytes free_mem2 = {0}; - EXPECT_TRUE(metrics->CalculateFreeMemory(&free_mem2)); - EXPECT_GE(free_mem2.total, free_mem2.largest); - // This test is flaky when using tcmalloc, because tcmalloc - // allocation strategy sometimes results in less than the - // full drop of 20Mb of free memory. - if (!using_tcmalloc) - EXPECT_GE(expected_total, free_mem2.total); - EXPECT_GE(expected_largest, free_mem2.largest); - EXPECT_TRUE(NULL != free_mem2.largest_ptr); -} - -TEST_F(ProcessUtilTest, GetAppOutput) { - // Let's create a decently long message. - std::string message; - for (int i = 0; i < 1025; i++) { // 1025 so it does not end on a kilo-byte - // boundary. - message += "Hello!"; - } - // cmd.exe's echo always adds a \r\n to its output. - std::string expected(message); - expected += "\r\n"; - - FilePath cmd(L"cmd.exe"); - CommandLine cmd_line(cmd); - cmd_line.AppendArg("/c"); - cmd_line.AppendArg("echo " + message + ""); - std::string output; - ASSERT_TRUE(base::GetAppOutput(cmd_line, &output)); - EXPECT_EQ(expected, output); - - // Let's make sure stderr is ignored. - CommandLine other_cmd_line(cmd); - other_cmd_line.AppendArg("/c"); - // http://msdn.microsoft.com/library/cc772622.aspx - cmd_line.AppendArg("echo " + message + " >&2"); - output.clear(); - ASSERT_TRUE(base::GetAppOutput(other_cmd_line, &output)); - EXPECT_EQ("", output); -} - -TEST_F(ProcessUtilTest, LaunchAsUser) { - base::UserTokenHandle token; - ASSERT_TRUE(OpenProcessToken(GetCurrentProcess(), TOKEN_ALL_ACCESS, &token)); - std::wstring cmdline = - this->MakeCmdLine("SimpleChildProcess", false).GetCommandLineString(); - base::LaunchOptions options; - options.as_user = token; - EXPECT_TRUE(base::LaunchProcess(cmdline, options, NULL)); -} - -#endif // defined(OS_WIN) - -#if defined(OS_POSIX) - -namespace { - -// Returns the maximum number of files that a process can have open. -// Returns 0 on error. -int GetMaxFilesOpenInProcess() { - struct rlimit rlim; - if (getrlimit(RLIMIT_NOFILE, &rlim) != 0) { - return 0; - } - - // rlim_t is a uint64 - clip to maxint. We do this since FD #s are ints - // which are all 32 bits on the supported platforms. - rlim_t max_int = static_cast(std::numeric_limits::max()); - if (rlim.rlim_cur > max_int) { - return max_int; - } - - return rlim.rlim_cur; -} - -const int kChildPipe = 20; // FD # for write end of pipe in child process. - -} // namespace - -MULTIPROCESS_TEST_MAIN(ProcessUtilsLeakFDChildProcess) { - // This child process counts the number of open FDs, it then writes that - // number out to a pipe connected to the parent. - int num_open_files = 0; - int write_pipe = kChildPipe; - int max_files = GetMaxFilesOpenInProcess(); - for (int i = STDERR_FILENO + 1; i < max_files; i++) { - if (i != kChildPipe) { - int fd; - if ((fd = HANDLE_EINTR(dup(i))) != -1) { - close(fd); - num_open_files += 1; - } - } - } - - int written = HANDLE_EINTR(write(write_pipe, &num_open_files, - sizeof(num_open_files))); - DCHECK_EQ(static_cast(written), sizeof(num_open_files)); - int ret = HANDLE_EINTR(close(write_pipe)); - DPCHECK(ret == 0); - - return 0; -} - -int ProcessUtilTest::CountOpenFDsInChild() { - int fds[2]; - if (pipe(fds) < 0) - NOTREACHED(); - - base::FileHandleMappingVector fd_mapping_vec; - fd_mapping_vec.push_back(std::pair(fds[1], kChildPipe)); - base::ProcessHandle handle = this->SpawnChild( - "ProcessUtilsLeakFDChildProcess", fd_mapping_vec, false); - CHECK(handle); - int ret = HANDLE_EINTR(close(fds[1])); - DPCHECK(ret == 0); - - // Read number of open files in client process from pipe; - int num_open_files = -1; - ssize_t bytes_read = - HANDLE_EINTR(read(fds[0], &num_open_files, sizeof(num_open_files))); - CHECK_EQ(bytes_read, static_cast(sizeof(num_open_files))); - -#if defined(THREAD_SANITIZER) || defined(USE_HEAPCHECKER) - // Compiler-based ThreadSanitizer makes this test slow. - CHECK(base::WaitForSingleProcess(handle, base::TimeDelta::FromSeconds(3))); -#else - CHECK(base::WaitForSingleProcess(handle, base::TimeDelta::FromSeconds(1))); -#endif - base::CloseProcessHandle(handle); - ret = HANDLE_EINTR(close(fds[0])); - DPCHECK(ret == 0); - - return num_open_files; -} - -#if defined(ADDRESS_SANITIZER) || defined(THREAD_SANITIZER) -// ProcessUtilTest.FDRemapping is flaky when ran under xvfb-run on Precise. -// The problem is 100% reproducible with both ASan and TSan. -// See http://crbug.com/136720. -#define MAYBE_FDRemapping DISABLED_FDRemapping -#else -#define MAYBE_FDRemapping FDRemapping -#endif -TEST_F(ProcessUtilTest, MAYBE_FDRemapping) { - int fds_before = CountOpenFDsInChild(); - - // open some dummy fds to make sure they don't propagate over to the - // child process. - int dev_null = open("/dev/null", O_RDONLY); - int sockets[2]; - socketpair(AF_UNIX, SOCK_STREAM, 0, sockets); - - int fds_after = CountOpenFDsInChild(); - - ASSERT_EQ(fds_after, fds_before); - - int ret; - ret = HANDLE_EINTR(close(sockets[0])); - DPCHECK(ret == 0); - ret = HANDLE_EINTR(close(sockets[1])); - DPCHECK(ret == 0); - ret = HANDLE_EINTR(close(dev_null)); - DPCHECK(ret == 0); -} - -namespace { - -std::string TestLaunchProcess(const base::EnvironmentVector& env_changes, - const int clone_flags) { - std::vector args; - base::FileHandleMappingVector fds_to_remap; - - args.push_back(kPosixShell); - args.push_back("-c"); - args.push_back("echo $BASE_TEST"); - - int fds[2]; - PCHECK(pipe(fds) == 0); - - fds_to_remap.push_back(std::make_pair(fds[1], 1)); - base::LaunchOptions options; - options.wait = true; - options.environ = &env_changes; - options.fds_to_remap = &fds_to_remap; -#if defined(OS_LINUX) - options.clone_flags = clone_flags; -#else - CHECK_EQ(0, clone_flags); -#endif // OS_LINUX - EXPECT_TRUE(base::LaunchProcess(args, options, NULL)); - PCHECK(HANDLE_EINTR(close(fds[1])) == 0); - - char buf[512]; - const ssize_t n = HANDLE_EINTR(read(fds[0], buf, sizeof(buf))); - PCHECK(n > 0); - - PCHECK(HANDLE_EINTR(close(fds[0])) == 0); - - return std::string(buf, n); -} - -const char kLargeString[] = - "0123456789012345678901234567890123456789012345678901234567890123456789" - "0123456789012345678901234567890123456789012345678901234567890123456789" - "0123456789012345678901234567890123456789012345678901234567890123456789" - "0123456789012345678901234567890123456789012345678901234567890123456789" - "0123456789012345678901234567890123456789012345678901234567890123456789" - "0123456789012345678901234567890123456789012345678901234567890123456789" - "0123456789012345678901234567890123456789012345678901234567890123456789"; - -} // namespace - -TEST_F(ProcessUtilTest, LaunchProcess) { - base::EnvironmentVector env_changes; - const int no_clone_flags = 0; - - env_changes.push_back(std::make_pair(std::string("BASE_TEST"), - std::string("bar"))); - EXPECT_EQ("bar\n", TestLaunchProcess(env_changes, no_clone_flags)); - env_changes.clear(); - - EXPECT_EQ(0, setenv("BASE_TEST", "testing", 1 /* override */)); - EXPECT_EQ("testing\n", TestLaunchProcess(env_changes, no_clone_flags)); - - env_changes.push_back( - std::make_pair(std::string("BASE_TEST"), std::string())); - EXPECT_EQ("\n", TestLaunchProcess(env_changes, no_clone_flags)); - - env_changes[0].second = "foo"; - EXPECT_EQ("foo\n", TestLaunchProcess(env_changes, no_clone_flags)); - - env_changes.clear(); - EXPECT_EQ(0, setenv("BASE_TEST", kLargeString, 1 /* override */)); - EXPECT_EQ(std::string(kLargeString) + "\n", - TestLaunchProcess(env_changes, no_clone_flags)); - - env_changes.push_back(std::make_pair(std::string("BASE_TEST"), - std::string("wibble"))); - EXPECT_EQ("wibble\n", TestLaunchProcess(env_changes, no_clone_flags)); - -#if defined(OS_LINUX) - // Test a non-trival value for clone_flags. - // Don't test on Valgrind as it has limited support for clone(). - if (!RunningOnValgrind()) { - EXPECT_EQ("wibble\n", TestLaunchProcess(env_changes, CLONE_FS | SIGCHLD)); - } -#endif -} - -TEST_F(ProcessUtilTest, AlterEnvironment) { - const char* const empty[] = { NULL }; - const char* const a2[] = { "A=2", NULL }; - base::EnvironmentVector changes; - char** e; - - e = base::AlterEnvironment(changes, empty); - EXPECT_TRUE(e[0] == NULL); - delete[] e; - - changes.push_back(std::make_pair(std::string("A"), std::string("1"))); - e = base::AlterEnvironment(changes, empty); - EXPECT_EQ(std::string("A=1"), e[0]); - EXPECT_TRUE(e[1] == NULL); - delete[] e; - - changes.clear(); - changes.push_back(std::make_pair(std::string("A"), std::string())); - e = base::AlterEnvironment(changes, empty); - EXPECT_TRUE(e[0] == NULL); - delete[] e; - - changes.clear(); - e = base::AlterEnvironment(changes, a2); - EXPECT_EQ(std::string("A=2"), e[0]); - EXPECT_TRUE(e[1] == NULL); - delete[] e; - - changes.clear(); - changes.push_back(std::make_pair(std::string("A"), std::string("1"))); - e = base::AlterEnvironment(changes, a2); - EXPECT_EQ(std::string("A=1"), e[0]); - EXPECT_TRUE(e[1] == NULL); - delete[] e; - - changes.clear(); - changes.push_back(std::make_pair(std::string("A"), std::string())); - e = base::AlterEnvironment(changes, a2); - EXPECT_TRUE(e[0] == NULL); - delete[] e; -} - -TEST_F(ProcessUtilTest, GetAppOutput) { - std::string output; - -#if defined(OS_ANDROID) - std::vector argv; - argv.push_back("sh"); // Instead of /bin/sh, force path search to find it. - argv.push_back("-c"); - - argv.push_back("exit 0"); - EXPECT_TRUE(base::GetAppOutput(CommandLine(argv), &output)); - EXPECT_STREQ("", output.c_str()); - - argv[2] = "exit 1"; - EXPECT_FALSE(base::GetAppOutput(CommandLine(argv), &output)); - EXPECT_STREQ("", output.c_str()); - - argv[2] = "echo foobar42"; - EXPECT_TRUE(base::GetAppOutput(CommandLine(argv), &output)); - EXPECT_STREQ("foobar42\n", output.c_str()); -#else - EXPECT_TRUE(base::GetAppOutput(CommandLine(FilePath("true")), &output)); - EXPECT_STREQ("", output.c_str()); - - EXPECT_FALSE(base::GetAppOutput(CommandLine(FilePath("false")), &output)); - - std::vector argv; - argv.push_back("/bin/echo"); - argv.push_back("-n"); - argv.push_back("foobar42"); - EXPECT_TRUE(base::GetAppOutput(CommandLine(argv), &output)); - EXPECT_STREQ("foobar42", output.c_str()); -#endif // defined(OS_ANDROID) -} - -TEST_F(ProcessUtilTest, GetAppOutputRestricted) { - // Unfortunately, since we can't rely on the path, we need to know where - // everything is. So let's use /bin/sh, which is on every POSIX system, and - // its built-ins. - std::vector argv; - argv.push_back(std::string(kShellPath)); // argv[0] - argv.push_back("-c"); // argv[1] - - // On success, should set |output|. We use |/bin/sh -c 'exit 0'| instead of - // |true| since the location of the latter may be |/bin| or |/usr/bin| (and we - // need absolute paths). - argv.push_back("exit 0"); // argv[2]; equivalent to "true" - std::string output = "abc"; - EXPECT_TRUE(base::GetAppOutputRestricted(CommandLine(argv), &output, 100)); - EXPECT_STREQ("", output.c_str()); - - argv[2] = "exit 1"; // equivalent to "false" - output = "before"; - EXPECT_FALSE(base::GetAppOutputRestricted(CommandLine(argv), - &output, 100)); - EXPECT_STREQ("", output.c_str()); - - // Amount of output exactly equal to space allowed. - argv[2] = "echo 123456789"; // (the sh built-in doesn't take "-n") - output.clear(); - EXPECT_TRUE(base::GetAppOutputRestricted(CommandLine(argv), &output, 10)); - EXPECT_STREQ("123456789\n", output.c_str()); - - // Amount of output greater than space allowed. - output.clear(); - EXPECT_TRUE(base::GetAppOutputRestricted(CommandLine(argv), &output, 5)); - EXPECT_STREQ("12345", output.c_str()); - - // Amount of output less than space allowed. - output.clear(); - EXPECT_TRUE(base::GetAppOutputRestricted(CommandLine(argv), &output, 15)); - EXPECT_STREQ("123456789\n", output.c_str()); - - // Zero space allowed. - output = "abc"; - EXPECT_TRUE(base::GetAppOutputRestricted(CommandLine(argv), &output, 0)); - EXPECT_STREQ("", output.c_str()); -} - -#if !defined(OS_MACOSX) && !defined(OS_OPENBSD) -// TODO(benwells): GetAppOutputRestricted should terminate applications -// with SIGPIPE when we have enough output. http://crbug.com/88502 -TEST_F(ProcessUtilTest, GetAppOutputRestrictedSIGPIPE) { - std::vector argv; - std::string output; - - argv.push_back(std::string(kShellPath)); // argv[0] - argv.push_back("-c"); -#if defined(OS_ANDROID) - argv.push_back("while echo 12345678901234567890; do :; done"); - EXPECT_TRUE(base::GetAppOutputRestricted(CommandLine(argv), &output, 10)); - EXPECT_STREQ("1234567890", output.c_str()); -#else - argv.push_back("yes"); - EXPECT_TRUE(base::GetAppOutputRestricted(CommandLine(argv), &output, 10)); - EXPECT_STREQ("y\ny\ny\ny\ny\n", output.c_str()); -#endif -} -#endif - -TEST_F(ProcessUtilTest, GetAppOutputRestrictedNoZombies) { - std::vector argv; - - argv.push_back(std::string(kShellPath)); // argv[0] - argv.push_back("-c"); // argv[1] - argv.push_back("echo 123456789012345678901234567890"); // argv[2] - - // Run |GetAppOutputRestricted()| 300 (> default per-user processes on Mac OS - // 10.5) times with an output buffer big enough to capture all output. - for (int i = 0; i < 300; i++) { - std::string output; - EXPECT_TRUE(base::GetAppOutputRestricted(CommandLine(argv), &output, 100)); - EXPECT_STREQ("123456789012345678901234567890\n", output.c_str()); - } - - // Ditto, but with an output buffer too small to capture all output. - for (int i = 0; i < 300; i++) { - std::string output; - EXPECT_TRUE(base::GetAppOutputRestricted(CommandLine(argv), &output, 10)); - EXPECT_STREQ("1234567890", output.c_str()); - } -} - -TEST_F(ProcessUtilTest, GetAppOutputWithExitCode) { - // Test getting output from a successful application. - std::vector argv; - std::string output; - int exit_code; - argv.push_back(std::string(kShellPath)); // argv[0] - argv.push_back("-c"); // argv[1] - argv.push_back("echo foo"); // argv[2]; - EXPECT_TRUE(base::GetAppOutputWithExitCode(CommandLine(argv), &output, - &exit_code)); - EXPECT_STREQ("foo\n", output.c_str()); - EXPECT_EQ(exit_code, 0); - - // Test getting output from an application which fails with a specific exit - // code. - output.clear(); - argv[2] = "echo foo; exit 2"; - EXPECT_TRUE(base::GetAppOutputWithExitCode(CommandLine(argv), &output, - &exit_code)); - EXPECT_STREQ("foo\n", output.c_str()); - EXPECT_EQ(exit_code, 2); -} - -TEST_F(ProcessUtilTest, GetParentProcessId) { - base::ProcessId ppid = base::GetParentProcessId(base::GetCurrentProcId()); - EXPECT_EQ(ppid, getppid()); -} - -#if defined(OS_LINUX) || defined(OS_ANDROID) -TEST_F(ProcessUtilTest, ParseProcStatCPU) { - // /proc/self/stat for a process running "top". - const char kTopStat[] = "960 (top) S 16230 960 16230 34818 960 " - "4202496 471 0 0 0 " - "12 16 0 0 " // <- These are the goods. - "20 0 1 0 121946157 15077376 314 18446744073709551615 4194304 " - "4246868 140733983044336 18446744073709551615 140244213071219 " - "0 0 0 138047495 0 0 0 17 1 0 0 0 0 0"; - EXPECT_EQ(12 + 16, base::ParseProcStatCPU(kTopStat)); - - // cat /proc/self/stat on a random other machine I have. - const char kSelfStat[] = "5364 (cat) R 5354 5364 5354 34819 5364 " - "0 142 0 0 0 " - "0 0 0 0 " // <- No CPU, apparently. - "16 0 1 0 1676099790 2957312 114 4294967295 134512640 134528148 " - "3221224832 3221224344 3086339742 0 0 0 0 0 0 0 17 0 0 0"; - - EXPECT_EQ(0, base::ParseProcStatCPU(kSelfStat)); -} - -// Disable on Android because base_unittests runs inside a Dalvik VM that -// starts and stop threads (crbug.com/175563). -#if !defined(OS_ANDROID) -TEST_F(ProcessUtilTest, GetNumberOfThreads) { - const base::ProcessHandle current = base::GetCurrentProcessHandle(); - const int initial_threads = base::GetNumberOfThreads(current); - ASSERT_GT(initial_threads, 0); - const int kNumAdditionalThreads = 10; - { - scoped_ptr my_threads[kNumAdditionalThreads]; - for (int i = 0; i < kNumAdditionalThreads; ++i) { - my_threads[i].reset(new base::Thread("GetNumberOfThreadsTest")); - my_threads[i]->Start(); - ASSERT_EQ(base::GetNumberOfThreads(current), initial_threads + 1 + i); - } - } - // The Thread destructor will stop them. - ASSERT_EQ(initial_threads, base::GetNumberOfThreads(current)); -} -#endif // !defined(OS_ANDROID) - -#endif // defined(OS_LINUX) || defined(OS_ANDROID) - -// TODO(port): port those unit tests. -bool IsProcessDead(base::ProcessHandle child) { - // waitpid() will actually reap the process which is exactly NOT what we - // want to test for. The good thing is that if it can't find the process - // we'll get a nice value for errno which we can test for. - const pid_t result = HANDLE_EINTR(waitpid(child, NULL, WNOHANG)); - return result == -1 && errno == ECHILD; -} - -TEST_F(ProcessUtilTest, DelayedTermination) { - base::ProcessHandle child_process = - SpawnChild("process_util_test_never_die", false); - ASSERT_TRUE(child_process); - base::EnsureProcessTerminated(child_process); - base::WaitForSingleProcess(child_process, base::TimeDelta::FromSeconds(5)); - - // Check that process was really killed. - EXPECT_TRUE(IsProcessDead(child_process)); - base::CloseProcessHandle(child_process); -} - -MULTIPROCESS_TEST_MAIN(process_util_test_never_die) { - while (1) { - sleep(500); - } - return 0; -} - -TEST_F(ProcessUtilTest, ImmediateTermination) { - base::ProcessHandle child_process = - SpawnChild("process_util_test_die_immediately", false); - ASSERT_TRUE(child_process); - // Give it time to die. - sleep(2); - base::EnsureProcessTerminated(child_process); - - // Check that process was really killed. - EXPECT_TRUE(IsProcessDead(child_process)); - base::CloseProcessHandle(child_process); -} - -MULTIPROCESS_TEST_MAIN(process_util_test_die_immediately) { - return 0; -} - -#endif // defined(OS_POSIX) diff --git a/base/process/process_util_unittest_ios.cc b/base/process/process_util_unittest_ios.cc deleted file mode 100644 index cad0f1b09f..0000000000 --- a/base/process/process_util_unittest_ios.cc +++ /dev/null @@ -1,15 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "base/memory/scoped_ptr.h" -#include "base/process/process_metrics.h" -#include "testing/gtest/include/gtest/gtest.h" - -TEST(ProcessUtilTestIos, Memory) { - scoped_ptr process_metrics( - base::ProcessMetrics::CreateProcessMetrics( - base::GetCurrentProcessHandle())); - - ASSERT_NE(0u, process_metrics->GetWorkingSetSize()); -} diff --git a/base/process/process_win.cc b/base/process/process_win.cc deleted file mode 100644 index 1217b50989..0000000000 --- a/base/process/process_win.cc +++ /dev/null @@ -1,92 +0,0 @@ -// Copyright (c) 2011 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "base/process/process.h" - -#include "base/logging.h" -#include "base/memory/scoped_ptr.h" -#include "base/win/windows_version.h" - -namespace base { - -void Process::Close() { - if (!process_) - return; - - // Don't call CloseHandle on a pseudo-handle. - if (process_ != ::GetCurrentProcess()) - ::CloseHandle(process_); - - process_ = NULL; -} - -void Process::Terminate(int result_code) { - if (!process_) - return; - - // Call NtTerminateProcess directly, without going through the import table, - // which might have been hooked with a buggy replacement by third party - // software. http://crbug.com/81449. - HMODULE module = GetModuleHandle(L"ntdll.dll"); - typedef UINT (WINAPI *TerminateProcessPtr)(HANDLE handle, UINT code); - TerminateProcessPtr terminate_process = reinterpret_cast( - GetProcAddress(module, "NtTerminateProcess")); - terminate_process(process_, result_code); -} - -bool Process::IsProcessBackgrounded() const { - if (!process_) - return false; // Failure case. - DWORD priority = GetPriority(); - if (priority == 0) - return false; // Failure case. - return ((priority == BELOW_NORMAL_PRIORITY_CLASS) || - (priority == IDLE_PRIORITY_CLASS)); -} - -bool Process::SetProcessBackgrounded(bool value) { - if (!process_) - return false; - // Vista and above introduce a real background mode, which not only - // sets the priority class on the threads but also on the IO generated - // by it. Unfortunately it can only be set for the calling process. - DWORD priority; - if ((base::win::GetVersion() >= base::win::VERSION_VISTA) && - (process_ == ::GetCurrentProcess())) { - priority = value ? PROCESS_MODE_BACKGROUND_BEGIN : - PROCESS_MODE_BACKGROUND_END; - } else { - priority = value ? BELOW_NORMAL_PRIORITY_CLASS : NORMAL_PRIORITY_CLASS; - } - - return (::SetPriorityClass(process_, priority) != 0); -} - -ProcessId Process::pid() const { - if (process_ == 0) - return 0; - - return GetProcId(process_); -} - -bool Process::is_current() const { - return process_ == GetCurrentProcess(); -} - -// static -Process Process::Current() { - return Process(::GetCurrentProcess()); -} - -// static -bool Process::CanBackgroundProcesses() { - return true; -} - -int Process::GetPriority() const { - DCHECK(process_); - return ::GetPriorityClass(process_); -} - -} // namespace base diff --git a/base/profiler/alternate_timer.cc b/base/profiler/alternate_timer.cc deleted file mode 100644 index 4eba89c255..0000000000 --- a/base/profiler/alternate_timer.cc +++ /dev/null @@ -1,37 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "base/profiler/alternate_timer.h" - -#include "base/logging.h" - -namespace { - -tracked_objects::NowFunction* g_time_function = NULL; -tracked_objects::TimeSourceType g_time_source_type = - tracked_objects::TIME_SOURCE_TYPE_WALL_TIME; - -} // anonymous namespace - -namespace tracked_objects { - -const char kAlternateProfilerTime[] = "CHROME_PROFILER_TIME"; - -// Set an alternate timer function to replace the OS time function when -// profiling. -void SetAlternateTimeSource(NowFunction* now_function, TimeSourceType type) { - DCHECK_EQ(reinterpret_cast(NULL), g_time_function); - g_time_function = now_function; - g_time_source_type = type; -} - -NowFunction* GetAlternateTimeSource() { - return g_time_function; -} - -TimeSourceType GetTimeSourceType() { - return g_time_source_type; -} - -} // namespace tracked_objects diff --git a/base/profiler/alternate_timer.h b/base/profiler/alternate_timer.h deleted file mode 100644 index fdc75dc6f0..0000000000 --- a/base/profiler/alternate_timer.h +++ /dev/null @@ -1,44 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -// This is a glue file, which allows third party code to call into our profiler -// without having to include most any functions from base. - -#ifndef BASE_PROFILER_ALTERNATE_TIMER_H_ -#define BASE_PROFILER_ALTERNATE_TIMER_H_ - -#include "base/base_export.h" - -namespace tracked_objects { - -enum TimeSourceType { - TIME_SOURCE_TYPE_WALL_TIME, - TIME_SOURCE_TYPE_TCMALLOC -}; - -// Provide type for an alternate timer function. -typedef unsigned int NowFunction(); - -// Environment variable name that is used to activate alternate timer profiling -// (such as using TCMalloc allocations to provide a pseudo-timer) for tasks -// instead of wall clock profiling. -BASE_EXPORT extern const char kAlternateProfilerTime[]; - -// Set an alternate timer function to replace the OS time function when -// profiling. Typically this is called by an allocator that is providing a -// function that indicates how much memory has been allocated on any given -// thread. -BASE_EXPORT void SetAlternateTimeSource(NowFunction* now_function, - TimeSourceType type); - -// Gets the pointer to a function that was set via SetAlternateTimeSource(). -// Returns NULL if no set was done prior to calling GetAlternateTimeSource. -NowFunction* GetAlternateTimeSource(); - -// Returns the type of the currently set time source. -BASE_EXPORT TimeSourceType GetTimeSourceType(); - -} // namespace tracked_objects - -#endif // BASE_PROFILER_ALTERNATE_TIMER_H_ diff --git a/base/profiler/scoped_profile.cc b/base/profiler/scoped_profile.cc deleted file mode 100644 index 93c86e92cc..0000000000 --- a/base/profiler/scoped_profile.cc +++ /dev/null @@ -1,31 +0,0 @@ -// Copyright (c) 2011 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "base/profiler/scoped_profile.h" - -#include "base/location.h" -#include "base/tracked_objects.h" - - -namespace tracked_objects { - - -ScopedProfile::ScopedProfile(const Location& location) - : birth_(ThreadData::TallyABirthIfActive(location)), - start_of_run_(ThreadData::NowForStartOfRun(birth_)) { -} - -ScopedProfile::~ScopedProfile() { - StopClockAndTally(); -} - -void ScopedProfile::StopClockAndTally() { - if (!birth_) - return; - ThreadData::TallyRunInAScopedRegionIfTracking(birth_, start_of_run_, - ThreadData::NowForEndOfRun()); - birth_ = NULL; -} - -} // namespace tracked_objects diff --git a/base/profiler/scoped_profile.h b/base/profiler/scoped_profile.h deleted file mode 100644 index 8b77d6d381..0000000000 --- a/base/profiler/scoped_profile.h +++ /dev/null @@ -1,67 +0,0 @@ -// Copyright (c) 2011 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - - -#ifndef BASE_PROFILER_SCOPED_PROFILE_H_ -#define BASE_PROFILER_SCOPED_PROFILE_H_ - -//------------------------------------------------------------------------------ -// ScopedProfile provides basic helper functions for profiling a short -// region of code within a scope. It is separate from the related ThreadData -// class so that it can be included without much other cruft, and provide the -// macros listed below. - -#include "base/base_export.h" -#include "base/location.h" -#include "base/profiler/tracked_time.h" - -#if defined(GOOGLE_CHROME_BUILD) - -// We don't ship these profiled regions. This is for developer builds only. -// It allows developers to do some profiling of their code, and see results on -// their about:profiler page. -#define TRACK_RUN_IN_THIS_SCOPED_REGION_FOR_DEVELOPER_BUILDS(scope_name) \ - ((void)0) - -#else - -#define TRACK_RUN_IN_THIS_SCOPED_REGION_FOR_DEVELOPER_BUILDS(scope_name) \ - ::tracked_objects::ScopedProfile LINE_BASED_VARIABLE_NAME_FOR_PROFILING( \ - FROM_HERE_WITH_EXPLICIT_FUNCTION(#scope_name)) - -#endif - - - -#define PASTE_LINE_NUMBER_ON_NAME(name, line) name##line - -#define LINE_BASED_VARIABLE_NAME_FOR_PROFILING \ - PASTE_LINE_NUMBER_ON_NAME(some_profiler_variable_, __LINE__) - -#define TRACK_RUN_IN_IPC_HANDLER(dispatch_function_name) \ - ::tracked_objects::ScopedProfile some_tracking_variable_name( \ - FROM_HERE_WITH_EXPLICIT_FUNCTION(#dispatch_function_name)) - - -namespace tracked_objects { -class Births; - -class BASE_EXPORT ScopedProfile { - public: - explicit ScopedProfile(const Location& location); - ~ScopedProfile(); - - // Stop tracing prior to the end destruction of the instance. - void StopClockAndTally(); - - private: - Births* birth_; // Place in code where tracking started. - const TrackedTime start_of_run_; - - DISALLOW_COPY_AND_ASSIGN(ScopedProfile); -}; - -} // namespace tracked_objects - -#endif // BASE_PROFILER_SCOPED_PROFILE_H_ diff --git a/base/profiler/tracked_time.cc b/base/profiler/tracked_time.cc deleted file mode 100644 index 27d3358be3..0000000000 --- a/base/profiler/tracked_time.cc +++ /dev/null @@ -1,76 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "base/profiler/tracked_time.h" - -#include "build/build_config.h" - -#if defined(OS_WIN) -#include // Declare timeGetTime()... after including build_config. -#endif - -namespace tracked_objects { - -Duration::Duration() : ms_(0) {} -Duration::Duration(int32 duration) : ms_(duration) {} - -Duration& Duration::operator+=(const Duration& other) { - ms_ += other.ms_; - return *this; -} - -Duration Duration::operator+(const Duration& other) const { - return Duration(ms_ + other.ms_); -} - -bool Duration::operator==(const Duration& other) const { - return ms_ == other.ms_; -} - -bool Duration::operator!=(const Duration& other) const { - return ms_ != other.ms_; -} - -bool Duration::operator>(const Duration& other) const { - return ms_ > other.ms_; -} - -// static -Duration Duration::FromMilliseconds(int ms) { return Duration(ms); } - -int32 Duration::InMilliseconds() const { return ms_; } - -//------------------------------------------------------------------------------ - -TrackedTime::TrackedTime() : ms_(0) {} -TrackedTime::TrackedTime(int32 ms) : ms_(ms) {} -TrackedTime::TrackedTime(const base::TimeTicks& time) - : ms_((time - base::TimeTicks()).InMilliseconds()) { -} - -// static -TrackedTime TrackedTime::Now() { -#if defined(OS_WIN) - // Use lock-free accessor to 32 bit time. - // Note that TimeTicks::Now() is built on this, so we have "compatible" - // times when we down-convert a TimeTicks sample. - // TODO(jar): Surface this interface via something in base/time/time.h. - return TrackedTime(static_cast(timeGetTime())); -#else - // Posix has nice cheap 64 bit times, so we just down-convert it. - return TrackedTime(base::TimeTicks::Now()); -#endif // OS_WIN -} - -Duration TrackedTime::operator-(const TrackedTime& other) const { - return Duration(ms_ - other.ms_); -} - -TrackedTime TrackedTime::operator+(const Duration& other) const { - return TrackedTime(ms_ + other.ms_); -} - -bool TrackedTime::is_null() const { return ms_ == 0; } - -} // namespace tracked_objects diff --git a/base/profiler/tracked_time.h b/base/profiler/tracked_time.h deleted file mode 100644 index 23632749a0..0000000000 --- a/base/profiler/tracked_time.h +++ /dev/null @@ -1,71 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef BASE_PROFILER_TRACKED_TIME_H_ -#define BASE_PROFILER_TRACKED_TIME_H_ - - -#include "base/base_export.h" -#include "base/basictypes.h" -#include "base/time/time.h" - -namespace tracked_objects { - -//------------------------------------------------------------------------------ - -// TimeTicks maintains a wasteful 64 bits of data (we need less than 32), and on -// windows, a 64 bit timer is expensive to even obtain. We use a simple -// millisecond counter for most of our time values, as well as millisecond units -// of duration between those values. This means we can only handle durations -// up to 49 days (range), or 24 days (non-negative time durations). -// We only define enough methods to service the needs of the tracking classes, -// and our interfaces are modeled after what TimeTicks and TimeDelta use (so we -// can swap them into place if we want to use the "real" classes). - -class BASE_EXPORT Duration { // Similar to base::TimeDelta. - public: - Duration(); - - Duration& operator+=(const Duration& other); - Duration operator+(const Duration& other) const; - - bool operator==(const Duration& other) const; - bool operator!=(const Duration& other) const; - bool operator>(const Duration& other) const; - - static Duration FromMilliseconds(int ms); - - int32 InMilliseconds() const; - - private: - friend class TrackedTime; - explicit Duration(int32 duration); - - // Internal time is stored directly in milliseconds. - int32 ms_; -}; - -class BASE_EXPORT TrackedTime { // Similar to base::TimeTicks. - public: - TrackedTime(); - explicit TrackedTime(const base::TimeTicks& time); - - static TrackedTime Now(); - Duration operator-(const TrackedTime& other) const; - TrackedTime operator+(const Duration& other) const; - bool is_null() const; - - static TrackedTime FromMilliseconds(int32 ms) { return TrackedTime(ms); } - - private: - friend class Duration; - explicit TrackedTime(int32 ms); - - // Internal duration is stored directly in milliseconds. - uint32 ms_; -}; - -} // namespace tracked_objects - -#endif // BASE_PROFILER_TRACKED_TIME_H_ diff --git a/base/profiler/tracked_time_unittest.cc b/base/profiler/tracked_time_unittest.cc deleted file mode 100644 index ef84f153a6..0000000000 --- a/base/profiler/tracked_time_unittest.cc +++ /dev/null @@ -1,110 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -// Test of classes in tracked_time.cc - -#include "base/profiler/tracked_time.h" -#include "base/time/time.h" -#include "base/tracked_objects.h" -#include "testing/gtest/include/gtest/gtest.h" - -namespace tracked_objects { - -TEST(TrackedTimeTest, TrackedTimerMilliseconds) { - // First make sure we basicallly transfer simple milliseconds values as - // expected. Most critically, things should not become null. - int32 kSomeMilliseconds = 243; // Some example times. - int64 kReallyBigMilliseconds = (1LL << 35) + kSomeMilliseconds; - - TrackedTime some = TrackedTime() + - Duration::FromMilliseconds(kSomeMilliseconds); - EXPECT_EQ(kSomeMilliseconds, (some - TrackedTime()).InMilliseconds()); - EXPECT_FALSE(some.is_null()); - - // Now create a big time, to check that it is wrapped modulo 2^32. - base::TimeTicks big = base::TimeTicks() + - base::TimeDelta::FromMilliseconds(kReallyBigMilliseconds); - EXPECT_EQ(kReallyBigMilliseconds, (big - base::TimeTicks()).InMilliseconds()); - - TrackedTime wrapped_big(big); - // Expect wrapping at 32 bits. - EXPECT_EQ(kSomeMilliseconds, (wrapped_big - TrackedTime()).InMilliseconds()); -} - -TEST(TrackedTimeTest, TrackedTimerDuration) { - int kFirstMilliseconds = 793; - int kSecondMilliseconds = 14889; - - Duration first = Duration::FromMilliseconds(kFirstMilliseconds); - Duration second = Duration::FromMilliseconds(kSecondMilliseconds); - - EXPECT_EQ(kFirstMilliseconds, first.InMilliseconds()); - EXPECT_EQ(kSecondMilliseconds, second.InMilliseconds()); - - Duration sum = first + second; - EXPECT_EQ(kFirstMilliseconds + kSecondMilliseconds, sum.InMilliseconds()); -} - -TEST(TrackedTimeTest, TrackedTimerVsTimeTicks) { - // Make sure that our 32 bit timer is aligned with the TimeTicks() timer. - - // First get a 64 bit timer (which should not be null). - base::TimeTicks ticks_before = base::TimeTicks::Now(); - EXPECT_FALSE(ticks_before.is_null()); - - // Then get a 32 bit timer that can be be null when it wraps. - TrackedTime now = TrackedTime::Now(); - - // Then get a bracketing time. - base::TimeTicks ticks_after = base::TimeTicks::Now(); - EXPECT_FALSE(ticks_after.is_null()); - - // Now make sure that we bracketed our tracked time nicely. - Duration before = now - TrackedTime(ticks_before); - EXPECT_LE(0, before.InMilliseconds()); - Duration after = now - TrackedTime(ticks_after); - EXPECT_GE(0, after.InMilliseconds()); -} - -TEST(TrackedTimeTest, TrackedTimerDisabled) { - // Check to be sure disabling the collection of data induces a null time - // (which we know will return much faster). - if (!ThreadData::InitializeAndSetTrackingStatus(ThreadData::DEACTIVATED)) - return; - // Since we disabled tracking, we should get a null response. - TrackedTime track_now = ThreadData::Now(); - EXPECT_TRUE(track_now.is_null()); - track_now = ThreadData::NowForStartOfRun(NULL); - EXPECT_TRUE(track_now.is_null()); - track_now = ThreadData::NowForEndOfRun(); - EXPECT_TRUE(track_now.is_null()); -} - -TEST(TrackedTimeTest, TrackedTimerEnabled) { - if (!ThreadData::InitializeAndSetTrackingStatus( - ThreadData::PROFILING_CHILDREN_ACTIVE)) - return; - // Make sure that when we enable tracking, we get a real timer result. - - // First get a 64 bit timer (which should not be null). - base::TimeTicks ticks_before = base::TimeTicks::Now(); - EXPECT_FALSE(ticks_before.is_null()); - - // Then get a 32 bit timer that can be null when it wraps. - // Crtical difference from the TrackedTimerVsTimeTicks test, is that we use - // ThreadData::Now(). It can sometimes return the null time. - TrackedTime now = ThreadData::Now(); - - // Then get a bracketing time. - base::TimeTicks ticks_after = base::TimeTicks::Now(); - EXPECT_FALSE(ticks_after.is_null()); - - // Now make sure that we bracketed our tracked time nicely. - Duration before = now - TrackedTime(ticks_before); - EXPECT_LE(0, before.InMilliseconds()); - Duration after = now - TrackedTime(ticks_after); - EXPECT_GE(0, after.InMilliseconds()); -} - -} // namespace tracked_objects diff --git a/base/rand_util.cc b/base/rand_util.cc deleted file mode 100644 index da6de87dc3..0000000000 --- a/base/rand_util.cc +++ /dev/null @@ -1,80 +0,0 @@ -// Copyright (c) 2011 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "base/rand_util.h" - -#include - -#include - -#include "base/basictypes.h" -#include "base/logging.h" -#include "base/strings/string_util.h" - -namespace base { - -int RandInt(int min, int max) { - DCHECK_LE(min, max); - - uint64 range = static_cast(max) - min + 1; - int result = min + static_cast(base::RandGenerator(range)); - DCHECK_GE(result, min); - DCHECK_LE(result, max); - return result; -} - -double RandDouble() { - return BitsToOpenEndedUnitInterval(base::RandUint64()); -} - -double BitsToOpenEndedUnitInterval(uint64 bits) { - // We try to get maximum precision by masking out as many bits as will fit - // in the target type's mantissa, and raising it to an appropriate power to - // produce output in the range [0, 1). For IEEE 754 doubles, the mantissa - // is expected to accommodate 53 bits. - - COMPILE_ASSERT(std::numeric_limits::radix == 2, otherwise_use_scalbn); - static const int kBits = std::numeric_limits::digits; - uint64 random_bits = bits & ((GG_UINT64_C(1) << kBits) - 1); - double result = ldexp(static_cast(random_bits), -1 * kBits); - DCHECK_GE(result, 0.0); - DCHECK_LT(result, 1.0); - return result; -} - -uint64 RandGenerator(uint64 range) { - DCHECK_GT(range, 0u); - // We must discard random results above this number, as they would - // make the random generator non-uniform (consider e.g. if - // MAX_UINT64 was 7 and |range| was 5, then a result of 1 would be twice - // as likely as a result of 3 or 4). - uint64 max_acceptable_value = - (std::numeric_limits::max() / range) * range - 1; - - uint64 value; - do { - value = base::RandUint64(); - } while (value > max_acceptable_value); - - return value % range; -} - -void RandBytes(void* output, size_t output_length) { - uint64 random_int; - size_t random_int_size = sizeof(random_int); - for (size_t i = 0; i < output_length; i += random_int_size) { - random_int = base::RandUint64(); - size_t copy_count = std::min(output_length - i, random_int_size); - memcpy(((uint8*)output) + i, &random_int, copy_count); - } -} - -std::string RandBytesAsString(size_t length) { - DCHECK_GT(length, 0u); - std::string result; - RandBytes(WriteInto(&result, length + 1), length); - return result; -} - -} // namespace base diff --git a/base/rand_util.h b/base/rand_util.h deleted file mode 100644 index bae8c31178..0000000000 --- a/base/rand_util.h +++ /dev/null @@ -1,58 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef BASE_RAND_UTIL_H_ -#define BASE_RAND_UTIL_H_ - -#include - -#include "base/base_export.h" -#include "base/basictypes.h" - -namespace base { - -// Returns a random number in range [0, kuint64max]. Thread-safe. -BASE_EXPORT uint64 RandUint64(); - -// Returns a random number between min and max (inclusive). Thread-safe. -BASE_EXPORT int RandInt(int min, int max); - -// Returns a random number in range [0, range). Thread-safe. -// -// Note that this can be used as an adapter for std::random_shuffle(): -// Given a pre-populated |std::vector myvector|, shuffle it as -// std::random_shuffle(myvector.begin(), myvector.end(), base::RandGenerator); -BASE_EXPORT uint64 RandGenerator(uint64 range); - -// Returns a random double in range [0, 1). Thread-safe. -BASE_EXPORT double RandDouble(); - -// Given input |bits|, convert with maximum precision to a double in -// the range [0, 1). Thread-safe. -BASE_EXPORT double BitsToOpenEndedUnitInterval(uint64 bits); - -// Fills |output_length| bytes of |output| with random data. -// -// WARNING: -// Do not use for security-sensitive purposes. -// See crypto/ for cryptographically secure random number generation APIs. -BASE_EXPORT void RandBytes(void* output, size_t output_length); - -// Fills a string of length |length| with with random data and returns it. -// |length| should be nonzero. -// -// Note that this is a variation of |RandBytes| with a different return type. -// -// WARNING: -// Do not use for security-sensitive purposes. -// See crypto/ for cryptographically secure random number generation APIs. -BASE_EXPORT std::string RandBytesAsString(size_t length); - -#if defined(OS_POSIX) -BASE_EXPORT int GetUrandomFD(); -#endif - -} // namespace base - -#endif // BASE_RAND_UTIL_H_ diff --git a/base/rand_util_nacl.cc b/base/rand_util_nacl.cc deleted file mode 100644 index 47450aaba6..0000000000 --- a/base/rand_util_nacl.cc +++ /dev/null @@ -1,53 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "base/rand_util.h" - -#include "base/basictypes.h" -#include "base/lazy_instance.h" -#include "base/logging.h" -#include "native_client/src/untrusted/irt/irt.h" - -namespace { - -class NaclRandom { - public: - NaclRandom() { - size_t result = nacl_interface_query(NACL_IRT_RANDOM_v0_1, - &random_, sizeof(random_)); - CHECK_EQ(result, sizeof(random_)); - } - - ~NaclRandom() { - } - - void GetRandomBytes(char* buffer, uint32_t num_bytes) { - while (num_bytes > 0) { - size_t nread; - int error = random_.get_random_bytes(buffer, num_bytes, &nread); - CHECK_EQ(error, 0); - CHECK_LE(nread, num_bytes); - buffer += nread; - num_bytes -= nread; - } - } - - private: - nacl_irt_random random_; -}; - -base::LazyInstance::Leaky g_nacl_random = LAZY_INSTANCE_INITIALIZER; - -} // namespace - -namespace base { - -uint64 RandUint64() { - uint64 result; - g_nacl_random.Pointer()->GetRandomBytes( - reinterpret_cast(&result), sizeof(result)); - return result; -} - -} // namespace base diff --git a/base/rand_util_posix.cc b/base/rand_util_posix.cc deleted file mode 100644 index 9b18777b99..0000000000 --- a/base/rand_util_posix.cc +++ /dev/null @@ -1,61 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "base/rand_util.h" - -#include -#include -#include - -#include "base/file_util.h" -#include "base/lazy_instance.h" -#include "base/logging.h" - -namespace { - -// We keep the file descriptor for /dev/urandom around so we don't need to -// reopen it (which is expensive), and since we may not even be able to reopen -// it if we are later put in a sandbox. This class wraps the file descriptor so -// we can use LazyInstance to handle opening it on the first access. -class URandomFd { - public: - URandomFd() { - fd_ = open("/dev/urandom", O_RDONLY); - DCHECK_GE(fd_, 0) << "Cannot open /dev/urandom: " << errno; - } - - ~URandomFd() { - close(fd_); - } - - int fd() const { return fd_; } - - private: - int fd_; -}; - -base::LazyInstance::Leaky g_urandom_fd = LAZY_INSTANCE_INITIALIZER; - -} // namespace - -namespace base { - -// NOTE: This function must be cryptographically secure. http://crbug.com/140076 -uint64 RandUint64() { - uint64 number; - - int urandom_fd = g_urandom_fd.Pointer()->fd(); - bool success = file_util::ReadFromFD(urandom_fd, - reinterpret_cast(&number), - sizeof(number)); - CHECK(success); - - return number; -} - -int GetUrandomFD(void) { - return g_urandom_fd.Pointer()->fd(); -} - -} // namespace base diff --git a/base/rand_util_unittest.cc b/base/rand_util_unittest.cc deleted file mode 100644 index e0e85ecaa9..0000000000 --- a/base/rand_util_unittest.cc +++ /dev/null @@ -1,122 +0,0 @@ -// Copyright (c) 2011 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "base/rand_util.h" - -#include -#include - -#include "testing/gtest/include/gtest/gtest.h" - -namespace { - -const int kIntMin = std::numeric_limits::min(); -const int kIntMax = std::numeric_limits::max(); - -} // namespace - -TEST(RandUtilTest, SameMinAndMax) { - EXPECT_EQ(base::RandInt(0, 0), 0); - EXPECT_EQ(base::RandInt(kIntMin, kIntMin), kIntMin); - EXPECT_EQ(base::RandInt(kIntMax, kIntMax), kIntMax); -} - -TEST(RandUtilTest, RandDouble) { - // Force 64-bit precision, making sure we're not in a 80-bit FPU register. - volatile double number = base::RandDouble(); - EXPECT_GT(1.0, number); - EXPECT_LE(0.0, number); -} - -TEST(RandUtilTest, RandBytes) { - const size_t buffer_size = 50; - char buffer[buffer_size]; - memset(buffer, 0, buffer_size); - base::RandBytes(buffer, buffer_size); - std::sort(buffer, buffer + buffer_size); - // Probability of occurrence of less than 25 unique bytes in 50 random bytes - // is below 10^-25. - EXPECT_GT(std::unique(buffer, buffer + buffer_size) - buffer, 25); -} - -TEST(RandUtilTest, RandBytesAsString) { - std::string random_string = base::RandBytesAsString(1); - EXPECT_EQ(1U, random_string.size()); - random_string = base::RandBytesAsString(145); - EXPECT_EQ(145U, random_string.size()); - char accumulator = 0; - for (size_t i = 0; i < random_string.size(); ++i) - accumulator |= random_string[i]; - // In theory this test can fail, but it won't before the universe dies of - // heat death. - EXPECT_NE(0, accumulator); -} - -// Make sure that it is still appropriate to use RandGenerator in conjunction -// with std::random_shuffle(). -TEST(RandUtilTest, RandGeneratorForRandomShuffle) { - EXPECT_EQ(base::RandGenerator(1), 0U); - EXPECT_LE(std::numeric_limits::max(), - std::numeric_limits::max()); -} - -TEST(RandUtilTest, RandGeneratorIsUniform) { - // Verify that RandGenerator has a uniform distribution. This is a - // regression test that consistently failed when RandGenerator was - // implemented this way: - // - // return base::RandUint64() % max; - // - // A degenerate case for such an implementation is e.g. a top of - // range that is 2/3rds of the way to MAX_UINT64, in which case the - // bottom half of the range would be twice as likely to occur as the - // top half. A bit of calculus care of jar@ shows that the largest - // measurable delta is when the top of the range is 3/4ths of the - // way, so that's what we use in the test. - const uint64 kTopOfRange = (std::numeric_limits::max() / 4ULL) * 3ULL; - const uint64 kExpectedAverage = kTopOfRange / 2ULL; - const uint64 kAllowedVariance = kExpectedAverage / 50ULL; // +/- 2% - const int kMinAttempts = 1000; - const int kMaxAttempts = 1000000; - - double cumulative_average = 0.0; - int count = 0; - while (count < kMaxAttempts) { - uint64 value = base::RandGenerator(kTopOfRange); - cumulative_average = (count * cumulative_average + value) / (count + 1); - - // Don't quit too quickly for things to start converging, or we may have - // a false positive. - if (count > kMinAttempts && - kExpectedAverage - kAllowedVariance < cumulative_average && - cumulative_average < kExpectedAverage + kAllowedVariance) { - break; - } - - ++count; - } - - ASSERT_LT(count, kMaxAttempts) << "Expected average was " << - kExpectedAverage << ", average ended at " << cumulative_average; -} - -TEST(RandUtilTest, RandUint64ProducesBothValuesOfAllBits) { - // This tests to see that our underlying random generator is good - // enough, for some value of good enough. - uint64 kAllZeros = 0ULL; - uint64 kAllOnes = ~kAllZeros; - uint64 found_ones = kAllZeros; - uint64 found_zeros = kAllOnes; - - for (size_t i = 0; i < 1000; ++i) { - uint64 value = base::RandUint64(); - found_ones |= value; - found_zeros &= value; - - if (found_zeros == kAllZeros && found_ones == kAllOnes) - return; - } - - FAIL() << "Didn't achieve all bit values in maximum number of tries."; -} diff --git a/base/rand_util_win.cc b/base/rand_util_win.cc deleted file mode 100644 index 391fe5b9e6..0000000000 --- a/base/rand_util_win.cc +++ /dev/null @@ -1,31 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "base/rand_util.h" - -#include - -#include "base/basictypes.h" -#include "base/logging.h" - -namespace { - -uint32 RandUint32() { - uint32 number; - CHECK_EQ(rand_s(&number), 0); - return number; -} - -} // namespace - -namespace base { - -// NOTE: This function must be cryptographically secure. http://crbug.com/140076 -uint64 RandUint64() { - uint32 first_half = RandUint32(); - uint32 second_half = RandUint32(); - return (static_cast(first_half) << 32) + second_half; -} - -} // namespace base diff --git a/base/run_loop.cc b/base/run_loop.cc deleted file mode 100644 index 991571eacd..0000000000 --- a/base/run_loop.cc +++ /dev/null @@ -1,94 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "base/run_loop.h" - -#include "base/bind.h" - -namespace base { - -RunLoop::RunLoop() - : loop_(MessageLoop::current()), - weak_factory_(this), - previous_run_loop_(NULL), - run_depth_(0), - run_called_(false), - quit_called_(false), - running_(false), - quit_when_idle_received_(false) { -#if !defined(OS_MACOSX) && !defined(OS_ANDROID) - dispatcher_ = NULL; -#endif -} - -#if !defined(OS_MACOSX) && !defined(OS_ANDROID) -RunLoop::RunLoop(MessageLoop::Dispatcher* dispatcher) - : loop_(MessageLoop::current()), - weak_factory_(this), - previous_run_loop_(NULL), - dispatcher_(dispatcher), - run_depth_(0), - run_called_(false), - quit_called_(false), - running_(false), - quit_when_idle_received_(false) { -} -#endif - -RunLoop::~RunLoop() { -} - -void RunLoop::Run() { - if (!BeforeRun()) - return; - loop_->RunHandler(); - AfterRun(); -} - -void RunLoop::RunUntilIdle() { - quit_when_idle_received_ = true; - Run(); -} - -void RunLoop::Quit() { - quit_called_ = true; - if (running_ && loop_->run_loop_ == this) { - // This is the inner-most RunLoop, so quit now. - loop_->QuitNow(); - } -} - -base::Closure RunLoop::QuitClosure() { - return base::Bind(&RunLoop::Quit, weak_factory_.GetWeakPtr()); -} - -bool RunLoop::BeforeRun() { - DCHECK(!run_called_); - run_called_ = true; - - // Allow Quit to be called before Run. - if (quit_called_) - return false; - - // Push RunLoop stack: - previous_run_loop_ = loop_->run_loop_; - run_depth_ = previous_run_loop_? previous_run_loop_->run_depth_ + 1 : 1; - loop_->run_loop_ = this; - - running_ = true; - return true; -} - -void RunLoop::AfterRun() { - running_ = false; - - // Pop RunLoop stack: - loop_->run_loop_ = previous_run_loop_; - - // Execute deferred QuitNow, if any: - if (previous_run_loop_ && previous_run_loop_->quit_called_) - loop_->QuitNow(); -} - -} // namespace base diff --git a/base/run_loop.h b/base/run_loop.h deleted file mode 100644 index 42a516000e..0000000000 --- a/base/run_loop.h +++ /dev/null @@ -1,121 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef BASE_RUN_LOOP_H_ -#define BASE_RUN_LOOP_H_ - -#include "base/base_export.h" -#include "base/callback.h" -#include "base/memory/weak_ptr.h" -#include "base/message_loop/message_loop.h" - -namespace base { -#if defined(OS_ANDROID) -class MessagePumpForUI; -#endif - -#if defined(OS_IOS) -class MessagePumpUIApplication; -#endif - -// Helper class to Run a nested MessageLoop. Please do not use nested -// MessageLoops in production code! If you must, use this class instead of -// calling MessageLoop::Run/Quit directly. RunLoop::Run can only be called once -// per RunLoop lifetime. Create a RunLoop on the stack and call Run/Quit to run -// a nested MessageLoop. -class BASE_EXPORT RunLoop { - public: - RunLoop(); -#if !defined(OS_MACOSX) && !defined(OS_ANDROID) - explicit RunLoop(MessageLoop::Dispatcher* dispatcher); -#endif - ~RunLoop(); - -#if !defined(OS_MACOSX) && !defined(OS_ANDROID) - void set_dispatcher(MessageLoop::Dispatcher* dispatcher) { - dispatcher_ = dispatcher; - } -#endif - - // Run the current MessageLoop. This blocks until Quit is called. Before - // calling Run, be sure to grab an AsWeakPtr or the QuitClosure in order to - // stop the MessageLoop asynchronously. MessageLoop::Quit and QuitNow will - // also trigger a return from Run, but those are deprecated. - void Run(); - - // Run the current MessageLoop until it doesn't find any tasks or messages in - // the queue (it goes idle). WARNING: This may never return! Only use this - // when repeating tasks such as animated web pages have been shut down. - void RunUntilIdle(); - - bool running() const { return running_; } - - // Quit an earlier call to Run(). There can be other nested RunLoops servicing - // the same task queue (MessageLoop); Quitting one RunLoop has no bearing on - // the others. Quit can be called before, during or after Run. If called - // before Run, Run will return immediately when called. Calling Quit after the - // RunLoop has already finished running has no effect. - // - // WARNING: You must NEVER assume that a call to Quit will terminate the - // targetted message loop. If a nested message loop continues running, the - // target may NEVER terminate. It is very easy to livelock (run forever) in - // such a case. - void Quit(); - - // Convenience method to get a closure that safely calls Quit (has no effect - // if the RunLoop instance is gone). - // - // Example: - // RunLoop run_loop; - // PostTask(run_loop.QuitClosure()); - // run_loop.Run(); - base::Closure QuitClosure(); - - private: - friend class MessageLoop; -#if defined(OS_ANDROID) - // Android doesn't support the blocking MessageLoop::Run, so it calls - // BeforeRun and AfterRun directly. - friend class base::MessagePumpForUI; -#endif - -#if defined(OS_IOS) - // iOS doesn't support the blocking MessageLoop::Run, so it calls - // BeforeRun directly. - friend class base::MessagePumpUIApplication; -#endif - - // Return false to abort the Run. - bool BeforeRun(); - void AfterRun(); - - MessageLoop* loop_; - - // WeakPtrFactory for QuitClosure safety. - base::WeakPtrFactory weak_factory_; - - // Parent RunLoop or NULL if this is the top-most RunLoop. - RunLoop* previous_run_loop_; - -#if !defined(OS_MACOSX) && !defined(OS_ANDROID) - MessageLoop::Dispatcher* dispatcher_; -#endif - - // Used to count how many nested Run() invocations are on the stack. - int run_depth_; - - bool run_called_; - bool quit_called_; - bool running_; - - // Used to record that QuitWhenIdle() was called on the MessageLoop, meaning - // that we should quit Run once it becomes idle. - bool quit_when_idle_received_; - - DISALLOW_COPY_AND_ASSIGN(RunLoop); -}; - -} // namespace base - -#endif // BASE_RUN_LOOP_H_ diff --git a/base/safe_numerics.h b/base/safe_numerics.h deleted file mode 100644 index ce5c72fcc7..0000000000 --- a/base/safe_numerics.h +++ /dev/null @@ -1,135 +0,0 @@ -// Copyright 2013 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef BASE_SAFE_NUMERICS_H_ -#define BASE_SAFE_NUMERICS_H_ - -#include - -#include "base/logging.h" - -namespace base { -namespace internal { - -template -struct IsValidNumericCastImpl; - -#define BASE_NUMERIC_CAST_CASE_SPECIALIZATION(A, B, C, D, Code) \ -template <> struct IsValidNumericCastImpl { \ - template static inline bool Test( \ - Source source, DestBounds min, DestBounds max) { \ - return Code; \ - } \ -} - -#define BASE_NUMERIC_CAST_CASE_SAME_SIZE(DestSigned, SourceSigned, Code) \ - BASE_NUMERIC_CAST_CASE_SPECIALIZATION( \ - true, true, DestSigned, SourceSigned, Code); \ - BASE_NUMERIC_CAST_CASE_SPECIALIZATION( \ - true, false, DestSigned, SourceSigned, Code) - -#define BASE_NUMERIC_CAST_CASE_SOURCE_LARGER(DestSigned, SourceSigned, Code) \ - BASE_NUMERIC_CAST_CASE_SPECIALIZATION( \ - false, false, DestSigned, SourceSigned, Code); \ - -#define BASE_NUMERIC_CAST_CASE_DEST_LARGER(DestSigned, SourceSigned, Code) \ - BASE_NUMERIC_CAST_CASE_SPECIALIZATION( \ - false, true, DestSigned, SourceSigned, Code); \ - -// The three top level cases are: -// - Same size -// - Source larger -// - Dest larger -// And for each of those three cases, we handle the 4 different possibilities -// of signed and unsigned. This gives 12 cases to handle, which we enumerate -// below. -// -// The last argument in each of the macros is the actual comparison code. It -// has three arguments available, source (the value), and min/max which are -// the ranges of the destination. - - -// These are the cases where both types have the same size. - -// Both signed. -BASE_NUMERIC_CAST_CASE_SAME_SIZE(true, true, true); -// Both unsigned. -BASE_NUMERIC_CAST_CASE_SAME_SIZE(false, false, true); -// Dest unsigned, Source signed. -BASE_NUMERIC_CAST_CASE_SAME_SIZE(false, true, source >= 0); -// Dest signed, Source unsigned. -// This cast is OK because Dest's max must be less than Source's. -BASE_NUMERIC_CAST_CASE_SAME_SIZE(true, false, - source <= static_cast(max)); - - -// These are the cases where Source is larger. - -// Both unsigned. -BASE_NUMERIC_CAST_CASE_SOURCE_LARGER(false, false, source <= max); -// Both signed. -BASE_NUMERIC_CAST_CASE_SOURCE_LARGER(true, true, - source >= min && source <= max); -// Dest is unsigned, Source is signed. -BASE_NUMERIC_CAST_CASE_SOURCE_LARGER(false, true, - source >= 0 && source <= max); -// Dest is signed, Source is unsigned. -// This cast is OK because Dest's max must be less than Source's. -BASE_NUMERIC_CAST_CASE_SOURCE_LARGER(true, false, - source <= static_cast(max)); - - -// These are the cases where Dest is larger. - -// Both unsigned. -BASE_NUMERIC_CAST_CASE_DEST_LARGER(false, false, true); -// Both signed. -BASE_NUMERIC_CAST_CASE_DEST_LARGER(true, true, true); -// Dest is unsigned, Source is signed. -BASE_NUMERIC_CAST_CASE_DEST_LARGER(false, true, source >= 0); -// Dest is signed, Source is unsigned. -BASE_NUMERIC_CAST_CASE_DEST_LARGER(true, false, true); - -#undef BASE_NUMERIC_CAST_CASE_SPECIALIZATION -#undef BASE_NUMERIC_CAST_CASE_SAME_SIZE -#undef BASE_NUMERIC_CAST_CASE_SOURCE_LARGER -#undef BASE_NUMERIC_CAST_CASE_DEST_LARGER - - -// The main test for whether the conversion will under or overflow. -template -inline bool IsValidNumericCast(Source source) { - typedef std::numeric_limits SourceLimits; - typedef std::numeric_limits DestLimits; - COMPILE_ASSERT(SourceLimits::is_specialized, argument_must_be_numeric); - COMPILE_ASSERT(SourceLimits::is_integer, argument_must_be_integral); - COMPILE_ASSERT(DestLimits::is_specialized, result_must_be_numeric); - COMPILE_ASSERT(DestLimits::is_integer, result_must_be_integral); - - return IsValidNumericCastImpl< - sizeof(Dest) == sizeof(Source), - (sizeof(Dest) > sizeof(Source)), - DestLimits::is_signed, - SourceLimits::is_signed>::Test( - source, - DestLimits::min(), - DestLimits::max()); -} - -} // namespace internal - -// checked_numeric_cast<> is analogous to static_cast<> for numeric types, -// except that it CHECKs that the specified numeric conversion will not -// overflow or underflow. Floating point arguments are not currently allowed -// (this is COMPILE_ASSERTd), though this could be supported if necessary. -template -inline Dest checked_numeric_cast(Source source) { - CHECK(internal::IsValidNumericCast(source)); - return static_cast(source); -} - -} // namespace base - -#endif // BASE_SAFE_NUMERICS_H_ diff --git a/base/safe_numerics_unittest.cc b/base/safe_numerics_unittest.cc deleted file mode 100644 index c66e56f3cf..0000000000 --- a/base/safe_numerics_unittest.cc +++ /dev/null @@ -1,151 +0,0 @@ -// Copyright 2013 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include - -#include -#include - -#include "base/safe_numerics.h" - -namespace base { -namespace internal { - -// This is far (far, far) too slow to run normally, but if you're refactoring -// it might be useful. -// #define RUN_EXHAUSTIVE_TEST - -#ifdef RUN_EXHAUSTIVE_TEST - -template void ExhaustiveCheckFromTo() { - fprintf(stderr, "."); - From i = std::numeric_limits::min(); - for (;;) { - std::ostringstream str_from, str_to; - str_from << i; - To to = static_cast(i); - str_to << to; - bool strings_equal = str_from.str() == str_to.str(); - EXPECT_EQ(IsValidNumericCast(i), strings_equal); - fprintf(stderr, "\r%s vs %s\x1B[K", - str_from.str().c_str(), str_to.str().c_str()); - ++i; - // If we wrap, then we've tested everything. - if (i == std::numeric_limits::min()) - break; - } -} - -template void ExhaustiveCheckFrom() { - ExhaustiveCheckFromTo(); - ExhaustiveCheckFromTo(); - ExhaustiveCheckFromTo(); - ExhaustiveCheckFromTo(); - ExhaustiveCheckFromTo(); - ExhaustiveCheckFromTo(); - ExhaustiveCheckFromTo(); - fprintf(stderr, "\n"); -} - -#endif - - -TEST(SafeNumerics, NumericCast) { - int small_positive = 1; - int small_negative = -1; - int large_positive = INT_MAX; - int large_negative = INT_MIN; - size_t size_t_small = 1; - size_t size_t_large = UINT_MAX; - - // Narrow signed destination. - EXPECT_TRUE(IsValidNumericCast(small_positive)); - EXPECT_TRUE(IsValidNumericCast(small_negative)); - EXPECT_FALSE(IsValidNumericCast(large_positive)); - EXPECT_FALSE(IsValidNumericCast(large_negative)); - EXPECT_TRUE(IsValidNumericCast(small_positive)); - EXPECT_TRUE(IsValidNumericCast(small_negative)); - - // Narrow unsigned destination. - EXPECT_TRUE(IsValidNumericCast(small_positive)); - EXPECT_FALSE(IsValidNumericCast(small_negative)); - EXPECT_FALSE(IsValidNumericCast(large_positive)); - EXPECT_FALSE(IsValidNumericCast(large_negative)); - EXPECT_FALSE(IsValidNumericCast(small_negative)); - EXPECT_FALSE(IsValidNumericCast(large_negative)); - - // Same width signed destination. - EXPECT_TRUE(IsValidNumericCast(small_positive)); - EXPECT_TRUE(IsValidNumericCast(small_negative)); - EXPECT_TRUE(IsValidNumericCast(large_positive)); - EXPECT_TRUE(IsValidNumericCast(large_negative)); - - // Same width unsigned destination. - EXPECT_TRUE(IsValidNumericCast(small_positive)); - EXPECT_FALSE(IsValidNumericCast(small_negative)); - EXPECT_TRUE(IsValidNumericCast(large_positive)); - EXPECT_FALSE(IsValidNumericCast(large_negative)); - - // Wider signed destination. - EXPECT_TRUE(IsValidNumericCast(small_positive)); - EXPECT_TRUE(IsValidNumericCast(large_negative)); - EXPECT_TRUE(IsValidNumericCast(small_positive)); - EXPECT_TRUE(IsValidNumericCast(large_negative)); - - // Wider unsigned destination. - EXPECT_TRUE(IsValidNumericCast(small_positive)); - EXPECT_FALSE(IsValidNumericCast(small_negative)); - EXPECT_TRUE(IsValidNumericCast(large_positive)); - EXPECT_FALSE(IsValidNumericCast(large_negative)); - - // Negative to size_t. - EXPECT_FALSE(IsValidNumericCast(small_negative)); - EXPECT_FALSE(IsValidNumericCast(large_negative)); - - // From unsigned. - // Small. - EXPECT_TRUE(IsValidNumericCast(size_t_small)); - EXPECT_TRUE(IsValidNumericCast(size_t_small)); - EXPECT_TRUE(IsValidNumericCast(size_t_small)); - EXPECT_TRUE(IsValidNumericCast(size_t_small)); - EXPECT_TRUE(IsValidNumericCast(size_t_small)); - EXPECT_TRUE(IsValidNumericCast(size_t_small)); - EXPECT_TRUE(IsValidNumericCast(size_t_small)); - EXPECT_TRUE(IsValidNumericCast(size_t_small)); - - // Large. - EXPECT_FALSE(IsValidNumericCast(size_t_large)); - EXPECT_FALSE(IsValidNumericCast(size_t_large)); - EXPECT_FALSE(IsValidNumericCast(size_t_large)); - EXPECT_FALSE(IsValidNumericCast(size_t_large)); - EXPECT_FALSE(IsValidNumericCast(size_t_large)); - EXPECT_TRUE(IsValidNumericCast(size_t_large)); - EXPECT_TRUE(IsValidNumericCast(size_t_large)); - EXPECT_TRUE(IsValidNumericCast(size_t_large)); - - // Various edge cases. - EXPECT_TRUE(IsValidNumericCast(static_cast(SHRT_MIN))); - EXPECT_FALSE( - IsValidNumericCast(static_cast(SHRT_MIN))); - EXPECT_FALSE(IsValidNumericCast(SHRT_MIN)); - - // Confirm that checked_numeric_cast<> actually compiles. - std::vector v; - unsigned int checked_size = - base::checked_numeric_cast(v.size()); - EXPECT_EQ(0u, checked_size); - -#ifdef RUN_EXHAUSTIVE_TEST - ExhaustiveCheckFrom(); - ExhaustiveCheckFrom(); - ExhaustiveCheckFrom(); - ExhaustiveCheckFrom(); - ExhaustiveCheckFrom(); - ExhaustiveCheckFrom(); - ExhaustiveCheckFrom(); -#endif -} - -} // namespace internal -} // namespace base diff --git a/base/safe_numerics_unittest.nc b/base/safe_numerics_unittest.nc deleted file mode 100644 index 4219cd56a4..0000000000 --- a/base/safe_numerics_unittest.nc +++ /dev/null @@ -1,29 +0,0 @@ -// Copyright (c) 2013 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include - -#include "base/safe_numerics.h" - -using base::internal::IsValidNumericCast; - -#if defined(NCTEST_NO_FLOATING_POINT_1) // [r"size of array is negative"] - -void WontCompile() { - IsValidNumericCast(0.0); -} - -#elif defined(NCTEST_NO_FLOATING_POINT_2) // [r"size of array is negative"] - -void WontCompile() { - IsValidNumericCast(0.0f); -} - -#elif defined(NCTEST_NO_FLOATING_POINT_3) // [r"size of array is negative"] - -void WontCompile() { - IsValidNumericCast(DBL_MAX); -} - -#endif diff --git a/base/safe_strerror_posix.cc b/base/safe_strerror_posix.cc deleted file mode 100644 index a91bb8de0c..0000000000 --- a/base/safe_strerror_posix.cc +++ /dev/null @@ -1,111 +0,0 @@ -// Copyright (c) 2006-2009 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "build/build_config.h" -#include "base/safe_strerror_posix.h" - -#include -#include -#include - -#define USE_HISTORICAL_STRERRO_R (defined(__GLIBC__) || defined(OS_NACL)) - -#if USE_HISTORICAL_STRERRO_R && defined(__GNUC__) -// GCC will complain about the unused second wrap function unless we tell it -// that we meant for them to be potentially unused, which is exactly what this -// attribute is for. -#define POSSIBLY_UNUSED __attribute__((unused)) -#else -#define POSSIBLY_UNUSED -#endif - -#if USE_HISTORICAL_STRERRO_R -// glibc has two strerror_r functions: a historical GNU-specific one that -// returns type char *, and a POSIX.1-2001 compliant one available since 2.3.4 -// that returns int. This wraps the GNU-specific one. -static void POSSIBLY_UNUSED wrap_posix_strerror_r( - char *(*strerror_r_ptr)(int, char *, size_t), - int err, - char *buf, - size_t len) { - // GNU version. - char *rc = (*strerror_r_ptr)(err, buf, len); - if (rc != buf) { - // glibc did not use buf and returned a static string instead. Copy it - // into buf. - buf[0] = '\0'; - strncat(buf, rc, len - 1); - } - // The GNU version never fails. Unknown errors get an "unknown error" message. - // The result is always null terminated. -} -#endif // USE_HISTORICAL_STRERRO_R - -// Wrapper for strerror_r functions that implement the POSIX interface. POSIX -// does not define the behaviour for some of the edge cases, so we wrap it to -// guarantee that they are handled. This is compiled on all POSIX platforms, but -// it will only be used on Linux if the POSIX strerror_r implementation is -// being used (see below). -static void POSSIBLY_UNUSED wrap_posix_strerror_r( - int (*strerror_r_ptr)(int, char *, size_t), - int err, - char *buf, - size_t len) { - int old_errno = errno; - // Have to cast since otherwise we get an error if this is the GNU version - // (but in such a scenario this function is never called). Sadly we can't use - // C++-style casts because the appropriate one is reinterpret_cast but it's - // considered illegal to reinterpret_cast a type to itself, so we get an - // error in the opposite case. - int result = (*strerror_r_ptr)(err, buf, len); - if (result == 0) { - // POSIX is vague about whether the string will be terminated, although - // it indirectly implies that typically ERANGE will be returned, instead - // of truncating the string. We play it safe by always terminating the - // string explicitly. - buf[len - 1] = '\0'; - } else { - // Error. POSIX is vague about whether the return value is itself a system - // error code or something else. On Linux currently it is -1 and errno is - // set. On BSD-derived systems it is a system error and errno is unchanged. - // We try and detect which case it is so as to put as much useful info as - // we can into our message. - int strerror_error; // The error encountered in strerror - int new_errno = errno; - if (new_errno != old_errno) { - // errno was changed, so probably the return value is just -1 or something - // else that doesn't provide any info, and errno is the error. - strerror_error = new_errno; - } else { - // Either the error from strerror_r was the same as the previous value, or - // errno wasn't used. Assume the latter. - strerror_error = result; - } - // snprintf truncates and always null-terminates. - snprintf(buf, - len, - "Error %d while retrieving error %d", - strerror_error, - err); - } - errno = old_errno; -} - -void safe_strerror_r(int err, char *buf, size_t len) { - if (buf == NULL || len <= 0) { - return; - } - // If using glibc (i.e., Linux), the compiler will automatically select the - // appropriate overloaded function based on the function type of strerror_r. - // The other one will be elided from the translation unit since both are - // static. - wrap_posix_strerror_r(&strerror_r, err, buf, len); -} - -std::string safe_strerror(int err) { - const int buffer_size = 256; - char buf[buffer_size]; - safe_strerror_r(err, buf, sizeof(buf)); - return std::string(buf); -} diff --git a/base/safe_strerror_posix.h b/base/safe_strerror_posix.h deleted file mode 100644 index 2f77d84a1b..0000000000 --- a/base/safe_strerror_posix.h +++ /dev/null @@ -1,38 +0,0 @@ -// Copyright (c) 2011 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef BASE_SAFE_STRERROR_POSIX_H_ -#define BASE_SAFE_STRERROR_POSIX_H_ - -#include - -#include "base/base_export.h" - -// BEFORE using anything from this file, first look at PLOG and friends in -// logging.h and use them instead if applicable. -// -// This file declares safe, portable alternatives to the POSIX strerror() -// function. strerror() is inherently unsafe in multi-threaded apps and should -// never be used. Doing so can cause crashes. Additionally, the thread-safe -// alternative strerror_r varies in semantics across platforms. Use these -// functions instead. - -// Thread-safe strerror function with dependable semantics that never fails. -// It will write the string form of error "err" to buffer buf of length len. -// If there is an error calling the OS's strerror_r() function then a message to -// that effect will be printed into buf, truncating if necessary. The final -// result is always null-terminated. The value of errno is never changed. -// -// Use this instead of strerror_r(). -BASE_EXPORT void safe_strerror_r(int err, char *buf, size_t len); - -// Calls safe_strerror_r with a buffer of suitable size and returns the result -// in a C++ string. -// -// Use this instead of strerror(). Note though that safe_strerror_r will be -// more robust in the case of heap corruption errors, since it doesn't need to -// allocate a string. -BASE_EXPORT std::string safe_strerror(int err); - -#endif // BASE_SAFE_STRERROR_POSIX_H_ diff --git a/base/scoped_clear_errno.h b/base/scoped_clear_errno.h deleted file mode 100644 index 7b972fc85a..0000000000 --- a/base/scoped_clear_errno.h +++ /dev/null @@ -1,34 +0,0 @@ -// Copyright (c) 2013 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef BASE_SCOPED_CLEAR_ERRNO_H_ -#define BASE_SCOPED_CLEAR_ERRNO_H_ - -#include - -#include "base/basictypes.h" - -namespace base { - -// Simple scoper that saves the current value of errno, resets it to 0, and on -// destruction puts the old value back. -class ScopedClearErrno { - public: - ScopedClearErrno() : old_errno_(errno) { - errno = 0; - } - ~ScopedClearErrno() { - if (errno == 0) - errno = old_errno_; - } - - private: - const int old_errno_; - - DISALLOW_COPY_AND_ASSIGN(ScopedClearErrno); -}; - -} // namespace base - -#endif // BASE_SCOPED_CLEAR_ERRNO_H_ diff --git a/base/scoped_clear_errno_unittest.cc b/base/scoped_clear_errno_unittest.cc deleted file mode 100644 index 8afb33e033..0000000000 --- a/base/scoped_clear_errno_unittest.cc +++ /dev/null @@ -1,30 +0,0 @@ -// Copyright (c) 2013 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include - -#include "base/scoped_clear_errno.h" -#include "testing/gtest/include/gtest/gtest.h" - -namespace base { - -TEST(ScopedClearErrno, TestNoError) { - errno = 1; - { - ScopedClearErrno clear_error; - EXPECT_EQ(0, errno); - } - EXPECT_EQ(1, errno); -} - -TEST(ScopedClearErrno, TestError) { - errno = 1; - { - ScopedClearErrno clear_error; - errno = 2; - } - EXPECT_EQ(2, errno); -} - -} // namespace base diff --git a/base/scoped_native_library.cc b/base/scoped_native_library.cc deleted file mode 100644 index 7290d29595..0000000000 --- a/base/scoped_native_library.cc +++ /dev/null @@ -1,44 +0,0 @@ -// Copyright (c) 2011 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "base/scoped_native_library.h" - -namespace base { - -ScopedNativeLibrary::ScopedNativeLibrary() : library_(NULL) { -} - -ScopedNativeLibrary::ScopedNativeLibrary(NativeLibrary library) - : library_(library) { -} - -ScopedNativeLibrary::ScopedNativeLibrary(const FilePath& library_path) { - library_ = base::LoadNativeLibrary(library_path, NULL); -} - -ScopedNativeLibrary::~ScopedNativeLibrary() { - if (library_) - base::UnloadNativeLibrary(library_); -} - -void* ScopedNativeLibrary::GetFunctionPointer( - const char* function_name) const { - if (!library_) - return NULL; - return base::GetFunctionPointerFromNativeLibrary(library_, function_name); -} - -void ScopedNativeLibrary::Reset(NativeLibrary library) { - if (library_) - base::UnloadNativeLibrary(library_); - library_ = library; -} - -NativeLibrary ScopedNativeLibrary::Release() { - NativeLibrary result = library_; - library_ = NULL; - return result; -} - -} // namespace base diff --git a/base/scoped_native_library.h b/base/scoped_native_library.h deleted file mode 100644 index e9923f4342..0000000000 --- a/base/scoped_native_library.h +++ /dev/null @@ -1,52 +0,0 @@ -// Copyright (c) 2011 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef BASE_SCOPED_NATIVE_LIBRARY_H_ -#define BASE_SCOPED_NATIVE_LIBRARY_H_ - -#include "base/base_export.h" -#include "base/native_library.h" - -namespace base { - -class FilePath; - -// A class which encapsulates a base::NativeLibrary object available only in a -// scope. -// This class automatically unloads the loaded library in its destructor. -class BASE_EXPORT ScopedNativeLibrary { - public: - // Initializes with a NULL library. - ScopedNativeLibrary(); - - // Takes ownership of the given library handle. - explicit ScopedNativeLibrary(NativeLibrary library); - - // Opens the given library and manages its lifetime. - explicit ScopedNativeLibrary(const FilePath& library_path); - - ~ScopedNativeLibrary(); - - // Returns true if there's a valid library loaded. - bool is_valid() const { return !!library_; } - - void* GetFunctionPointer(const char* function_name) const; - - // Takes ownership of the given library handle. Any existing handle will - // be freed. - void Reset(NativeLibrary library); - - // Returns the native library handle and removes it from this object. The - // caller must manage the lifetime of the handle. - NativeLibrary Release(); - - private: - NativeLibrary library_; - - DISALLOW_COPY_AND_ASSIGN(ScopedNativeLibrary); -}; - -} // namespace base - -#endif // BASE_MEMORY_NATIVE_LIBRARY_H_ diff --git a/base/scoped_native_library_unittest.cc b/base/scoped_native_library_unittest.cc deleted file mode 100644 index c120555ec6..0000000000 --- a/base/scoped_native_library_unittest.cc +++ /dev/null @@ -1,37 +0,0 @@ -// Copyright (c) 2011 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "base/scoped_native_library.h" -#if defined(OS_WIN) -#include "base/files/file_path.h" -#endif - -#include "testing/gtest/include/gtest/gtest.h" - -namespace base { - -// Tests whether or not a function pointer retrieved via ScopedNativeLibrary -// is available only in a scope. -TEST(ScopedNativeLibrary, Basic) { -#if defined(OS_WIN) - // Get the pointer to DirectDrawCreate() from "ddraw.dll" and verify it - // is valid only in this scope. - // FreeLibrary() doesn't actually unload a DLL until its reference count - // becomes zero, i.e. this function pointer is still valid if the DLL used - // in this test is also used by another part of this executable. - // So, this test uses "ddraw.dll", which is not used by Chrome at all but - // installed on all versions of Windows. - FARPROC test_function; - { - FilePath path(GetNativeLibraryName(L"ddraw")); - ScopedNativeLibrary library(path); - test_function = reinterpret_cast( - library.GetFunctionPointer("DirectDrawCreate")); - EXPECT_EQ(0, IsBadCodePtr(test_function)); - } - EXPECT_NE(0, IsBadCodePtr(test_function)); -#endif -} - -} // namespace base diff --git a/base/scoped_observer.h b/base/scoped_observer.h deleted file mode 100644 index eae6367204..0000000000 --- a/base/scoped_observer.h +++ /dev/null @@ -1,54 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef BASE_SCOPED_OBSERVER_H_ -#define BASE_SCOPED_OBSERVER_H_ - -#include -#include - -#include "base/basictypes.h" - -// ScopedObserver is used to keep track of the set of sources an object has -// attached itself to as an observer. When ScopedObserver is destroyed it -// removes the object as an observer from all sources it has been added to. -template -class ScopedObserver { - public: - explicit ScopedObserver(Observer* observer) : observer_(observer) {} - - ~ScopedObserver() { - for (size_t i = 0; i < sources_.size(); ++i) - sources_[i]->RemoveObserver(observer_); - } - - // Adds the object passed to the constructor as an observer on |source|. - void Add(Source* source) { - sources_.push_back(source); - source->AddObserver(observer_); - } - - // Remove the object passed to the constructor as an observer from |source|. - void Remove(Source* source) { - sources_.erase(std::find(sources_.begin(), sources_.end(), source)); - source->RemoveObserver(observer_); - } - - bool IsObserving(Source* source) const { - for (size_t i = 0; i < sources_.size(); ++i) { - if (sources_[i] == source) - return true; - } - return false; - } - - private: - Observer* observer_; - - std::vector sources_; - - DISALLOW_COPY_AND_ASSIGN(ScopedObserver); -}; - -#endif // BASE_SCOPED_OBSERVER_H_ diff --git a/base/security_unittest.cc b/base/security_unittest.cc deleted file mode 100644 index 5b266b0a11..0000000000 --- a/base/security_unittest.cc +++ /dev/null @@ -1,306 +0,0 @@ -// Copyright (c) 2013 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include -#include -#include -#include -#include -#include - -#include -#include - -#include "base/file_util.h" -#include "base/logging.h" -#include "base/memory/scoped_ptr.h" -#include "build/build_config.h" -#include "testing/gtest/include/gtest/gtest.h" - -#if defined(OS_POSIX) -#include -#include -#endif - -using std::nothrow; -using std::numeric_limits; - -namespace { - -// This function acts as a compiler optimization barrier. We use it to -// prevent the compiler from making an expression a compile-time constant. -// We also use it so that the compiler doesn't discard certain return values -// as something we don't need (see the comment with calloc below). -template -Type HideValueFromCompiler(volatile Type value) { -#if defined(__GNUC__) - // In a GCC compatible compiler (GCC or Clang), make this compiler barrier - // more robust than merely using "volatile". - __asm__ volatile ("" : "+r" (value)); -#endif // __GNUC__ - return value; -} - -// - NO_TCMALLOC (should be defined if we compile with linux_use_tcmalloc=0) -// - ADDRESS_SANITIZER because it has its own memory allocator -// - IOS does not use tcmalloc -// - OS_MACOSX does not use tcmalloc -#if !defined(NO_TCMALLOC) && !defined(ADDRESS_SANITIZER) && \ - !defined(OS_IOS) && !defined(OS_MACOSX) - #define TCMALLOC_TEST(function) function -#else - #define TCMALLOC_TEST(function) DISABLED_##function -#endif - -// TODO(jln): switch to std::numeric_limits::max() when we switch to -// C++11. -const size_t kTooBigAllocSize = INT_MAX; - -// Detect runtime TCMalloc bypasses. -bool IsTcMallocBypassed() { -#if defined(OS_LINUX) || defined(OS_CHROMEOS) - // This should detect a TCMalloc bypass from Valgrind. - char* g_slice = getenv("G_SLICE"); - if (g_slice && !strcmp(g_slice, "always-malloc")) - return true; -#elif defined(OS_WIN) - // This should detect a TCMalloc bypass from setting - // the CHROME_ALLOCATOR environment variable. - char* allocator = getenv("CHROME_ALLOCATOR"); - if (allocator && strcmp(allocator, "tcmalloc")) - return true; -#endif - return false; -} - -bool CallocDiesOnOOM() { -// The wrapper function in base/process_util_linux.cc that is used when we -// compile without TCMalloc will just die on OOM instead of returning NULL. -// This function is explicitly disabled if we compile with AddressSanitizer, -// MemorySanitizer or ThreadSanitizer. -#if defined(OS_LINUX) && defined(NO_TCMALLOC) && \ - (!defined(ADDRESS_SANITIZER) && \ - !defined(MEMORY_SANITIZER) && \ - !defined(THREAD_SANITIZER)) - return true; -#else - return false; -#endif -} - -// Fake test that allow to know the state of TCMalloc by looking at bots. -TEST(SecurityTest, TCMALLOC_TEST(IsTCMallocDynamicallyBypassed)) { - printf("Malloc is dynamically bypassed: %s\n", - IsTcMallocBypassed() ? "yes." : "no."); -} - -// The MemoryAllocationRestrictions* tests test that we can not allocate a -// memory range that cannot be indexed via an int. This is used to mitigate -// vulnerabilities in libraries that use int instead of size_t. See -// crbug.com/169327. - -TEST(SecurityTest, TCMALLOC_TEST(MemoryAllocationRestrictionsMalloc)) { - if (!IsTcMallocBypassed()) { - scoped_ptr ptr(static_cast( - HideValueFromCompiler(malloc(kTooBigAllocSize)))); - ASSERT_TRUE(!ptr); - } -} - -TEST(SecurityTest, TCMALLOC_TEST(MemoryAllocationRestrictionsCalloc)) { - if (!IsTcMallocBypassed()) { - scoped_ptr ptr(static_cast( - HideValueFromCompiler(calloc(kTooBigAllocSize, 1)))); - ASSERT_TRUE(!ptr); - } -} - -TEST(SecurityTest, TCMALLOC_TEST(MemoryAllocationRestrictionsRealloc)) { - if (!IsTcMallocBypassed()) { - char* orig_ptr = static_cast(malloc(1)); - ASSERT_TRUE(orig_ptr); - scoped_ptr ptr(static_cast( - HideValueFromCompiler(realloc(orig_ptr, kTooBigAllocSize)))); - ASSERT_TRUE(!ptr); - // If realloc() did not succeed, we need to free orig_ptr. - free(orig_ptr); - } -} - -typedef struct { - char large_array[kTooBigAllocSize]; -} VeryLargeStruct; - -TEST(SecurityTest, TCMALLOC_TEST(MemoryAllocationRestrictionsNew)) { - if (!IsTcMallocBypassed()) { - scoped_ptr ptr( - HideValueFromCompiler(new (nothrow) VeryLargeStruct)); - ASSERT_TRUE(!ptr); - } -} - -TEST(SecurityTest, TCMALLOC_TEST(MemoryAllocationRestrictionsNewArray)) { - if (!IsTcMallocBypassed()) { - scoped_ptr ptr( - HideValueFromCompiler(new (nothrow) char[kTooBigAllocSize])); - ASSERT_TRUE(!ptr); - } -} - -// The tests bellow check for overflows in new[] and calloc(). - -#if defined(OS_IOS) || defined(OS_WIN) - #define DISABLE_ON_IOS_AND_WIN(function) DISABLED_##function -#else - #define DISABLE_ON_IOS_AND_WIN(function) function -#endif - -// There are platforms where these tests are known to fail. We would like to -// be able to easily check the status on the bots, but marking tests as -// FAILS_ is too clunky. -void OverflowTestsSoftExpectTrue(bool overflow_detected) { - if (!overflow_detected) { -#if defined(OS_LINUX) || defined(OS_ANDROID) || defined(OS_MACOSX) - // Sadly, on Linux, Android, and OSX we don't have a good story yet. Don't - // fail the test, but report. - printf("Platform has overflow: %s\n", - !overflow_detected ? "yes." : "no."); -#else - // Otherwise, fail the test. (Note: EXPECT are ok in subfunctions, ASSERT - // aren't). - EXPECT_TRUE(overflow_detected); -#endif - } -} - -// Test array[TooBig][X] and array[X][TooBig] allocations for int overflows. -// IOS doesn't honor nothrow, so disable the test there. -// Crashes on Windows Dbg builds, disable there as well. -TEST(SecurityTest, DISABLE_ON_IOS_AND_WIN(NewOverflow)) { - const size_t kArraySize = 4096; - // We want something "dynamic" here, so that the compiler doesn't - // immediately reject crazy arrays. - const size_t kDynamicArraySize = HideValueFromCompiler(kArraySize); - // numeric_limits are still not constexpr until we switch to C++11, so we - // use an ugly cast. - const size_t kMaxSizeT = ~static_cast(0); - ASSERT_EQ(numeric_limits::max(), kMaxSizeT); - const size_t kArraySize2 = kMaxSizeT / kArraySize + 10; - const size_t kDynamicArraySize2 = HideValueFromCompiler(kArraySize2); - { - scoped_ptr array_pointer(new (nothrow) - char[kDynamicArraySize2][kArraySize]); - OverflowTestsSoftExpectTrue(!array_pointer); - } - // On windows, the compiler prevents static array sizes of more than - // 0x7fffffff (error C2148). -#if !defined(OS_WIN) || !defined(ARCH_CPU_64_BITS) - { - scoped_ptr array_pointer(new (nothrow) - char[kDynamicArraySize][kArraySize2]); - OverflowTestsSoftExpectTrue(!array_pointer); - } -#endif // !defined(OS_WIN) || !defined(ARCH_CPU_64_BITS) -} - -// Call calloc(), eventually free the memory and return whether or not -// calloc() did succeed. -bool CallocReturnsNull(size_t nmemb, size_t size) { - scoped_ptr array_pointer( - static_cast(calloc(nmemb, size))); - // We need the call to HideValueFromCompiler(): we have seen LLVM - // optimize away the call to calloc() entirely and assume - // the pointer to not be NULL. - return HideValueFromCompiler(array_pointer.get()) == NULL; -} - -// Test if calloc() can overflow. -TEST(SecurityTest, CallocOverflow) { - const size_t kArraySize = 4096; - const size_t kMaxSizeT = numeric_limits::max(); - const size_t kArraySize2 = kMaxSizeT / kArraySize + 10; - if (!CallocDiesOnOOM()) { - EXPECT_TRUE(CallocReturnsNull(kArraySize, kArraySize2)); - EXPECT_TRUE(CallocReturnsNull(kArraySize2, kArraySize)); - } else { - // It's also ok for calloc to just terminate the process. -#if defined(GTEST_HAS_DEATH_TEST) - EXPECT_DEATH(CallocReturnsNull(kArraySize, kArraySize2), ""); - EXPECT_DEATH(CallocReturnsNull(kArraySize2, kArraySize), ""); -#endif // GTEST_HAS_DEATH_TEST - } -} - -#if (defined(OS_LINUX) || defined(OS_CHROMEOS)) && defined(__x86_64__) -// Useful for debugging. -void PrintProcSelfMaps() { - int fd = open("/proc/self/maps", O_RDONLY); - file_util::ScopedFD fd_closer(&fd); - ASSERT_GE(fd, 0); - char buffer[1<<13]; - int ret; - ret = read(fd, buffer, sizeof(buffer) - 1); - ASSERT_GT(ret, 0); - buffer[ret - 1] = 0; - fprintf(stdout, "%s\n", buffer); -} - -// Check if ptr1 and ptr2 are separated by less than size chars. -bool ArePointersToSameArea(void* ptr1, void* ptr2, size_t size) { - ptrdiff_t ptr_diff = reinterpret_cast(std::max(ptr1, ptr2)) - - reinterpret_cast(std::min(ptr1, ptr2)); - return static_cast(ptr_diff) <= size; -} - -// Check if TCMalloc uses an underlying random memory allocator. -TEST(SecurityTest, TCMALLOC_TEST(RandomMemoryAllocations)) { - if (IsTcMallocBypassed()) - return; - size_t kPageSize = 4096; // We support x86_64 only. - // Check that malloc() returns an address that is neither the kernel's - // un-hinted mmap area, nor the current brk() area. The first malloc() may - // not be at a random address because TCMalloc will first exhaust any memory - // that it has allocated early on, before starting the sophisticated - // allocators. - void* default_mmap_heap_address = - mmap(0, kPageSize, PROT_READ|PROT_WRITE, - MAP_PRIVATE|MAP_ANONYMOUS, -1, 0); - ASSERT_NE(default_mmap_heap_address, - static_cast(MAP_FAILED)); - ASSERT_EQ(munmap(default_mmap_heap_address, kPageSize), 0); - void* brk_heap_address = sbrk(0); - ASSERT_NE(brk_heap_address, reinterpret_cast(-1)); - ASSERT_TRUE(brk_heap_address != NULL); - // 1 MB should get us past what TCMalloc pre-allocated before initializing - // the sophisticated allocators. - size_t kAllocSize = 1<<20; - scoped_ptr ptr( - static_cast(malloc(kAllocSize))); - ASSERT_TRUE(ptr != NULL); - // If two pointers are separated by less than 512MB, they are considered - // to be in the same area. - // Our random pointer could be anywhere within 0x3fffffffffff (46bits), - // and we are checking that it's not withing 1GB (30 bits) from two - // addresses (brk and mmap heap). We have roughly one chance out of - // 2^15 to flake. - const size_t kAreaRadius = 1<<29; - bool in_default_mmap_heap = ArePointersToSameArea( - ptr.get(), default_mmap_heap_address, kAreaRadius); - EXPECT_FALSE(in_default_mmap_heap); - - bool in_default_brk_heap = ArePointersToSameArea( - ptr.get(), brk_heap_address, kAreaRadius); - EXPECT_FALSE(in_default_brk_heap); - - // In the implementation, we always mask our random addresses with - // kRandomMask, so we use it as an additional detection mechanism. - const uintptr_t kRandomMask = 0x3fffffffffffULL; - bool impossible_random_address = - reinterpret_cast(ptr.get()) & ~kRandomMask; - EXPECT_FALSE(impossible_random_address); -} - -#endif // (defined(OS_LINUX) || defined(OS_CHROMEOS)) && defined(__x86_64__) - -} // namespace diff --git a/base/sequence_checker.h b/base/sequence_checker.h deleted file mode 100644 index 89bbd7eca9..0000000000 --- a/base/sequence_checker.h +++ /dev/null @@ -1,68 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef BASE_SEQUENCE_CHECKER_H_ -#define BASE_SEQUENCE_CHECKER_H_ - -#include "base/memory/ref_counted.h" - -// See comments for the similar block in thread_checker.h. -#if (!defined(NDEBUG) || defined(DCHECK_ALWAYS_ON)) -#define ENABLE_SEQUENCE_CHECKER 1 -#else -#define ENABLE_SEQUENCE_CHECKER 0 -#endif - -#if ENABLE_SEQUENCE_CHECKER -#include "base/sequence_checker_impl.h" -#endif - -namespace base { - -class SequencedTaskRunner; - -// Do nothing implementation, for use in release mode. -// -// Note: You should almost always use the SequenceChecker class to get -// the right version for your build configuration. -class SequenceCheckerDoNothing { - public: - bool CalledOnValidSequencedThread() const { - return true; - } - - void DetachFromSequence() {} -}; - -// SequenceChecker is a helper class used to help verify that some -// methods of a class are called in sequence -- that is, called from -// the same SequencedTaskRunner. It is a generalization of -// ThreadChecker; see comments in sequence_checker_impl.h for details. -// -// Example: -// class MyClass { -// public: -// void Foo() { -// DCHECK(sequence_checker_.CalledOnValidSequence()); -// ... (do stuff) ... -// } -// -// private: -// SequenceChecker sequence_checker_; -// } -// -// In Release mode, CalledOnValidSequence will always return true. -#if ENABLE_SEQUENCE_CHECKER -class SequenceChecker : public SequenceCheckerImpl { -}; -#else -class SequenceChecker : public SequenceCheckerDoNothing { -}; -#endif // ENABLE_SEQUENCE_CHECKER - -#undef ENABLE_SEQUENCE_CHECKER - -} // namespace base - -#endif // BASE_SEQUENCE_CHECKER_H_ diff --git a/base/sequence_checker_impl.cc b/base/sequence_checker_impl.cc deleted file mode 100644 index e95b8ee5f3..0000000000 --- a/base/sequence_checker_impl.cc +++ /dev/null @@ -1,46 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "base/sequence_checker_impl.h" - -namespace base { - -SequenceCheckerImpl::SequenceCheckerImpl() - : sequence_token_assigned_(false) { - AutoLock auto_lock(lock_); - EnsureSequenceTokenAssigned(); -} - -SequenceCheckerImpl::~SequenceCheckerImpl() {} - -bool SequenceCheckerImpl::CalledOnValidSequencedThread() const { - AutoLock auto_lock(lock_); - EnsureSequenceTokenAssigned(); - - // If this thread is not associated with a SequencedWorkerPool, - // SequenceChecker behaves as a ThreadChecker. See header for details. - if (!sequence_token_.IsValid()) - return thread_checker_.CalledOnValidThread(); - - return sequence_token_.Equals( - SequencedWorkerPool::GetSequenceTokenForCurrentThread()); -} - -void SequenceCheckerImpl::DetachFromSequence() { - AutoLock auto_lock(lock_); - thread_checker_.DetachFromThread(); - sequence_token_assigned_ = false; - sequence_token_ = SequencedWorkerPool::SequenceToken(); -} - -void SequenceCheckerImpl::EnsureSequenceTokenAssigned() const { - lock_.AssertAcquired(); - if (sequence_token_assigned_) - return; - - sequence_token_assigned_ = true; - sequence_token_ = SequencedWorkerPool::GetSequenceTokenForCurrentThread(); -} - -} // namespace base diff --git a/base/sequence_checker_impl.h b/base/sequence_checker_impl.h deleted file mode 100644 index 741aafee64..0000000000 --- a/base/sequence_checker_impl.h +++ /dev/null @@ -1,52 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef BASE_SEQUENCE_CHECKER_IMPL_H_ -#define BASE_SEQUENCE_CHECKER_IMPL_H_ - -#include "base/base_export.h" -#include "base/basictypes.h" -#include "base/synchronization/lock.h" -#include "base/threading/sequenced_worker_pool.h" -#include "base/threading/thread_checker_impl.h" - -namespace base { - -// SequenceCheckerImpl is used to help verify that some methods of a -// class are called in sequence -- that is, called from the same -// SequencedTaskRunner. It is a generalization of ThreadChecker; in -// particular, it behaves exactly like ThreadChecker if constructed -// on a thread that is not part of a SequencedWorkerPool. -class BASE_EXPORT SequenceCheckerImpl { - public: - SequenceCheckerImpl(); - ~SequenceCheckerImpl(); - - // Returns whether the we are being called on the same sequence token - // as previous calls. If there is no associated sequence, then returns - // whether we are being called on the underlying ThreadChecker's thread. - bool CalledOnValidSequencedThread() const; - - // Unbinds the checker from the currently associated sequence. The - // checker will be re-bound on the next call to CalledOnValidSequence(). - void DetachFromSequence(); - - private: - void EnsureSequenceTokenAssigned() const; - - // Guards all variables below. - mutable Lock lock_; - - // Used if |sequence_token_| is not valid. - ThreadCheckerImpl thread_checker_; - mutable bool sequence_token_assigned_; - - mutable SequencedWorkerPool::SequenceToken sequence_token_; - - DISALLOW_COPY_AND_ASSIGN(SequenceCheckerImpl); -}; - -} // namespace base - -#endif // BASE_SEQUENCE_CHECKER_IMPL_H_ diff --git a/base/sequence_checker_unittest.cc b/base/sequence_checker_unittest.cc deleted file mode 100644 index 7df7614926..0000000000 --- a/base/sequence_checker_unittest.cc +++ /dev/null @@ -1,339 +0,0 @@ -// Copyright 2013 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "base/basictypes.h" -#include "base/bind.h" -#include "base/bind_helpers.h" -#include "base/location.h" -#include "base/logging.h" -#include "base/memory/ref_counted.h" -#include "base/memory/scoped_ptr.h" -#include "base/message_loop/message_loop.h" -#include "base/sequence_checker.h" -#include "base/test/sequenced_worker_pool_owner.h" -#include "base/threading/thread.h" -#include "testing/gtest/include/gtest/gtest.h" - -// Duplicated from base/sequence_checker.h so that we can be good citizens -// there and undef the macro. -#if (!defined(NDEBUG) || defined(DCHECK_ALWAYS_ON)) -#define ENABLE_SEQUENCE_CHECKER 1 -#else -#define ENABLE_SEQUENCE_CHECKER 0 -#endif - -namespace base { - -namespace { - -const size_t kNumWorkerThreads = 3; - -// Simple class to exercise the basics of SequenceChecker. -// DoStuff should verify that it's called on a valid sequenced thread. -// SequenceCheckedObject can be destroyed on any thread (like WeakPtr). -class SequenceCheckedObject { - public: - SequenceCheckedObject() {} - ~SequenceCheckedObject() {} - - // Verifies that it was called on the same thread as the constructor. - void DoStuff() { - DCHECK(sequence_checker_.CalledOnValidSequencedThread()); - } - - void DetachFromSequence() { - sequence_checker_.DetachFromSequence(); - } - - private: - SequenceChecker sequence_checker_; - - DISALLOW_COPY_AND_ASSIGN(SequenceCheckedObject); -}; - -class SequenceCheckerTest : public testing::Test { - public: - SequenceCheckerTest() : other_thread_("sequence_checker_test_other_thread") {} - - virtual ~SequenceCheckerTest() {} - - virtual void SetUp() OVERRIDE { - other_thread_.Start(); - ResetPool(); - } - - virtual void TearDown() OVERRIDE { - other_thread_.Stop(); - pool()->Shutdown(); - } - - protected: - base::Thread* other_thread() { return &other_thread_; } - - const scoped_refptr& pool() { - return pool_owner_->pool(); - } - - void PostDoStuffToWorkerPool(SequenceCheckedObject* sequence_checked_object, - const std::string& token_name) { - pool()->PostNamedSequencedWorkerTask( - token_name, - FROM_HERE, - base::Bind(&SequenceCheckedObject::DoStuff, - base::Unretained(sequence_checked_object))); - } - - void PostDoStuffToOtherThread( - SequenceCheckedObject* sequence_checked_object) { - other_thread()->message_loop()->PostTask( - FROM_HERE, - base::Bind(&SequenceCheckedObject::DoStuff, - base::Unretained(sequence_checked_object))); - } - - void PostDeleteToOtherThread( - scoped_ptr sequence_checked_object) { - other_thread()->message_loop()->DeleteSoon( - FROM_HERE, - sequence_checked_object.release()); - } - - // Destroys the SequencedWorkerPool instance, blocking until it is fully shut - // down, and creates a new instance. - void ResetPool() { - pool_owner_.reset(new SequencedWorkerPoolOwner(kNumWorkerThreads, "test")); - } - - void MethodOnDifferentThreadDeathTest(); - void DetachThenCallFromDifferentThreadDeathTest(); - void DifferentSequenceTokensDeathTest(); - void WorkerPoolAndSimpleThreadDeathTest(); - void TwoDifferentWorkerPoolsDeathTest(); - - private: - MessageLoop message_loop_; // Needed by SequencedWorkerPool to function. - base::Thread other_thread_; - scoped_ptr pool_owner_; -}; - -TEST_F(SequenceCheckerTest, CallsAllowedOnSameThread) { - scoped_ptr sequence_checked_object( - new SequenceCheckedObject); - - // Verify that DoStuff doesn't assert. - sequence_checked_object->DoStuff(); - - // Verify that the destructor doesn't assert. - sequence_checked_object.reset(); -} - -TEST_F(SequenceCheckerTest, DestructorAllowedOnDifferentThread) { - scoped_ptr sequence_checked_object( - new SequenceCheckedObject); - - // Verify the destructor doesn't assert when called on a different thread. - PostDeleteToOtherThread(sequence_checked_object.Pass()); - other_thread()->Stop(); -} - -TEST_F(SequenceCheckerTest, DetachFromSequence) { - scoped_ptr sequence_checked_object( - new SequenceCheckedObject); - - // Verify that DoStuff doesn't assert when called on a different thread after - // a call to DetachFromSequence. - sequence_checked_object->DetachFromSequence(); - - PostDoStuffToOtherThread(sequence_checked_object.get()); - other_thread()->Stop(); -} - -TEST_F(SequenceCheckerTest, SameSequenceTokenValid) { - scoped_ptr sequence_checked_object( - new SequenceCheckedObject); - - sequence_checked_object->DetachFromSequence(); - PostDoStuffToWorkerPool(sequence_checked_object.get(), "A"); - PostDoStuffToWorkerPool(sequence_checked_object.get(), "A"); - PostDoStuffToWorkerPool(sequence_checked_object.get(), "A"); - PostDoStuffToWorkerPool(sequence_checked_object.get(), "A"); - pool()->FlushForTesting(); - - PostDeleteToOtherThread(sequence_checked_object.Pass()); - other_thread()->Stop(); -} - -TEST_F(SequenceCheckerTest, DetachSequenceTokenValid) { - scoped_ptr sequence_checked_object( - new SequenceCheckedObject); - - sequence_checked_object->DetachFromSequence(); - PostDoStuffToWorkerPool(sequence_checked_object.get(), "A"); - PostDoStuffToWorkerPool(sequence_checked_object.get(), "A"); - pool()->FlushForTesting(); - - sequence_checked_object->DetachFromSequence(); - PostDoStuffToWorkerPool(sequence_checked_object.get(), "B"); - PostDoStuffToWorkerPool(sequence_checked_object.get(), "B"); - pool()->FlushForTesting(); - - PostDeleteToOtherThread(sequence_checked_object.Pass()); - other_thread()->Stop(); -} - -#if GTEST_HAS_DEATH_TEST || !ENABLE_SEQUENCE_CHECKER - -void SequenceCheckerTest::MethodOnDifferentThreadDeathTest() { - scoped_ptr sequence_checked_object( - new SequenceCheckedObject); - - // DoStuff should assert in debug builds only when called on a - // different thread. - PostDoStuffToOtherThread(sequence_checked_object.get()); - other_thread()->Stop(); -} - -#if ENABLE_SEQUENCE_CHECKER -TEST_F(SequenceCheckerTest, MethodNotAllowedOnDifferentThreadDeathTestInDebug) { - // The default style "fast" does not support multi-threaded tests. - ::testing::FLAGS_gtest_death_test_style = "threadsafe"; - ASSERT_DEATH({ - MethodOnDifferentThreadDeathTest(); - }, ""); -} -#else -TEST_F(SequenceCheckerTest, MethodAllowedOnDifferentThreadDeathTestInRelease) { - MethodOnDifferentThreadDeathTest(); -} -#endif // ENABLE_SEQUENCE_CHECKER - -void SequenceCheckerTest::DetachThenCallFromDifferentThreadDeathTest() { - scoped_ptr sequence_checked_object( - new SequenceCheckedObject); - - // DoStuff doesn't assert when called on a different thread - // after a call to DetachFromSequence. - sequence_checked_object->DetachFromSequence(); - PostDoStuffToOtherThread(sequence_checked_object.get()); - other_thread()->Stop(); - - // DoStuff should assert in debug builds only after moving to - // another thread. - sequence_checked_object->DoStuff(); -} - -#if ENABLE_SEQUENCE_CHECKER -TEST_F(SequenceCheckerTest, DetachFromSequenceDeathTestInDebug) { - // The default style "fast" does not support multi-threaded tests. - ::testing::FLAGS_gtest_death_test_style = "threadsafe"; - ASSERT_DEATH({ - DetachThenCallFromDifferentThreadDeathTest(); - }, ""); -} -#else -TEST_F(SequenceCheckerTest, DetachFromThreadDeathTestInRelease) { - DetachThenCallFromDifferentThreadDeathTest(); -} -#endif // ENABLE_SEQUENCE_CHECKER - -void SequenceCheckerTest::DifferentSequenceTokensDeathTest() { - scoped_ptr sequence_checked_object( - new SequenceCheckedObject); - - sequence_checked_object->DetachFromSequence(); - PostDoStuffToWorkerPool(sequence_checked_object.get(), "A"); - PostDoStuffToWorkerPool(sequence_checked_object.get(), "A"); - PostDoStuffToWorkerPool(sequence_checked_object.get(), "B"); - PostDoStuffToWorkerPool(sequence_checked_object.get(), "B"); - pool()->FlushForTesting(); - - PostDeleteToOtherThread(sequence_checked_object.Pass()); - other_thread()->Stop(); -} - -#if ENABLE_SEQUENCE_CHECKER -TEST_F(SequenceCheckerTest, DifferentSequenceTokensDeathTestInDebug) { - // The default style "fast" does not support multi-threaded tests. - ::testing::FLAGS_gtest_death_test_style = "threadsafe"; - ASSERT_DEATH({ - DifferentSequenceTokensDeathTest(); - }, ""); -} -#else -TEST_F(SequenceCheckerTest, - DifferentSequenceTokensDeathTestInRelease) { - DifferentSequenceTokensDeathTest(); -} -#endif // ENABLE_SEQUENCE_CHECKER - -void SequenceCheckerTest::WorkerPoolAndSimpleThreadDeathTest() { - scoped_ptr sequence_checked_object( - new SequenceCheckedObject); - - sequence_checked_object->DetachFromSequence(); - PostDoStuffToWorkerPool(sequence_checked_object.get(), "A"); - PostDoStuffToWorkerPool(sequence_checked_object.get(), "A"); - pool()->FlushForTesting(); - - PostDoStuffToOtherThread(sequence_checked_object.get()); - other_thread()->Stop(); -} - -#if ENABLE_SEQUENCE_CHECKER -TEST_F(SequenceCheckerTest, WorkerPoolAndSimpleThreadDeathTestInDebug) { - // The default style "fast" does not support multi-threaded tests. - ::testing::FLAGS_gtest_death_test_style = "threadsafe"; - ASSERT_DEATH({ - WorkerPoolAndSimpleThreadDeathTest(); - }, ""); -} -#else -TEST_F(SequenceCheckerTest, - WorkerPoolAndSimpleThreadDeathTestInRelease) { - WorkerPoolAndSimpleThreadDeathTest(); -} -#endif // ENABLE_SEQUENCE_CHECKER - -void SequenceCheckerTest::TwoDifferentWorkerPoolsDeathTest() { - scoped_ptr sequence_checked_object( - new SequenceCheckedObject); - - sequence_checked_object->DetachFromSequence(); - PostDoStuffToWorkerPool(sequence_checked_object.get(), "A"); - PostDoStuffToWorkerPool(sequence_checked_object.get(), "A"); - pool()->FlushForTesting(); - - SequencedWorkerPoolOwner second_pool_owner(kNumWorkerThreads, "test2"); - second_pool_owner.pool()->PostNamedSequencedWorkerTask( - "A", - FROM_HERE, - base::Bind(&SequenceCheckedObject::DoStuff, - base::Unretained(sequence_checked_object.get()))); - second_pool_owner.pool()->FlushForTesting(); - second_pool_owner.pool()->Shutdown(); -} - -#if ENABLE_SEQUENCE_CHECKER -TEST_F(SequenceCheckerTest, TwoDifferentWorkerPoolsDeathTestInDebug) { - // The default style "fast" does not support multi-threaded tests. - ::testing::FLAGS_gtest_death_test_style = "threadsafe"; - ASSERT_DEATH({ - TwoDifferentWorkerPoolsDeathTest(); - }, ""); -} -#else -TEST_F(SequenceCheckerTest, - TwoDifferentWorkerPoolsDeathTestInRelease) { - TwoDifferentWorkerPoolsDeathTest(); -} -#endif // ENABLE_SEQUENCE_CHECKER - -#endif // GTEST_HAS_DEATH_TEST || !ENABLE_SEQUENCE_CHECKER - -} // namespace - -} // namespace base - -// Just in case we ever get lumped together with other compilation units. -#undef ENABLE_SEQUENCE_CHECKER diff --git a/base/sequenced_task_runner.cc b/base/sequenced_task_runner.cc deleted file mode 100644 index 00d4048815..0000000000 --- a/base/sequenced_task_runner.cc +++ /dev/null @@ -1,31 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "base/sequenced_task_runner.h" - -#include "base/bind.h" - -namespace base { - -bool SequencedTaskRunner::PostNonNestableTask( - const tracked_objects::Location& from_here, - const Closure& task) { - return PostNonNestableDelayedTask(from_here, task, base::TimeDelta()); -} - -bool SequencedTaskRunner::DeleteSoonInternal( - const tracked_objects::Location& from_here, - void(*deleter)(const void*), - const void* object) { - return PostNonNestableTask(from_here, Bind(deleter, object)); -} - -bool SequencedTaskRunner::ReleaseSoonInternal( - const tracked_objects::Location& from_here, - void(*releaser)(const void*), - const void* object) { - return PostNonNestableTask(from_here, Bind(releaser, object)); -} - -} // namespace base diff --git a/base/sequenced_task_runner.h b/base/sequenced_task_runner.h deleted file mode 100644 index f6ca646781..0000000000 --- a/base/sequenced_task_runner.h +++ /dev/null @@ -1,159 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef BASE_SEQUENCED_TASKRUNNER_H_ -#define BASE_SEQUENCED_TASKRUNNER_H_ - -#include "base/base_export.h" -#include "base/sequenced_task_runner_helpers.h" -#include "base/task_runner.h" - -namespace base { - -// A SequencedTaskRunner is a subclass of TaskRunner that provides -// additional guarantees on the order that tasks are started, as well -// as guarantees on when tasks are in sequence, i.e. one task finishes -// before the other one starts. -// -// Summary -// ------- -// Non-nested tasks with the same delay will run one by one in FIFO -// order. -// -// Detailed guarantees -// ------------------- -// -// SequencedTaskRunner also adds additional methods for posting -// non-nestable tasks. In general, an implementation of TaskRunner -// may expose task-running methods which are themselves callable from -// within tasks. A non-nestable task is one that is guaranteed to not -// be run from within an already-running task. Conversely, a nestable -// task (the default) is a task that can be run from within an -// already-running task. -// -// The guarantees of SequencedTaskRunner are as follows: -// -// - Given two tasks T2 and T1, T2 will start after T1 starts if: -// -// * T2 is posted after T1; and -// * T2 has equal or higher delay than T1; and -// * T2 is non-nestable or T1 is nestable. -// -// - If T2 will start after T1 starts by the above guarantee, then -// T2 will start after T1 finishes and is destroyed if: -// -// * T2 is non-nestable, or -// * T1 doesn't call any task-running methods. -// -// - If T2 will start after T1 finishes by the above guarantee, then -// all memory changes in T1 and T1's destruction will be visible -// to T2. -// -// - If T2 runs nested within T1 via a call to the task-running -// method M, then all memory changes in T1 up to the call to M -// will be visible to T2, and all memory changes in T2 will be -// visible to T1 from the return from M. -// -// Note that SequencedTaskRunner does not guarantee that tasks are run -// on a single dedicated thread, although the above guarantees provide -// most (but not all) of the same guarantees. If you do need to -// guarantee that tasks are run on a single dedicated thread, see -// SingleThreadTaskRunner (in single_thread_task_runner.h). -// -// Some corollaries to the above guarantees, assuming the tasks in -// question don't call any task-running methods: -// -// - Tasks posted via PostTask are run in FIFO order. -// -// - Tasks posted via PostNonNestableTask are run in FIFO order. -// -// - Tasks posted with the same delay and the same nestable state -// are run in FIFO order. -// -// - A list of tasks with the same nestable state posted in order of -// non-decreasing delay is run in FIFO order. -// -// - A list of tasks posted in order of non-decreasing delay with at -// most a single change in nestable state from nestable to -// non-nestable is run in FIFO order. (This is equivalent to the -// statement of the first guarantee above.) -// -// Some theoretical implementations of SequencedTaskRunner: -// -// - A SequencedTaskRunner that wraps a regular TaskRunner but makes -// sure that only one task at a time is posted to the TaskRunner, -// with appropriate memory barriers in between tasks. -// -// - A SequencedTaskRunner that, for each task, spawns a joinable -// thread to run that task and immediately quit, and then -// immediately joins that thread. -// -// - A SequencedTaskRunner that stores the list of posted tasks and -// has a method Run() that runs each runnable task in FIFO order -// that can be called from any thread, but only if another -// (non-nested) Run() call isn't already happening. -class BASE_EXPORT SequencedTaskRunner : public TaskRunner { - public: - // The two PostNonNestable*Task methods below are like their - // nestable equivalents in TaskRunner, but they guarantee that the - // posted task will not run nested within an already-running task. - // - // A simple corollary is that posting a task as non-nestable can - // only delay when the task gets run. That is, posting a task as - // non-nestable may not affect when the task gets run, or it could - // make it run later than it normally would, but it won't make it - // run earlier than it normally would. - - // TODO(akalin): Get rid of the boolean return value for the methods - // below. - - bool PostNonNestableTask(const tracked_objects::Location& from_here, - const Closure& task); - - virtual bool PostNonNestableDelayedTask( - const tracked_objects::Location& from_here, - const Closure& task, - base::TimeDelta delay) = 0; - - // Submits a non-nestable task to delete the given object. Returns - // true if the object may be deleted at some point in the future, - // and false if the object definitely will not be deleted. - template - bool DeleteSoon(const tracked_objects::Location& from_here, - const T* object) { - return - subtle::DeleteHelperInternal::DeleteViaSequencedTaskRunner( - this, from_here, object); - } - - // Submits a non-nestable task to release the given object. Returns - // true if the object may be released at some point in the future, - // and false if the object definitely will not be released. - template - bool ReleaseSoon(const tracked_objects::Location& from_here, - T* object) { - return - subtle::ReleaseHelperInternal::ReleaseViaSequencedTaskRunner( - this, from_here, object); - } - - protected: - virtual ~SequencedTaskRunner() {} - - private: - template friend class subtle::DeleteHelperInternal; - template friend class subtle::ReleaseHelperInternal; - - bool DeleteSoonInternal(const tracked_objects::Location& from_here, - void(*deleter)(const void*), - const void* object); - - bool ReleaseSoonInternal(const tracked_objects::Location& from_here, - void(*releaser)(const void*), - const void* object); -}; - -} // namespace base - -#endif // BASE_SEQUENCED_TASKRUNNER_H_ diff --git a/base/sequenced_task_runner_helpers.h b/base/sequenced_task_runner_helpers.h deleted file mode 100644 index 2d0d493290..0000000000 --- a/base/sequenced_task_runner_helpers.h +++ /dev/null @@ -1,112 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef BASE_SEQUENCED_TASK_RUNNER_HELPERS_H_ -#define BASE_SEQUENCED_TASK_RUNNER_HELPERS_H_ - -#include "base/basictypes.h" - -// TODO(akalin): Investigate whether it's possible to just have -// SequencedTaskRunner use these helpers (instead of MessageLoop). -// Then we can just move these to sequenced_task_runner.h. - -namespace tracked_objects { -class Location; -} - -namespace base { - -namespace subtle { -template class DeleteHelperInternal; -template class ReleaseHelperInternal; -} - -// Template helpers which use function indirection to erase T from the -// function signature while still remembering it so we can call the -// correct destructor/release function. -// -// We use this trick so we don't need to include bind.h in a header -// file like sequenced_task_runner.h. We also wrap the helpers in a -// templated class to make it easier for users of DeleteSoon to -// declare the helper as a friend. -template -class DeleteHelper { - private: - template friend class subtle::DeleteHelperInternal; - - static void DoDelete(const void* object) { - delete reinterpret_cast(object); - } - - DISALLOW_COPY_AND_ASSIGN(DeleteHelper); -}; - -template -class ReleaseHelper { - private: - template friend class subtle::ReleaseHelperInternal; - - static void DoRelease(const void* object) { - reinterpret_cast(object)->Release(); - } - - DISALLOW_COPY_AND_ASSIGN(ReleaseHelper); -}; - -namespace subtle { - -// An internal SequencedTaskRunner-like class helper for DeleteHelper -// and ReleaseHelper. We don't want to expose the Do*() functions -// directly directly since the void* argument makes it possible to -// pass/ an object of the wrong type to delete. Instead, we force -// callers to go through these internal helpers for type -// safety. SequencedTaskRunner-like classes which expose DeleteSoon or -// ReleaseSoon methods should friend the appropriate helper and -// implement a corresponding *Internal method with the following -// signature: -// -// bool(const tracked_objects::Location&, -// void(*function)(const void*), -// void* object) -// -// An implementation of this function should simply create a -// base::Closure from (function, object) and return the result of -// posting the task. -template -class DeleteHelperInternal { - public: - template - static ReturnType DeleteViaSequencedTaskRunner( - SequencedTaskRunnerType* sequenced_task_runner, - const tracked_objects::Location& from_here, - const T* object) { - return sequenced_task_runner->DeleteSoonInternal( - from_here, &DeleteHelper::DoDelete, object); - } - - private: - DISALLOW_COPY_AND_ASSIGN(DeleteHelperInternal); -}; - -template -class ReleaseHelperInternal { - public: - template - static ReturnType ReleaseViaSequencedTaskRunner( - SequencedTaskRunnerType* sequenced_task_runner, - const tracked_objects::Location& from_here, - const T* object) { - return sequenced_task_runner->ReleaseSoonInternal( - from_here, &ReleaseHelper::DoRelease, object); - } - - private: - DISALLOW_COPY_AND_ASSIGN(ReleaseHelperInternal); -}; - -} // namespace subtle - -} // namespace base - -#endif // BASE_SEQUENCED_TASK_RUNNER_HELPERS_H_ diff --git a/base/sha1.h b/base/sha1.h deleted file mode 100644 index 998cccba8d..0000000000 --- a/base/sha1.h +++ /dev/null @@ -1,29 +0,0 @@ -// Copyright (c) 2011 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef BASE_SHA1_H_ -#define BASE_SHA1_H_ - -#include - -#include "base/base_export.h" - -namespace base { - -// These functions perform SHA-1 operations. - -static const size_t kSHA1Length = 20; // Length in bytes of a SHA-1 hash. - -// Computes the SHA-1 hash of the input string |str| and returns the full -// hash. -BASE_EXPORT std::string SHA1HashString(const std::string& str); - -// Computes the SHA-1 hash of the |len| bytes in |data| and puts the hash -// in |hash|. |hash| must be kSHA1Length bytes long. -BASE_EXPORT void SHA1HashBytes(const unsigned char* data, size_t len, - unsigned char* hash); - -} // namespace base - -#endif // BASE_SHA1_H_ diff --git a/base/sha1_portable.cc b/base/sha1_portable.cc deleted file mode 100644 index 529fc905b7..0000000000 --- a/base/sha1_portable.cc +++ /dev/null @@ -1,215 +0,0 @@ -// Copyright (c) 2011 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "base/sha1.h" - -#include - -#include "base/basictypes.h" - -namespace base { - -// Implementation of SHA-1. Only handles data in byte-sized blocks, -// which simplifies the code a fair bit. - -// Identifier names follow notation in FIPS PUB 180-3, where you'll -// also find a description of the algorithm: -// http://csrc.nist.gov/publications/fips/fips180-3/fips180-3_final.pdf - -// Usage example: -// -// SecureHashAlgorithm sha; -// while(there is data to hash) -// sha.Update(moredata, size of data); -// sha.Final(); -// memcpy(somewhere, sha.Digest(), 20); -// -// to reuse the instance of sha, call sha.Init(); - -// TODO(jhawkins): Replace this implementation with a per-platform -// implementation using each platform's crypto library. See -// http://crbug.com/47218 - -class SecureHashAlgorithm { - public: - SecureHashAlgorithm() { Init(); } - - static const int kDigestSizeBytes; - - void Init(); - void Update(const void* data, size_t nbytes); - void Final(); - - // 20 bytes of message digest. - const unsigned char* Digest() const { - return reinterpret_cast(H); - } - - private: - void Pad(); - void Process(); - - uint32 A, B, C, D, E; - - uint32 H[5]; - - union { - uint32 W[80]; - uint8 M[64]; - }; - - uint32 cursor; - uint32 l; -}; - -static inline uint32 f(uint32 t, uint32 B, uint32 C, uint32 D) { - if (t < 20) { - return (B & C) | ((~B) & D); - } else if (t < 40) { - return B ^ C ^ D; - } else if (t < 60) { - return (B & C) | (B & D) | (C & D); - } else { - return B ^ C ^ D; - } -} - -static inline uint32 S(uint32 n, uint32 X) { - return (X << n) | (X >> (32-n)); -} - -static inline uint32 K(uint32 t) { - if (t < 20) { - return 0x5a827999; - } else if (t < 40) { - return 0x6ed9eba1; - } else if (t < 60) { - return 0x8f1bbcdc; - } else { - return 0xca62c1d6; - } -} - -static inline void swapends(uint32* t) { - *t = ((*t & 0xff000000) >> 24) | - ((*t & 0xff0000) >> 8) | - ((*t & 0xff00) << 8) | - ((*t & 0xff) << 24); -} - -const int SecureHashAlgorithm::kDigestSizeBytes = 20; - -void SecureHashAlgorithm::Init() { - A = 0; - B = 0; - C = 0; - D = 0; - E = 0; - cursor = 0; - l = 0; - H[0] = 0x67452301; - H[1] = 0xefcdab89; - H[2] = 0x98badcfe; - H[3] = 0x10325476; - H[4] = 0xc3d2e1f0; -} - -void SecureHashAlgorithm::Final() { - Pad(); - Process(); - - for (int t = 0; t < 5; ++t) - swapends(&H[t]); -} - -void SecureHashAlgorithm::Update(const void* data, size_t nbytes) { - const uint8* d = reinterpret_cast(data); - while (nbytes--) { - M[cursor++] = *d++; - if (cursor >= 64) - Process(); - l += 8; - } -} - -void SecureHashAlgorithm::Pad() { - M[cursor++] = 0x80; - - if (cursor > 64-8) { - // pad out to next block - while (cursor < 64) - M[cursor++] = 0; - - Process(); - } - - while (cursor < 64-4) - M[cursor++] = 0; - - M[64-4] = (l & 0xff000000) >> 24; - M[64-3] = (l & 0xff0000) >> 16; - M[64-2] = (l & 0xff00) >> 8; - M[64-1] = (l & 0xff); -} - -void SecureHashAlgorithm::Process() { - uint32 t; - - // Each a...e corresponds to a section in the FIPS 180-3 algorithm. - - // a. - // - // W and M are in a union, so no need to memcpy. - // memcpy(W, M, sizeof(M)); - for (t = 0; t < 16; ++t) - swapends(&W[t]); - - // b. - for (t = 16; t < 80; ++t) - W[t] = S(1, W[t - 3] ^ W[t - 8] ^ W[t - 14] ^ W[t - 16]); - - // c. - A = H[0]; - B = H[1]; - C = H[2]; - D = H[3]; - E = H[4]; - - // d. - for (t = 0; t < 80; ++t) { - uint32 TEMP = S(5, A) + f(t, B, C, D) + E + W[t] + K(t); - E = D; - D = C; - C = S(30, B); - B = A; - A = TEMP; - } - - // e. - H[0] += A; - H[1] += B; - H[2] += C; - H[3] += D; - H[4] += E; - - cursor = 0; -} - -std::string SHA1HashString(const std::string& str) { - char hash[SecureHashAlgorithm::kDigestSizeBytes]; - SHA1HashBytes(reinterpret_cast(str.c_str()), - str.length(), reinterpret_cast(hash)); - return std::string(hash, SecureHashAlgorithm::kDigestSizeBytes); -} - -void SHA1HashBytes(const unsigned char* data, size_t len, - unsigned char* hash) { - SecureHashAlgorithm sha; - sha.Update(data, len); - sha.Final(); - - memcpy(hash, sha.Digest(), SecureHashAlgorithm::kDigestSizeBytes); -} - -} // namespace base diff --git a/base/sha1_unittest.cc b/base/sha1_unittest.cc deleted file mode 100644 index b29fe4662a..0000000000 --- a/base/sha1_unittest.cc +++ /dev/null @@ -1,108 +0,0 @@ -// Copyright (c) 2011 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "base/sha1.h" - -#include - -#include "base/basictypes.h" -#include "testing/gtest/include/gtest/gtest.h" - -TEST(SHA1Test, Test1) { - // Example A.1 from FIPS 180-2: one-block message. - std::string input = "abc"; - - int expected[] = { 0xa9, 0x99, 0x3e, 0x36, - 0x47, 0x06, 0x81, 0x6a, - 0xba, 0x3e, 0x25, 0x71, - 0x78, 0x50, 0xc2, 0x6c, - 0x9c, 0xd0, 0xd8, 0x9d }; - - std::string output = base::SHA1HashString(input); - for (size_t i = 0; i < base::kSHA1Length; i++) - EXPECT_EQ(expected[i], output[i] & 0xFF); -} - -TEST(SHA1Test, Test2) { - // Example A.2 from FIPS 180-2: multi-block message. - std::string input = - "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq"; - - int expected[] = { 0x84, 0x98, 0x3e, 0x44, - 0x1c, 0x3b, 0xd2, 0x6e, - 0xba, 0xae, 0x4a, 0xa1, - 0xf9, 0x51, 0x29, 0xe5, - 0xe5, 0x46, 0x70, 0xf1 }; - - std::string output = base::SHA1HashString(input); - for (size_t i = 0; i < base::kSHA1Length; i++) - EXPECT_EQ(expected[i], output[i] & 0xFF); -} - -TEST(SHA1Test, Test3) { - // Example A.3 from FIPS 180-2: long message. - std::string input(1000000, 'a'); - - int expected[] = { 0x34, 0xaa, 0x97, 0x3c, - 0xd4, 0xc4, 0xda, 0xa4, - 0xf6, 0x1e, 0xeb, 0x2b, - 0xdb, 0xad, 0x27, 0x31, - 0x65, 0x34, 0x01, 0x6f }; - - std::string output = base::SHA1HashString(input); - for (size_t i = 0; i < base::kSHA1Length; i++) - EXPECT_EQ(expected[i], output[i] & 0xFF); -} - -TEST(SHA1Test, Test1Bytes) { - // Example A.1 from FIPS 180-2: one-block message. - std::string input = "abc"; - unsigned char output[base::kSHA1Length]; - - unsigned char expected[] = { 0xa9, 0x99, 0x3e, 0x36, - 0x47, 0x06, 0x81, 0x6a, - 0xba, 0x3e, 0x25, 0x71, - 0x78, 0x50, 0xc2, 0x6c, - 0x9c, 0xd0, 0xd8, 0x9d }; - - base::SHA1HashBytes(reinterpret_cast(input.c_str()), - input.length(), output); - for (size_t i = 0; i < base::kSHA1Length; i++) - EXPECT_EQ(expected[i], output[i]); -} - -TEST(SHA1Test, Test2Bytes) { - // Example A.2 from FIPS 180-2: multi-block message. - std::string input = - "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq"; - unsigned char output[base::kSHA1Length]; - - unsigned char expected[] = { 0x84, 0x98, 0x3e, 0x44, - 0x1c, 0x3b, 0xd2, 0x6e, - 0xba, 0xae, 0x4a, 0xa1, - 0xf9, 0x51, 0x29, 0xe5, - 0xe5, 0x46, 0x70, 0xf1 }; - - base::SHA1HashBytes(reinterpret_cast(input.c_str()), - input.length(), output); - for (size_t i = 0; i < base::kSHA1Length; i++) - EXPECT_EQ(expected[i], output[i]); -} - -TEST(SHA1Test, Test3Bytes) { - // Example A.3 from FIPS 180-2: long message. - std::string input(1000000, 'a'); - unsigned char output[base::kSHA1Length]; - - unsigned char expected[] = { 0x34, 0xaa, 0x97, 0x3c, - 0xd4, 0xc4, 0xda, 0xa4, - 0xf6, 0x1e, 0xeb, 0x2b, - 0xdb, 0xad, 0x27, 0x31, - 0x65, 0x34, 0x01, 0x6f }; - - base::SHA1HashBytes(reinterpret_cast(input.c_str()), - input.length(), output); - for (size_t i = 0; i < base::kSHA1Length; i++) - EXPECT_EQ(expected[i], output[i]); -} diff --git a/base/sha1_win.cc b/base/sha1_win.cc deleted file mode 100644 index 98c3840f0e..0000000000 --- a/base/sha1_win.cc +++ /dev/null @@ -1,67 +0,0 @@ -// Copyright (c) 2011 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "base/sha1.h" - -#include -#include - -// This file is not being compiled at the moment (see bug 47218). If we keep -// sha1 inside base, we cannot depend on src/crypto. -// #include "crypto/scoped_capi_types.h" -#include "base/logging.h" - -namespace base { - -std::string SHA1HashString(const std::string& str) { - ScopedHCRYPTPROV provider; - if (!CryptAcquireContext(provider.receive(), NULL, NULL, PROV_RSA_FULL, - CRYPT_VERIFYCONTEXT)) { - DLOG_GETLASTERROR(ERROR) << "CryptAcquireContext failed"; - return std::string(kSHA1Length, '\0'); - } - - { - ScopedHCRYPTHASH hash; - if (!CryptCreateHash(provider, CALG_SHA1, 0, 0, hash.receive())) { - DLOG_GETLASTERROR(ERROR) << "CryptCreateHash failed"; - return std::string(kSHA1Length, '\0'); - } - - if (!CryptHashData(hash, reinterpret_cast(str.data()), - static_cast(str.length()), 0)) { - DLOG_GETLASTERROR(ERROR) << "CryptHashData failed"; - return std::string(kSHA1Length, '\0'); - } - - DWORD hash_len = 0; - DWORD buffer_size = sizeof hash_len; - if (!CryptGetHashParam(hash, HP_HASHSIZE, - reinterpret_cast(&hash_len), - &buffer_size, 0)) { - DLOG_GETLASTERROR(ERROR) << "CryptGetHashParam(HP_HASHSIZE) failed"; - return std::string(kSHA1Length, '\0'); - } - - std::string result; - if (!CryptGetHashParam(hash, HP_HASHVAL, - // We need the + 1 here not because the call will write a trailing \0, - // but so that result.length() is correctly set to |hash_len|. - reinterpret_cast(WriteInto(&result, hash_len + 1)), &hash_len, - 0))) { - DLOG_GETLASTERROR(ERROR) << "CryptGetHashParam(HP_HASHVAL) failed"; - return std::string(kSHA1Length, '\0'); - } - - if (hash_len != kSHA1Length) { - DLOG(ERROR) << "Returned hash value is wrong length: " << hash_len - << " should be " << kSHA1Length; - return std::string(kSHA1Length, '\0'); - } - - return result; - } -} - -} // namespace base diff --git a/base/single_thread_task_runner.h b/base/single_thread_task_runner.h deleted file mode 100644 index e82941a348..0000000000 --- a/base/single_thread_task_runner.h +++ /dev/null @@ -1,37 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef BASE_SINGLE_THREAD_TASK_RUNNER_H_ -#define BASE_SINGLE_THREAD_TASK_RUNNER_H_ - -#include "base/base_export.h" -#include "base/sequenced_task_runner.h" - -namespace base { - -// A SingleThreadTaskRunner is a SequencedTaskRunner with one more -// guarantee; namely, that all tasks are run on a single dedicated -// thread. Most use cases require only a SequencedTaskRunner, unless -// there is a specific need to run tasks on only a single thread. -// -// SingleThreadTaskRunner implementations might: -// - Post tasks to an existing thread's MessageLoop (see MessageLoopProxy). -// - Create their own worker thread and MessageLoop to post tasks to. -// - Add tasks to a FIFO and signal to a non-MessageLoop thread for them to -// be processed. This allows TaskRunner-oriented code run on threads -// running other kinds of message loop, e.g. Jingle threads. -class BASE_EXPORT SingleThreadTaskRunner : public SequencedTaskRunner { - public: - // A more explicit alias to RunsTasksOnCurrentThread(). - bool BelongsToCurrentThread() const { - return RunsTasksOnCurrentThread(); - } - - protected: - virtual ~SingleThreadTaskRunner() {} -}; - -} // namespace base - -#endif // BASE_SINGLE_THREAD_TASK_RUNNER_H_ diff --git a/base/stl_util.h b/base/stl_util.h deleted file mode 100644 index edd8803f63..0000000000 --- a/base/stl_util.h +++ /dev/null @@ -1,222 +0,0 @@ -// Copyright (c) 2011 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -// Derived from google3/util/gtl/stl_util.h - -#ifndef BASE_STL_UTIL_H_ -#define BASE_STL_UTIL_H_ - -#include -#include -#include -#include - -#include "base/logging.h" - -// Clears internal memory of an STL object. -// STL clear()/reserve(0) does not always free internal memory allocated -// This function uses swap/destructor to ensure the internal memory is freed. -template -void STLClearObject(T* obj) { - T tmp; - tmp.swap(*obj); - // Sometimes "T tmp" allocates objects with memory (arena implementation?). - // Hence using additional reserve(0) even if it doesn't always work. - obj->reserve(0); -} - -// For a range within a container of pointers, calls delete (non-array version) -// on these pointers. -// NOTE: for these three functions, we could just implement a DeleteObject -// functor and then call for_each() on the range and functor, but this -// requires us to pull in all of algorithm.h, which seems expensive. -// For hash_[multi]set, it is important that this deletes behind the iterator -// because the hash_set may call the hash function on the iterator when it is -// advanced, which could result in the hash function trying to deference a -// stale pointer. -template -void STLDeleteContainerPointers(ForwardIterator begin, ForwardIterator end) { - while (begin != end) { - ForwardIterator temp = begin; - ++begin; - delete *temp; - } -} - -// For a range within a container of pairs, calls delete (non-array version) on -// BOTH items in the pairs. -// NOTE: Like STLDeleteContainerPointers, it is important that this deletes -// behind the iterator because if both the key and value are deleted, the -// container may call the hash function on the iterator when it is advanced, -// which could result in the hash function trying to dereference a stale -// pointer. -template -void STLDeleteContainerPairPointers(ForwardIterator begin, - ForwardIterator end) { - while (begin != end) { - ForwardIterator temp = begin; - ++begin; - delete temp->first; - delete temp->second; - } -} - -// For a range within a container of pairs, calls delete (non-array version) on -// the FIRST item in the pairs. -// NOTE: Like STLDeleteContainerPointers, deleting behind the iterator. -template -void STLDeleteContainerPairFirstPointers(ForwardIterator begin, - ForwardIterator end) { - while (begin != end) { - ForwardIterator temp = begin; - ++begin; - delete temp->first; - } -} - -// For a range within a container of pairs, calls delete. -// NOTE: Like STLDeleteContainerPointers, deleting behind the iterator. -// Deleting the value does not always invalidate the iterator, but it may -// do so if the key is a pointer into the value object. -template -void STLDeleteContainerPairSecondPointers(ForwardIterator begin, - ForwardIterator end) { - while (begin != end) { - ForwardIterator temp = begin; - ++begin; - delete temp->second; - } -} - -// To treat a possibly-empty vector as an array, use these functions. -// If you know the array will never be empty, you can use &*v.begin() -// directly, but that is undefined behaviour if |v| is empty. -template -inline T* vector_as_array(std::vector* v) { - return v->empty() ? NULL : &*v->begin(); -} - -template -inline const T* vector_as_array(const std::vector* v) { - return v->empty() ? NULL : &*v->begin(); -} - -// Return a mutable char* pointing to a string's internal buffer, -// which may not be null-terminated. Writing through this pointer will -// modify the string. -// -// string_as_array(&str)[i] is valid for 0 <= i < str.size() until the -// next call to a string method that invalidates iterators. -// -// As of 2006-04, there is no standard-blessed way of getting a -// mutable reference to a string's internal buffer. However, issue 530 -// (http://www.open-std.org/JTC1/SC22/WG21/docs/lwg-active.html#530) -// proposes this as the method. According to Matt Austern, this should -// already work on all current implementations. -inline char* string_as_array(std::string* str) { - // DO NOT USE const_cast(str->data()) - return str->empty() ? NULL : &*str->begin(); -} - -// The following functions are useful for cleaning up STL containers whose -// elements point to allocated memory. - -// STLDeleteElements() deletes all the elements in an STL container and clears -// the container. This function is suitable for use with a vector, set, -// hash_set, or any other STL container which defines sensible begin(), end(), -// and clear() methods. -// -// If container is NULL, this function is a no-op. -// -// As an alternative to calling STLDeleteElements() directly, consider -// STLElementDeleter (defined below), which ensures that your container's -// elements are deleted when the STLElementDeleter goes out of scope. -template -void STLDeleteElements(T* container) { - if (!container) - return; - STLDeleteContainerPointers(container->begin(), container->end()); - container->clear(); -} - -// Given an STL container consisting of (key, value) pairs, STLDeleteValues -// deletes all the "value" components and clears the container. Does nothing -// in the case it's given a NULL pointer. -template -void STLDeleteValues(T* container) { - if (!container) - return; - for (typename T::iterator i(container->begin()); i != container->end(); ++i) - delete i->second; - container->clear(); -} - - -// The following classes provide a convenient way to delete all elements or -// values from STL containers when they goes out of scope. This greatly -// simplifies code that creates temporary objects and has multiple return -// statements. Example: -// -// vector tmp_proto; -// STLElementDeleter > d(&tmp_proto); -// if (...) return false; -// ... -// return success; - -// Given a pointer to an STL container this class will delete all the element -// pointers when it goes out of scope. -template -class STLElementDeleter { - public: - STLElementDeleter(T* container) : container_(container) {} - ~STLElementDeleter() { STLDeleteElements(container_); } - - private: - T* container_; -}; - -// Given a pointer to an STL container this class will delete all the value -// pointers when it goes out of scope. -template -class STLValueDeleter { - public: - STLValueDeleter(T* container) : container_(container) {} - ~STLValueDeleter() { STLDeleteValues(container_); } - - private: - T* container_; -}; - -// Test to see if a set, map, hash_set or hash_map contains a particular key. -// Returns true if the key is in the collection. -template -bool ContainsKey(const Collection& collection, const Key& key) { - return collection.find(key) != collection.end(); -} - -namespace base { - -// Returns true if the container is sorted. -template -bool STLIsSorted(const Container& cont) { - return std::adjacent_find(cont.begin(), cont.end(), - std::greater()) - == cont.end(); -} - -// Returns a new ResultType containing the difference of two sorted containers. -template -ResultType STLSetDifference(const Arg1& a1, const Arg2& a2) { - DCHECK(STLIsSorted(a1)); - DCHECK(STLIsSorted(a2)); - ResultType difference; - std::set_difference(a1.begin(), a1.end(), - a2.begin(), a2.end(), - std::inserter(difference, difference.end())); - return difference; -} - -} // namespace base - -#endif // BASE_STL_UTIL_H_ diff --git a/base/stl_util_unittest.cc b/base/stl_util_unittest.cc deleted file mode 100644 index 63d5c5c1ee..0000000000 --- a/base/stl_util_unittest.cc +++ /dev/null @@ -1,82 +0,0 @@ -// Copyright 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "base/stl_util.h" - -#include - -#include "testing/gtest/include/gtest/gtest.h" - -namespace base { -namespace { - -TEST(STLUtilTest, STLIsSorted) { - { - std::set set; - set.insert(24); - set.insert(1); - set.insert(12); - EXPECT_TRUE(STLIsSorted(set)); - } - - { - std::vector vector; - vector.push_back(1); - vector.push_back(1); - vector.push_back(4); - vector.push_back(64); - vector.push_back(12432); - EXPECT_TRUE(STLIsSorted(vector)); - vector.back() = 1; - EXPECT_FALSE(STLIsSorted(vector)); - } -} - -TEST(STLUtilTest, STLSetDifference) { - std::set a1; - a1.insert(1); - a1.insert(2); - a1.insert(3); - a1.insert(4); - - std::set a2; - a2.insert(3); - a2.insert(4); - a2.insert(5); - a2.insert(6); - a2.insert(7); - - { - std::set difference; - difference.insert(1); - difference.insert(2); - EXPECT_EQ(difference, STLSetDifference >(a1, a2)); - } - - { - std::set difference; - difference.insert(5); - difference.insert(6); - difference.insert(7); - EXPECT_EQ(difference, STLSetDifference >(a2, a1)); - } - - { - std::vector difference; - difference.push_back(1); - difference.push_back(2); - EXPECT_EQ(difference, STLSetDifference >(a1, a2)); - } - - { - std::vector difference; - difference.push_back(5); - difference.push_back(6); - difference.push_back(7); - EXPECT_EQ(difference, STLSetDifference >(a2, a1)); - } -} - -} // namespace -} // namespace base diff --git a/base/strings/latin1_string_conversions.cc b/base/strings/latin1_string_conversions.cc deleted file mode 100644 index dca62ced53..0000000000 --- a/base/strings/latin1_string_conversions.cc +++ /dev/null @@ -1,19 +0,0 @@ -// Copyright 2013 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "base/strings/latin1_string_conversions.h" - -namespace base { - -string16 Latin1OrUTF16ToUTF16(size_t length, - const Latin1Char* latin1, - const char16* utf16) { - if (!length) - return string16(); - if (latin1) - return string16(latin1, latin1 + length); - return string16(utf16, utf16 + length); -} - -} // namespace base diff --git a/base/strings/latin1_string_conversions.h b/base/strings/latin1_string_conversions.h deleted file mode 100644 index 387cb65a52..0000000000 --- a/base/strings/latin1_string_conversions.h +++ /dev/null @@ -1,32 +0,0 @@ -// Copyright 2013 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef BASE_STRINGS_LATIN1_STRING_CONVERSIONS_H_ -#define BASE_STRINGS_LATIN1_STRING_CONVERSIONS_H_ - -#include - -#include "base/base_export.h" -#include "base/strings/string16.h" - -namespace base { - -// This definition of Latin1Char matches the definition of LChar in Blink. We -// use unsigned char rather than char to make less tempting to mix and match -// Latin-1 and UTF-8 characters.. -typedef unsigned char Latin1Char; - -// This somewhat odd function is designed to help us convert from Blink Strings -// to string16. A Blink string is either backed by an array of Latin-1 -// characters or an array of UTF-16 characters. This function is called by -// WebString::operator string16() to convert one or the other character array -// to string16. This function is defined here rather than in WebString.h to -// avoid binary bloat in all the callers of the conversion operator. -BASE_EXPORT string16 Latin1OrUTF16ToUTF16(size_t length, - const Latin1Char* latin1, - const char16* utf16); - -} // namespace base - -#endif // BASE_STRINGS_LATIN1_STRING_CONVERSIONS_H_ diff --git a/base/strings/nullable_string16.cc b/base/strings/nullable_string16.cc deleted file mode 100644 index 07f81d4339..0000000000 --- a/base/strings/nullable_string16.cc +++ /dev/null @@ -1,17 +0,0 @@ -// Copyright (c) 2013 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "base/strings/nullable_string16.h" - -#include - -#include "base/strings/utf_string_conversions.h" - -namespace base { - -std::ostream& operator<<(std::ostream& out, const NullableString16& value) { - return value.is_null() ? out << "(null)" : out << UTF16ToUTF8(value.string()); -} - -} // namespace base diff --git a/base/strings/nullable_string16.h b/base/strings/nullable_string16.h deleted file mode 100644 index 5997d17441..0000000000 --- a/base/strings/nullable_string16.h +++ /dev/null @@ -1,46 +0,0 @@ -// Copyright (c) 2010 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef BASE_STRINGS_NULLABLE_STRING16_H_ -#define BASE_STRINGS_NULLABLE_STRING16_H_ - -#include - -#include "base/base_export.h" -#include "base/strings/string16.h" - -namespace base { - -// This class is a simple wrapper for string16 which also contains a null -// state. This should be used only where the difference between null and -// empty is meaningful. -class NullableString16 { - public: - NullableString16() : is_null_(true) { } - NullableString16(const string16& string, bool is_null) - : string_(string), is_null_(is_null) { - } - - const string16& string() const { return string_; } - bool is_null() const { return is_null_; } - - private: - string16 string_; - bool is_null_; -}; - -inline bool operator==(const NullableString16& a, const NullableString16& b) { - return a.is_null() == b.is_null() && a.string() == b.string(); -} - -inline bool operator!=(const NullableString16& a, const NullableString16& b) { - return !(a == b); -} - -BASE_EXPORT std::ostream& operator<<(std::ostream& out, - const NullableString16& value); - -} // namespace - -#endif // BASE_STRINGS_NULLABLE_STRING16_H_ diff --git a/base/strings/nullable_string16_unittest.cc b/base/strings/nullable_string16_unittest.cc deleted file mode 100644 index f02fdcebfe..0000000000 --- a/base/strings/nullable_string16_unittest.cc +++ /dev/null @@ -1,35 +0,0 @@ -// Copyright 2013 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "base/strings/nullable_string16.h" -#include "base/strings/utf_string_conversions.h" -#include "testing/gtest/include/gtest/gtest.h" - -namespace base { - -TEST(NullableString16Test, DefaultConstructor) { - NullableString16 s; - EXPECT_TRUE(s.is_null()); - EXPECT_EQ(string16(), s.string()); -} - -TEST(NullableString16Test, Equals) { - NullableString16 a(ASCIIToUTF16("hello"), false); - NullableString16 b(ASCIIToUTF16("hello"), false); - EXPECT_EQ(a, b); -} - -TEST(NullableString16Test, NotEquals) { - NullableString16 a(ASCIIToUTF16("hello"), false); - NullableString16 b(ASCIIToUTF16("world"), false); - EXPECT_NE(a, b); -} - -TEST(NullableString16Test, NotEqualsNull) { - NullableString16 a(ASCIIToUTF16("hello"), false); - NullableString16 b; - EXPECT_NE(a, b); -} - -} // namespace base diff --git a/base/strings/string16.cc b/base/strings/string16.cc deleted file mode 100644 index c802eef128..0000000000 --- a/base/strings/string16.cc +++ /dev/null @@ -1,82 +0,0 @@ -// Copyright 2013 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "base/strings/string16.h" - -#if defined(WCHAR_T_IS_UTF16) - -#error This file should not be used on 2-byte wchar_t systems -// If this winds up being needed on 2-byte wchar_t systems, either the -// definitions below can be used, or the host system's wide character -// functions like wmemcmp can be wrapped. - -#elif defined(WCHAR_T_IS_UTF32) - -#include - -#include "base/strings/utf_string_conversions.h" - -namespace base { - -int c16memcmp(const char16* s1, const char16* s2, size_t n) { - // We cannot call memcmp because that changes the semantics. - while (n-- > 0) { - if (*s1 != *s2) { - // We cannot use (*s1 - *s2) because char16 is unsigned. - return ((*s1 < *s2) ? -1 : 1); - } - ++s1; - ++s2; - } - return 0; -} - -size_t c16len(const char16* s) { - const char16 *s_orig = s; - while (*s) { - ++s; - } - return s - s_orig; -} - -const char16* c16memchr(const char16* s, char16 c, size_t n) { - while (n-- > 0) { - if (*s == c) { - return s; - } - ++s; - } - return 0; -} - -char16* c16memmove(char16* s1, const char16* s2, size_t n) { - return static_cast(memmove(s1, s2, n * sizeof(char16))); -} - -char16* c16memcpy(char16* s1, const char16* s2, size_t n) { - return static_cast(memcpy(s1, s2, n * sizeof(char16))); -} - -char16* c16memset(char16* s, char16 c, size_t n) { - char16 *s_orig = s; - while (n-- > 0) { - *s = c; - ++s; - } - return s_orig; -} - -std::ostream& operator<<(std::ostream& out, const string16& str) { - return out << UTF16ToUTF8(str); -} - -void PrintTo(const string16& str, std::ostream* out) { - *out << str; -} - -} // namespace base - -template class std::basic_string; - -#endif // WCHAR_T_IS_UTF32 diff --git a/base/strings/string16.h b/base/strings/string16.h deleted file mode 100644 index fd98f1b5be..0000000000 --- a/base/strings/string16.h +++ /dev/null @@ -1,189 +0,0 @@ -// Copyright 2013 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef BASE_STRINGS_STRING16_H_ -#define BASE_STRINGS_STRING16_H_ - -// WHAT: -// A version of std::basic_string that provides 2-byte characters even when -// wchar_t is not implemented as a 2-byte type. You can access this class as -// string16. We also define char16, which string16 is based upon. -// -// WHY: -// On Windows, wchar_t is 2 bytes, and it can conveniently handle UTF-16/UCS-2 -// data. Plenty of existing code operates on strings encoded as UTF-16. -// -// On many other platforms, sizeof(wchar_t) is 4 bytes by default. We can make -// it 2 bytes by using the GCC flag -fshort-wchar. But then std::wstring fails -// at run time, because it calls some functions (like wcslen) that come from -// the system's native C library -- which was built with a 4-byte wchar_t! -// It's wasteful to use 4-byte wchar_t strings to carry UTF-16 data, and it's -// entirely improper on those systems where the encoding of wchar_t is defined -// as UTF-32. -// -// Here, we define string16, which is similar to std::wstring but replaces all -// libc functions with custom, 2-byte-char compatible routines. It is capable -// of carrying UTF-16-encoded data. - -#include -#include - -#include "base/base_export.h" -#include "base/basictypes.h" - -#if defined(WCHAR_T_IS_UTF16) - -namespace base { - -typedef wchar_t char16; -typedef std::wstring string16; -typedef std::char_traits string16_char_traits; - -} // namespace base - -#elif defined(WCHAR_T_IS_UTF32) - -namespace base { - -typedef uint16 char16; - -// char16 versions of the functions required by string16_char_traits; these -// are based on the wide character functions of similar names ("w" or "wcs" -// instead of "c16"). -BASE_EXPORT int c16memcmp(const char16* s1, const char16* s2, size_t n); -BASE_EXPORT size_t c16len(const char16* s); -BASE_EXPORT const char16* c16memchr(const char16* s, char16 c, size_t n); -BASE_EXPORT char16* c16memmove(char16* s1, const char16* s2, size_t n); -BASE_EXPORT char16* c16memcpy(char16* s1, const char16* s2, size_t n); -BASE_EXPORT char16* c16memset(char16* s, char16 c, size_t n); - -struct string16_char_traits { - typedef char16 char_type; - typedef int int_type; - - // int_type needs to be able to hold each possible value of char_type, and in - // addition, the distinct value of eof(). - COMPILE_ASSERT(sizeof(int_type) > sizeof(char_type), unexpected_type_width); - - typedef std::streamoff off_type; - typedef mbstate_t state_type; - typedef std::fpos pos_type; - - static void assign(char_type& c1, const char_type& c2) { - c1 = c2; - } - - static bool eq(const char_type& c1, const char_type& c2) { - return c1 == c2; - } - static bool lt(const char_type& c1, const char_type& c2) { - return c1 < c2; - } - - static int compare(const char_type* s1, const char_type* s2, size_t n) { - return c16memcmp(s1, s2, n); - } - - static size_t length(const char_type* s) { - return c16len(s); - } - - static const char_type* find(const char_type* s, size_t n, - const char_type& a) { - return c16memchr(s, a, n); - } - - static char_type* move(char_type* s1, const char_type* s2, int_type n) { - return c16memmove(s1, s2, n); - } - - static char_type* copy(char_type* s1, const char_type* s2, size_t n) { - return c16memcpy(s1, s2, n); - } - - static char_type* assign(char_type* s, size_t n, char_type a) { - return c16memset(s, a, n); - } - - static int_type not_eof(const int_type& c) { - return eq_int_type(c, eof()) ? 0 : c; - } - - static char_type to_char_type(const int_type& c) { - return char_type(c); - } - - static int_type to_int_type(const char_type& c) { - return int_type(c); - } - - static bool eq_int_type(const int_type& c1, const int_type& c2) { - return c1 == c2; - } - - static int_type eof() { - return static_cast(EOF); - } -}; - -typedef std::basic_string string16; - -BASE_EXPORT extern std::ostream& operator<<(std::ostream& out, - const string16& str); - -// This is required by googletest to print a readable output on test failures. -BASE_EXPORT extern void PrintTo(const string16& str, std::ostream* out); - -} // namespace base - -// The string class will be explicitly instantiated only once, in string16.cc. -// -// std::basic_string<> in GNU libstdc++ contains a static data member, -// _S_empty_rep_storage, to represent empty strings. When an operation such -// as assignment or destruction is performed on a string, causing its existing -// data member to be invalidated, it must not be freed if this static data -// member is being used. Otherwise, it counts as an attempt to free static -// (and not allocated) data, which is a memory error. -// -// Generally, due to C++ template magic, _S_empty_rep_storage will be marked -// as a coalesced symbol, meaning that the linker will combine multiple -// instances into a single one when generating output. -// -// If a string class is used by multiple shared libraries, a problem occurs. -// Each library will get its own copy of _S_empty_rep_storage. When strings -// are passed across a library boundary for alteration or destruction, memory -// errors will result. GNU libstdc++ contains a configuration option, -// --enable-fully-dynamic-string (_GLIBCXX_FULLY_DYNAMIC_STRING), which -// disables the static data member optimization, but it's a good optimization -// and non-STL code is generally at the mercy of the system's STL -// configuration. Fully-dynamic strings are not the default for GNU libstdc++ -// libstdc++ itself or for the libstdc++ installations on the systems we care -// about, such as Mac OS X and relevant flavors of Linux. -// -// See also http://gcc.gnu.org/bugzilla/show_bug.cgi?id=24196 . -// -// To avoid problems, string classes need to be explicitly instantiated only -// once, in exactly one library. All other string users see it via an "extern" -// declaration. This is precisely how GNU libstdc++ handles -// std::basic_string (string) and std::basic_string (wstring). -// -// This also works around a Mac OS X linker bug in ld64-85.2.1 (Xcode 3.1.2), -// in which the linker does not fully coalesce symbols when dead code -// stripping is enabled. This bug causes the memory errors described above -// to occur even when a std::basic_string<> does not cross shared library -// boundaries, such as in statically-linked executables. -// -// TODO(mark): File this bug with Apple and update this note with a bug number. - -extern template -class BASE_EXPORT std::basic_string; - -#endif // WCHAR_T_IS_UTF32 - -// TODO(brettw) update users of string16 to use the namespace and remove -// this "using". -using base::char16; -using base::string16; - -#endif // BASE_STRINGS_STRING16_H_ diff --git a/base/strings/string16_unittest.cc b/base/strings/string16_unittest.cc deleted file mode 100644 index d98b2a9ec5..0000000000 --- a/base/strings/string16_unittest.cc +++ /dev/null @@ -1,54 +0,0 @@ -// Copyright 2013 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include - -#include "base/strings/string16.h" - -#include "base/strings/utf_string_conversions.h" -#include "testing/gtest/include/gtest/gtest.h" - -#if defined(WCHAR_T_IS_UTF32) - -// We define a custom operator<< for string16 so we can use it with logging. -// This tests that conversion. -TEST(String16Test, OutputStream) { - // Basic stream test. - { - std::ostringstream stream; - stream << "Empty '" << string16() << "' standard '" - << string16(ASCIIToUTF16("Hello, world")) << "'"; - EXPECT_STREQ("Empty '' standard 'Hello, world'", - stream.str().c_str()); - } - - // Interesting edge cases. - { - // These should each get converted to the invalid character: EF BF BD. - string16 initial_surrogate; - initial_surrogate.push_back(0xd800); - string16 final_surrogate; - final_surrogate.push_back(0xdc00); - - // Old italic A = U+10300, will get converted to: F0 90 8C 80 'z'. - string16 surrogate_pair; - surrogate_pair.push_back(0xd800); - surrogate_pair.push_back(0xdf00); - surrogate_pair.push_back('z'); - - // Will get converted to the invalid char + 's': EF BF BD 's'. - string16 unterminated_surrogate; - unterminated_surrogate.push_back(0xd800); - unterminated_surrogate.push_back('s'); - - std::ostringstream stream; - stream << initial_surrogate << "," << final_surrogate << "," - << surrogate_pair << "," << unterminated_surrogate; - - EXPECT_STREQ("\xef\xbf\xbd,\xef\xbf\xbd,\xf0\x90\x8c\x80z,\xef\xbf\xbds", - stream.str().c_str()); - } -} - -#endif diff --git a/base/strings/string_number_conversions.cc b/base/strings/string_number_conversions.cc deleted file mode 100644 index b9412d9313..0000000000 --- a/base/strings/string_number_conversions.cc +++ /dev/null @@ -1,516 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "base/strings/string_number_conversions.h" - -#include -#include -#include -#include - -#include - -#include "base/logging.h" -#include "base/scoped_clear_errno.h" -#include "base/strings/utf_string_conversions.h" -#include "base/third_party/dmg_fp/dmg_fp.h" - -namespace base { - -namespace { - -template -struct IntToStringT { - // This is to avoid a compiler warning about unary minus on unsigned type. - // For example, say you had the following code: - // template - // INT abs(INT value) { return value < 0 ? -value : value; } - // Even though if INT is unsigned, it's impossible for value < 0, so the - // unary minus will never be taken, the compiler will still generate a - // warning. We do a little specialization dance... - template - struct ToUnsignedT {}; - - template - struct ToUnsignedT { - static UINT2 ToUnsigned(INT2 value) { - return static_cast(value); - } - }; - - template - struct ToUnsignedT { - static UINT2 ToUnsigned(INT2 value) { - return static_cast(value < 0 ? -value : value); - } - }; - - // This set of templates is very similar to the above templates, but - // for testing whether an integer is negative. - template - struct TestNegT {}; - template - struct TestNegT { - static bool TestNeg(INT2 value) { - // value is unsigned, and can never be negative. - return false; - } - }; - template - struct TestNegT { - static bool TestNeg(INT2 value) { - return value < 0; - } - }; - - static STR IntToString(INT value) { - // log10(2) ~= 0.3 bytes needed per bit or per byte log10(2**8) ~= 2.4. - // So round up to allocate 3 output characters per byte, plus 1 for '-'. - const int kOutputBufSize = 3 * sizeof(INT) + 1; - - // Allocate the whole string right away, we will right back to front, and - // then return the substr of what we ended up using. - STR outbuf(kOutputBufSize, 0); - - bool is_neg = TestNegT::TestNeg(value); - // Even though is_neg will never be true when INT is parameterized as - // unsigned, even the presence of the unary operation causes a warning. - UINT res = ToUnsignedT::ToUnsigned(value); - - for (typename STR::iterator it = outbuf.end();;) { - --it; - DCHECK(it != outbuf.begin()); - *it = static_cast((res % 10) + '0'); - res /= 10; - - // We're done.. - if (res == 0) { - if (is_neg) { - --it; - DCHECK(it != outbuf.begin()); - *it = static_cast('-'); - } - return STR(it, outbuf.end()); - } - } - NOTREACHED(); - return STR(); - } -}; - -// Utility to convert a character to a digit in a given base -template class BaseCharToDigit { -}; - -// Faster specialization for bases <= 10 -template class BaseCharToDigit { - public: - static bool Convert(CHAR c, uint8* digit) { - if (c >= '0' && c < '0' + BASE) { - *digit = c - '0'; - return true; - } - return false; - } -}; - -// Specialization for bases where 10 < base <= 36 -template class BaseCharToDigit { - public: - static bool Convert(CHAR c, uint8* digit) { - if (c >= '0' && c <= '9') { - *digit = c - '0'; - } else if (c >= 'a' && c < 'a' + BASE - 10) { - *digit = c - 'a' + 10; - } else if (c >= 'A' && c < 'A' + BASE - 10) { - *digit = c - 'A' + 10; - } else { - return false; - } - return true; - } -}; - -template bool CharToDigit(CHAR c, uint8* digit) { - return BaseCharToDigit::Convert(c, digit); -} - -// There is an IsWhitespace for wchars defined in string_util.h, but it is -// locale independent, whereas the functions we are replacing were -// locale-dependent. TBD what is desired, but for the moment let's not introduce -// a change in behaviour. -template class WhitespaceHelper { -}; - -template<> class WhitespaceHelper { - public: - static bool Invoke(char c) { - return 0 != isspace(static_cast(c)); - } -}; - -template<> class WhitespaceHelper { - public: - static bool Invoke(char16 c) { - return 0 != iswspace(c); - } -}; - -template bool LocalIsWhitespace(CHAR c) { - return WhitespaceHelper::Invoke(c); -} - -// IteratorRangeToNumberTraits should provide: -// - a typedef for iterator_type, the iterator type used as input. -// - a typedef for value_type, the target numeric type. -// - static functions min, max (returning the minimum and maximum permitted -// values) -// - constant kBase, the base in which to interpret the input -template -class IteratorRangeToNumber { - public: - typedef IteratorRangeToNumberTraits traits; - typedef typename traits::iterator_type const_iterator; - typedef typename traits::value_type value_type; - - // Generalized iterator-range-to-number conversion. - // - static bool Invoke(const_iterator begin, - const_iterator end, - value_type* output) { - bool valid = true; - - while (begin != end && LocalIsWhitespace(*begin)) { - valid = false; - ++begin; - } - - if (begin != end && *begin == '-') { - if (!std::numeric_limits::is_signed) { - valid = false; - } else if (!Negative::Invoke(begin + 1, end, output)) { - valid = false; - } - } else { - if (begin != end && *begin == '+') { - ++begin; - } - if (!Positive::Invoke(begin, end, output)) { - valid = false; - } - } - - return valid; - } - - private: - // Sign provides: - // - a static function, CheckBounds, that determines whether the next digit - // causes an overflow/underflow - // - a static function, Increment, that appends the next digit appropriately - // according to the sign of the number being parsed. - template - class Base { - public: - static bool Invoke(const_iterator begin, const_iterator end, - typename traits::value_type* output) { - *output = 0; - - if (begin == end) { - return false; - } - - // Note: no performance difference was found when using template - // specialization to remove this check in bases other than 16 - if (traits::kBase == 16 && end - begin > 2 && *begin == '0' && - (*(begin + 1) == 'x' || *(begin + 1) == 'X')) { - begin += 2; - } - - for (const_iterator current = begin; current != end; ++current) { - uint8 new_digit = 0; - - if (!CharToDigit(*current, &new_digit)) { - return false; - } - - if (current != begin) { - if (!Sign::CheckBounds(output, new_digit)) { - return false; - } - *output *= traits::kBase; - } - - Sign::Increment(new_digit, output); - } - return true; - } - }; - - class Positive : public Base { - public: - static bool CheckBounds(value_type* output, uint8 new_digit) { - if (*output > static_cast(traits::max() / traits::kBase) || - (*output == static_cast(traits::max() / traits::kBase) && - new_digit > traits::max() % traits::kBase)) { - *output = traits::max(); - return false; - } - return true; - } - static void Increment(uint8 increment, value_type* output) { - *output += increment; - } - }; - - class Negative : public Base { - public: - static bool CheckBounds(value_type* output, uint8 new_digit) { - if (*output < traits::min() / traits::kBase || - (*output == traits::min() / traits::kBase && - new_digit > 0 - traits::min() % traits::kBase)) { - *output = traits::min(); - return false; - } - return true; - } - static void Increment(uint8 increment, value_type* output) { - *output -= increment; - } - }; -}; - -template -class BaseIteratorRangeToNumberTraits { - public: - typedef ITERATOR iterator_type; - typedef VALUE value_type; - static value_type min() { - return std::numeric_limits::min(); - } - static value_type max() { - return std::numeric_limits::max(); - } - static const int kBase = BASE; -}; - -template -class BaseHexIteratorRangeToIntTraits - : public BaseIteratorRangeToNumberTraits { -}; - -template -class BaseHexIteratorRangeToInt64Traits - : public BaseIteratorRangeToNumberTraits { -}; - -template -class BaseHexIteratorRangeToUInt64Traits - : public BaseIteratorRangeToNumberTraits { -}; - -typedef BaseHexIteratorRangeToIntTraits - HexIteratorRangeToIntTraits; - -typedef BaseHexIteratorRangeToInt64Traits - HexIteratorRangeToInt64Traits; - -typedef BaseHexIteratorRangeToUInt64Traits - HexIteratorRangeToUInt64Traits; - -template -bool HexStringToBytesT(const STR& input, std::vector* output) { - DCHECK_EQ(output->size(), 0u); - size_t count = input.size(); - if (count == 0 || (count % 2) != 0) - return false; - for (uintptr_t i = 0; i < count / 2; ++i) { - uint8 msb = 0; // most significant 4 bits - uint8 lsb = 0; // least significant 4 bits - if (!CharToDigit<16>(input[i * 2], &msb) || - !CharToDigit<16>(input[i * 2 + 1], &lsb)) - return false; - output->push_back((msb << 4) | lsb); - } - return true; -} - -template -class StringPieceToNumberTraits - : public BaseIteratorRangeToNumberTraits { -}; - -template -bool StringToIntImpl(const StringPiece& input, VALUE* output) { - return IteratorRangeToNumber >::Invoke( - input.begin(), input.end(), output); -} - -template -class StringPiece16ToNumberTraits - : public BaseIteratorRangeToNumberTraits { -}; - -template -bool String16ToIntImpl(const StringPiece16& input, VALUE* output) { - return IteratorRangeToNumber >::Invoke( - input.begin(), input.end(), output); -} - -} // namespace - -std::string IntToString(int value) { - return IntToStringT:: - IntToString(value); -} - -string16 IntToString16(int value) { - return IntToStringT:: - IntToString(value); -} - -std::string UintToString(unsigned int value) { - return IntToStringT:: - IntToString(value); -} - -string16 UintToString16(unsigned int value) { - return IntToStringT:: - IntToString(value); -} - -std::string Int64ToString(int64 value) { - return IntToStringT:: - IntToString(value); -} - -string16 Int64ToString16(int64 value) { - return IntToStringT::IntToString(value); -} - -std::string Uint64ToString(uint64 value) { - return IntToStringT:: - IntToString(value); -} - -string16 Uint64ToString16(uint64 value) { - return IntToStringT:: - IntToString(value); -} - -std::string DoubleToString(double value) { - // According to g_fmt.cc, it is sufficient to declare a buffer of size 32. - char buffer[32]; - dmg_fp::g_fmt(buffer, value); - return std::string(buffer); -} - -bool StringToInt(const StringPiece& input, int* output) { - return StringToIntImpl(input, output); -} - -bool StringToInt(const StringPiece16& input, int* output) { - return String16ToIntImpl(input, output); -} - -bool StringToUint(const StringPiece& input, unsigned* output) { - return StringToIntImpl(input, output); -} - -bool StringToUint(const StringPiece16& input, unsigned* output) { - return String16ToIntImpl(input, output); -} - -bool StringToInt64(const StringPiece& input, int64* output) { - return StringToIntImpl(input, output); -} - -bool StringToInt64(const StringPiece16& input, int64* output) { - return String16ToIntImpl(input, output); -} - -bool StringToUint64(const StringPiece& input, uint64* output) { - return StringToIntImpl(input, output); -} - -bool StringToUint64(const StringPiece16& input, uint64* output) { - return String16ToIntImpl(input, output); -} - -bool StringToSizeT(const StringPiece& input, size_t* output) { - return StringToIntImpl(input, output); -} - -bool StringToSizeT(const StringPiece16& input, size_t* output) { - return String16ToIntImpl(input, output); -} - -bool StringToDouble(const std::string& input, double* output) { - // Thread-safe? It is on at least Mac, Linux, and Windows. - ScopedClearErrno clear_errno; - - char* endptr = NULL; - *output = dmg_fp::strtod(input.c_str(), &endptr); - - // Cases to return false: - // - If errno is ERANGE, there was an overflow or underflow. - // - If the input string is empty, there was nothing to parse. - // - If endptr does not point to the end of the string, there are either - // characters remaining in the string after a parsed number, or the string - // does not begin with a parseable number. endptr is compared to the - // expected end given the string's stated length to correctly catch cases - // where the string contains embedded NUL characters. - // - If the first character is a space, there was leading whitespace - return errno == 0 && - !input.empty() && - input.c_str() + input.length() == endptr && - !isspace(input[0]); -} - -// Note: if you need to add String16ToDouble, first ask yourself if it's -// really necessary. If it is, probably the best implementation here is to -// convert to 8-bit and then use the 8-bit version. - -// Note: if you need to add an iterator range version of StringToDouble, first -// ask yourself if it's really necessary. If it is, probably the best -// implementation here is to instantiate a string and use the string version. - -std::string HexEncode(const void* bytes, size_t size) { - static const char kHexChars[] = "0123456789ABCDEF"; - - // Each input byte creates two output hex characters. - std::string ret(size * 2, '\0'); - - for (size_t i = 0; i < size; ++i) { - char b = reinterpret_cast(bytes)[i]; - ret[(i * 2)] = kHexChars[(b >> 4) & 0xf]; - ret[(i * 2) + 1] = kHexChars[b & 0xf]; - } - return ret; -} - -bool HexStringToInt(const StringPiece& input, int* output) { - return IteratorRangeToNumber::Invoke( - input.begin(), input.end(), output); -} - -bool HexStringToInt64(const StringPiece& input, int64* output) { - return IteratorRangeToNumber::Invoke( - input.begin(), input.end(), output); -} - -bool HexStringToUInt64(const StringPiece& input, uint64* output) { - return IteratorRangeToNumber::Invoke( - input.begin(), input.end(), output); -} - -bool HexStringToBytes(const std::string& input, std::vector* output) { - return HexStringToBytesT(input, output); -} - -} // namespace base diff --git a/base/strings/string_number_conversions.h b/base/strings/string_number_conversions.h deleted file mode 100644 index b199bb5f7a..0000000000 --- a/base/strings/string_number_conversions.h +++ /dev/null @@ -1,122 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef BASE_STRINGS_STRING_NUMBER_CONVERSIONS_H_ -#define BASE_STRINGS_STRING_NUMBER_CONVERSIONS_H_ - -#include -#include - -#include "base/base_export.h" -#include "base/basictypes.h" -#include "base/strings/string16.h" -#include "base/strings/string_piece.h" - -// ---------------------------------------------------------------------------- -// IMPORTANT MESSAGE FROM YOUR SPONSOR -// -// This file contains no "wstring" variants. New code should use string16. If -// you need to make old code work, use the UTF8 version and convert. Please do -// not add wstring variants. -// -// Please do not add "convenience" functions for converting strings to integers -// that return the value and ignore success/failure. That encourages people to -// write code that doesn't properly handle the error conditions. -// ---------------------------------------------------------------------------- - -namespace base { - -// Number -> string conversions ------------------------------------------------ - -BASE_EXPORT std::string IntToString(int value); -BASE_EXPORT string16 IntToString16(int value); - -BASE_EXPORT std::string UintToString(unsigned value); -BASE_EXPORT string16 UintToString16(unsigned value); - -BASE_EXPORT std::string Int64ToString(int64 value); -BASE_EXPORT string16 Int64ToString16(int64 value); - -BASE_EXPORT std::string Uint64ToString(uint64 value); -BASE_EXPORT string16 Uint64ToString16(uint64 value); - -// DoubleToString converts the double to a string format that ignores the -// locale. If you want to use locale specific formatting, use ICU. -BASE_EXPORT std::string DoubleToString(double value); - -// String -> number conversions ------------------------------------------------ - -// Perform a best-effort conversion of the input string to a numeric type, -// setting |*output| to the result of the conversion. Returns true for -// "perfect" conversions; returns false in the following cases: -// - Overflow. |*output| will be set to the maximum value supported -// by the data type. -// - Underflow. |*output| will be set to the minimum value supported -// by the data type. -// - Trailing characters in the string after parsing the number. |*output| -// will be set to the value of the number that was parsed. -// - Leading whitespace in the string before parsing the number. |*output| will -// be set to the value of the number that was parsed. -// - No characters parseable as a number at the beginning of the string. -// |*output| will be set to 0. -// - Empty string. |*output| will be set to 0. -BASE_EXPORT bool StringToInt(const StringPiece& input, int* output); -BASE_EXPORT bool StringToInt(const StringPiece16& input, int* output); - -BASE_EXPORT bool StringToUint(const StringPiece& input, unsigned* output); -BASE_EXPORT bool StringToUint(const StringPiece16& input, unsigned* output); - -BASE_EXPORT bool StringToInt64(const StringPiece& input, int64* output); -BASE_EXPORT bool StringToInt64(const StringPiece16& input, int64* output); - -BASE_EXPORT bool StringToUint64(const StringPiece& input, uint64* output); -BASE_EXPORT bool StringToUint64(const StringPiece16& input, uint64* output); - -BASE_EXPORT bool StringToSizeT(const StringPiece& input, size_t* output); -BASE_EXPORT bool StringToSizeT(const StringPiece16& input, size_t* output); - -// For floating-point conversions, only conversions of input strings in decimal -// form are defined to work. Behavior with strings representing floating-point -// numbers in hexadecimal, and strings representing non-fininte values (such as -// NaN and inf) is undefined. Otherwise, these behave the same as the integral -// variants. This expects the input string to NOT be specific to the locale. -// If your input is locale specific, use ICU to read the number. -BASE_EXPORT bool StringToDouble(const std::string& input, double* output); - -// Hex encoding ---------------------------------------------------------------- - -// Returns a hex string representation of a binary buffer. The returned hex -// string will be in upper case. This function does not check if |size| is -// within reasonable limits since it's written with trusted data in mind. If -// you suspect that the data you want to format might be large, the absolute -// max size for |size| should be is -// std::numeric_limits::max() / 2 -BASE_EXPORT std::string HexEncode(const void* bytes, size_t size); - -// Best effort conversion, see StringToInt above for restrictions. -// Will only successful parse hex values that will fit into |output|, i.e. -// -0x80000000 < |input| < 0x7FFFFFFF. -BASE_EXPORT bool HexStringToInt(const StringPiece& input, int* output); - -// Best effort conversion, see StringToInt above for restrictions. -// Will only successful parse hex values that will fit into |output|, i.e. -// -0x8000000000000000 < |input| < 0x7FFFFFFFFFFFFFFF. -BASE_EXPORT bool HexStringToInt64(const StringPiece& input, int64* output); - -// Best effort conversion, see StringToInt above for restrictions. -// Will only successful parse hex values that will fit into |output|, i.e. -// 0x0000000000000000 < |input| < 0xFFFFFFFFFFFFFFFF. -// The string is not required to start with 0x. -BASE_EXPORT bool HexStringToUInt64(const StringPiece& input, uint64* output); - -// Similar to the previous functions, except that output is a vector of bytes. -// |*output| will contain as many bytes as were successfully parsed prior to the -// error. There is no overflow, but input.size() must be evenly divisible by 2. -// Leading 0x or +/- are not allowed. -BASE_EXPORT bool HexStringToBytes(const std::string& input, - std::vector* output); - -} // namespace base - -#endif // BASE_STRINGS_STRING_NUMBER_CONVERSIONS_H_ diff --git a/base/strings/string_number_conversions_unittest.cc b/base/strings/string_number_conversions_unittest.cc deleted file mode 100644 index b8619647de..0000000000 --- a/base/strings/string_number_conversions_unittest.cc +++ /dev/null @@ -1,713 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include -#include -#include - -#include -#include - -#include "base/format_macros.h" -#include "base/strings/string_number_conversions.h" -#include "base/strings/stringprintf.h" -#include "base/strings/utf_string_conversions.h" -#include "testing/gtest/include/gtest/gtest.h" - -namespace base { - -namespace { - -template -struct IntToStringTest { - INT num; - const char* sexpected; - const char* uexpected; -}; - -} // namespace - -TEST(StringNumberConversionsTest, IntToString) { - static const IntToStringTest int_tests[] = { - { 0, "0", "0" }, - { -1, "-1", "4294967295" }, - { std::numeric_limits::max(), "2147483647", "2147483647" }, - { std::numeric_limits::min(), "-2147483648", "2147483648" }, - }; - static const IntToStringTest int64_tests[] = { - { 0, "0", "0" }, - { -1, "-1", "18446744073709551615" }, - { std::numeric_limits::max(), - "9223372036854775807", - "9223372036854775807", }, - { std::numeric_limits::min(), - "-9223372036854775808", - "9223372036854775808" }, - }; - - for (size_t i = 0; i < arraysize(int_tests); ++i) { - const IntToStringTest* test = &int_tests[i]; - EXPECT_EQ(IntToString(test->num), test->sexpected); - EXPECT_EQ(IntToString16(test->num), UTF8ToUTF16(test->sexpected)); - EXPECT_EQ(UintToString(test->num), test->uexpected); - EXPECT_EQ(UintToString16(test->num), UTF8ToUTF16(test->uexpected)); - } - for (size_t i = 0; i < arraysize(int64_tests); ++i) { - const IntToStringTest* test = &int64_tests[i]; - EXPECT_EQ(Int64ToString(test->num), test->sexpected); - EXPECT_EQ(Int64ToString16(test->num), UTF8ToUTF16(test->sexpected)); - EXPECT_EQ(Uint64ToString(test->num), test->uexpected); - EXPECT_EQ(Uint64ToString16(test->num), UTF8ToUTF16(test->uexpected)); - } -} - -TEST(StringNumberConversionsTest, Uint64ToString) { - static const struct { - uint64 input; - std::string output; - } cases[] = { - {0, "0"}, - {42, "42"}, - {INT_MAX, "2147483647"}, - {kuint64max, "18446744073709551615"}, - }; - - for (size_t i = 0; i < ARRAYSIZE_UNSAFE(cases); ++i) - EXPECT_EQ(cases[i].output, Uint64ToString(cases[i].input)); -} - -TEST(StringNumberConversionsTest, StringToInt) { - static const struct { - std::string input; - int output; - bool success; - } cases[] = { - {"0", 0, true}, - {"42", 42, true}, - {"42\x99", 42, false}, - {"\x99" "42\x99", 0, false}, - {"-2147483648", INT_MIN, true}, - {"2147483647", INT_MAX, true}, - {"", 0, false}, - {" 42", 42, false}, - {"42 ", 42, false}, - {"\t\n\v\f\r 42", 42, false}, - {"blah42", 0, false}, - {"42blah", 42, false}, - {"blah42blah", 0, false}, - {"-273.15", -273, false}, - {"+98.6", 98, false}, - {"--123", 0, false}, - {"++123", 0, false}, - {"-+123", 0, false}, - {"+-123", 0, false}, - {"-", 0, false}, - {"-2147483649", INT_MIN, false}, - {"-99999999999", INT_MIN, false}, - {"2147483648", INT_MAX, false}, - {"99999999999", INT_MAX, false}, - }; - - for (size_t i = 0; i < ARRAYSIZE_UNSAFE(cases); ++i) { - int output = 0; - EXPECT_EQ(cases[i].success, StringToInt(cases[i].input, &output)); - EXPECT_EQ(cases[i].output, output); - - string16 utf16_input = UTF8ToUTF16(cases[i].input); - output = 0; - EXPECT_EQ(cases[i].success, StringToInt(utf16_input, &output)); - EXPECT_EQ(cases[i].output, output); - } - - // One additional test to verify that conversion of numbers in strings with - // embedded NUL characters. The NUL and extra data after it should be - // interpreted as junk after the number. - const char input[] = "6\06"; - std::string input_string(input, arraysize(input) - 1); - int output; - EXPECT_FALSE(StringToInt(input_string, &output)); - EXPECT_EQ(6, output); - - string16 utf16_input = UTF8ToUTF16(input_string); - output = 0; - EXPECT_FALSE(StringToInt(utf16_input, &output)); - EXPECT_EQ(6, output); - - output = 0; - const char16 negative_wide_input[] = { 0xFF4D, '4', '2', 0}; - EXPECT_FALSE(StringToInt(string16(negative_wide_input), &output)); - EXPECT_EQ(0, output); -} - -TEST(StringNumberConversionsTest, StringToUint) { - static const struct { - std::string input; - unsigned output; - bool success; - } cases[] = { - {"0", 0, true}, - {"42", 42, true}, - {"42\x99", 42, false}, - {"\x99" "42\x99", 0, false}, - {"-2147483648", 0, false}, - {"2147483647", INT_MAX, true}, - {"", 0, false}, - {" 42", 42, false}, - {"42 ", 42, false}, - {"\t\n\v\f\r 42", 42, false}, - {"blah42", 0, false}, - {"42blah", 42, false}, - {"blah42blah", 0, false}, - {"-273.15", 0, false}, - {"+98.6", 98, false}, - {"--123", 0, false}, - {"++123", 0, false}, - {"-+123", 0, false}, - {"+-123", 0, false}, - {"-", 0, false}, - {"-2147483649", 0, false}, - {"-99999999999", 0, false}, - {"4294967295", UINT_MAX, true}, - {"4294967296", UINT_MAX, false}, - {"99999999999", UINT_MAX, false}, - }; - - for (size_t i = 0; i < ARRAYSIZE_UNSAFE(cases); ++i) { - unsigned output = 0; - EXPECT_EQ(cases[i].success, StringToUint(cases[i].input, &output)); - EXPECT_EQ(cases[i].output, output); - - string16 utf16_input = UTF8ToUTF16(cases[i].input); - output = 0; - EXPECT_EQ(cases[i].success, StringToUint(utf16_input, &output)); - EXPECT_EQ(cases[i].output, output); - } - - // One additional test to verify that conversion of numbers in strings with - // embedded NUL characters. The NUL and extra data after it should be - // interpreted as junk after the number. - const char input[] = "6\06"; - std::string input_string(input, arraysize(input) - 1); - unsigned output; - EXPECT_FALSE(StringToUint(input_string, &output)); - EXPECT_EQ(6U, output); - - string16 utf16_input = UTF8ToUTF16(input_string); - output = 0; - EXPECT_FALSE(StringToUint(utf16_input, &output)); - EXPECT_EQ(6U, output); - - output = 0; - const char16 negative_wide_input[] = { 0xFF4D, '4', '2', 0}; - EXPECT_FALSE(StringToUint(string16(negative_wide_input), &output)); - EXPECT_EQ(0U, output); -} - -TEST(StringNumberConversionsTest, StringToInt64) { - static const struct { - std::string input; - int64 output; - bool success; - } cases[] = { - {"0", 0, true}, - {"42", 42, true}, - {"-2147483648", INT_MIN, true}, - {"2147483647", INT_MAX, true}, - {"-2147483649", GG_INT64_C(-2147483649), true}, - {"-99999999999", GG_INT64_C(-99999999999), true}, - {"2147483648", GG_INT64_C(2147483648), true}, - {"99999999999", GG_INT64_C(99999999999), true}, - {"9223372036854775807", kint64max, true}, - {"-9223372036854775808", kint64min, true}, - {"09", 9, true}, - {"-09", -9, true}, - {"", 0, false}, - {" 42", 42, false}, - {"42 ", 42, false}, - {"0x42", 0, false}, - {"\t\n\v\f\r 42", 42, false}, - {"blah42", 0, false}, - {"42blah", 42, false}, - {"blah42blah", 0, false}, - {"-273.15", -273, false}, - {"+98.6", 98, false}, - {"--123", 0, false}, - {"++123", 0, false}, - {"-+123", 0, false}, - {"+-123", 0, false}, - {"-", 0, false}, - {"-9223372036854775809", kint64min, false}, - {"-99999999999999999999", kint64min, false}, - {"9223372036854775808", kint64max, false}, - {"99999999999999999999", kint64max, false}, - }; - - for (size_t i = 0; i < ARRAYSIZE_UNSAFE(cases); ++i) { - int64 output = 0; - EXPECT_EQ(cases[i].success, StringToInt64(cases[i].input, &output)); - EXPECT_EQ(cases[i].output, output); - - string16 utf16_input = UTF8ToUTF16(cases[i].input); - output = 0; - EXPECT_EQ(cases[i].success, StringToInt64(utf16_input, &output)); - EXPECT_EQ(cases[i].output, output); - } - - // One additional test to verify that conversion of numbers in strings with - // embedded NUL characters. The NUL and extra data after it should be - // interpreted as junk after the number. - const char input[] = "6\06"; - std::string input_string(input, arraysize(input) - 1); - int64 output; - EXPECT_FALSE(StringToInt64(input_string, &output)); - EXPECT_EQ(6, output); - - string16 utf16_input = UTF8ToUTF16(input_string); - output = 0; - EXPECT_FALSE(StringToInt64(utf16_input, &output)); - EXPECT_EQ(6, output); -} - -TEST(StringNumberConversionsTest, StringToUint64) { - static const struct { - std::string input; - uint64 output; - bool success; - } cases[] = { - {"0", 0, true}, - {"42", 42, true}, - {"-2147483648", 0, false}, - {"2147483647", INT_MAX, true}, - {"-2147483649", 0, false}, - {"-99999999999", 0, false}, - {"2147483648", GG_UINT64_C(2147483648), true}, - {"99999999999", GG_UINT64_C(99999999999), true}, - {"9223372036854775807", kint64max, true}, - {"-9223372036854775808", 0, false}, - {"09", 9, true}, - {"-09", 0, false}, - {"", 0, false}, - {" 42", 42, false}, - {"42 ", 42, false}, - {"0x42", 0, false}, - {"\t\n\v\f\r 42", 42, false}, - {"blah42", 0, false}, - {"42blah", 42, false}, - {"blah42blah", 0, false}, - {"-273.15", 0, false}, - {"+98.6", 98, false}, - {"--123", 0, false}, - {"++123", 0, false}, - {"-+123", 0, false}, - {"+-123", 0, false}, - {"-", 0, false}, - {"-9223372036854775809", 0, false}, - {"-99999999999999999999", 0, false}, - {"9223372036854775808", GG_UINT64_C(9223372036854775808), true}, - {"99999999999999999999", kuint64max, false}, - {"18446744073709551615", kuint64max, true}, - {"18446744073709551616", kuint64max, false}, - }; - - for (size_t i = 0; i < ARRAYSIZE_UNSAFE(cases); ++i) { - uint64 output = 0; - EXPECT_EQ(cases[i].success, StringToUint64(cases[i].input, &output)); - EXPECT_EQ(cases[i].output, output); - - string16 utf16_input = UTF8ToUTF16(cases[i].input); - output = 0; - EXPECT_EQ(cases[i].success, StringToUint64(utf16_input, &output)); - EXPECT_EQ(cases[i].output, output); - } - - // One additional test to verify that conversion of numbers in strings with - // embedded NUL characters. The NUL and extra data after it should be - // interpreted as junk after the number. - const char input[] = "6\06"; - std::string input_string(input, arraysize(input) - 1); - uint64 output; - EXPECT_FALSE(StringToUint64(input_string, &output)); - EXPECT_EQ(6U, output); - - string16 utf16_input = UTF8ToUTF16(input_string); - output = 0; - EXPECT_FALSE(StringToUint64(utf16_input, &output)); - EXPECT_EQ(6U, output); -} - -TEST(StringNumberConversionsTest, StringToSizeT) { - - size_t size_t_max = std::numeric_limits::max(); - std::string size_t_max_string = StringPrintf("%" PRIuS, size_t_max); - - static const struct { - std::string input; - size_t output; - bool success; - } cases[] = { - {"0", 0, true}, - {"42", 42, true}, - {"-2147483648", 0, false}, - {"2147483647", INT_MAX, true}, - {"-2147483649", 0, false}, - {"-99999999999", 0, false}, - {"2147483648", 2147483648U, true}, -#if SIZE_MAX > 4294967295U - {"99999999999", 99999999999U, true}, -#endif - {"-9223372036854775808", 0, false}, - {"09", 9, true}, - {"-09", 0, false}, - {"", 0, false}, - {" 42", 42, false}, - {"42 ", 42, false}, - {"0x42", 0, false}, - {"\t\n\v\f\r 42", 42, false}, - {"blah42", 0, false}, - {"42blah", 42, false}, - {"blah42blah", 0, false}, - {"-273.15", 0, false}, - {"+98.6", 98, false}, - {"--123", 0, false}, - {"++123", 0, false}, - {"-+123", 0, false}, - {"+-123", 0, false}, - {"-", 0, false}, - {"-9223372036854775809", 0, false}, - {"-99999999999999999999", 0, false}, - {"999999999999999999999999", size_t_max, false}, - {size_t_max_string, size_t_max, true}, - }; - - for (size_t i = 0; i < ARRAYSIZE_UNSAFE(cases); ++i) { - size_t output = 0; - EXPECT_EQ(cases[i].success, StringToSizeT(cases[i].input, &output)); - EXPECT_EQ(cases[i].output, output); - - string16 utf16_input = UTF8ToUTF16(cases[i].input); - output = 0; - EXPECT_EQ(cases[i].success, StringToSizeT(utf16_input, &output)); - EXPECT_EQ(cases[i].output, output); - } - - // One additional test to verify that conversion of numbers in strings with - // embedded NUL characters. The NUL and extra data after it should be - // interpreted as junk after the number. - const char input[] = "6\06"; - std::string input_string(input, arraysize(input) - 1); - size_t output; - EXPECT_FALSE(StringToSizeT(input_string, &output)); - EXPECT_EQ(6U, output); - - string16 utf16_input = UTF8ToUTF16(input_string); - output = 0; - EXPECT_FALSE(StringToSizeT(utf16_input, &output)); - EXPECT_EQ(6U, output); -} - -TEST(StringNumberConversionsTest, HexStringToInt) { - static const struct { - std::string input; - int64 output; - bool success; - } cases[] = { - {"0", 0, true}, - {"42", 66, true}, - {"-42", -66, true}, - {"+42", 66, true}, - {"7fffffff", INT_MAX, true}, - {"-80000000", INT_MIN, true}, - {"80000000", INT_MAX, false}, // Overflow test. - {"-80000001", INT_MIN, false}, // Underflow test. - {"0x42", 66, true}, - {"-0x42", -66, true}, - {"+0x42", 66, true}, - {"0x7fffffff", INT_MAX, true}, - {"-0x80000000", INT_MIN, true}, - {"-80000000", INT_MIN, true}, - {"80000000", INT_MAX, false}, // Overflow test. - {"-80000001", INT_MIN, false}, // Underflow test. - {"0x0f", 15, true}, - {"0f", 15, true}, - {" 45", 0x45, false}, - {"\t\n\v\f\r 0x45", 0x45, false}, - {" 45", 0x45, false}, - {"45 ", 0x45, false}, - {"45:", 0x45, false}, - {"efgh", 0xef, false}, - {"0xefgh", 0xef, false}, - {"hgfe", 0, false}, - {"-", 0, false}, - {"", 0, false}, - {"0x", 0, false}, - }; - - for (size_t i = 0; i < ARRAYSIZE_UNSAFE(cases); ++i) { - int output = 0; - EXPECT_EQ(cases[i].success, HexStringToInt(cases[i].input, &output)); - EXPECT_EQ(cases[i].output, output); - } - // One additional test to verify that conversion of numbers in strings with - // embedded NUL characters. The NUL and extra data after it should be - // interpreted as junk after the number. - const char input[] = "0xc0ffee\09"; - std::string input_string(input, arraysize(input) - 1); - int output; - EXPECT_FALSE(HexStringToInt(input_string, &output)); - EXPECT_EQ(0xc0ffee, output); -} - -TEST(StringNumberConversionsTest, HexStringToInt64) { - static const struct { - std::string input; - int64 output; - bool success; - } cases[] = { - {"0", 0, true}, - {"42", 66, true}, - {"-42", -66, true}, - {"+42", 66, true}, - {"40acd88557b", GG_INT64_C(4444444448123), true}, - {"7fffffff", INT_MAX, true}, - {"-80000000", INT_MIN, true}, - {"ffffffff", 0xffffffff, true}, - {"DeadBeef", 0xdeadbeef, true}, - {"0x42", 66, true}, - {"-0x42", -66, true}, - {"+0x42", 66, true}, - {"0x40acd88557b", GG_INT64_C(4444444448123), true}, - {"0x7fffffff", INT_MAX, true}, - {"-0x80000000", INT_MIN, true}, - {"0xffffffff", 0xffffffff, true}, - {"0XDeadBeef", 0xdeadbeef, true}, - {"0x7fffffffffffffff", kint64max, true}, - {"-0x8000000000000000", kint64min, true}, - {"0x8000000000000000", kint64max, false}, // Overflow test. - {"-0x8000000000000001", kint64min, false}, // Underflow test. - {"0x0f", 15, true}, - {"0f", 15, true}, - {" 45", 0x45, false}, - {"\t\n\v\f\r 0x45", 0x45, false}, - {" 45", 0x45, false}, - {"45 ", 0x45, false}, - {"45:", 0x45, false}, - {"efgh", 0xef, false}, - {"0xefgh", 0xef, false}, - {"hgfe", 0, false}, - {"-", 0, false}, - {"", 0, false}, - {"0x", 0, false}, - }; - - for (size_t i = 0; i < ARRAYSIZE_UNSAFE(cases); ++i) { - int64 output = 0; - EXPECT_EQ(cases[i].success, HexStringToInt64(cases[i].input, &output)); - EXPECT_EQ(cases[i].output, output); - } - // One additional test to verify that conversion of numbers in strings with - // embedded NUL characters. The NUL and extra data after it should be - // interpreted as junk after the number. - const char input[] = "0xc0ffee\09"; - std::string input_string(input, arraysize(input) - 1); - int64 output; - EXPECT_FALSE(HexStringToInt64(input_string, &output)); - EXPECT_EQ(0xc0ffee, output); -} - -TEST(StringNumberConversionsTest, HexStringToUInt64) { - static const struct { - std::string input; - uint64 output; - bool success; - } cases[] = { - {"0", 0, true}, - {"42", 66, true}, - {"-42", 0, false}, - {"+42", 66, true}, - {"40acd88557b", GG_INT64_C(4444444448123), true}, - {"7fffffff", INT_MAX, true}, - {"-80000000", 0, false}, - {"ffffffff", 0xffffffff, true}, - {"DeadBeef", 0xdeadbeef, true}, - {"0x42", 66, true}, - {"-0x42", 0, false}, - {"+0x42", 66, true}, - {"0x40acd88557b", GG_INT64_C(4444444448123), true}, - {"0x7fffffff", INT_MAX, true}, - {"-0x80000000", 0, false}, - {"0xffffffff", 0xffffffff, true}, - {"0XDeadBeef", 0xdeadbeef, true}, - {"0x7fffffffffffffff", kint64max, true}, - {"-0x8000000000000000", 0, false}, - {"0x8000000000000000", GG_UINT64_C(0x8000000000000000), true}, - {"-0x8000000000000001", 0, false}, - {"0xFFFFFFFFFFFFFFFF", kuint64max, true}, - {"FFFFFFFFFFFFFFFF", kuint64max, true}, - {"0x0000000000000000", 0, true}, - {"0000000000000000", 0, true}, - {"1FFFFFFFFFFFFFFFF", kuint64max, false}, // Overflow test. - {"0x0f", 15, true}, - {"0f", 15, true}, - {" 45", 0x45, false}, - {"\t\n\v\f\r 0x45", 0x45, false}, - {" 45", 0x45, false}, - {"45 ", 0x45, false}, - {"45:", 0x45, false}, - {"efgh", 0xef, false}, - {"0xefgh", 0xef, false}, - {"hgfe", 0, false}, - {"-", 0, false}, - {"", 0, false}, - {"0x", 0, false}, - }; - - for (size_t i = 0; i < ARRAYSIZE_UNSAFE(cases); ++i) { - uint64 output = 0; - EXPECT_EQ(cases[i].success, HexStringToUInt64(cases[i].input, &output)); - EXPECT_EQ(cases[i].output, output); - } - // One additional test to verify that conversion of numbers in strings with - // embedded NUL characters. The NUL and extra data after it should be - // interpreted as junk after the number. - const char input[] = "0xc0ffee\09"; - std::string input_string(input, arraysize(input) - 1); - uint64 output; - EXPECT_FALSE(HexStringToUInt64(input_string, &output)); - EXPECT_EQ(0xc0ffeeU, output); -} - -TEST(StringNumberConversionsTest, HexStringToBytes) { - static const struct { - const std::string input; - const char* output; - size_t output_len; - bool success; - } cases[] = { - {"0", "", 0, false}, // odd number of characters fails - {"00", "\0", 1, true}, - {"42", "\x42", 1, true}, - {"-42", "", 0, false}, // any non-hex value fails - {"+42", "", 0, false}, - {"7fffffff", "\x7f\xff\xff\xff", 4, true}, - {"80000000", "\x80\0\0\0", 4, true}, - {"deadbeef", "\xde\xad\xbe\xef", 4, true}, - {"DeadBeef", "\xde\xad\xbe\xef", 4, true}, - {"0x42", "", 0, false}, // leading 0x fails (x is not hex) - {"0f", "\xf", 1, true}, - {"45 ", "\x45", 1, false}, - {"efgh", "\xef", 1, false}, - {"", "", 0, false}, - {"0123456789ABCDEF", "\x01\x23\x45\x67\x89\xAB\xCD\xEF", 8, true}, - {"0123456789ABCDEF012345", - "\x01\x23\x45\x67\x89\xAB\xCD\xEF\x01\x23\x45", 11, true}, - }; - - - for (size_t i = 0; i < ARRAYSIZE_UNSAFE(cases); ++i) { - std::vector output; - std::vector compare; - EXPECT_EQ(cases[i].success, HexStringToBytes(cases[i].input, &output)) << - i << ": " << cases[i].input; - for (size_t j = 0; j < cases[i].output_len; ++j) - compare.push_back(static_cast(cases[i].output[j])); - ASSERT_EQ(output.size(), compare.size()) << i << ": " << cases[i].input; - EXPECT_TRUE(std::equal(output.begin(), output.end(), compare.begin())) << - i << ": " << cases[i].input; - } -} - -TEST(StringNumberConversionsTest, StringToDouble) { - static const struct { - std::string input; - double output; - bool success; - } cases[] = { - {"0", 0.0, true}, - {"42", 42.0, true}, - {"-42", -42.0, true}, - {"123.45", 123.45, true}, - {"-123.45", -123.45, true}, - {"+123.45", 123.45, true}, - {"2.99792458e8", 299792458.0, true}, - {"149597870.691E+3", 149597870691.0, true}, - {"6.", 6.0, true}, - {"9e99999999999999999999", HUGE_VAL, false}, - {"-9e99999999999999999999", -HUGE_VAL, false}, - {"1e-2", 0.01, true}, - {"42 ", 42.0, false}, - {" 1e-2", 0.01, false}, - {"1e-2 ", 0.01, false}, - {"-1E-7", -0.0000001, true}, - {"01e02", 100, true}, - {"2.3e15", 2.3e15, true}, - {"\t\n\v\f\r -123.45e2", -12345.0, false}, - {"+123 e4", 123.0, false}, - {"123e ", 123.0, false}, - {"123e", 123.0, false}, - {" 2.99", 2.99, false}, - {"1e3.4", 1000.0, false}, - {"nothing", 0.0, false}, - {"-", 0.0, false}, - {"+", 0.0, false}, - {"", 0.0, false}, - }; - - for (size_t i = 0; i < ARRAYSIZE_UNSAFE(cases); ++i) { - double output; - errno = 1; - EXPECT_EQ(cases[i].success, StringToDouble(cases[i].input, &output)); - if (cases[i].success) - EXPECT_EQ(1, errno) << i; // confirm that errno is unchanged. - EXPECT_DOUBLE_EQ(cases[i].output, output); - } - - // One additional test to verify that conversion of numbers in strings with - // embedded NUL characters. The NUL and extra data after it should be - // interpreted as junk after the number. - const char input[] = "3.14\0159"; - std::string input_string(input, arraysize(input) - 1); - double output; - EXPECT_FALSE(StringToDouble(input_string, &output)); - EXPECT_DOUBLE_EQ(3.14, output); -} - -TEST(StringNumberConversionsTest, DoubleToString) { - static const struct { - double input; - const char* expected; - } cases[] = { - {0.0, "0"}, - {1.25, "1.25"}, - {1.33518e+012, "1.33518e+12"}, - {1.33489e+012, "1.33489e+12"}, - {1.33505e+012, "1.33505e+12"}, - {1.33545e+009, "1335450000"}, - {1.33503e+009, "1335030000"}, - }; - - for (size_t i = 0; i < ARRAYSIZE_UNSAFE(cases); ++i) { - EXPECT_EQ(cases[i].expected, DoubleToString(cases[i].input)); - } - - // The following two values were seen in crashes in the wild. - const char input_bytes[8] = {0, 0, 0, 0, '\xee', '\x6d', '\x73', '\x42'}; - double input = 0; - memcpy(&input, input_bytes, arraysize(input_bytes)); - EXPECT_EQ("1335179083776", DoubleToString(input)); - const char input_bytes2[8] = - {0, 0, 0, '\xa0', '\xda', '\x6c', '\x73', '\x42'}; - input = 0; - memcpy(&input, input_bytes2, arraysize(input_bytes2)); - EXPECT_EQ("1334890332160", DoubleToString(input)); -} - -TEST(StringNumberConversionsTest, HexEncode) { - std::string hex(HexEncode(NULL, 0)); - EXPECT_EQ(hex.length(), 0U); - unsigned char bytes[] = {0x01, 0xff, 0x02, 0xfe, 0x03, 0x80, 0x81}; - hex = HexEncode(bytes, sizeof(bytes)); - EXPECT_EQ(hex.compare("01FF02FE038081"), 0); -} - -} // namespace base diff --git a/base/strings/string_piece.cc b/base/strings/string_piece.cc deleted file mode 100644 index 79a42d7842..0000000000 --- a/base/strings/string_piece.cc +++ /dev/null @@ -1,255 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. -// Copied from strings/stringpiece.cc with modifications - -#include "base/strings/string_piece.h" - -#include -#include - -namespace base { - -// MSVC doesn't like complex extern templates and DLLs. -#if !defined(COMPILER_MSVC) -namespace internal { -template class StringPieceDetail; -template class StringPieceDetail; -} // namespace internal - -template class BasicStringPiece; -#endif - -bool operator==(const StringPiece& x, const StringPiece& y) { - if (x.size() != y.size()) - return false; - - return StringPiece::wordmemcmp(x.data(), y.data(), x.size()) == 0; -} - -std::ostream& operator<<(std::ostream& o, const StringPiece& piece) { - o.write(piece.data(), static_cast(piece.size())); - return o; -} - -namespace internal { -void CopyToString(const StringPiece& self, std::string* target) { - target->assign(!self.empty() ? self.data() : "", self.size()); -} - -void AppendToString(const StringPiece& self, std::string* target) { - if (!self.empty()) - target->append(self.data(), self.size()); -} - -StringPiece::size_type copy(const StringPiece& self, - char* buf, - StringPiece::size_type n, - StringPiece::size_type pos) { - StringPiece::size_type ret = std::min(self.size() - pos, n); - memcpy(buf, self.data() + pos, ret); - return ret; -} - -StringPiece::size_type find(const StringPiece& self, - const StringPiece& s, - StringPiece::size_type pos) { - if (pos > self.size()) - return StringPiece::npos; - - StringPiece::const_iterator result = - std::search(self.begin() + pos, self.end(), s.begin(), s.end()); - const StringPiece::size_type xpos = - static_cast(result - self.begin()); - return xpos + s.size() <= self.size() ? xpos : StringPiece::npos; -} - -StringPiece::size_type find(const StringPiece& self, - char c, - StringPiece::size_type pos) { - if (pos >= self.size()) - return StringPiece::npos; - - StringPiece::const_iterator result = - std::find(self.begin() + pos, self.end(), c); - return result != self.end() ? - static_cast(result - self.begin()) : StringPiece::npos; -} - -StringPiece::size_type rfind(const StringPiece& self, - const StringPiece& s, - StringPiece::size_type pos) { - if (self.size() < s.size()) - return StringPiece::npos; - - if (s.empty()) - return std::min(self.size(), pos); - - StringPiece::const_iterator last = - self.begin() + std::min(self.size() - s.size(), pos) + s.size(); - StringPiece::const_iterator result = - std::find_end(self.begin(), last, s.begin(), s.end()); - return result != last ? - static_cast(result - self.begin()) : StringPiece::npos; -} - -StringPiece::size_type rfind(const StringPiece& self, - char c, - StringPiece::size_type pos) { - if (self.size() == 0) - return StringPiece::npos; - - for (StringPiece::size_type i = std::min(pos, self.size() - 1); ; --i) { - if (self.data()[i] == c) - return i; - if (i == 0) - break; - } - return StringPiece::npos; -} - -// For each character in characters_wanted, sets the index corresponding -// to the ASCII code of that character to 1 in table. This is used by -// the find_.*_of methods below to tell whether or not a character is in -// the lookup table in constant time. -// The argument `table' must be an array that is large enough to hold all -// the possible values of an unsigned char. Thus it should be be declared -// as follows: -// bool table[UCHAR_MAX + 1] -static inline void BuildLookupTable(const StringPiece& characters_wanted, - bool* table) { - const StringPiece::size_type length = characters_wanted.length(); - const char* const data = characters_wanted.data(); - for (StringPiece::size_type i = 0; i < length; ++i) { - table[static_cast(data[i])] = true; - } -} - -StringPiece::size_type find_first_of(const StringPiece& self, - const StringPiece& s, - StringPiece::size_type pos) { - if (self.size() == 0 || s.size() == 0) - return StringPiece::npos; - - // Avoid the cost of BuildLookupTable() for a single-character search. - if (s.size() == 1) - return find(self, s.data()[0], pos); - - bool lookup[UCHAR_MAX + 1] = { false }; - BuildLookupTable(s, lookup); - for (StringPiece::size_type i = pos; i < self.size(); ++i) { - if (lookup[static_cast(self.data()[i])]) { - return i; - } - } - return StringPiece::npos; -} - -StringPiece::size_type find_first_not_of(const StringPiece& self, - const StringPiece& s, - StringPiece::size_type pos) { - if (self.size() == 0) - return StringPiece::npos; - - if (s.size() == 0) - return 0; - - // Avoid the cost of BuildLookupTable() for a single-character search. - if (s.size() == 1) - return find_first_not_of(self, s.data()[0], pos); - - bool lookup[UCHAR_MAX + 1] = { false }; - BuildLookupTable(s, lookup); - for (StringPiece::size_type i = pos; i < self.size(); ++i) { - if (!lookup[static_cast(self.data()[i])]) { - return i; - } - } - return StringPiece::npos; -} - -StringPiece::size_type find_first_not_of(const StringPiece& self, - char c, - StringPiece::size_type pos) { - if (self.size() == 0) - return StringPiece::npos; - - for (; pos < self.size(); ++pos) { - if (self.data()[pos] != c) { - return pos; - } - } - return StringPiece::npos; -} - -StringPiece::size_type find_last_of(const StringPiece& self, - const StringPiece& s, - StringPiece::size_type pos) { - if (self.size() == 0 || s.size() == 0) - return StringPiece::npos; - - // Avoid the cost of BuildLookupTable() for a single-character search. - if (s.size() == 1) - return rfind(self, s.data()[0], pos); - - bool lookup[UCHAR_MAX + 1] = { false }; - BuildLookupTable(s, lookup); - for (StringPiece::size_type i = std::min(pos, self.size() - 1); ; --i) { - if (lookup[static_cast(self.data()[i])]) - return i; - if (i == 0) - break; - } - return StringPiece::npos; -} - -StringPiece::size_type find_last_not_of(const StringPiece& self, - const StringPiece& s, - StringPiece::size_type pos) { - if (self.size() == 0) - return StringPiece::npos; - - StringPiece::size_type i = std::min(pos, self.size() - 1); - if (s.size() == 0) - return i; - - // Avoid the cost of BuildLookupTable() for a single-character search. - if (s.size() == 1) - return find_last_not_of(self, s.data()[0], pos); - - bool lookup[UCHAR_MAX + 1] = { false }; - BuildLookupTable(s, lookup); - for (; ; --i) { - if (!lookup[static_cast(self.data()[i])]) - return i; - if (i == 0) - break; - } - return StringPiece::npos; -} - -StringPiece::size_type find_last_not_of(const StringPiece& self, - char c, - StringPiece::size_type pos) { - if (self.size() == 0) - return StringPiece::npos; - - for (StringPiece::size_type i = std::min(pos, self.size() - 1); ; --i) { - if (self.data()[i] != c) - return i; - if (i == 0) - break; - } - return StringPiece::npos; -} - -StringPiece substr(const StringPiece& self, - StringPiece::size_type pos, - StringPiece::size_type n) { - if (pos > self.size()) pos = self.size(); - if (n > self.size() - pos) n = self.size() - pos; - return StringPiece(self.data() + pos, n); -} - -} // namespace internal -} // namespace base diff --git a/base/strings/string_piece.h b/base/strings/string_piece.h deleted file mode 100644 index 818d6ca598..0000000000 --- a/base/strings/string_piece.h +++ /dev/null @@ -1,451 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. -// Copied from strings/stringpiece.h with modifications -// -// A string-like object that points to a sized piece of memory. -// -// Functions or methods may use const StringPiece& parameters to accept either -// a "const char*" or a "string" value that will be implicitly converted to -// a StringPiece. The implicit conversion means that it is often appropriate -// to include this .h file in other files rather than forward-declaring -// StringPiece as would be appropriate for most other Google classes. -// -// Systematic usage of StringPiece is encouraged as it will reduce unnecessary -// conversions from "const char*" to "string" and back again. -// -// StringPiece16 is similar to StringPiece but for base::string16 instead of -// std::string. We do not define as large of a subset of the STL functions -// from basic_string as in StringPiece, but this can be changed if these -// functions (find, find_first_of, etc.) are found to be useful in this context. -// - -#ifndef BASE_STRINGS_STRING_PIECE_H_ -#define BASE_STRINGS_STRING_PIECE_H_ - -#include - -#include -#include - -#include "base/base_export.h" -#include "base/basictypes.h" -#include "base/containers/hash_tables.h" -#include "base/strings/string16.h" - -namespace base { - -template class BasicStringPiece; -typedef BasicStringPiece StringPiece; -typedef BasicStringPiece StringPiece16; - -namespace internal { - -// Defines the types, methods, operators, and data members common to both -// StringPiece and StringPiece16. Do not refer to this class directly, but -// rather to BasicStringPiece, StringPiece, or StringPiece16. -template class StringPieceDetail { - public: - // standard STL container boilerplate - typedef size_t size_type; - typedef typename STRING_TYPE::value_type value_type; - typedef const value_type* pointer; - typedef const value_type& reference; - typedef const value_type& const_reference; - typedef ptrdiff_t difference_type; - typedef const value_type* const_iterator; - typedef std::reverse_iterator const_reverse_iterator; - - static const size_type npos; - - public: - // We provide non-explicit singleton constructors so users can pass - // in a "const char*" or a "string" wherever a "StringPiece" is - // expected (likewise for char16, string16, StringPiece16). - StringPieceDetail() : ptr_(NULL), length_(0) {} - StringPieceDetail(const value_type* str) - : ptr_(str), - length_((str == NULL) ? 0 : STRING_TYPE::traits_type::length(str)) {} - StringPieceDetail(const STRING_TYPE& str) - : ptr_(str.data()), length_(str.size()) {} - StringPieceDetail(const value_type* offset, size_type len) - : ptr_(offset), length_(len) {} - StringPieceDetail(const typename STRING_TYPE::const_iterator& begin, - const typename STRING_TYPE::const_iterator& end) - : ptr_((end > begin) ? &(*begin) : NULL), - length_((end > begin) ? (size_type)(end - begin) : 0) {} - - // data() may return a pointer to a buffer with embedded NULs, and the - // returned buffer may or may not be null terminated. Therefore it is - // typically a mistake to pass data() to a routine that expects a NUL - // terminated string. - const value_type* data() const { return ptr_; } - size_type size() const { return length_; } - size_type length() const { return length_; } - bool empty() const { return length_ == 0; } - - void clear() { - ptr_ = NULL; - length_ = 0; - } - void set(const value_type* data, size_type len) { - ptr_ = data; - length_ = len; - } - void set(const value_type* str) { - ptr_ = str; - length_ = str ? STRING_TYPE::traits_type::length(str) : 0; - } - - value_type operator[](size_type i) const { return ptr_[i]; } - - void remove_prefix(size_type n) { - ptr_ += n; - length_ -= n; - } - - void remove_suffix(size_type n) { - length_ -= n; - } - - int compare(const BasicStringPiece& x) const { - int r = wordmemcmp( - ptr_, x.ptr_, (length_ < x.length_ ? length_ : x.length_)); - if (r == 0) { - if (length_ < x.length_) r = -1; - else if (length_ > x.length_) r = +1; - } - return r; - } - - STRING_TYPE as_string() const { - // std::string doesn't like to take a NULL pointer even with a 0 size. - return empty() ? STRING_TYPE() : STRING_TYPE(data(), size()); - } - - const_iterator begin() const { return ptr_; } - const_iterator end() const { return ptr_ + length_; } - const_reverse_iterator rbegin() const { - return const_reverse_iterator(ptr_ + length_); - } - const_reverse_iterator rend() const { - return const_reverse_iterator(ptr_); - } - - size_type max_size() const { return length_; } - size_type capacity() const { return length_; } - - static int wordmemcmp(const value_type* p, - const value_type* p2, - size_type N) { - return STRING_TYPE::traits_type::compare(p, p2, N); - } - - protected: - const value_type* ptr_; - size_type length_; -}; - -template -const typename StringPieceDetail::size_type -StringPieceDetail::npos = - typename StringPieceDetail::size_type(-1); - -// MSVC doesn't like complex extern templates and DLLs. -#if !defined(COMPILER_MSVC) -extern template class BASE_EXPORT StringPieceDetail; -extern template class BASE_EXPORT StringPieceDetail; -#endif - -BASE_EXPORT void CopyToString(const StringPiece& self, std::string* target); -BASE_EXPORT void AppendToString(const StringPiece& self, std::string* target); -BASE_EXPORT StringPieceDetail::size_type copy( - const StringPiece& self, - char* buf, - StringPieceDetail::size_type n, - StringPieceDetail::size_type pos); -BASE_EXPORT StringPieceDetail::size_type find( - const StringPiece& self, - const StringPiece& s, - StringPieceDetail::size_type pos); -BASE_EXPORT StringPieceDetail::size_type find( - const StringPiece& self, - char c, - StringPieceDetail::size_type pos); -BASE_EXPORT StringPieceDetail::size_type rfind( - const StringPiece& self, - const StringPiece& s, - StringPieceDetail::size_type pos); -BASE_EXPORT StringPieceDetail::size_type rfind( - const StringPiece& self, - char c, - StringPieceDetail::size_type pos); -BASE_EXPORT StringPieceDetail::size_type find_first_of( - const StringPiece& self, - const StringPiece& s, - StringPieceDetail::size_type pos); -BASE_EXPORT StringPieceDetail::size_type find_first_not_of( - const StringPiece& self, - const StringPiece& s, - StringPieceDetail::size_type pos); -BASE_EXPORT StringPieceDetail::size_type find_first_not_of( - const StringPiece& self, - char c, - StringPieceDetail::size_type pos); -BASE_EXPORT StringPieceDetail::size_type find_last_of( - const StringPiece& self, - const StringPiece& s, - StringPieceDetail::size_type pos); -BASE_EXPORT StringPieceDetail::size_type find_last_of( - const StringPiece& self, - char c, - StringPieceDetail::size_type pos); -BASE_EXPORT StringPieceDetail::size_type find_last_not_of( - const StringPiece& self, - const StringPiece& s, - StringPieceDetail::size_type pos); -BASE_EXPORT StringPieceDetail::size_type find_last_not_of( - const StringPiece& self, - char c, - StringPieceDetail::size_type pos); -BASE_EXPORT StringPiece substr(const StringPiece& self, - StringPieceDetail::size_type pos, - StringPieceDetail::size_type n); -} // namespace internal - -// Defines the template type that is instantiated as either StringPiece or -// StringPiece16. -template class BasicStringPiece : - public internal::StringPieceDetail { - public: - typedef typename internal::StringPieceDetail::value_type - value_type; - typedef typename internal::StringPieceDetail::size_type - size_type; - - BasicStringPiece() {} - BasicStringPiece(const value_type*str) - : internal::StringPieceDetail(str) {} - BasicStringPiece(const STRING_TYPE& str) - : internal::StringPieceDetail(str) {} - BasicStringPiece(const value_type* offset, size_type len) - : internal::StringPieceDetail(offset, len) {} - BasicStringPiece(const typename STRING_TYPE::const_iterator& begin, - const typename STRING_TYPE::const_iterator& end) - : internal::StringPieceDetail(begin, end) {} -}; - -// Specializes BasicStringPiece for std::string to add a few operations that -// are not needed for string16. -template <> class BasicStringPiece : - public internal::StringPieceDetail { - public: - BasicStringPiece() {} - BasicStringPiece(const char* str) - : internal::StringPieceDetail(str) {} - BasicStringPiece(const std::string& str) - : internal::StringPieceDetail(str) {} - BasicStringPiece(const char* offset, size_type len) - : internal::StringPieceDetail(offset, len) {} - BasicStringPiece(const std::string::const_iterator& begin, - const std::string::const_iterator& end) - : internal::StringPieceDetail(begin, end) {} - - // Prevent the following overload of set() from hiding the definitions in the - // base class. - using internal::StringPieceDetail::set; - - void set(const void* data, size_type len) { - ptr_ = reinterpret_cast(data); - length_ = len; - } - - void CopyToString(std::string* target) const { - internal::CopyToString(*this, target); - } - - void AppendToString(std::string* target) const { - internal::AppendToString(*this, target); - } - - // Does "this" start with "x" - bool starts_with(const BasicStringPiece& x) const { - return ((length_ >= x.length_) && - (wordmemcmp(ptr_, x.ptr_, x.length_) == 0)); - } - - // Does "this" end with "x" - bool ends_with(const BasicStringPiece& x) const { - return ((length_ >= x.length_) && - (wordmemcmp(ptr_ + (length_-x.length_), x.ptr_, x.length_) == 0)); - } - - size_type copy(char* buf, size_type n, size_type pos = 0) const { - return internal::copy(*this, buf, n, pos); - } - - size_type find(const BasicStringPiece& s, size_type pos = 0) const { - return internal::find(*this, s, pos); - } - - size_type find(char c, size_type pos = 0) const { - return internal::find(*this, c, pos); - } - - size_type rfind(const BasicStringPiece& s, size_type pos = npos) const { - return internal::rfind(*this, s, pos); - } - - size_type rfind(char c, size_type pos = npos) const { - return internal::rfind(*this, c, pos); - } - - size_type find_first_of(const BasicStringPiece& s, size_type pos = 0) const { - return internal::find_first_of(*this, s, pos); - } - - size_type find_first_of(char c, size_type pos = 0) const { - return find(c, pos); - } - - size_type find_first_not_of(const BasicStringPiece& s, - size_type pos = 0) const { - return internal::find_first_not_of(*this, s, pos); - } - - size_type find_first_not_of(char c, size_type pos = 0) const { - return internal::find_first_not_of(*this, c, pos); - } - - size_type find_last_of(const BasicStringPiece& s, - size_type pos = npos) const { - return internal::find_last_of(*this, s, pos); - } - - size_type find_last_of(char c, size_type pos = npos) const { - return rfind(c, pos); - } - - size_type find_last_not_of(const BasicStringPiece& s, - size_type pos = npos) const { - return internal::find_last_not_of(*this, s, pos); - } - - size_type find_last_not_of(char c, size_type pos = npos) const { - return internal::find_last_not_of(*this, c, pos); - } - - BasicStringPiece substr(size_type pos, size_type n = npos) const { - return internal::substr(*this, pos, n); - } -}; - -// MSVC doesn't like complex extern templates and DLLs. -#if !defined(COMPILER_MSVC) -// We can't explicitly declare the std::string instantiation here because it was -// already instantiated when specialized, above. Not only is it a no-op, but -// currently it also crashes Clang (see http://crbug.com/107412). -extern template class BASE_EXPORT BasicStringPiece; -#endif - -BASE_EXPORT bool operator==(const StringPiece& x, const StringPiece& y); - -inline bool operator!=(const StringPiece& x, const StringPiece& y) { - return !(x == y); -} - -inline bool operator<(const StringPiece& x, const StringPiece& y) { - const int r = StringPiece::wordmemcmp( - x.data(), y.data(), (x.size() < y.size() ? x.size() : y.size())); - return ((r < 0) || ((r == 0) && (x.size() < y.size()))); -} - -inline bool operator>(const StringPiece& x, const StringPiece& y) { - return y < x; -} - -inline bool operator<=(const StringPiece& x, const StringPiece& y) { - return !(x > y); -} - -inline bool operator>=(const StringPiece& x, const StringPiece& y) { - return !(x < y); -} - -inline bool operator==(const StringPiece16& x, const StringPiece16& y) { - if (x.size() != y.size()) - return false; - - return StringPiece16::wordmemcmp(x.data(), y.data(), x.size()) == 0; -} - -inline bool operator!=(const StringPiece16& x, const StringPiece16& y) { - return !(x == y); -} - -inline bool operator<(const StringPiece16& x, const StringPiece16& y) { - const int r = StringPiece16::wordmemcmp( - x.data(), y.data(), (x.size() < y.size() ? x.size() : y.size())); - return ((r < 0) || ((r == 0) && (x.size() < y.size()))); -} - -inline bool operator>(const StringPiece16& x, const StringPiece16& y) { - return y < x; -} - -inline bool operator<=(const StringPiece16& x, const StringPiece16& y) { - return !(x > y); -} - -inline bool operator>=(const StringPiece16& x, const StringPiece16& y) { - return !(x < y); -} - -BASE_EXPORT std::ostream& operator<<(std::ostream& o, - const StringPiece& piece); - -} // namespace base - -// We provide appropriate hash functions so StringPiece and StringPiece16 can -// be used as keys in hash sets and maps. - -// This hash function is copied from base/containers/hash_tables.h. We don't -// use the ones already defined for string and string16 directly because it -// would require the string constructors to be called, which we don't want. -#define HASH_STRING_PIECE(StringPieceType, string_piece) \ - std::size_t result = 0; \ - for (StringPieceType::const_iterator i = string_piece.begin(); \ - i != string_piece.end(); ++i) \ - result = (result * 131) + *i; \ - return result; \ - -namespace BASE_HASH_NAMESPACE { -#if defined(COMPILER_GCC) - -template<> -struct hash { - std::size_t operator()(const base::StringPiece& sp) const { - HASH_STRING_PIECE(base::StringPiece, sp); - } -}; -template<> -struct hash { - std::size_t operator()(const base::StringPiece16& sp16) const { - HASH_STRING_PIECE(base::StringPiece16, sp16); - } -}; - -#elif defined(COMPILER_MSVC) - -inline size_t hash_value(const base::StringPiece& sp) { - HASH_STRING_PIECE(base::StringPiece, sp); -} -inline size_t hash_value(const base::StringPiece16& sp16) { - HASH_STRING_PIECE(base::StringPiece16, sp16); -} - -#endif // COMPILER - -} // namespace BASE_HASH_NAMESPACE - -#endif // BASE_STRINGS_STRING_PIECE_H_ diff --git a/base/strings/string_piece_unittest.cc b/base/strings/string_piece_unittest.cc deleted file mode 100644 index 84ed9efca8..0000000000 --- a/base/strings/string_piece_unittest.cc +++ /dev/null @@ -1,677 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include - -#include "base/strings/string16.h" -#include "base/strings/string_piece.h" -#include "base/strings/utf_string_conversions.h" -#include "testing/gtest/include/gtest/gtest.h" - -namespace base { - -template -class CommonStringPieceTest : public ::testing::Test { - public: - static const T as_string(const char* input) { - return T(input); - } - static const T& as_string(const T& input) { - return input; - } -}; - -template <> -class CommonStringPieceTest : public ::testing::Test { - public: - static const string16 as_string(const char* input) { - return ASCIIToUTF16(input); - } - static const string16 as_string(const std::string& input) { - return ASCIIToUTF16(input); - } -}; - -typedef ::testing::Types SupportedStringTypes; - -TYPED_TEST_CASE(CommonStringPieceTest, SupportedStringTypes); - -TYPED_TEST(CommonStringPieceTest, CheckComparisonOperators) { -#define CMP_Y(op, x, y) \ - { \ - TypeParam lhs(TestFixture::as_string(x)); \ - TypeParam rhs(TestFixture::as_string(y)); \ - ASSERT_TRUE( (BasicStringPiece((lhs.c_str())) op \ - BasicStringPiece((rhs.c_str())))); \ - ASSERT_TRUE( (BasicStringPiece((lhs.c_str())).compare( \ - BasicStringPiece((rhs.c_str()))) op 0)); \ - } - -#define CMP_N(op, x, y) \ - { \ - TypeParam lhs(TestFixture::as_string(x)); \ - TypeParam rhs(TestFixture::as_string(y)); \ - ASSERT_FALSE( (BasicStringPiece((lhs.c_str())) op \ - BasicStringPiece((rhs.c_str())))); \ - ASSERT_FALSE( (BasicStringPiece((lhs.c_str())).compare( \ - BasicStringPiece((rhs.c_str()))) op 0)); \ - } - - CMP_Y(==, "", ""); - CMP_Y(==, "a", "a"); - CMP_Y(==, "aa", "aa"); - CMP_N(==, "a", ""); - CMP_N(==, "", "a"); - CMP_N(==, "a", "b"); - CMP_N(==, "a", "aa"); - CMP_N(==, "aa", "a"); - - CMP_N(!=, "", ""); - CMP_N(!=, "a", "a"); - CMP_N(!=, "aa", "aa"); - CMP_Y(!=, "a", ""); - CMP_Y(!=, "", "a"); - CMP_Y(!=, "a", "b"); - CMP_Y(!=, "a", "aa"); - CMP_Y(!=, "aa", "a"); - - CMP_Y(<, "a", "b"); - CMP_Y(<, "a", "aa"); - CMP_Y(<, "aa", "b"); - CMP_Y(<, "aa", "bb"); - CMP_N(<, "a", "a"); - CMP_N(<, "b", "a"); - CMP_N(<, "aa", "a"); - CMP_N(<, "b", "aa"); - CMP_N(<, "bb", "aa"); - - CMP_Y(<=, "a", "a"); - CMP_Y(<=, "a", "b"); - CMP_Y(<=, "a", "aa"); - CMP_Y(<=, "aa", "b"); - CMP_Y(<=, "aa", "bb"); - CMP_N(<=, "b", "a"); - CMP_N(<=, "aa", "a"); - CMP_N(<=, "b", "aa"); - CMP_N(<=, "bb", "aa"); - - CMP_N(>=, "a", "b"); - CMP_N(>=, "a", "aa"); - CMP_N(>=, "aa", "b"); - CMP_N(>=, "aa", "bb"); - CMP_Y(>=, "a", "a"); - CMP_Y(>=, "b", "a"); - CMP_Y(>=, "aa", "a"); - CMP_Y(>=, "b", "aa"); - CMP_Y(>=, "bb", "aa"); - - CMP_N(>, "a", "a"); - CMP_N(>, "a", "b"); - CMP_N(>, "a", "aa"); - CMP_N(>, "aa", "b"); - CMP_N(>, "aa", "bb"); - CMP_Y(>, "b", "a"); - CMP_Y(>, "aa", "a"); - CMP_Y(>, "b", "aa"); - CMP_Y(>, "bb", "aa"); - - std::string x; - for (int i = 0; i < 256; i++) { - x += 'a'; - std::string y = x; - CMP_Y(==, x, y); - for (int j = 0; j < i; j++) { - std::string z = x; - z[j] = 'b'; // Differs in position 'j' - CMP_N(==, x, z); - } - } - -#undef CMP_Y -#undef CMP_N -} - -TYPED_TEST(CommonStringPieceTest, CheckSTL) { - TypeParam alphabet(TestFixture::as_string("abcdefghijklmnopqrstuvwxyz")); - TypeParam abc(TestFixture::as_string("abc")); - TypeParam xyz(TestFixture::as_string("xyz")); - TypeParam foobar(TestFixture::as_string("foobar")); - - BasicStringPiece a(alphabet); - BasicStringPiece b(abc); - BasicStringPiece c(xyz); - BasicStringPiece d(foobar); - BasicStringPiece e; - TypeParam temp(TestFixture::as_string("123")); - temp += static_cast(0); - temp += TestFixture::as_string("456"); - BasicStringPiece f(temp); - - ASSERT_EQ(a[6], static_cast('g')); - ASSERT_EQ(b[0], static_cast('a')); - ASSERT_EQ(c[2], static_cast('z')); - ASSERT_EQ(f[3], static_cast('\0')); - ASSERT_EQ(f[5], static_cast('5')); - - ASSERT_EQ(*d.data(), static_cast('f')); - ASSERT_EQ(d.data()[5], static_cast('r')); - ASSERT_TRUE(e.data() == NULL); - - ASSERT_EQ(*a.begin(), static_cast('a')); - ASSERT_EQ(*(b.begin() + 2), static_cast('c')); - ASSERT_EQ(*(c.end() - 1), static_cast('z')); - - ASSERT_EQ(*a.rbegin(), static_cast('z')); - ASSERT_EQ(*(b.rbegin() + 2), - static_cast('a')); - ASSERT_EQ(*(c.rend() - 1), static_cast('x')); - ASSERT_TRUE(a.rbegin() + 26 == a.rend()); - - ASSERT_EQ(a.size(), 26U); - ASSERT_EQ(b.size(), 3U); - ASSERT_EQ(c.size(), 3U); - ASSERT_EQ(d.size(), 6U); - ASSERT_EQ(e.size(), 0U); - ASSERT_EQ(f.size(), 7U); - - ASSERT_TRUE(!d.empty()); - ASSERT_TRUE(d.begin() != d.end()); - ASSERT_TRUE(d.begin() + 6 == d.end()); - - ASSERT_TRUE(e.empty()); - ASSERT_TRUE(e.begin() == e.end()); - - d.clear(); - ASSERT_EQ(d.size(), 0U); - ASSERT_TRUE(d.empty()); - ASSERT_TRUE(d.data() == NULL); - ASSERT_TRUE(d.begin() == d.end()); - - ASSERT_GE(a.max_size(), a.capacity()); - ASSERT_GE(a.capacity(), a.size()); -} - -// STL stuff only supported by the std::string version -TEST(StringPieceTest, CheckSTL) { - StringPiece a("abcdefghijklmnopqrstuvwxyz"); - StringPiece b("abc"); - StringPiece c("xyz"); - StringPiece d("foobar"); - d.clear(); - StringPiece e; - std::string temp("123"); - temp += '\0'; - temp += "456"; - StringPiece f(temp); - - char buf[4] = { '%', '%', '%', '%' }; - ASSERT_EQ(a.copy(buf, 4), 4U); - ASSERT_EQ(buf[0], a[0]); - ASSERT_EQ(buf[1], a[1]); - ASSERT_EQ(buf[2], a[2]); - ASSERT_EQ(buf[3], a[3]); - ASSERT_EQ(a.copy(buf, 3, 7), 3U); - ASSERT_EQ(buf[0], a[7]); - ASSERT_EQ(buf[1], a[8]); - ASSERT_EQ(buf[2], a[9]); - ASSERT_EQ(buf[3], a[3]); - ASSERT_EQ(c.copy(buf, 99), 3U); - ASSERT_EQ(buf[0], c[0]); - ASSERT_EQ(buf[1], c[1]); - ASSERT_EQ(buf[2], c[2]); - ASSERT_EQ(buf[3], a[3]); - - ASSERT_EQ(StringPiece::npos, std::string::npos); - - ASSERT_EQ(a.find(b), 0U); - ASSERT_EQ(a.find(b, 1), StringPiece::npos); - ASSERT_EQ(a.find(c), 23U); - ASSERT_EQ(a.find(c, 9), 23U); - ASSERT_EQ(a.find(c, StringPiece::npos), StringPiece::npos); - ASSERT_EQ(b.find(c), StringPiece::npos); - ASSERT_EQ(b.find(c, StringPiece::npos), StringPiece::npos); - ASSERT_EQ(a.find(d), 0U); - ASSERT_EQ(a.find(e), 0U); - ASSERT_EQ(a.find(d, 12), 12U); - ASSERT_EQ(a.find(e, 17), 17U); - StringPiece g("xx not found bb"); - ASSERT_EQ(a.find(g), StringPiece::npos); - // empty string nonsense - ASSERT_EQ(d.find(b), StringPiece::npos); - ASSERT_EQ(e.find(b), StringPiece::npos); - ASSERT_EQ(d.find(b, 4), StringPiece::npos); - ASSERT_EQ(e.find(b, 7), StringPiece::npos); - - size_t empty_search_pos = std::string().find(std::string()); - ASSERT_EQ(d.find(d), empty_search_pos); - ASSERT_EQ(d.find(e), empty_search_pos); - ASSERT_EQ(e.find(d), empty_search_pos); - ASSERT_EQ(e.find(e), empty_search_pos); - ASSERT_EQ(d.find(d, 4), std::string().find(std::string(), 4)); - ASSERT_EQ(d.find(e, 4), std::string().find(std::string(), 4)); - ASSERT_EQ(e.find(d, 4), std::string().find(std::string(), 4)); - ASSERT_EQ(e.find(e, 4), std::string().find(std::string(), 4)); - - ASSERT_EQ(a.find('a'), 0U); - ASSERT_EQ(a.find('c'), 2U); - ASSERT_EQ(a.find('z'), 25U); - ASSERT_EQ(a.find('$'), StringPiece::npos); - ASSERT_EQ(a.find('\0'), StringPiece::npos); - ASSERT_EQ(f.find('\0'), 3U); - ASSERT_EQ(f.find('3'), 2U); - ASSERT_EQ(f.find('5'), 5U); - ASSERT_EQ(g.find('o'), 4U); - ASSERT_EQ(g.find('o', 4), 4U); - ASSERT_EQ(g.find('o', 5), 8U); - ASSERT_EQ(a.find('b', 5), StringPiece::npos); - // empty string nonsense - ASSERT_EQ(d.find('\0'), StringPiece::npos); - ASSERT_EQ(e.find('\0'), StringPiece::npos); - ASSERT_EQ(d.find('\0', 4), StringPiece::npos); - ASSERT_EQ(e.find('\0', 7), StringPiece::npos); - ASSERT_EQ(d.find('x'), StringPiece::npos); - ASSERT_EQ(e.find('x'), StringPiece::npos); - ASSERT_EQ(d.find('x', 4), StringPiece::npos); - ASSERT_EQ(e.find('x', 7), StringPiece::npos); - - ASSERT_EQ(a.rfind(b), 0U); - ASSERT_EQ(a.rfind(b, 1), 0U); - ASSERT_EQ(a.rfind(c), 23U); - ASSERT_EQ(a.rfind(c, 22U), StringPiece::npos); - ASSERT_EQ(a.rfind(c, 1U), StringPiece::npos); - ASSERT_EQ(a.rfind(c, 0U), StringPiece::npos); - ASSERT_EQ(b.rfind(c), StringPiece::npos); - ASSERT_EQ(b.rfind(c, 0U), StringPiece::npos); - ASSERT_EQ(a.rfind(d), (size_t) a.as_string().rfind(std::string())); - ASSERT_EQ(a.rfind(e), a.as_string().rfind(std::string())); - ASSERT_EQ(a.rfind(d, 12), 12U); - ASSERT_EQ(a.rfind(e, 17), 17U); - ASSERT_EQ(a.rfind(g), StringPiece::npos); - ASSERT_EQ(d.rfind(b), StringPiece::npos); - ASSERT_EQ(e.rfind(b), StringPiece::npos); - ASSERT_EQ(d.rfind(b, 4), StringPiece::npos); - ASSERT_EQ(e.rfind(b, 7), StringPiece::npos); - // empty string nonsense - ASSERT_EQ(d.rfind(d, 4), std::string().rfind(std::string())); - ASSERT_EQ(e.rfind(d, 7), std::string().rfind(std::string())); - ASSERT_EQ(d.rfind(e, 4), std::string().rfind(std::string())); - ASSERT_EQ(e.rfind(e, 7), std::string().rfind(std::string())); - ASSERT_EQ(d.rfind(d), std::string().rfind(std::string())); - ASSERT_EQ(e.rfind(d), std::string().rfind(std::string())); - ASSERT_EQ(d.rfind(e), std::string().rfind(std::string())); - ASSERT_EQ(e.rfind(e), std::string().rfind(std::string())); - - ASSERT_EQ(g.rfind('o'), 8U); - ASSERT_EQ(g.rfind('q'), StringPiece::npos); - ASSERT_EQ(g.rfind('o', 8), 8U); - ASSERT_EQ(g.rfind('o', 7), 4U); - ASSERT_EQ(g.rfind('o', 3), StringPiece::npos); - ASSERT_EQ(f.rfind('\0'), 3U); - ASSERT_EQ(f.rfind('\0', 12), 3U); - ASSERT_EQ(f.rfind('3'), 2U); - ASSERT_EQ(f.rfind('5'), 5U); - // empty string nonsense - ASSERT_EQ(d.rfind('o'), StringPiece::npos); - ASSERT_EQ(e.rfind('o'), StringPiece::npos); - ASSERT_EQ(d.rfind('o', 4), StringPiece::npos); - ASSERT_EQ(e.rfind('o', 7), StringPiece::npos); - - ASSERT_EQ( - StringPiece("one,two:three;four").find_first_of(StringPiece(",:"), 1), - 3U); - ASSERT_EQ(a.find_first_of(b), 0U); - ASSERT_EQ(a.find_first_of(b, 0), 0U); - ASSERT_EQ(a.find_first_of(b, 1), 1U); - ASSERT_EQ(a.find_first_of(b, 2), 2U); - ASSERT_EQ(a.find_first_of(b, 3), StringPiece::npos); - ASSERT_EQ(a.find_first_of(c), 23U); - ASSERT_EQ(a.find_first_of(c, 23), 23U); - ASSERT_EQ(a.find_first_of(c, 24), 24U); - ASSERT_EQ(a.find_first_of(c, 25), 25U); - ASSERT_EQ(a.find_first_of(c, 26), StringPiece::npos); - ASSERT_EQ(g.find_first_of(b), 13U); - ASSERT_EQ(g.find_first_of(c), 0U); - ASSERT_EQ(a.find_first_of(f), StringPiece::npos); - ASSERT_EQ(f.find_first_of(a), StringPiece::npos); - // empty string nonsense - ASSERT_EQ(a.find_first_of(d), StringPiece::npos); - ASSERT_EQ(a.find_first_of(e), StringPiece::npos); - ASSERT_EQ(d.find_first_of(b), StringPiece::npos); - ASSERT_EQ(e.find_first_of(b), StringPiece::npos); - ASSERT_EQ(d.find_first_of(d), StringPiece::npos); - ASSERT_EQ(e.find_first_of(d), StringPiece::npos); - ASSERT_EQ(d.find_first_of(e), StringPiece::npos); - ASSERT_EQ(e.find_first_of(e), StringPiece::npos); - - ASSERT_EQ(a.find_first_not_of(b), 3U); - ASSERT_EQ(a.find_first_not_of(c), 0U); - ASSERT_EQ(b.find_first_not_of(a), StringPiece::npos); - ASSERT_EQ(c.find_first_not_of(a), StringPiece::npos); - ASSERT_EQ(f.find_first_not_of(a), 0U); - ASSERT_EQ(a.find_first_not_of(f), 0U); - ASSERT_EQ(a.find_first_not_of(d), 0U); - ASSERT_EQ(a.find_first_not_of(e), 0U); - // empty string nonsense - ASSERT_EQ(d.find_first_not_of(a), StringPiece::npos); - ASSERT_EQ(e.find_first_not_of(a), StringPiece::npos); - ASSERT_EQ(d.find_first_not_of(d), StringPiece::npos); - ASSERT_EQ(e.find_first_not_of(d), StringPiece::npos); - ASSERT_EQ(d.find_first_not_of(e), StringPiece::npos); - ASSERT_EQ(e.find_first_not_of(e), StringPiece::npos); - - StringPiece h("===="); - ASSERT_EQ(h.find_first_not_of('='), StringPiece::npos); - ASSERT_EQ(h.find_first_not_of('=', 3), StringPiece::npos); - ASSERT_EQ(h.find_first_not_of('\0'), 0U); - ASSERT_EQ(g.find_first_not_of('x'), 2U); - ASSERT_EQ(f.find_first_not_of('\0'), 0U); - ASSERT_EQ(f.find_first_not_of('\0', 3), 4U); - ASSERT_EQ(f.find_first_not_of('\0', 2), 2U); - // empty string nonsense - ASSERT_EQ(d.find_first_not_of('x'), StringPiece::npos); - ASSERT_EQ(e.find_first_not_of('x'), StringPiece::npos); - ASSERT_EQ(d.find_first_not_of('\0'), StringPiece::npos); - ASSERT_EQ(e.find_first_not_of('\0'), StringPiece::npos); - - // StringPiece g("xx not found bb"); - StringPiece i("56"); - ASSERT_EQ(h.find_last_of(a), StringPiece::npos); - ASSERT_EQ(g.find_last_of(a), g.size()-1); - ASSERT_EQ(a.find_last_of(b), 2U); - ASSERT_EQ(a.find_last_of(c), a.size()-1); - ASSERT_EQ(f.find_last_of(i), 6U); - ASSERT_EQ(a.find_last_of('a'), 0U); - ASSERT_EQ(a.find_last_of('b'), 1U); - ASSERT_EQ(a.find_last_of('z'), 25U); - ASSERT_EQ(a.find_last_of('a', 5), 0U); - ASSERT_EQ(a.find_last_of('b', 5), 1U); - ASSERT_EQ(a.find_last_of('b', 0), StringPiece::npos); - ASSERT_EQ(a.find_last_of('z', 25), 25U); - ASSERT_EQ(a.find_last_of('z', 24), StringPiece::npos); - ASSERT_EQ(f.find_last_of(i, 5), 5U); - ASSERT_EQ(f.find_last_of(i, 6), 6U); - ASSERT_EQ(f.find_last_of(a, 4), StringPiece::npos); - // empty string nonsense - ASSERT_EQ(f.find_last_of(d), StringPiece::npos); - ASSERT_EQ(f.find_last_of(e), StringPiece::npos); - ASSERT_EQ(f.find_last_of(d, 4), StringPiece::npos); - ASSERT_EQ(f.find_last_of(e, 4), StringPiece::npos); - ASSERT_EQ(d.find_last_of(d), StringPiece::npos); - ASSERT_EQ(d.find_last_of(e), StringPiece::npos); - ASSERT_EQ(e.find_last_of(d), StringPiece::npos); - ASSERT_EQ(e.find_last_of(e), StringPiece::npos); - ASSERT_EQ(d.find_last_of(f), StringPiece::npos); - ASSERT_EQ(e.find_last_of(f), StringPiece::npos); - ASSERT_EQ(d.find_last_of(d, 4), StringPiece::npos); - ASSERT_EQ(d.find_last_of(e, 4), StringPiece::npos); - ASSERT_EQ(e.find_last_of(d, 4), StringPiece::npos); - ASSERT_EQ(e.find_last_of(e, 4), StringPiece::npos); - ASSERT_EQ(d.find_last_of(f, 4), StringPiece::npos); - ASSERT_EQ(e.find_last_of(f, 4), StringPiece::npos); - - ASSERT_EQ(a.find_last_not_of(b), a.size()-1); - ASSERT_EQ(a.find_last_not_of(c), 22U); - ASSERT_EQ(b.find_last_not_of(a), StringPiece::npos); - ASSERT_EQ(b.find_last_not_of(b), StringPiece::npos); - ASSERT_EQ(f.find_last_not_of(i), 4U); - ASSERT_EQ(a.find_last_not_of(c, 24), 22U); - ASSERT_EQ(a.find_last_not_of(b, 3), 3U); - ASSERT_EQ(a.find_last_not_of(b, 2), StringPiece::npos); - // empty string nonsense - ASSERT_EQ(f.find_last_not_of(d), f.size()-1); - ASSERT_EQ(f.find_last_not_of(e), f.size()-1); - ASSERT_EQ(f.find_last_not_of(d, 4), 4U); - ASSERT_EQ(f.find_last_not_of(e, 4), 4U); - ASSERT_EQ(d.find_last_not_of(d), StringPiece::npos); - ASSERT_EQ(d.find_last_not_of(e), StringPiece::npos); - ASSERT_EQ(e.find_last_not_of(d), StringPiece::npos); - ASSERT_EQ(e.find_last_not_of(e), StringPiece::npos); - ASSERT_EQ(d.find_last_not_of(f), StringPiece::npos); - ASSERT_EQ(e.find_last_not_of(f), StringPiece::npos); - ASSERT_EQ(d.find_last_not_of(d, 4), StringPiece::npos); - ASSERT_EQ(d.find_last_not_of(e, 4), StringPiece::npos); - ASSERT_EQ(e.find_last_not_of(d, 4), StringPiece::npos); - ASSERT_EQ(e.find_last_not_of(e, 4), StringPiece::npos); - ASSERT_EQ(d.find_last_not_of(f, 4), StringPiece::npos); - ASSERT_EQ(e.find_last_not_of(f, 4), StringPiece::npos); - - ASSERT_EQ(h.find_last_not_of('x'), h.size() - 1); - ASSERT_EQ(h.find_last_not_of('='), StringPiece::npos); - ASSERT_EQ(b.find_last_not_of('c'), 1U); - ASSERT_EQ(h.find_last_not_of('x', 2), 2U); - ASSERT_EQ(h.find_last_not_of('=', 2), StringPiece::npos); - ASSERT_EQ(b.find_last_not_of('b', 1), 0U); - // empty string nonsense - ASSERT_EQ(d.find_last_not_of('x'), StringPiece::npos); - ASSERT_EQ(e.find_last_not_of('x'), StringPiece::npos); - ASSERT_EQ(d.find_last_not_of('\0'), StringPiece::npos); - ASSERT_EQ(e.find_last_not_of('\0'), StringPiece::npos); - - ASSERT_EQ(a.substr(0, 3), b); - ASSERT_EQ(a.substr(23), c); - ASSERT_EQ(a.substr(23, 3), c); - ASSERT_EQ(a.substr(23, 99), c); - ASSERT_EQ(a.substr(0), a); - ASSERT_EQ(a.substr(3, 2), "de"); - // empty string nonsense - ASSERT_EQ(a.substr(99, 2), e); - ASSERT_EQ(d.substr(99), e); - ASSERT_EQ(d.substr(0, 99), e); - ASSERT_EQ(d.substr(99, 99), e); -} - -TYPED_TEST(CommonStringPieceTest, CheckCustom) { - TypeParam foobar(TestFixture::as_string("foobar")); - BasicStringPiece a(foobar); - TypeParam s1(TestFixture::as_string("123")); - s1 += static_cast('\0'); - s1 += TestFixture::as_string("456"); - BasicStringPiece b(s1); - BasicStringPiece e; - TypeParam s2; - - // remove_prefix - BasicStringPiece c(a); - c.remove_prefix(3); - ASSERT_EQ(c, TestFixture::as_string("bar")); - c = a; - c.remove_prefix(0); - ASSERT_EQ(c, a); - c.remove_prefix(c.size()); - ASSERT_EQ(c, e); - - // remove_suffix - c = a; - c.remove_suffix(3); - ASSERT_EQ(c, TestFixture::as_string("foo")); - c = a; - c.remove_suffix(0); - ASSERT_EQ(c, a); - c.remove_suffix(c.size()); - ASSERT_EQ(c, e); - - // set - c.set(foobar.c_str()); - ASSERT_EQ(c, a); - c.set(foobar.c_str(), 6); - ASSERT_EQ(c, a); - c.set(foobar.c_str(), 0); - ASSERT_EQ(c, e); - c.set(foobar.c_str(), 7); // Note, has an embedded NULL - ASSERT_NE(c, a); - - // as_string - TypeParam s3(a.as_string().c_str(), 7); // Note, has an embedded NULL - ASSERT_TRUE(c == s3); - TypeParam s4(e.as_string()); - ASSERT_TRUE(s4.empty()); -} - -TEST(StringPieceTest, CheckCustom) { - StringPiece a("foobar"); - std::string s1("123"); - s1 += '\0'; - s1 += "456"; - StringPiece b(s1); - StringPiece e; - std::string s2; - - // CopyToString - a.CopyToString(&s2); - ASSERT_EQ(s2.size(), 6U); - ASSERT_EQ(s2, "foobar"); - b.CopyToString(&s2); - ASSERT_EQ(s2.size(), 7U); - ASSERT_EQ(s1, s2); - e.CopyToString(&s2); - ASSERT_TRUE(s2.empty()); - - // AppendToString - s2.erase(); - a.AppendToString(&s2); - ASSERT_EQ(s2.size(), 6U); - ASSERT_EQ(s2, "foobar"); - a.AppendToString(&s2); - ASSERT_EQ(s2.size(), 12U); - ASSERT_EQ(s2, "foobarfoobar"); - - // starts_with - ASSERT_TRUE(a.starts_with(a)); - ASSERT_TRUE(a.starts_with("foo")); - ASSERT_TRUE(a.starts_with(e)); - ASSERT_TRUE(b.starts_with(s1)); - ASSERT_TRUE(b.starts_with(b)); - ASSERT_TRUE(b.starts_with(e)); - ASSERT_TRUE(e.starts_with("")); - ASSERT_TRUE(!a.starts_with(b)); - ASSERT_TRUE(!b.starts_with(a)); - ASSERT_TRUE(!e.starts_with(a)); - - // ends with - ASSERT_TRUE(a.ends_with(a)); - ASSERT_TRUE(a.ends_with("bar")); - ASSERT_TRUE(a.ends_with(e)); - ASSERT_TRUE(b.ends_with(s1)); - ASSERT_TRUE(b.ends_with(b)); - ASSERT_TRUE(b.ends_with(e)); - ASSERT_TRUE(e.ends_with("")); - ASSERT_TRUE(!a.ends_with(b)); - ASSERT_TRUE(!b.ends_with(a)); - ASSERT_TRUE(!e.ends_with(a)); - - StringPiece c; - c.set(static_cast("foobar"), 6); - ASSERT_EQ(c, a); - c.set(static_cast("foobar"), 0); - ASSERT_EQ(c, e); - c.set(static_cast("foobar"), 7); - ASSERT_NE(c, a); -} - -TYPED_TEST(CommonStringPieceTest, CheckNULL) { - // we used to crash here, but now we don't. - BasicStringPiece s(NULL); - ASSERT_EQ(s.data(), (const typename TypeParam::value_type*)NULL); - ASSERT_EQ(s.size(), 0U); - - s.set(NULL); - ASSERT_EQ(s.data(), (const typename TypeParam::value_type*)NULL); - ASSERT_EQ(s.size(), 0U); - - TypeParam str = s.as_string(); - ASSERT_EQ(str.length(), 0U); - ASSERT_EQ(str, TypeParam()); -} - -TYPED_TEST(CommonStringPieceTest, CheckComparisons2) { - TypeParam alphabet(TestFixture::as_string("abcdefghijklmnopqrstuvwxyz")); - TypeParam alphabet_z(TestFixture::as_string("abcdefghijklmnopqrstuvwxyzz")); - TypeParam alphabet_y(TestFixture::as_string("abcdefghijklmnopqrstuvwxyy")); - BasicStringPiece abc(alphabet); - - // check comparison operations on strings longer than 4 bytes. - ASSERT_TRUE(abc == BasicStringPiece(alphabet)); - ASSERT_TRUE(abc.compare(BasicStringPiece(alphabet)) == 0); - - ASSERT_TRUE(abc < BasicStringPiece(alphabet_z)); - ASSERT_TRUE(abc.compare(BasicStringPiece(alphabet_z)) < 0); - - ASSERT_TRUE(abc > BasicStringPiece(alphabet_y)); - ASSERT_TRUE(abc.compare(BasicStringPiece(alphabet_y)) > 0); -} - -// Test operations only supported by std::string version. -TEST(StringPieceTest, CheckComparisons2) { - StringPiece abc("abcdefghijklmnopqrstuvwxyz"); - - // starts_with - ASSERT_TRUE(abc.starts_with(abc)); - ASSERT_TRUE(abc.starts_with("abcdefghijklm")); - ASSERT_TRUE(!abc.starts_with("abcdefguvwxyz")); - - // ends_with - ASSERT_TRUE(abc.ends_with(abc)); - ASSERT_TRUE(!abc.ends_with("abcdefguvwxyz")); - ASSERT_TRUE(abc.ends_with("nopqrstuvwxyz")); -} - -TYPED_TEST(CommonStringPieceTest, StringCompareNotAmbiguous) { - ASSERT_TRUE(TestFixture::as_string("hello").c_str() == - TestFixture::as_string("hello")); - ASSERT_TRUE(TestFixture::as_string("hello").c_str() < - TestFixture::as_string("world")); -} - -TYPED_TEST(CommonStringPieceTest, HeterogenousStringPieceEquals) { - TypeParam hello(TestFixture::as_string("hello")); - - ASSERT_TRUE(BasicStringPiece(hello) == hello); - ASSERT_TRUE(hello.c_str() == BasicStringPiece(hello)); -} - -// string16-specific stuff -TEST(StringPiece16Test, CheckSTL) { - // Check some non-ascii characters. - string16 fifth(ASCIIToUTF16("123")); - fifth.push_back(0x0000); - fifth.push_back(0xd8c5); - fifth.push_back(0xdffe); - StringPiece16 f(fifth); - - ASSERT_EQ(f[3], '\0'); - ASSERT_EQ(f[5], static_cast(0xdffe)); - - ASSERT_EQ(f.size(), 6U); -} - - - -TEST(StringPiece16Test, CheckConversion) { - // Make sure that we can convert from UTF8 to UTF16 and back. We use a two - // byte character (G clef) to test this. - ASSERT_EQ( - UTF16ToUTF8( - StringPiece16(UTF8ToUTF16("\xf0\x9d\x84\x9e")).as_string()), - "\xf0\x9d\x84\x9e"); -} - -TYPED_TEST(CommonStringPieceTest, CheckConstructors) { - TypeParam str(TestFixture::as_string("hello world")); - TypeParam empty; - - ASSERT_TRUE(str == BasicStringPiece(str)); - ASSERT_TRUE(str == BasicStringPiece(str.c_str())); - ASSERT_TRUE(TestFixture::as_string("hello") == - BasicStringPiece(str.c_str(), 5)); - ASSERT_TRUE(empty == BasicStringPiece(str.c_str(), 0U)); - ASSERT_TRUE(empty == BasicStringPiece(NULL)); - ASSERT_TRUE(empty == BasicStringPiece(NULL, 0U)); - ASSERT_TRUE(empty == BasicStringPiece()); - ASSERT_TRUE(str == BasicStringPiece(str.begin(), str.end())); - ASSERT_TRUE(empty == BasicStringPiece(str.begin(), str.begin())); - ASSERT_TRUE(empty == BasicStringPiece(empty)); - ASSERT_TRUE(empty == BasicStringPiece(empty.begin(), empty.end())); -} - -} // namespace base diff --git a/base/strings/string_split.cc b/base/strings/string_split.cc deleted file mode 100644 index 210789cd22..0000000000 --- a/base/strings/string_split.cc +++ /dev/null @@ -1,219 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "base/strings/string_split.h" - -#include "base/logging.h" -#include "base/strings/string_util.h" -#include "base/strings/utf_string_conversions.h" -#include "base/third_party/icu/icu_utf.h" - -namespace base { - -template -static void SplitStringT(const STR& str, - const typename STR::value_type s, - bool trim_whitespace, - std::vector* r) { - r->clear(); - size_t last = 0; - size_t c = str.size(); - for (size_t i = 0; i <= c; ++i) { - if (i == c || str[i] == s) { - STR tmp(str, last, i - last); - if (trim_whitespace) - TrimWhitespace(tmp, TRIM_ALL, &tmp); - // Avoid converting an empty or all-whitespace source string into a vector - // of one empty string. - if (i != c || !r->empty() || !tmp.empty()) - r->push_back(tmp); - last = i + 1; - } - } -} - -void SplitString(const string16& str, - char16 c, - std::vector* r) { - DCHECK(CBU16_IS_SINGLE(c)); - SplitStringT(str, c, true, r); -} - -void SplitString(const std::string& str, - char c, - std::vector* r) { -#if CHAR_MIN < 0 - DCHECK(c >= 0); -#endif - DCHECK(c < 0x7F); - SplitStringT(str, c, true, r); -} - -bool SplitStringIntoKeyValues( - const std::string& line, - char key_value_delimiter, - std::string* key, std::vector* values) { - key->clear(); - values->clear(); - - // Find the key string. - size_t end_key_pos = line.find_first_of(key_value_delimiter); - if (end_key_pos == std::string::npos) { - DVLOG(1) << "cannot parse key from line: " << line; - return false; // no key - } - key->assign(line, 0, end_key_pos); - - // Find the values string. - std::string remains(line, end_key_pos, line.size() - end_key_pos); - size_t begin_values_pos = remains.find_first_not_of(key_value_delimiter); - if (begin_values_pos == std::string::npos) { - DVLOG(1) << "cannot parse value from line: " << line; - return false; // no value - } - std::string values_string(remains, begin_values_pos, - remains.size() - begin_values_pos); - - // Construct the values vector. - values->push_back(values_string); - return true; -} - -bool SplitStringIntoKeyValuePairs(const std::string& line, - char key_value_delimiter, - char key_value_pair_delimiter, - StringPairs* key_value_pairs) { - key_value_pairs->clear(); - - std::vector pairs; - SplitString(line, key_value_pair_delimiter, &pairs); - - bool success = true; - for (size_t i = 0; i < pairs.size(); ++i) { - // Empty pair. SplitStringIntoKeyValues is more strict about an empty pair - // line, so continue with the next pair. - if (pairs[i].empty()) - continue; - - std::string key; - std::vector value; - if (!SplitStringIntoKeyValues(pairs[i], - key_value_delimiter, - &key, &value)) { - // Don't return here, to allow for keys without associated - // values; just record that our split failed. - success = false; - } - DCHECK_LE(value.size(), 1U); - key_value_pairs->push_back( - make_pair(key, value.empty() ? std::string() : value[0])); - } - return success; -} - -template -static void SplitStringUsingSubstrT(const STR& str, - const STR& s, - std::vector* r) { - r->clear(); - typename STR::size_type begin_index = 0; - while (true) { - const typename STR::size_type end_index = str.find(s, begin_index); - if (end_index == STR::npos) { - const STR term = str.substr(begin_index); - STR tmp; - TrimWhitespace(term, TRIM_ALL, &tmp); - r->push_back(tmp); - return; - } - const STR term = str.substr(begin_index, end_index - begin_index); - STR tmp; - TrimWhitespace(term, TRIM_ALL, &tmp); - r->push_back(tmp); - begin_index = end_index + s.size(); - } -} - -void SplitStringUsingSubstr(const string16& str, - const string16& s, - std::vector* r) { - SplitStringUsingSubstrT(str, s, r); -} - -void SplitStringUsingSubstr(const std::string& str, - const std::string& s, - std::vector* r) { - SplitStringUsingSubstrT(str, s, r); -} - -void SplitStringDontTrim(const string16& str, - char16 c, - std::vector* r) { - DCHECK(CBU16_IS_SINGLE(c)); - SplitStringT(str, c, false, r); -} - -void SplitStringDontTrim(const std::string& str, - char c, - std::vector* r) { - DCHECK(IsStringUTF8(str)); -#if CHAR_MIN < 0 - DCHECK(c >= 0); -#endif - DCHECK(c < 0x7F); - SplitStringT(str, c, false, r); -} - -template -void SplitStringAlongWhitespaceT(const STR& str, std::vector* result) { - result->clear(); - const size_t length = str.length(); - if (!length) - return; - - bool last_was_ws = false; - size_t last_non_ws_start = 0; - for (size_t i = 0; i < length; ++i) { - switch (str[i]) { - // HTML 5 defines whitespace as: space, tab, LF, line tab, FF, or CR. - case L' ': - case L'\t': - case L'\xA': - case L'\xB': - case L'\xC': - case L'\xD': - if (!last_was_ws) { - if (i > 0) { - result->push_back( - str.substr(last_non_ws_start, i - last_non_ws_start)); - } - last_was_ws = true; - } - break; - - default: // Not a space character. - if (last_was_ws) { - last_was_ws = false; - last_non_ws_start = i; - } - break; - } - } - if (!last_was_ws) { - result->push_back( - str.substr(last_non_ws_start, length - last_non_ws_start)); - } -} - -void SplitStringAlongWhitespace(const string16& str, - std::vector* result) { - SplitStringAlongWhitespaceT(str, result); -} - -void SplitStringAlongWhitespace(const std::string& str, - std::vector* result) { - SplitStringAlongWhitespaceT(str, result); -} - -} // namespace base diff --git a/base/strings/string_split.h b/base/strings/string_split.h deleted file mode 100644 index faf08d6985..0000000000 --- a/base/strings/string_split.h +++ /dev/null @@ -1,83 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef BASE_STRINGS_STRING_SPLIT_H_ -#define BASE_STRINGS_STRING_SPLIT_H_ - -#include -#include -#include - -#include "base/base_export.h" -#include "base/strings/string16.h" - -namespace base { - -// Splits |str| into a vector of strings delimited by |s|, placing the results -// in |r|. If several instances of |s| are contiguous, or if |str| begins with -// or ends with |s|, then an empty string is inserted. -// -// Every substring is trimmed of any leading or trailing white space. -// NOTE: |c| must be in BMP (Basic Multilingual Plane) -BASE_EXPORT void SplitString(const string16& str, - char16 c, - std::vector* r); -// |str| should not be in a multi-byte encoding like Shift-JIS or GBK in which -// the trailing byte of a multi-byte character can be in the ASCII range. -// UTF-8, and other single/multi-byte ASCII-compatible encodings are OK. -// Note: |c| must be in the ASCII range. -BASE_EXPORT void SplitString(const std::string& str, - char c, - std::vector* r); - -BASE_EXPORT bool SplitStringIntoKeyValues(const std::string& line, - char key_value_delimiter, - std::string* key, - std::vector* values); - -typedef std::vector > StringPairs;; - -BASE_EXPORT bool SplitStringIntoKeyValuePairs( - const std::string& line, - char key_value_delimiter, - char key_value_pair_delimiter, - StringPairs* key_value_pairs); - -// The same as SplitString, but use a substring delimiter instead of a char. -BASE_EXPORT void SplitStringUsingSubstr(const string16& str, - const string16& s, - std::vector* r); -BASE_EXPORT void SplitStringUsingSubstr(const std::string& str, - const std::string& s, - std::vector* r); - -// The same as SplitString, but don't trim white space. -// NOTE: |c| must be in BMP (Basic Multilingual Plane) -BASE_EXPORT void SplitStringDontTrim(const string16& str, - char16 c, - std::vector* r); -// |str| should not be in a multi-byte encoding like Shift-JIS or GBK in which -// the trailing byte of a multi-byte character can be in the ASCII range. -// UTF-8, and other single/multi-byte ASCII-compatible encodings are OK. -// Note: |c| must be in the ASCII range. -BASE_EXPORT void SplitStringDontTrim(const std::string& str, - char c, - std::vector* r); - -// WARNING: this uses whitespace as defined by the HTML5 spec. If you need -// a function similar to this but want to trim all types of whitespace, then -// factor this out into a function that takes a string containing the characters -// that are treated as whitespace. -// -// Splits the string along whitespace (where whitespace is the five space -// characters defined by HTML 5). Each contiguous block of non-whitespace -// characters is added to result. -BASE_EXPORT void SplitStringAlongWhitespace(const string16& str, - std::vector* result); -BASE_EXPORT void SplitStringAlongWhitespace(const std::string& str, - std::vector* result); - -} // namespace base - -#endif // BASE_STRINGS_STRING_SPLIT_H_ diff --git a/base/strings/string_split_unittest.cc b/base/strings/string_split_unittest.cc deleted file mode 100644 index eb69b68fcb..0000000000 --- a/base/strings/string_split_unittest.cc +++ /dev/null @@ -1,318 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "base/strings/string_split.h" - -#include "base/strings/utf_string_conversions.h" -#include "testing/gmock/include/gmock/gmock.h" -#include "testing/gtest/include/gtest/gtest.h" - -using ::testing::ElementsAre; - -namespace base { - -namespace { - -#if !defined(WCHAR_T_IS_UTF16) -// Overload SplitString with a wide-char version to make it easier to -// test the string16 version with wide character literals. -void SplitString(const std::wstring& str, - wchar_t c, - std::vector* result) { - std::vector result16; - SplitString(WideToUTF16(str), c, &result16); - for (size_t i = 0; i < result16.size(); ++i) - result->push_back(UTF16ToWide(result16[i])); -} -#endif - -} // anonymous namespace - -class SplitStringIntoKeyValuesTest : public testing::Test { - protected: - std::string key; - std::vector values; -}; - -TEST_F(SplitStringIntoKeyValuesTest, EmptyInputMultipleValues) { - EXPECT_FALSE(SplitStringIntoKeyValues(std::string(), // Empty input - '\t', // Key separators - &key, - &values)); - EXPECT_TRUE(key.empty()); - EXPECT_TRUE(values.empty()); -} - -TEST_F(SplitStringIntoKeyValuesTest, EmptyValueInputMultipleValues) { - EXPECT_FALSE(SplitStringIntoKeyValues("key_with_no_value\t", - '\t', // Key separators - &key, &values)); - EXPECT_EQ("key_with_no_value", key); - EXPECT_TRUE(values.empty()); -} - -TEST_F(SplitStringIntoKeyValuesTest, EmptyKeyInputMultipleValues) { - EXPECT_TRUE(SplitStringIntoKeyValues("\tvalue for empty key", - '\t', // Key separators - &key, &values)); - EXPECT_TRUE(key.empty()); - ASSERT_EQ(1U, values.size()); -} - -TEST_F(SplitStringIntoKeyValuesTest, KeyWithMultipleValues) { - EXPECT_TRUE(SplitStringIntoKeyValues("key1\tvalue1, value2 value3", - '\t', // Key separators - &key, &values)); - EXPECT_EQ("key1", key); - ASSERT_EQ(1U, values.size()); - EXPECT_EQ("value1, value2 value3", values[0]); -} - -TEST_F(SplitStringIntoKeyValuesTest, EmptyInputSingleValue) { - EXPECT_FALSE(SplitStringIntoKeyValues(std::string(), // Empty input - '\t', // Key separators - &key, - &values)); - EXPECT_TRUE(key.empty()); - EXPECT_TRUE(values.empty()); -} - -TEST_F(SplitStringIntoKeyValuesTest, EmptyValueInputSingleValue) { - EXPECT_FALSE(SplitStringIntoKeyValues("key_with_no_value\t", - '\t', // Key separators - &key, &values)); - EXPECT_EQ("key_with_no_value", key); - EXPECT_TRUE(values.empty()); -} - -TEST_F(SplitStringIntoKeyValuesTest, EmptyKeyInputSingleValue) { - EXPECT_TRUE(SplitStringIntoKeyValues("\tvalue for empty key", - '\t', // Key separators - &key, &values)); - EXPECT_TRUE(key.empty()); - ASSERT_EQ(1U, values.size()); - EXPECT_EQ("value for empty key", values[0]); -} - -TEST_F(SplitStringIntoKeyValuesTest, KeyWithSingleValue) { - EXPECT_TRUE(SplitStringIntoKeyValues("key1\tvalue1, value2 value3", - '\t', // Key separators - &key, &values)); - EXPECT_EQ("key1", key); - ASSERT_EQ(1U, values.size()); - EXPECT_EQ("value1, value2 value3", values[0]); -} - -class SplitStringIntoKeyValuePairsTest : public testing::Test { - protected: - std::vector > kv_pairs; -}; - -TEST_F(SplitStringIntoKeyValuePairsTest, EmptyString) { - EXPECT_TRUE(SplitStringIntoKeyValuePairs(std::string(), - ':', // Key-value delimiters - ',', // Key-value pair delims - &kv_pairs)); - EXPECT_TRUE(kv_pairs.empty()); -} - -TEST_F(SplitStringIntoKeyValuePairsTest, EmptySecondPair) { - EXPECT_TRUE(SplitStringIntoKeyValuePairs("key1:value1,,key3:value3", - ':', // Key-value delimiters - ',', // Key-value pair delims - &kv_pairs)); - ASSERT_EQ(2U, kv_pairs.size()); - EXPECT_EQ("key1", kv_pairs[0].first); - EXPECT_EQ("value1", kv_pairs[0].second); - EXPECT_EQ("key3", kv_pairs[1].first); - EXPECT_EQ("value3", kv_pairs[1].second); -} - -TEST_F(SplitStringIntoKeyValuePairsTest, EmptySecondValue) { - EXPECT_FALSE(SplitStringIntoKeyValuePairs("key1:value1 , key2:", - ':', // Key-value delimiters - ',', // Key-value pair delims - &kv_pairs)); - ASSERT_EQ(2U, kv_pairs.size()); - EXPECT_EQ("key1", kv_pairs[0].first); - EXPECT_EQ("value1", kv_pairs[0].second); - EXPECT_EQ("key2", kv_pairs[1].first); - EXPECT_EQ("", kv_pairs[1].second); -} - -TEST_F(SplitStringIntoKeyValuePairsTest, DelimiterInValue) { - EXPECT_TRUE(SplitStringIntoKeyValuePairs("key1:va:ue1 , key2:value2", - ':', // Key-value delimiters - ',', // Key-value pair delims - &kv_pairs)); - ASSERT_EQ(2U, kv_pairs.size()); - EXPECT_EQ("key1", kv_pairs[0].first); - EXPECT_EQ("va:ue1", kv_pairs[0].second); - EXPECT_EQ("key2", kv_pairs[1].first); - EXPECT_EQ("value2", kv_pairs[1].second); -} - -TEST(SplitStringUsingSubstrTest, EmptyString) { - std::vector results; - SplitStringUsingSubstr(std::string(), "DELIMITER", &results); - ASSERT_EQ(1u, results.size()); - EXPECT_THAT(results, ElementsAre("")); -} - -// Test for SplitString -TEST(StringUtilTest, SplitString) { - std::vector r; - - SplitString(std::wstring(), L',', &r); - EXPECT_EQ(0U, r.size()); - r.clear(); - - SplitString(L"a,b,c", L',', &r); - ASSERT_EQ(3U, r.size()); - EXPECT_EQ(r[0], L"a"); - EXPECT_EQ(r[1], L"b"); - EXPECT_EQ(r[2], L"c"); - r.clear(); - - SplitString(L"a, b, c", L',', &r); - ASSERT_EQ(3U, r.size()); - EXPECT_EQ(r[0], L"a"); - EXPECT_EQ(r[1], L"b"); - EXPECT_EQ(r[2], L"c"); - r.clear(); - - SplitString(L"a,,c", L',', &r); - ASSERT_EQ(3U, r.size()); - EXPECT_EQ(r[0], L"a"); - EXPECT_EQ(r[1], L""); - EXPECT_EQ(r[2], L"c"); - r.clear(); - - SplitString(L" ", L'*', &r); - EXPECT_EQ(0U, r.size()); - r.clear(); - - SplitString(L"foo", L'*', &r); - ASSERT_EQ(1U, r.size()); - EXPECT_EQ(r[0], L"foo"); - r.clear(); - - SplitString(L"foo ,", L',', &r); - ASSERT_EQ(2U, r.size()); - EXPECT_EQ(r[0], L"foo"); - EXPECT_EQ(r[1], L""); - r.clear(); - - SplitString(L",", L',', &r); - ASSERT_EQ(2U, r.size()); - EXPECT_EQ(r[0], L""); - EXPECT_EQ(r[1], L""); - r.clear(); - - SplitString(L"\t\ta\t", L'\t', &r); - ASSERT_EQ(4U, r.size()); - EXPECT_EQ(r[0], L""); - EXPECT_EQ(r[1], L""); - EXPECT_EQ(r[2], L"a"); - EXPECT_EQ(r[3], L""); - r.clear(); - - SplitString(L"\ta\t\nb\tcc", L'\n', &r); - ASSERT_EQ(2U, r.size()); - EXPECT_EQ(r[0], L"a"); - EXPECT_EQ(r[1], L"b\tcc"); - r.clear(); -} - -TEST(SplitStringUsingSubstrTest, StringWithNoDelimiter) { - std::vector results; - SplitStringUsingSubstr("alongwordwithnodelimiter", "DELIMITER", &results); - ASSERT_EQ(1u, results.size()); - EXPECT_THAT(results, ElementsAre("alongwordwithnodelimiter")); -} - -TEST(SplitStringUsingSubstrTest, LeadingDelimitersSkipped) { - std::vector results; - SplitStringUsingSubstr( - "DELIMITERDELIMITERDELIMITERoneDELIMITERtwoDELIMITERthree", - "DELIMITER", - &results); - ASSERT_EQ(6u, results.size()); - EXPECT_THAT(results, ElementsAre("", "", "", "one", "two", "three")); -} - -TEST(SplitStringUsingSubstrTest, ConsecutiveDelimitersSkipped) { - std::vector results; - SplitStringUsingSubstr( - "unoDELIMITERDELIMITERDELIMITERdosDELIMITERtresDELIMITERDELIMITERcuatro", - "DELIMITER", - &results); - ASSERT_EQ(7u, results.size()); - EXPECT_THAT(results, ElementsAre("uno", "", "", "dos", "tres", "", "cuatro")); -} - -TEST(SplitStringUsingSubstrTest, TrailingDelimitersSkipped) { - std::vector results; - SplitStringUsingSubstr( - "unDELIMITERdeuxDELIMITERtroisDELIMITERquatreDELIMITERDELIMITERDELIMITER", - "DELIMITER", - &results); - ASSERT_EQ(7u, results.size()); - EXPECT_THAT( - results, ElementsAre("un", "deux", "trois", "quatre", "", "", "")); -} - -TEST(StringSplitTest, StringSplitDontTrim) { - std::vector r; - - SplitStringDontTrim(" ", '*', &r); - ASSERT_EQ(1U, r.size()); - EXPECT_EQ(r[0], " "); - - SplitStringDontTrim("\t \ta\t ", '\t', &r); - ASSERT_EQ(4U, r.size()); - EXPECT_EQ(r[0], ""); - EXPECT_EQ(r[1], " "); - EXPECT_EQ(r[2], "a"); - EXPECT_EQ(r[3], " "); - - SplitStringDontTrim("\ta\t\nb\tcc", '\n', &r); - ASSERT_EQ(2U, r.size()); - EXPECT_EQ(r[0], "\ta\t"); - EXPECT_EQ(r[1], "b\tcc"); -} - -TEST(StringSplitTest, SplitStringAlongWhitespace) { - struct TestData { - const char* input; - const size_t expected_result_count; - const char* output1; - const char* output2; - } data[] = { - { "a", 1, "a", "" }, - { " ", 0, "", "" }, - { " a", 1, "a", "" }, - { " ab ", 1, "ab", "" }, - { " ab c", 2, "ab", "c" }, - { " ab c ", 2, "ab", "c" }, - { " ab cd", 2, "ab", "cd" }, - { " ab cd ", 2, "ab", "cd" }, - { " \ta\t", 1, "a", "" }, - { " b\ta\t", 2, "b", "a" }, - { " b\tat", 2, "b", "at" }, - { "b\tat", 2, "b", "at" }, - { "b\t at", 2, "b", "at" }, - }; - for (size_t i = 0; i < ARRAYSIZE_UNSAFE(data); ++i) { - std::vector results; - SplitStringAlongWhitespace(data[i].input, &results); - ASSERT_EQ(data[i].expected_result_count, results.size()); - if (data[i].expected_result_count > 0) - ASSERT_EQ(data[i].output1, results[0]); - if (data[i].expected_result_count > 1) - ASSERT_EQ(data[i].output2, results[1]); - } -} - -} // namespace base diff --git a/base/strings/string_tokenizer.h b/base/strings/string_tokenizer.h deleted file mode 100644 index 8defbac3b8..0000000000 --- a/base/strings/string_tokenizer.h +++ /dev/null @@ -1,260 +0,0 @@ -// Copyright (c) 2011 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef BASE_STRINGS_STRING_TOKENIZER_H_ -#define BASE_STRINGS_STRING_TOKENIZER_H_ - -#include -#include - -#include "base/strings/string_piece.h" - -namespace base { - -// StringTokenizerT is a simple string tokenizer class. It works like an -// iterator that with each step (see the Advance method) updates members that -// refer to the next token in the input string. The user may optionally -// configure the tokenizer to return delimiters. -// -// Warning: be careful not to pass a C string into the 2-arg constructor: -// StringTokenizer t("this is a test", " "); // WRONG -// This will create a temporary std::string, save the begin() and end() -// iterators, and then the string will be freed before we actually start -// tokenizing it. -// Instead, use a std::string or use the 3 arg constructor of CStringTokenizer. -// -// -// EXAMPLE 1: -// -// char input[] = "this is a test"; -// CStringTokenizer t(input, input + strlen(input), " "); -// while (t.GetNext()) { -// printf("%s\n", t.token().c_str()); -// } -// -// Output: -// -// this -// is -// a -// test -// -// -// EXAMPLE 2: -// -// std::string input = "no-cache=\"foo, bar\", private"; -// StringTokenizer t(input, ", "); -// t.set_quote_chars("\""); -// while (t.GetNext()) { -// printf("%s\n", t.token().c_str()); -// } -// -// Output: -// -// no-cache="foo, bar" -// private -// -// -// EXAMPLE 3: -// -// bool next_is_option = false, next_is_value = false; -// std::string input = "text/html; charset=UTF-8; foo=bar"; -// StringTokenizer t(input, "; ="); -// t.set_options(StringTokenizer::RETURN_DELIMS); -// while (t.GetNext()) { -// if (t.token_is_delim()) { -// switch (*t.token_begin()) { -// case ';': -// next_is_option = true; -// break; -// case '=': -// next_is_value = true; -// break; -// } -// } else { -// const char* label; -// if (next_is_option) { -// label = "option-name"; -// next_is_option = false; -// } else if (next_is_value) { -// label = "option-value"; -// next_is_value = false; -// } else { -// label = "mime-type"; -// } -// printf("%s: %s\n", label, t.token().c_str()); -// } -// } -// -// -template -class StringTokenizerT { - public: - typedef typename str::value_type char_type; - - // Options that may be pass to set_options() - enum { - // Specifies the delimiters should be returned as tokens - RETURN_DELIMS = 1 << 0, - }; - - // The string object must live longer than the tokenizer. (In particular this - // should not be constructed with a temporary.) - StringTokenizerT(const str& string, - const str& delims) { - Init(string.begin(), string.end(), delims); - } - - StringTokenizerT(const_iterator string_begin, - const_iterator string_end, - const str& delims) { - Init(string_begin, string_end, delims); - } - - // Set the options for this tokenizer. By default, this is 0. - void set_options(int options) { options_ = options; } - - // Set the characters to regard as quotes. By default, this is empty. When - // a quote char is encountered, the tokenizer will switch into a mode where - // it ignores delimiters that it finds. It switches out of this mode once it - // finds another instance of the quote char. If a backslash is encountered - // within a quoted string, then the next character is skipped. - void set_quote_chars(const str& quotes) { quotes_ = quotes; } - - // Call this method to advance the tokenizer to the next delimiter. This - // returns false if the tokenizer is complete. This method must be called - // before calling any of the token* methods. - bool GetNext() { - if (quotes_.empty() && options_ == 0) - return QuickGetNext(); - else - return FullGetNext(); - } - - // Start iterating through tokens from the beginning of the string. - void Reset() { - token_end_ = start_pos_; - } - - // Returns true if token is a delimiter. When the tokenizer is constructed - // with the RETURN_DELIMS option, this method can be used to check if the - // returned token is actually a delimiter. - bool token_is_delim() const { return token_is_delim_; } - - // If GetNext() returned true, then these methods may be used to read the - // value of the token. - const_iterator token_begin() const { return token_begin_; } - const_iterator token_end() const { return token_end_; } - str token() const { return str(token_begin_, token_end_); } - base::StringPiece token_piece() const { - return base::StringPiece(&*token_begin_, - std::distance(token_begin_, token_end_)); - } - - private: - void Init(const_iterator string_begin, - const_iterator string_end, - const str& delims) { - start_pos_ = string_begin; - token_begin_ = string_begin; - token_end_ = string_begin; - end_ = string_end; - delims_ = delims; - options_ = 0; - token_is_delim_ = false; - } - - // Implementation of GetNext() for when we have no quote characters. We have - // two separate implementations because AdvanceOne() is a hot spot in large - // text files with large tokens. - bool QuickGetNext() { - token_is_delim_ = false; - for (;;) { - token_begin_ = token_end_; - if (token_end_ == end_) - return false; - ++token_end_; - if (delims_.find(*token_begin_) == str::npos) - break; - // else skip over delimiter. - } - while (token_end_ != end_ && delims_.find(*token_end_) == str::npos) - ++token_end_; - return true; - } - - // Implementation of GetNext() for when we have to take quotes into account. - bool FullGetNext() { - AdvanceState state; - token_is_delim_ = false; - for (;;) { - token_begin_ = token_end_; - if (token_end_ == end_) - return false; - ++token_end_; - if (AdvanceOne(&state, *token_begin_)) - break; - if (options_ & RETURN_DELIMS) { - token_is_delim_ = true; - return true; - } - // else skip over delimiter. - } - while (token_end_ != end_ && AdvanceOne(&state, *token_end_)) - ++token_end_; - return true; - } - - bool IsDelim(char_type c) const { - return delims_.find(c) != str::npos; - } - - bool IsQuote(char_type c) const { - return quotes_.find(c) != str::npos; - } - - struct AdvanceState { - bool in_quote; - bool in_escape; - char_type quote_char; - AdvanceState() : in_quote(false), in_escape(false), quote_char('\0') {} - }; - - // Returns true if a delimiter was not hit. - bool AdvanceOne(AdvanceState* state, char_type c) { - if (state->in_quote) { - if (state->in_escape) { - state->in_escape = false; - } else if (c == '\\') { - state->in_escape = true; - } else if (c == state->quote_char) { - state->in_quote = false; - } - } else { - if (IsDelim(c)) - return false; - state->in_quote = IsQuote(state->quote_char = c); - } - return true; - } - - const_iterator start_pos_; - const_iterator token_begin_; - const_iterator token_end_; - const_iterator end_; - str delims_; - str quotes_; - int options_; - bool token_is_delim_; -}; - -typedef StringTokenizerT - StringTokenizer; -typedef StringTokenizerT - WStringTokenizer; -typedef StringTokenizerT CStringTokenizer; - -} // namespace base - -#endif // BASE_STRINGS_STRING_TOKENIZER_H_ diff --git a/base/strings/string_tokenizer_unittest.cc b/base/strings/string_tokenizer_unittest.cc deleted file mode 100644 index d391845328..0000000000 --- a/base/strings/string_tokenizer_unittest.cc +++ /dev/null @@ -1,234 +0,0 @@ -// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "base/strings/string_tokenizer.h" - -#include "testing/gtest/include/gtest/gtest.h" - -using std::string; - -namespace base { - -namespace { - -TEST(StringTokenizerTest, Simple) { - string input = "this is a test"; - StringTokenizer t(input, " "); - - EXPECT_TRUE(t.GetNext()); - EXPECT_EQ(string("this"), t.token()); - - EXPECT_TRUE(t.GetNext()); - EXPECT_EQ(string("is"), t.token()); - - EXPECT_TRUE(t.GetNext()); - EXPECT_EQ(string("a"), t.token()); - - EXPECT_TRUE(t.GetNext()); - EXPECT_EQ(string("test"), t.token()); - - EXPECT_FALSE(t.GetNext()); -} - -TEST(StringTokenizerTest, Reset) { - string input = "this is a test"; - StringTokenizer t(input, " "); - - for (int i = 0; i < 2; ++i) { - EXPECT_TRUE(t.GetNext()); - EXPECT_EQ(string("this"), t.token()); - - EXPECT_TRUE(t.GetNext()); - EXPECT_EQ(string("is"), t.token()); - - EXPECT_TRUE(t.GetNext()); - EXPECT_EQ(string("a"), t.token()); - - EXPECT_TRUE(t.GetNext()); - EXPECT_EQ(string("test"), t.token()); - - EXPECT_FALSE(t.GetNext()); - t.Reset(); - } -} - -TEST(StringTokenizerTest, RetDelims) { - string input = "this is a test"; - StringTokenizer t(input, " "); - t.set_options(StringTokenizer::RETURN_DELIMS); - - EXPECT_TRUE(t.GetNext()); - EXPECT_EQ(string("this"), t.token()); - - EXPECT_TRUE(t.GetNext()); - EXPECT_EQ(string(" "), t.token()); - - EXPECT_TRUE(t.GetNext()); - EXPECT_EQ(string("is"), t.token()); - - EXPECT_TRUE(t.GetNext()); - EXPECT_EQ(string(" "), t.token()); - - EXPECT_TRUE(t.GetNext()); - EXPECT_EQ(string("a"), t.token()); - - EXPECT_TRUE(t.GetNext()); - EXPECT_EQ(string(" "), t.token()); - - EXPECT_TRUE(t.GetNext()); - EXPECT_EQ(string("test"), t.token()); - - EXPECT_FALSE(t.GetNext()); -} - -TEST(StringTokenizerTest, ManyDelims) { - string input = "this: is, a-test"; - StringTokenizer t(input, ": ,-"); - - EXPECT_TRUE(t.GetNext()); - EXPECT_EQ(string("this"), t.token()); - - EXPECT_TRUE(t.GetNext()); - EXPECT_EQ(string("is"), t.token()); - - EXPECT_TRUE(t.GetNext()); - EXPECT_EQ(string("a"), t.token()); - - EXPECT_TRUE(t.GetNext()); - EXPECT_EQ(string("test"), t.token()); - - EXPECT_FALSE(t.GetNext()); -} - -TEST(StringTokenizerTest, ParseHeader) { - string input = "Content-Type: text/html ; charset=UTF-8"; - StringTokenizer t(input, ": ;="); - t.set_options(StringTokenizer::RETURN_DELIMS); - - EXPECT_TRUE(t.GetNext()); - EXPECT_FALSE(t.token_is_delim()); - EXPECT_EQ(string("Content-Type"), t.token()); - - EXPECT_TRUE(t.GetNext()); - EXPECT_TRUE(t.token_is_delim()); - EXPECT_EQ(string(":"), t.token()); - - EXPECT_TRUE(t.GetNext()); - EXPECT_TRUE(t.token_is_delim()); - EXPECT_EQ(string(" "), t.token()); - - EXPECT_TRUE(t.GetNext()); - EXPECT_FALSE(t.token_is_delim()); - EXPECT_EQ(string("text/html"), t.token()); - - EXPECT_TRUE(t.GetNext()); - EXPECT_TRUE(t.token_is_delim()); - EXPECT_EQ(string(" "), t.token()); - - EXPECT_TRUE(t.GetNext()); - EXPECT_TRUE(t.token_is_delim()); - EXPECT_EQ(string(";"), t.token()); - - EXPECT_TRUE(t.GetNext()); - EXPECT_TRUE(t.token_is_delim()); - EXPECT_EQ(string(" "), t.token()); - - EXPECT_TRUE(t.GetNext()); - EXPECT_FALSE(t.token_is_delim()); - EXPECT_EQ(string("charset"), t.token()); - - EXPECT_TRUE(t.GetNext()); - EXPECT_TRUE(t.token_is_delim()); - EXPECT_EQ(string("="), t.token()); - - EXPECT_TRUE(t.GetNext()); - EXPECT_FALSE(t.token_is_delim()); - EXPECT_EQ(string("UTF-8"), t.token()); - - EXPECT_FALSE(t.GetNext()); - EXPECT_FALSE(t.token_is_delim()); -} - -TEST(StringTokenizerTest, ParseQuotedString) { - string input = "foo bar 'hello world' baz"; - StringTokenizer t(input, " "); - t.set_quote_chars("'"); - - EXPECT_TRUE(t.GetNext()); - EXPECT_EQ(string("foo"), t.token()); - - EXPECT_TRUE(t.GetNext()); - EXPECT_EQ(string("bar"), t.token()); - - EXPECT_TRUE(t.GetNext()); - EXPECT_EQ(string("'hello world'"), t.token()); - - EXPECT_TRUE(t.GetNext()); - EXPECT_EQ(string("baz"), t.token()); - - EXPECT_FALSE(t.GetNext()); -} - -TEST(StringTokenizerTest, ParseQuotedString_Malformed) { - string input = "bar 'hello wo"; - StringTokenizer t(input, " "); - t.set_quote_chars("'"); - - EXPECT_TRUE(t.GetNext()); - EXPECT_EQ(string("bar"), t.token()); - - EXPECT_TRUE(t.GetNext()); - EXPECT_EQ(string("'hello wo"), t.token()); - - EXPECT_FALSE(t.GetNext()); -} - -TEST(StringTokenizerTest, ParseQuotedString_Multiple) { - string input = "bar 'hel\"lo\" wo' baz\""; - StringTokenizer t(input, " "); - t.set_quote_chars("'\""); - - EXPECT_TRUE(t.GetNext()); - EXPECT_EQ(string("bar"), t.token()); - - EXPECT_TRUE(t.GetNext()); - EXPECT_EQ(string("'hel\"lo\" wo'"), t.token()); - - EXPECT_TRUE(t.GetNext()); - EXPECT_EQ(string("baz\""), t.token()); - - EXPECT_FALSE(t.GetNext()); -} - -TEST(StringTokenizerTest, ParseQuotedString_EscapedQuotes) { - string input = "foo 'don\\'t do that'"; - StringTokenizer t(input, " "); - t.set_quote_chars("'"); - - EXPECT_TRUE(t.GetNext()); - EXPECT_EQ(string("foo"), t.token()); - - EXPECT_TRUE(t.GetNext()); - EXPECT_EQ(string("'don\\'t do that'"), t.token()); - - EXPECT_FALSE(t.GetNext()); -} - -TEST(StringTokenizerTest, ParseQuotedString_EscapedQuotes2) { - string input = "foo='a, b', bar"; - StringTokenizer t(input, ", "); - t.set_quote_chars("'"); - - EXPECT_TRUE(t.GetNext()); - EXPECT_EQ(string("foo='a, b'"), t.token()); - - EXPECT_TRUE(t.GetNext()); - EXPECT_EQ(string("bar"), t.token()); - - EXPECT_FALSE(t.GetNext()); -} - -} // namespace - -} // namespace base diff --git a/base/strings/string_util.cc b/base/strings/string_util.cc deleted file mode 100644 index 3ed706978e..0000000000 --- a/base/strings/string_util.cc +++ /dev/null @@ -1,1011 +0,0 @@ -// Copyright 2013 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "base/strings/string_util.h" - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include - -#include "base/basictypes.h" -#include "base/logging.h" -#include "base/memory/singleton.h" -#include "base/strings/utf_string_conversion_utils.h" -#include "base/strings/utf_string_conversions.h" -#include "base/third_party/icu/icu_utf.h" -#include "build/build_config.h" - -namespace { - -// Force the singleton used by Empty[W]String[16] to be a unique type. This -// prevents other code that might accidentally use Singleton from -// getting our internal one. -struct EmptyStrings { - EmptyStrings() {} - const std::string s; - const std::wstring ws; - const string16 s16; - - static EmptyStrings* GetInstance() { - return Singleton::get(); - } -}; - -// Used by ReplaceStringPlaceholders to track the position in the string of -// replaced parameters. -struct ReplacementOffset { - ReplacementOffset(uintptr_t parameter, size_t offset) - : parameter(parameter), - offset(offset) {} - - // Index of the parameter. - uintptr_t parameter; - - // Starting position in the string. - size_t offset; -}; - -static bool CompareParameter(const ReplacementOffset& elem1, - const ReplacementOffset& elem2) { - return elem1.parameter < elem2.parameter; -} - -} // namespace - -namespace base { - -bool IsWprintfFormatPortable(const wchar_t* format) { - for (const wchar_t* position = format; *position != '\0'; ++position) { - if (*position == '%') { - bool in_specification = true; - bool modifier_l = false; - while (in_specification) { - // Eat up characters until reaching a known specifier. - if (*++position == '\0') { - // The format string ended in the middle of a specification. Call - // it portable because no unportable specifications were found. The - // string is equally broken on all platforms. - return true; - } - - if (*position == 'l') { - // 'l' is the only thing that can save the 's' and 'c' specifiers. - modifier_l = true; - } else if (((*position == 's' || *position == 'c') && !modifier_l) || - *position == 'S' || *position == 'C' || *position == 'F' || - *position == 'D' || *position == 'O' || *position == 'U') { - // Not portable. - return false; - } - - if (wcschr(L"diouxXeEfgGaAcspn%", *position)) { - // Portable, keep scanning the rest of the format string. - in_specification = false; - } - } - } - } - - return true; -} - -} // namespace base - - -const std::string& EmptyString() { - return EmptyStrings::GetInstance()->s; -} - -const std::wstring& EmptyWString() { - return EmptyStrings::GetInstance()->ws; -} - -const string16& EmptyString16() { - return EmptyStrings::GetInstance()->s16; -} - -template -bool ReplaceCharsT(const STR& input, - const typename STR::value_type replace_chars[], - const STR& replace_with, - STR* output) { - bool removed = false; - size_t replace_length = replace_with.length(); - - *output = input; - - size_t found = output->find_first_of(replace_chars); - while (found != STR::npos) { - removed = true; - output->replace(found, 1, replace_with); - found = output->find_first_of(replace_chars, found + replace_length); - } - - return removed; -} - -bool ReplaceChars(const string16& input, - const char16 replace_chars[], - const string16& replace_with, - string16* output) { - return ReplaceCharsT(input, replace_chars, replace_with, output); -} - -bool ReplaceChars(const std::string& input, - const char replace_chars[], - const std::string& replace_with, - std::string* output) { - return ReplaceCharsT(input, replace_chars, replace_with, output); -} - -bool RemoveChars(const string16& input, - const char16 remove_chars[], - string16* output) { - return ReplaceChars(input, remove_chars, string16(), output); -} - -bool RemoveChars(const std::string& input, - const char remove_chars[], - std::string* output) { - return ReplaceChars(input, remove_chars, std::string(), output); -} - -template -TrimPositions TrimStringT(const STR& input, - const typename STR::value_type trim_chars[], - TrimPositions positions, - STR* output) { - // Find the edges of leading/trailing whitespace as desired. - const typename STR::size_type last_char = input.length() - 1; - const typename STR::size_type first_good_char = (positions & TRIM_LEADING) ? - input.find_first_not_of(trim_chars) : 0; - const typename STR::size_type last_good_char = (positions & TRIM_TRAILING) ? - input.find_last_not_of(trim_chars) : last_char; - - // When the string was all whitespace, report that we stripped off whitespace - // from whichever position the caller was interested in. For empty input, we - // stripped no whitespace, but we still need to clear |output|. - if (input.empty() || - (first_good_char == STR::npos) || (last_good_char == STR::npos)) { - bool input_was_empty = input.empty(); // in case output == &input - output->clear(); - return input_was_empty ? TRIM_NONE : positions; - } - - // Trim the whitespace. - *output = - input.substr(first_good_char, last_good_char - first_good_char + 1); - - // Return where we trimmed from. - return static_cast( - ((first_good_char == 0) ? TRIM_NONE : TRIM_LEADING) | - ((last_good_char == last_char) ? TRIM_NONE : TRIM_TRAILING)); -} - -bool TrimString(const std::wstring& input, - const wchar_t trim_chars[], - std::wstring* output) { - return TrimStringT(input, trim_chars, TRIM_ALL, output) != TRIM_NONE; -} - -#if !defined(WCHAR_T_IS_UTF16) -bool TrimString(const string16& input, - const char16 trim_chars[], - string16* output) { - return TrimStringT(input, trim_chars, TRIM_ALL, output) != TRIM_NONE; -} -#endif - -bool TrimString(const std::string& input, - const char trim_chars[], - std::string* output) { - return TrimStringT(input, trim_chars, TRIM_ALL, output) != TRIM_NONE; -} - -void TruncateUTF8ToByteSize(const std::string& input, - const size_t byte_size, - std::string* output) { - DCHECK(output); - if (byte_size > input.length()) { - *output = input; - return; - } - DCHECK_LE(byte_size, static_cast(kint32max)); - // Note: This cast is necessary because CBU8_NEXT uses int32s. - int32 truncation_length = static_cast(byte_size); - int32 char_index = truncation_length - 1; - const char* data = input.data(); - - // Using CBU8, we will move backwards from the truncation point - // to the beginning of the string looking for a valid UTF8 - // character. Once a full UTF8 character is found, we will - // truncate the string to the end of that character. - while (char_index >= 0) { - int32 prev = char_index; - uint32 code_point = 0; - CBU8_NEXT(data, char_index, truncation_length, code_point); - if (!base::IsValidCharacter(code_point) || - !base::IsValidCodepoint(code_point)) { - char_index = prev - 1; - } else { - break; - } - } - - if (char_index >= 0 ) - *output = input.substr(0, char_index); - else - output->clear(); -} - -TrimPositions TrimWhitespace(const string16& input, - TrimPositions positions, - string16* output) { - return TrimStringT(input, kWhitespaceUTF16, positions, output); -} - -TrimPositions TrimWhitespaceASCII(const std::string& input, - TrimPositions positions, - std::string* output) { - return TrimStringT(input, kWhitespaceASCII, positions, output); -} - -// This function is only for backward-compatibility. -// To be removed when all callers are updated. -TrimPositions TrimWhitespace(const std::string& input, - TrimPositions positions, - std::string* output) { - return TrimWhitespaceASCII(input, positions, output); -} - -template -STR CollapseWhitespaceT(const STR& text, - bool trim_sequences_with_line_breaks) { - STR result; - result.resize(text.size()); - - // Set flags to pretend we're already in a trimmed whitespace sequence, so we - // will trim any leading whitespace. - bool in_whitespace = true; - bool already_trimmed = true; - - int chars_written = 0; - for (typename STR::const_iterator i(text.begin()); i != text.end(); ++i) { - if (IsWhitespace(*i)) { - if (!in_whitespace) { - // Reduce all whitespace sequences to a single space. - in_whitespace = true; - result[chars_written++] = L' '; - } - if (trim_sequences_with_line_breaks && !already_trimmed && - ((*i == '\n') || (*i == '\r'))) { - // Whitespace sequences containing CR or LF are eliminated entirely. - already_trimmed = true; - --chars_written; - } - } else { - // Non-whitespace chracters are copied straight across. - in_whitespace = false; - already_trimmed = false; - result[chars_written++] = *i; - } - } - - if (in_whitespace && !already_trimmed) { - // Any trailing whitespace is eliminated. - --chars_written; - } - - result.resize(chars_written); - return result; -} - -std::wstring CollapseWhitespace(const std::wstring& text, - bool trim_sequences_with_line_breaks) { - return CollapseWhitespaceT(text, trim_sequences_with_line_breaks); -} - -#if !defined(WCHAR_T_IS_UTF16) -string16 CollapseWhitespace(const string16& text, - bool trim_sequences_with_line_breaks) { - return CollapseWhitespaceT(text, trim_sequences_with_line_breaks); -} -#endif - -std::string CollapseWhitespaceASCII(const std::string& text, - bool trim_sequences_with_line_breaks) { - return CollapseWhitespaceT(text, trim_sequences_with_line_breaks); -} - -bool ContainsOnlyWhitespaceASCII(const std::string& str) { - for (std::string::const_iterator i(str.begin()); i != str.end(); ++i) { - if (!IsAsciiWhitespace(*i)) - return false; - } - return true; -} - -bool ContainsOnlyWhitespace(const string16& str) { - return str.find_first_not_of(kWhitespaceUTF16) == string16::npos; -} - -template -static bool ContainsOnlyCharsT(const STR& input, const STR& characters) { - for (typename STR::const_iterator iter = input.begin(); - iter != input.end(); ++iter) { - if (characters.find(*iter) == STR::npos) - return false; - } - return true; -} - -bool ContainsOnlyChars(const std::wstring& input, - const std::wstring& characters) { - return ContainsOnlyCharsT(input, characters); -} - -#if !defined(WCHAR_T_IS_UTF16) -bool ContainsOnlyChars(const string16& input, const string16& characters) { - return ContainsOnlyCharsT(input, characters); -} -#endif - -bool ContainsOnlyChars(const std::string& input, - const std::string& characters) { - return ContainsOnlyCharsT(input, characters); -} - -std::string WideToASCII(const std::wstring& wide) { - DCHECK(IsStringASCII(wide)) << wide; - return std::string(wide.begin(), wide.end()); -} - -std::string UTF16ToASCII(const string16& utf16) { - DCHECK(IsStringASCII(utf16)) << utf16; - return std::string(utf16.begin(), utf16.end()); -} - -// Latin1 is just the low range of Unicode, so we can copy directly to convert. -bool WideToLatin1(const std::wstring& wide, std::string* latin1) { - std::string output; - output.resize(wide.size()); - latin1->clear(); - for (size_t i = 0; i < wide.size(); i++) { - if (wide[i] > 255) - return false; - output[i] = static_cast(wide[i]); - } - latin1->swap(output); - return true; -} - -template -static bool DoIsStringASCII(const STR& str) { - for (size_t i = 0; i < str.length(); i++) { - typename ToUnsigned::Unsigned c = str[i]; - if (c > 0x7F) - return false; - } - return true; -} - -bool IsStringASCII(const std::wstring& str) { - return DoIsStringASCII(str); -} - -#if !defined(WCHAR_T_IS_UTF16) -bool IsStringASCII(const string16& str) { - return DoIsStringASCII(str); -} -#endif - -bool IsStringASCII(const base::StringPiece& str) { - return DoIsStringASCII(str); -} - -bool IsStringUTF8(const std::string& str) { - const char *src = str.data(); - int32 src_len = static_cast(str.length()); - int32 char_index = 0; - - while (char_index < src_len) { - int32 code_point; - CBU8_NEXT(src, char_index, src_len, code_point); - if (!base::IsValidCharacter(code_point)) - return false; - } - return true; -} - -template -static inline bool DoLowerCaseEqualsASCII(Iter a_begin, - Iter a_end, - const char* b) { - for (Iter it = a_begin; it != a_end; ++it, ++b) { - if (!*b || base::ToLowerASCII(*it) != *b) - return false; - } - return *b == 0; -} - -// Front-ends for LowerCaseEqualsASCII. -bool LowerCaseEqualsASCII(const std::string& a, const char* b) { - return DoLowerCaseEqualsASCII(a.begin(), a.end(), b); -} - -bool LowerCaseEqualsASCII(const std::wstring& a, const char* b) { - return DoLowerCaseEqualsASCII(a.begin(), a.end(), b); -} - -#if !defined(WCHAR_T_IS_UTF16) -bool LowerCaseEqualsASCII(const string16& a, const char* b) { - return DoLowerCaseEqualsASCII(a.begin(), a.end(), b); -} -#endif - -bool LowerCaseEqualsASCII(std::string::const_iterator a_begin, - std::string::const_iterator a_end, - const char* b) { - return DoLowerCaseEqualsASCII(a_begin, a_end, b); -} - -bool LowerCaseEqualsASCII(std::wstring::const_iterator a_begin, - std::wstring::const_iterator a_end, - const char* b) { - return DoLowerCaseEqualsASCII(a_begin, a_end, b); -} - -#if !defined(WCHAR_T_IS_UTF16) -bool LowerCaseEqualsASCII(string16::const_iterator a_begin, - string16::const_iterator a_end, - const char* b) { - return DoLowerCaseEqualsASCII(a_begin, a_end, b); -} -#endif - -// TODO(port): Resolve wchar_t/iterator issues that require OS_ANDROID here. -#if !defined(OS_ANDROID) -bool LowerCaseEqualsASCII(const char* a_begin, - const char* a_end, - const char* b) { - return DoLowerCaseEqualsASCII(a_begin, a_end, b); -} - -bool LowerCaseEqualsASCII(const wchar_t* a_begin, - const wchar_t* a_end, - const char* b) { - return DoLowerCaseEqualsASCII(a_begin, a_end, b); -} - -#if !defined(WCHAR_T_IS_UTF16) -bool LowerCaseEqualsASCII(const char16* a_begin, - const char16* a_end, - const char* b) { - return DoLowerCaseEqualsASCII(a_begin, a_end, b); -} -#endif - -#endif // !defined(OS_ANDROID) - -bool EqualsASCII(const string16& a, const base::StringPiece& b) { - if (a.length() != b.length()) - return false; - return std::equal(b.begin(), b.end(), a.begin()); -} - -bool StartsWithASCII(const std::string& str, - const std::string& search, - bool case_sensitive) { - if (case_sensitive) - return str.compare(0, search.length(), search) == 0; - else - return base::strncasecmp(str.c_str(), search.c_str(), search.length()) == 0; -} - -template -bool StartsWithT(const STR& str, const STR& search, bool case_sensitive) { - if (case_sensitive) { - return str.compare(0, search.length(), search) == 0; - } else { - if (search.size() > str.size()) - return false; - return std::equal(search.begin(), search.end(), str.begin(), - base::CaseInsensitiveCompare()); - } -} - -bool StartsWith(const std::wstring& str, const std::wstring& search, - bool case_sensitive) { - return StartsWithT(str, search, case_sensitive); -} - -#if !defined(WCHAR_T_IS_UTF16) -bool StartsWith(const string16& str, const string16& search, - bool case_sensitive) { - return StartsWithT(str, search, case_sensitive); -} -#endif - -template -bool EndsWithT(const STR& str, const STR& search, bool case_sensitive) { - typename STR::size_type str_length = str.length(); - typename STR::size_type search_length = search.length(); - if (search_length > str_length) - return false; - if (case_sensitive) { - return str.compare(str_length - search_length, search_length, search) == 0; - } else { - return std::equal(search.begin(), search.end(), - str.begin() + (str_length - search_length), - base::CaseInsensitiveCompare()); - } -} - -bool EndsWith(const std::string& str, const std::string& search, - bool case_sensitive) { - return EndsWithT(str, search, case_sensitive); -} - -bool EndsWith(const std::wstring& str, const std::wstring& search, - bool case_sensitive) { - return EndsWithT(str, search, case_sensitive); -} - -#if !defined(WCHAR_T_IS_UTF16) -bool EndsWith(const string16& str, const string16& search, - bool case_sensitive) { - return EndsWithT(str, search, case_sensitive); -} -#endif - -static const char* const kByteStringsUnlocalized[] = { - " B", - " kB", - " MB", - " GB", - " TB", - " PB" -}; - -string16 FormatBytesUnlocalized(int64 bytes) { - double unit_amount = static_cast(bytes); - size_t dimension = 0; - const int kKilo = 1024; - while (unit_amount >= kKilo && - dimension < arraysize(kByteStringsUnlocalized) - 1) { - unit_amount /= kKilo; - dimension++; - } - - char buf[64]; - if (bytes != 0 && dimension > 0 && unit_amount < 100) { - base::snprintf(buf, arraysize(buf), "%.1lf%s", unit_amount, - kByteStringsUnlocalized[dimension]); - } else { - base::snprintf(buf, arraysize(buf), "%.0lf%s", unit_amount, - kByteStringsUnlocalized[dimension]); - } - - return ASCIIToUTF16(buf); -} - -template -void DoReplaceSubstringsAfterOffset(StringType* str, - typename StringType::size_type start_offset, - const StringType& find_this, - const StringType& replace_with, - bool replace_all) { - if ((start_offset == StringType::npos) || (start_offset >= str->length())) - return; - - DCHECK(!find_this.empty()); - for (typename StringType::size_type offs(str->find(find_this, start_offset)); - offs != StringType::npos; offs = str->find(find_this, offs)) { - str->replace(offs, find_this.length(), replace_with); - offs += replace_with.length(); - - if (!replace_all) - break; - } -} - -void ReplaceFirstSubstringAfterOffset(string16* str, - string16::size_type start_offset, - const string16& find_this, - const string16& replace_with) { - DoReplaceSubstringsAfterOffset(str, start_offset, find_this, replace_with, - false); // replace first instance -} - -void ReplaceFirstSubstringAfterOffset(std::string* str, - std::string::size_type start_offset, - const std::string& find_this, - const std::string& replace_with) { - DoReplaceSubstringsAfterOffset(str, start_offset, find_this, replace_with, - false); // replace first instance -} - -void ReplaceSubstringsAfterOffset(string16* str, - string16::size_type start_offset, - const string16& find_this, - const string16& replace_with) { - DoReplaceSubstringsAfterOffset(str, start_offset, find_this, replace_with, - true); // replace all instances -} - -void ReplaceSubstringsAfterOffset(std::string* str, - std::string::size_type start_offset, - const std::string& find_this, - const std::string& replace_with) { - DoReplaceSubstringsAfterOffset(str, start_offset, find_this, replace_with, - true); // replace all instances -} - - -template -static size_t TokenizeT(const STR& str, - const STR& delimiters, - std::vector* tokens) { - tokens->clear(); - - typename STR::size_type start = str.find_first_not_of(delimiters); - while (start != STR::npos) { - typename STR::size_type end = str.find_first_of(delimiters, start + 1); - if (end == STR::npos) { - tokens->push_back(str.substr(start)); - break; - } else { - tokens->push_back(str.substr(start, end - start)); - start = str.find_first_not_of(delimiters, end + 1); - } - } - - return tokens->size(); -} - -size_t Tokenize(const std::wstring& str, - const std::wstring& delimiters, - std::vector* tokens) { - return TokenizeT(str, delimiters, tokens); -} - -#if !defined(WCHAR_T_IS_UTF16) -size_t Tokenize(const string16& str, - const string16& delimiters, - std::vector* tokens) { - return TokenizeT(str, delimiters, tokens); -} -#endif - -size_t Tokenize(const std::string& str, - const std::string& delimiters, - std::vector* tokens) { - return TokenizeT(str, delimiters, tokens); -} - -size_t Tokenize(const base::StringPiece& str, - const base::StringPiece& delimiters, - std::vector* tokens) { - return TokenizeT(str, delimiters, tokens); -} - -template -static STR JoinStringT(const std::vector& parts, const STR& sep) { - if (parts.empty()) - return STR(); - - STR result(parts[0]); - typename std::vector::const_iterator iter = parts.begin(); - ++iter; - - for (; iter != parts.end(); ++iter) { - result += sep; - result += *iter; - } - - return result; -} - -std::string JoinString(const std::vector& parts, char sep) { - return JoinStringT(parts, std::string(1, sep)); -} - -string16 JoinString(const std::vector& parts, char16 sep) { - return JoinStringT(parts, string16(1, sep)); -} - -std::string JoinString(const std::vector& parts, - const std::string& separator) { - return JoinStringT(parts, separator); -} - -string16 JoinString(const std::vector& parts, - const string16& separator) { - return JoinStringT(parts, separator); -} - -template -OutStringType DoReplaceStringPlaceholders(const FormatStringType& format_string, - const std::vector& subst, std::vector* offsets) { - size_t substitutions = subst.size(); - - size_t sub_length = 0; - for (typename std::vector::const_iterator iter = subst.begin(); - iter != subst.end(); ++iter) { - sub_length += iter->length(); - } - - OutStringType formatted; - formatted.reserve(format_string.length() + sub_length); - - std::vector r_offsets; - for (typename FormatStringType::const_iterator i = format_string.begin(); - i != format_string.end(); ++i) { - if ('$' == *i) { - if (i + 1 != format_string.end()) { - ++i; - DCHECK('$' == *i || '1' <= *i) << "Invalid placeholder: " << *i; - if ('$' == *i) { - while (i != format_string.end() && '$' == *i) { - formatted.push_back('$'); - ++i; - } - --i; - } else { - uintptr_t index = 0; - while (i != format_string.end() && '0' <= *i && *i <= '9') { - index *= 10; - index += *i - '0'; - ++i; - } - --i; - index -= 1; - if (offsets) { - ReplacementOffset r_offset(index, - static_cast(formatted.size())); - r_offsets.insert(std::lower_bound(r_offsets.begin(), - r_offsets.end(), - r_offset, - &CompareParameter), - r_offset); - } - if (index < substitutions) - formatted.append(subst.at(index)); - } - } - } else { - formatted.push_back(*i); - } - } - if (offsets) { - for (std::vector::const_iterator i = r_offsets.begin(); - i != r_offsets.end(); ++i) { - offsets->push_back(i->offset); - } - } - return formatted; -} - -string16 ReplaceStringPlaceholders(const string16& format_string, - const std::vector& subst, - std::vector* offsets) { - return DoReplaceStringPlaceholders(format_string, subst, offsets); -} - -std::string ReplaceStringPlaceholders(const base::StringPiece& format_string, - const std::vector& subst, - std::vector* offsets) { - return DoReplaceStringPlaceholders(format_string, subst, offsets); -} - -string16 ReplaceStringPlaceholders(const string16& format_string, - const string16& a, - size_t* offset) { - std::vector offsets; - std::vector subst; - subst.push_back(a); - string16 result = ReplaceStringPlaceholders(format_string, subst, &offsets); - - DCHECK(offsets.size() == 1); - if (offset) { - *offset = offsets[0]; - } - return result; -} - -static bool IsWildcard(base_icu::UChar32 character) { - return character == '*' || character == '?'; -} - -// Move the strings pointers to the point where they start to differ. -template -static void EatSameChars(const CHAR** pattern, const CHAR* pattern_end, - const CHAR** string, const CHAR* string_end, - NEXT next) { - const CHAR* escape = NULL; - while (*pattern != pattern_end && *string != string_end) { - if (!escape && IsWildcard(**pattern)) { - // We don't want to match wildcard here, except if it's escaped. - return; - } - - // Check if the escapement char is found. If so, skip it and move to the - // next character. - if (!escape && **pattern == '\\') { - escape = *pattern; - next(pattern, pattern_end); - continue; - } - - // Check if the chars match, if so, increment the ptrs. - const CHAR* pattern_next = *pattern; - const CHAR* string_next = *string; - base_icu::UChar32 pattern_char = next(&pattern_next, pattern_end); - if (pattern_char == next(&string_next, string_end) && - pattern_char != (base_icu::UChar32) CBU_SENTINEL) { - *pattern = pattern_next; - *string = string_next; - } else { - // Uh ho, it did not match, we are done. If the last char was an - // escapement, that means that it was an error to advance the ptr here, - // let's put it back where it was. This also mean that the MatchPattern - // function will return false because if we can't match an escape char - // here, then no one will. - if (escape) { - *pattern = escape; - } - return; - } - - escape = NULL; - } -} - -template -static void EatWildcard(const CHAR** pattern, const CHAR* end, NEXT next) { - while (*pattern != end) { - if (!IsWildcard(**pattern)) - return; - next(pattern, end); - } -} - -template -static bool MatchPatternT(const CHAR* eval, const CHAR* eval_end, - const CHAR* pattern, const CHAR* pattern_end, - int depth, - NEXT next) { - const int kMaxDepth = 16; - if (depth > kMaxDepth) - return false; - - // Eat all the matching chars. - EatSameChars(&pattern, pattern_end, &eval, eval_end, next); - - // If the string is empty, then the pattern must be empty too, or contains - // only wildcards. - if (eval == eval_end) { - EatWildcard(&pattern, pattern_end, next); - return pattern == pattern_end; - } - - // Pattern is empty but not string, this is not a match. - if (pattern == pattern_end) - return false; - - // If this is a question mark, then we need to compare the rest with - // the current string or the string with one character eaten. - const CHAR* next_pattern = pattern; - next(&next_pattern, pattern_end); - if (pattern[0] == '?') { - if (MatchPatternT(eval, eval_end, next_pattern, pattern_end, - depth + 1, next)) - return true; - const CHAR* next_eval = eval; - next(&next_eval, eval_end); - if (MatchPatternT(next_eval, eval_end, next_pattern, pattern_end, - depth + 1, next)) - return true; - } - - // This is a *, try to match all the possible substrings with the remainder - // of the pattern. - if (pattern[0] == '*') { - // Collapse duplicate wild cards (********** into *) so that the - // method does not recurse unnecessarily. http://crbug.com/52839 - EatWildcard(&next_pattern, pattern_end, next); - - while (eval != eval_end) { - if (MatchPatternT(eval, eval_end, next_pattern, pattern_end, - depth + 1, next)) - return true; - eval++; - } - - // We reached the end of the string, let see if the pattern contains only - // wildcards. - if (eval == eval_end) { - EatWildcard(&pattern, pattern_end, next); - if (pattern != pattern_end) - return false; - return true; - } - } - - return false; -} - -struct NextCharUTF8 { - base_icu::UChar32 operator()(const char** p, const char* end) { - base_icu::UChar32 c; - int offset = 0; - CBU8_NEXT(*p, offset, end - *p, c); - *p += offset; - return c; - } -}; - -struct NextCharUTF16 { - base_icu::UChar32 operator()(const char16** p, const char16* end) { - base_icu::UChar32 c; - int offset = 0; - CBU16_NEXT(*p, offset, end - *p, c); - *p += offset; - return c; - } -}; - -bool MatchPattern(const base::StringPiece& eval, - const base::StringPiece& pattern) { - return MatchPatternT(eval.data(), eval.data() + eval.size(), - pattern.data(), pattern.data() + pattern.size(), - 0, NextCharUTF8()); -} - -bool MatchPattern(const string16& eval, const string16& pattern) { - return MatchPatternT(eval.c_str(), eval.c_str() + eval.size(), - pattern.c_str(), pattern.c_str() + pattern.size(), - 0, NextCharUTF16()); -} - -// The following code is compatible with the OpenBSD lcpy interface. See: -// http://www.gratisoft.us/todd/papers/strlcpy.html -// ftp://ftp.openbsd.org/pub/OpenBSD/src/lib/libc/string/{wcs,str}lcpy.c - -namespace { - -template -size_t lcpyT(CHAR* dst, const CHAR* src, size_t dst_size) { - for (size_t i = 0; i < dst_size; ++i) { - if ((dst[i] = src[i]) == 0) // We hit and copied the terminating NULL. - return i; - } - - // We were left off at dst_size. We over copied 1 byte. Null terminate. - if (dst_size != 0) - dst[dst_size - 1] = 0; - - // Count the rest of the |src|, and return it's length in characters. - while (src[dst_size]) ++dst_size; - return dst_size; -} - -} // namespace - -size_t base::strlcpy(char* dst, const char* src, size_t dst_size) { - return lcpyT(dst, src, dst_size); -} -size_t base::wcslcpy(wchar_t* dst, const wchar_t* src, size_t dst_size) { - return lcpyT(dst, src, dst_size); -} diff --git a/base/strings/string_util.h b/base/strings/string_util.h deleted file mode 100644 index d2a216efaf..0000000000 --- a/base/strings/string_util.h +++ /dev/null @@ -1,576 +0,0 @@ -// Copyright 2013 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. -// -// This file defines utility functions for working with strings. - -#ifndef BASE_STRINGS_STRING_UTIL_H_ -#define BASE_STRINGS_STRING_UTIL_H_ - -#include -#include // va_list - -#include -#include - -#include "base/base_export.h" -#include "base/basictypes.h" -#include "base/compiler_specific.h" -#include "base/strings/string16.h" -#include "base/strings/string_piece.h" // For implicit conversions. - -// Safe standard library wrappers for all platforms. - -namespace base { - -// C standard-library functions like "strncasecmp" and "snprintf" that aren't -// cross-platform are provided as "base::strncasecmp", and their prototypes -// are listed below. These functions are then implemented as inline calls -// to the platform-specific equivalents in the platform-specific headers. - -// Compares the two strings s1 and s2 without regard to case using -// the current locale; returns 0 if they are equal, 1 if s1 > s2, and -1 if -// s2 > s1 according to a lexicographic comparison. -int strcasecmp(const char* s1, const char* s2); - -// Compares up to count characters of s1 and s2 without regard to case using -// the current locale; returns 0 if they are equal, 1 if s1 > s2, and -1 if -// s2 > s1 according to a lexicographic comparison. -int strncasecmp(const char* s1, const char* s2, size_t count); - -// Same as strncmp but for char16 strings. -int strncmp16(const char16* s1, const char16* s2, size_t count); - -// Wrapper for vsnprintf that always null-terminates and always returns the -// number of characters that would be in an untruncated formatted -// string, even when truncation occurs. -int vsnprintf(char* buffer, size_t size, const char* format, va_list arguments) - PRINTF_FORMAT(3, 0); - -// vswprintf always null-terminates, but when truncation occurs, it will either -// return -1 or the number of characters that would be in an untruncated -// formatted string. The actual return value depends on the underlying -// C library's vswprintf implementation. -int vswprintf(wchar_t* buffer, size_t size, - const wchar_t* format, va_list arguments) - WPRINTF_FORMAT(3, 0); - -// Some of these implementations need to be inlined. - -// We separate the declaration from the implementation of this inline -// function just so the PRINTF_FORMAT works. -inline int snprintf(char* buffer, size_t size, const char* format, ...) - PRINTF_FORMAT(3, 4); -inline int snprintf(char* buffer, size_t size, const char* format, ...) { - va_list arguments; - va_start(arguments, format); - int result = vsnprintf(buffer, size, format, arguments); - va_end(arguments); - return result; -} - -// We separate the declaration from the implementation of this inline -// function just so the WPRINTF_FORMAT works. -inline int swprintf(wchar_t* buffer, size_t size, const wchar_t* format, ...) - WPRINTF_FORMAT(3, 4); -inline int swprintf(wchar_t* buffer, size_t size, const wchar_t* format, ...) { - va_list arguments; - va_start(arguments, format); - int result = vswprintf(buffer, size, format, arguments); - va_end(arguments); - return result; -} - -// BSD-style safe and consistent string copy functions. -// Copies |src| to |dst|, where |dst_size| is the total allocated size of |dst|. -// Copies at most |dst_size|-1 characters, and always NULL terminates |dst|, as -// long as |dst_size| is not 0. Returns the length of |src| in characters. -// If the return value is >= dst_size, then the output was truncated. -// NOTE: All sizes are in number of characters, NOT in bytes. -BASE_EXPORT size_t strlcpy(char* dst, const char* src, size_t dst_size); -BASE_EXPORT size_t wcslcpy(wchar_t* dst, const wchar_t* src, size_t dst_size); - -// Scan a wprintf format string to determine whether it's portable across a -// variety of systems. This function only checks that the conversion -// specifiers used by the format string are supported and have the same meaning -// on a variety of systems. It doesn't check for other errors that might occur -// within a format string. -// -// Nonportable conversion specifiers for wprintf are: -// - 's' and 'c' without an 'l' length modifier. %s and %c operate on char -// data on all systems except Windows, which treat them as wchar_t data. -// Use %ls and %lc for wchar_t data instead. -// - 'S' and 'C', which operate on wchar_t data on all systems except Windows, -// which treat them as char data. Use %ls and %lc for wchar_t data -// instead. -// - 'F', which is not identified by Windows wprintf documentation. -// - 'D', 'O', and 'U', which are deprecated and not available on all systems. -// Use %ld, %lo, and %lu instead. -// -// Note that there is no portable conversion specifier for char data when -// working with wprintf. -// -// This function is intended to be called from base::vswprintf. -BASE_EXPORT bool IsWprintfFormatPortable(const wchar_t* format); - -// ASCII-specific tolower. The standard library's tolower is locale sensitive, -// so we don't want to use it here. -template inline Char ToLowerASCII(Char c) { - return (c >= 'A' && c <= 'Z') ? (c + ('a' - 'A')) : c; -} - -// ASCII-specific toupper. The standard library's toupper is locale sensitive, -// so we don't want to use it here. -template inline Char ToUpperASCII(Char c) { - return (c >= 'a' && c <= 'z') ? (c + ('A' - 'a')) : c; -} - -// Function objects to aid in comparing/searching strings. - -template struct CaseInsensitiveCompare { - public: - bool operator()(Char x, Char y) const { - // TODO(darin): Do we really want to do locale sensitive comparisons here? - // See http://crbug.com/24917 - return tolower(x) == tolower(y); - } -}; - -template struct CaseInsensitiveCompareASCII { - public: - bool operator()(Char x, Char y) const { - return ToLowerASCII(x) == ToLowerASCII(y); - } -}; - -} // namespace base - -#if defined(OS_WIN) -#include "base/strings/string_util_win.h" -#elif defined(OS_POSIX) -#include "base/strings/string_util_posix.h" -#else -#error Define string operations appropriately for your platform -#endif - -// These threadsafe functions return references to globally unique empty -// strings. -// -// DO NOT USE THESE AS A GENERAL-PURPOSE SUBSTITUTE FOR DEFAULT CONSTRUCTORS. -// There is only one case where you should use these: functions which need to -// return a string by reference (e.g. as a class member accessor), and don't -// have an empty string to use (e.g. in an error case). These should not be -// used as initializers, function arguments, or return values for functions -// which return by value or outparam. -BASE_EXPORT const std::string& EmptyString(); -BASE_EXPORT const std::wstring& EmptyWString(); -BASE_EXPORT const string16& EmptyString16(); - -BASE_EXPORT extern const wchar_t kWhitespaceWide[]; -BASE_EXPORT extern const char16 kWhitespaceUTF16[]; -BASE_EXPORT extern const char kWhitespaceASCII[]; - -BASE_EXPORT extern const char kUtf8ByteOrderMark[]; - -// Removes characters in |remove_chars| from anywhere in |input|. Returns true -// if any characters were removed. |remove_chars| must be null-terminated. -// NOTE: Safe to use the same variable for both |input| and |output|. -BASE_EXPORT bool RemoveChars(const string16& input, - const char16 remove_chars[], - string16* output); -BASE_EXPORT bool RemoveChars(const std::string& input, - const char remove_chars[], - std::string* output); - -// Replaces characters in |replace_chars| from anywhere in |input| with -// |replace_with|. Each character in |replace_chars| will be replaced with -// the |replace_with| string. Returns true if any characters were replaced. -// |replace_chars| must be null-terminated. -// NOTE: Safe to use the same variable for both |input| and |output|. -BASE_EXPORT bool ReplaceChars(const string16& input, - const char16 replace_chars[], - const string16& replace_with, - string16* output); -BASE_EXPORT bool ReplaceChars(const std::string& input, - const char replace_chars[], - const std::string& replace_with, - std::string* output); - -// Removes characters in |trim_chars| from the beginning and end of |input|. -// |trim_chars| must be null-terminated. -// NOTE: Safe to use the same variable for both |input| and |output|. -BASE_EXPORT bool TrimString(const std::wstring& input, - const wchar_t trim_chars[], - std::wstring* output); -BASE_EXPORT bool TrimString(const string16& input, - const char16 trim_chars[], - string16* output); -BASE_EXPORT bool TrimString(const std::string& input, - const char trim_chars[], - std::string* output); - -// Truncates a string to the nearest UTF-8 character that will leave -// the string less than or equal to the specified byte size. -BASE_EXPORT void TruncateUTF8ToByteSize(const std::string& input, - const size_t byte_size, - std::string* output); - -// Trims any whitespace from either end of the input string. Returns where -// whitespace was found. -// The non-wide version has two functions: -// * TrimWhitespaceASCII() -// This function is for ASCII strings and only looks for ASCII whitespace; -// Please choose the best one according to your usage. -// NOTE: Safe to use the same variable for both input and output. -enum TrimPositions { - TRIM_NONE = 0, - TRIM_LEADING = 1 << 0, - TRIM_TRAILING = 1 << 1, - TRIM_ALL = TRIM_LEADING | TRIM_TRAILING, -}; -BASE_EXPORT TrimPositions TrimWhitespace(const string16& input, - TrimPositions positions, - string16* output); -BASE_EXPORT TrimPositions TrimWhitespaceASCII(const std::string& input, - TrimPositions positions, - std::string* output); - -// Deprecated. This function is only for backward compatibility and calls -// TrimWhitespaceASCII(). -BASE_EXPORT TrimPositions TrimWhitespace(const std::string& input, - TrimPositions positions, - std::string* output); - -// Searches for CR or LF characters. Removes all contiguous whitespace -// strings that contain them. This is useful when trying to deal with text -// copied from terminals. -// Returns |text|, with the following three transformations: -// (1) Leading and trailing whitespace is trimmed. -// (2) If |trim_sequences_with_line_breaks| is true, any other whitespace -// sequences containing a CR or LF are trimmed. -// (3) All other whitespace sequences are converted to single spaces. -BASE_EXPORT std::wstring CollapseWhitespace( - const std::wstring& text, - bool trim_sequences_with_line_breaks); -BASE_EXPORT string16 CollapseWhitespace( - const string16& text, - bool trim_sequences_with_line_breaks); -BASE_EXPORT std::string CollapseWhitespaceASCII( - const std::string& text, - bool trim_sequences_with_line_breaks); - -// Returns true if the passed string is empty or contains only white-space -// characters. -BASE_EXPORT bool ContainsOnlyWhitespaceASCII(const std::string& str); -BASE_EXPORT bool ContainsOnlyWhitespace(const string16& str); - -// Returns true if |input| is empty or contains only characters found in -// |characters|. -BASE_EXPORT bool ContainsOnlyChars(const std::wstring& input, - const std::wstring& characters); -BASE_EXPORT bool ContainsOnlyChars(const string16& input, - const string16& characters); -BASE_EXPORT bool ContainsOnlyChars(const std::string& input, - const std::string& characters); - -// Converts to 7-bit ASCII by truncating. The result must be known to be ASCII -// beforehand. -BASE_EXPORT std::string WideToASCII(const std::wstring& wide); -BASE_EXPORT std::string UTF16ToASCII(const string16& utf16); - -// Converts the given wide string to the corresponding Latin1. This will fail -// (return false) if any characters are more than 255. -BASE_EXPORT bool WideToLatin1(const std::wstring& wide, std::string* latin1); - -// Returns true if the specified string matches the criteria. How can a wide -// string be 8-bit or UTF8? It contains only characters that are < 256 (in the -// first case) or characters that use only 8-bits and whose 8-bit -// representation looks like a UTF-8 string (the second case). -// -// Note that IsStringUTF8 checks not only if the input is structurally -// valid but also if it doesn't contain any non-character codepoint -// (e.g. U+FFFE). It's done on purpose because all the existing callers want -// to have the maximum 'discriminating' power from other encodings. If -// there's a use case for just checking the structural validity, we have to -// add a new function for that. -BASE_EXPORT bool IsStringUTF8(const std::string& str); -BASE_EXPORT bool IsStringASCII(const std::wstring& str); -BASE_EXPORT bool IsStringASCII(const base::StringPiece& str); -BASE_EXPORT bool IsStringASCII(const string16& str); - -// Converts the elements of the given string. This version uses a pointer to -// clearly differentiate it from the non-pointer variant. -template inline void StringToLowerASCII(str* s) { - for (typename str::iterator i = s->begin(); i != s->end(); ++i) - *i = base::ToLowerASCII(*i); -} - -template inline str StringToLowerASCII(const str& s) { - // for std::string and std::wstring - str output(s); - StringToLowerASCII(&output); - return output; -} - -// Converts the elements of the given string. This version uses a pointer to -// clearly differentiate it from the non-pointer variant. -template inline void StringToUpperASCII(str* s) { - for (typename str::iterator i = s->begin(); i != s->end(); ++i) - *i = base::ToUpperASCII(*i); -} - -template inline str StringToUpperASCII(const str& s) { - // for std::string and std::wstring - str output(s); - StringToUpperASCII(&output); - return output; -} - -// Compare the lower-case form of the given string against the given ASCII -// string. This is useful for doing checking if an input string matches some -// token, and it is optimized to avoid intermediate string copies. This API is -// borrowed from the equivalent APIs in Mozilla. -BASE_EXPORT bool LowerCaseEqualsASCII(const std::string& a, const char* b); -BASE_EXPORT bool LowerCaseEqualsASCII(const std::wstring& a, const char* b); -BASE_EXPORT bool LowerCaseEqualsASCII(const string16& a, const char* b); - -// Same thing, but with string iterators instead. -BASE_EXPORT bool LowerCaseEqualsASCII(std::string::const_iterator a_begin, - std::string::const_iterator a_end, - const char* b); -BASE_EXPORT bool LowerCaseEqualsASCII(std::wstring::const_iterator a_begin, - std::wstring::const_iterator a_end, - const char* b); -BASE_EXPORT bool LowerCaseEqualsASCII(string16::const_iterator a_begin, - string16::const_iterator a_end, - const char* b); -BASE_EXPORT bool LowerCaseEqualsASCII(const char* a_begin, - const char* a_end, - const char* b); -BASE_EXPORT bool LowerCaseEqualsASCII(const wchar_t* a_begin, - const wchar_t* a_end, - const char* b); -BASE_EXPORT bool LowerCaseEqualsASCII(const char16* a_begin, - const char16* a_end, - const char* b); - -// Performs a case-sensitive string compare. The behavior is undefined if both -// strings are not ASCII. -BASE_EXPORT bool EqualsASCII(const string16& a, const base::StringPiece& b); - -// Returns true if str starts with search, or false otherwise. -BASE_EXPORT bool StartsWithASCII(const std::string& str, - const std::string& search, - bool case_sensitive); -BASE_EXPORT bool StartsWith(const std::wstring& str, - const std::wstring& search, - bool case_sensitive); -BASE_EXPORT bool StartsWith(const string16& str, - const string16& search, - bool case_sensitive); - -// Returns true if str ends with search, or false otherwise. -BASE_EXPORT bool EndsWith(const std::string& str, - const std::string& search, - bool case_sensitive); -BASE_EXPORT bool EndsWith(const std::wstring& str, - const std::wstring& search, - bool case_sensitive); -BASE_EXPORT bool EndsWith(const string16& str, - const string16& search, - bool case_sensitive); - - -// Determines the type of ASCII character, independent of locale (the C -// library versions will change based on locale). -template -inline bool IsAsciiWhitespace(Char c) { - return c == ' ' || c == '\r' || c == '\n' || c == '\t'; -} -template -inline bool IsAsciiAlpha(Char c) { - return ((c >= 'A') && (c <= 'Z')) || ((c >= 'a') && (c <= 'z')); -} -template -inline bool IsAsciiDigit(Char c) { - return c >= '0' && c <= '9'; -} - -template -inline bool IsHexDigit(Char c) { - return (c >= '0' && c <= '9') || - (c >= 'A' && c <= 'F') || - (c >= 'a' && c <= 'f'); -} - -template -inline Char HexDigitToInt(Char c) { - DCHECK(IsHexDigit(c)); - if (c >= '0' && c <= '9') - return c - '0'; - if (c >= 'A' && c <= 'F') - return c - 'A' + 10; - if (c >= 'a' && c <= 'f') - return c - 'a' + 10; - return 0; -} - -// Returns true if it's a whitespace character. -inline bool IsWhitespace(wchar_t c) { - return wcschr(kWhitespaceWide, c) != NULL; -} - -// Return a byte string in human-readable format with a unit suffix. Not -// appropriate for use in any UI; use of FormatBytes and friends in ui/base is -// highly recommended instead. TODO(avi): Figure out how to get callers to use -// FormatBytes instead; remove this. -BASE_EXPORT string16 FormatBytesUnlocalized(int64 bytes); - -// Starting at |start_offset| (usually 0), replace the first instance of -// |find_this| with |replace_with|. -BASE_EXPORT void ReplaceFirstSubstringAfterOffset( - string16* str, - string16::size_type start_offset, - const string16& find_this, - const string16& replace_with); -BASE_EXPORT void ReplaceFirstSubstringAfterOffset( - std::string* str, - std::string::size_type start_offset, - const std::string& find_this, - const std::string& replace_with); - -// Starting at |start_offset| (usually 0), look through |str| and replace all -// instances of |find_this| with |replace_with|. -// -// This does entire substrings; use std::replace in for single -// characters, for example: -// std::replace(str.begin(), str.end(), 'a', 'b'); -BASE_EXPORT void ReplaceSubstringsAfterOffset( - string16* str, - string16::size_type start_offset, - const string16& find_this, - const string16& replace_with); -BASE_EXPORT void ReplaceSubstringsAfterOffset( - std::string* str, - std::string::size_type start_offset, - const std::string& find_this, - const std::string& replace_with); - -// Reserves enough memory in |str| to accommodate |length_with_null| characters, -// sets the size of |str| to |length_with_null - 1| characters, and returns a -// pointer to the underlying contiguous array of characters. This is typically -// used when calling a function that writes results into a character array, but -// the caller wants the data to be managed by a string-like object. It is -// convenient in that is can be used inline in the call, and fast in that it -// avoids copying the results of the call from a char* into a string. -// -// |length_with_null| must be at least 2, since otherwise the underlying string -// would have size 0, and trying to access &((*str)[0]) in that case can result -// in a number of problems. -// -// Internally, this takes linear time because the resize() call 0-fills the -// underlying array for potentially all -// (|length_with_null - 1| * sizeof(string_type::value_type)) bytes. Ideally we -// could avoid this aspect of the resize() call, as we expect the caller to -// immediately write over this memory, but there is no other way to set the size -// of the string, and not doing that will mean people who access |str| rather -// than str.c_str() will get back a string of whatever size |str| had on entry -// to this function (probably 0). -template -inline typename string_type::value_type* WriteInto(string_type* str, - size_t length_with_null) { - DCHECK_GT(length_with_null, 1u); - str->reserve(length_with_null); - str->resize(length_with_null - 1); - return &((*str)[0]); -} - -//----------------------------------------------------------------------------- - -// Splits a string into its fields delimited by any of the characters in -// |delimiters|. Each field is added to the |tokens| vector. Returns the -// number of tokens found. -BASE_EXPORT size_t Tokenize(const std::wstring& str, - const std::wstring& delimiters, - std::vector* tokens); -BASE_EXPORT size_t Tokenize(const string16& str, - const string16& delimiters, - std::vector* tokens); -BASE_EXPORT size_t Tokenize(const std::string& str, - const std::string& delimiters, - std::vector* tokens); -BASE_EXPORT size_t Tokenize(const base::StringPiece& str, - const base::StringPiece& delimiters, - std::vector* tokens); - -// Does the opposite of SplitString(). -BASE_EXPORT string16 JoinString(const std::vector& parts, char16 s); -BASE_EXPORT std::string JoinString( - const std::vector& parts, char s); - -// Join |parts| using |separator|. -BASE_EXPORT std::string JoinString( - const std::vector& parts, - const std::string& separator); -BASE_EXPORT string16 JoinString( - const std::vector& parts, - const string16& separator); - -// Replace $1-$2-$3..$9 in the format string with |a|-|b|-|c|..|i| respectively. -// Additionally, any number of consecutive '$' characters is replaced by that -// number less one. Eg $$->$, $$$->$$, etc. The offsets parameter here can be -// NULL. This only allows you to use up to nine replacements. -BASE_EXPORT string16 ReplaceStringPlaceholders( - const string16& format_string, - const std::vector& subst, - std::vector* offsets); - -BASE_EXPORT std::string ReplaceStringPlaceholders( - const base::StringPiece& format_string, - const std::vector& subst, - std::vector* offsets); - -// Single-string shortcut for ReplaceStringHolders. |offset| may be NULL. -BASE_EXPORT string16 ReplaceStringPlaceholders(const string16& format_string, - const string16& a, - size_t* offset); - -// Returns true if the string passed in matches the pattern. The pattern -// string can contain wildcards like * and ? -// The backslash character (\) is an escape character for * and ? -// We limit the patterns to having a max of 16 * or ? characters. -// ? matches 0 or 1 character, while * matches 0 or more characters. -BASE_EXPORT bool MatchPattern(const base::StringPiece& string, - const base::StringPiece& pattern); -BASE_EXPORT bool MatchPattern(const string16& string, const string16& pattern); - -// Hack to convert any char-like type to its unsigned counterpart. -// For example, it will convert char, signed char and unsigned char to unsigned -// char. -template -struct ToUnsigned { - typedef T Unsigned; -}; - -template<> -struct ToUnsigned { - typedef unsigned char Unsigned; -}; -template<> -struct ToUnsigned { - typedef unsigned char Unsigned; -}; -template<> -struct ToUnsigned { -#if defined(WCHAR_T_IS_UTF16) - typedef unsigned short Unsigned; -#elif defined(WCHAR_T_IS_UTF32) - typedef uint32 Unsigned; -#endif -}; -template<> -struct ToUnsigned { - typedef unsigned short Unsigned; -}; - -#endif // BASE_STRINGS_STRING_UTIL_H_ diff --git a/base/strings/string_util_constants.cc b/base/strings/string_util_constants.cc deleted file mode 100644 index d92e40cf37..0000000000 --- a/base/strings/string_util_constants.cc +++ /dev/null @@ -1,55 +0,0 @@ -// Copyright 2013 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "base/strings/string_util.h" - -#define WHITESPACE_UNICODE \ - 0x0009, /* to */ \ - 0x000A, \ - 0x000B, \ - 0x000C, \ - 0x000D, \ - 0x0020, /* Space */ \ - 0x0085, /* */ \ - 0x00A0, /* No-Break Space */ \ - 0x1680, /* Ogham Space Mark */ \ - 0x180E, /* Mongolian Vowel Separator */ \ - 0x2000, /* En Quad to Hair Space */ \ - 0x2001, \ - 0x2002, \ - 0x2003, \ - 0x2004, \ - 0x2005, \ - 0x2006, \ - 0x2007, \ - 0x2008, \ - 0x2009, \ - 0x200A, \ - 0x200C, /* Zero Width Non-Joiner */ \ - 0x2028, /* Line Separator */ \ - 0x2029, /* Paragraph Separator */ \ - 0x202F, /* Narrow No-Break Space */ \ - 0x205F, /* Medium Mathematical Space */ \ - 0x3000, /* Ideographic Space */ \ - 0 - -const wchar_t kWhitespaceWide[] = { - WHITESPACE_UNICODE -}; - -const char16 kWhitespaceUTF16[] = { - WHITESPACE_UNICODE -}; - -const char kWhitespaceASCII[] = { - 0x09, // to - 0x0A, - 0x0B, - 0x0C, - 0x0D, - 0x20, // Space - 0 -}; - -const char kUtf8ByteOrderMark[] = "\xEF\xBB\xBF"; diff --git a/base/strings/string_util_posix.h b/base/strings/string_util_posix.h deleted file mode 100644 index 34b14f178f..0000000000 --- a/base/strings/string_util_posix.h +++ /dev/null @@ -1,53 +0,0 @@ -// Copyright 2013 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef BASE_STRINGS_STRING_UTIL_POSIX_H_ -#define BASE_STRINGS_STRING_UTIL_POSIX_H_ - -#include -#include -#include -#include - -#include "base/logging.h" -#include "base/strings/string_util.h" - -namespace base { - -// Chromium code style is to not use malloc'd strings; this is only for use -// for interaction with APIs that require it. -inline char* strdup(const char* str) { - return ::strdup(str); -} - -inline int strcasecmp(const char* string1, const char* string2) { - return ::strcasecmp(string1, string2); -} - -inline int strncasecmp(const char* string1, const char* string2, size_t count) { - return ::strncasecmp(string1, string2, count); -} - -inline int vsnprintf(char* buffer, size_t size, - const char* format, va_list arguments) { - return ::vsnprintf(buffer, size, format, arguments); -} - -inline int strncmp16(const char16* s1, const char16* s2, size_t count) { -#if defined(WCHAR_T_IS_UTF16) - return ::wcsncmp(s1, s2, count); -#elif defined(WCHAR_T_IS_UTF32) - return c16memcmp(s1, s2, count); -#endif -} - -inline int vswprintf(wchar_t* buffer, size_t size, - const wchar_t* format, va_list arguments) { - DCHECK(IsWprintfFormatPortable(format)); - return ::vswprintf(buffer, size, format, arguments); -} - -} // namespace base - -#endif // BASE_STRINGS_STRING_UTIL_POSIX_H_ diff --git a/base/strings/string_util_unittest.cc b/base/strings/string_util_unittest.cc deleted file mode 100644 index 58b7620b35..0000000000 --- a/base/strings/string_util_unittest.cc +++ /dev/null @@ -1,1191 +0,0 @@ -// Copyright 2013 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "base/strings/string_util.h" - -#include -#include - -#include -#include - -#include "base/basictypes.h" -#include "base/strings/string16.h" -#include "base/strings/utf_string_conversions.h" -#include "testing/gmock/include/gmock/gmock.h" -#include "testing/gtest/include/gtest/gtest.h" - -using ::testing::ElementsAre; - -namespace base { - -static const struct trim_case { - const wchar_t* input; - const TrimPositions positions; - const wchar_t* output; - const TrimPositions return_value; -} trim_cases[] = { - {L" Google Video ", TRIM_LEADING, L"Google Video ", TRIM_LEADING}, - {L" Google Video ", TRIM_TRAILING, L" Google Video", TRIM_TRAILING}, - {L" Google Video ", TRIM_ALL, L"Google Video", TRIM_ALL}, - {L"Google Video", TRIM_ALL, L"Google Video", TRIM_NONE}, - {L"", TRIM_ALL, L"", TRIM_NONE}, - {L" ", TRIM_LEADING, L"", TRIM_LEADING}, - {L" ", TRIM_TRAILING, L"", TRIM_TRAILING}, - {L" ", TRIM_ALL, L"", TRIM_ALL}, - {L"\t\rTest String\n", TRIM_ALL, L"Test String", TRIM_ALL}, - {L"\x2002Test String\x00A0\x3000", TRIM_ALL, L"Test String", TRIM_ALL}, -}; - -static const struct trim_case_ascii { - const char* input; - const TrimPositions positions; - const char* output; - const TrimPositions return_value; -} trim_cases_ascii[] = { - {" Google Video ", TRIM_LEADING, "Google Video ", TRIM_LEADING}, - {" Google Video ", TRIM_TRAILING, " Google Video", TRIM_TRAILING}, - {" Google Video ", TRIM_ALL, "Google Video", TRIM_ALL}, - {"Google Video", TRIM_ALL, "Google Video", TRIM_NONE}, - {"", TRIM_ALL, "", TRIM_NONE}, - {" ", TRIM_LEADING, "", TRIM_LEADING}, - {" ", TRIM_TRAILING, "", TRIM_TRAILING}, - {" ", TRIM_ALL, "", TRIM_ALL}, - {"\t\rTest String\n", TRIM_ALL, "Test String", TRIM_ALL}, -}; - -namespace { - -// Helper used to test TruncateUTF8ToByteSize. -bool Truncated(const std::string& input, const size_t byte_size, - std::string* output) { - size_t prev = input.length(); - TruncateUTF8ToByteSize(input, byte_size, output); - return prev != output->length(); -} - -} // namespace - -TEST(StringUtilTest, TruncateUTF8ToByteSize) { - std::string output; - - // Empty strings and invalid byte_size arguments - EXPECT_FALSE(Truncated(std::string(), 0, &output)); - EXPECT_EQ(output, ""); - EXPECT_TRUE(Truncated("\xe1\x80\xbf", 0, &output)); - EXPECT_EQ(output, ""); - EXPECT_FALSE(Truncated("\xe1\x80\xbf", -1, &output)); - EXPECT_FALSE(Truncated("\xe1\x80\xbf", 4, &output)); - - // Testing the truncation of valid UTF8 correctly - EXPECT_TRUE(Truncated("abc", 2, &output)); - EXPECT_EQ(output, "ab"); - EXPECT_TRUE(Truncated("\xc2\x81\xc2\x81", 2, &output)); - EXPECT_EQ(output.compare("\xc2\x81"), 0); - EXPECT_TRUE(Truncated("\xc2\x81\xc2\x81", 3, &output)); - EXPECT_EQ(output.compare("\xc2\x81"), 0); - EXPECT_FALSE(Truncated("\xc2\x81\xc2\x81", 4, &output)); - EXPECT_EQ(output.compare("\xc2\x81\xc2\x81"), 0); - - { - const char array[] = "\x00\x00\xc2\x81\xc2\x81"; - const std::string array_string(array, arraysize(array)); - EXPECT_TRUE(Truncated(array_string, 4, &output)); - EXPECT_EQ(output.compare(std::string("\x00\x00\xc2\x81", 4)), 0); - } - - { - const char array[] = "\x00\xc2\x81\xc2\x81"; - const std::string array_string(array, arraysize(array)); - EXPECT_TRUE(Truncated(array_string, 4, &output)); - EXPECT_EQ(output.compare(std::string("\x00\xc2\x81", 3)), 0); - } - - // Testing invalid UTF8 - EXPECT_TRUE(Truncated("\xed\xa0\x80\xed\xbf\xbf", 6, &output)); - EXPECT_EQ(output.compare(""), 0); - EXPECT_TRUE(Truncated("\xed\xa0\x8f", 3, &output)); - EXPECT_EQ(output.compare(""), 0); - EXPECT_TRUE(Truncated("\xed\xbf\xbf", 3, &output)); - EXPECT_EQ(output.compare(""), 0); - - // Testing invalid UTF8 mixed with valid UTF8 - EXPECT_FALSE(Truncated("\xe1\x80\xbf", 3, &output)); - EXPECT_EQ(output.compare("\xe1\x80\xbf"), 0); - EXPECT_FALSE(Truncated("\xf1\x80\xa0\xbf", 4, &output)); - EXPECT_EQ(output.compare("\xf1\x80\xa0\xbf"), 0); - EXPECT_FALSE(Truncated("a\xc2\x81\xe1\x80\xbf\xf1\x80\xa0\xbf", - 10, &output)); - EXPECT_EQ(output.compare("a\xc2\x81\xe1\x80\xbf\xf1\x80\xa0\xbf"), 0); - EXPECT_TRUE(Truncated("a\xc2\x81\xe1\x80\xbf\xf1""a""\x80\xa0", - 10, &output)); - EXPECT_EQ(output.compare("a\xc2\x81\xe1\x80\xbf\xf1""a"), 0); - EXPECT_FALSE(Truncated("\xef\xbb\xbf" "abc", 6, &output)); - EXPECT_EQ(output.compare("\xef\xbb\xbf" "abc"), 0); - - // Overlong sequences - EXPECT_TRUE(Truncated("\xc0\x80", 2, &output)); - EXPECT_EQ(output.compare(""), 0); - EXPECT_TRUE(Truncated("\xc1\x80\xc1\x81", 4, &output)); - EXPECT_EQ(output.compare(""), 0); - EXPECT_TRUE(Truncated("\xe0\x80\x80", 3, &output)); - EXPECT_EQ(output.compare(""), 0); - EXPECT_TRUE(Truncated("\xe0\x82\x80", 3, &output)); - EXPECT_EQ(output.compare(""), 0); - EXPECT_TRUE(Truncated("\xe0\x9f\xbf", 3, &output)); - EXPECT_EQ(output.compare(""), 0); - EXPECT_TRUE(Truncated("\xf0\x80\x80\x8D", 4, &output)); - EXPECT_EQ(output.compare(""), 0); - EXPECT_TRUE(Truncated("\xf0\x80\x82\x91", 4, &output)); - EXPECT_EQ(output.compare(""), 0); - EXPECT_TRUE(Truncated("\xf0\x80\xa0\x80", 4, &output)); - EXPECT_EQ(output.compare(""), 0); - EXPECT_TRUE(Truncated("\xf0\x8f\xbb\xbf", 4, &output)); - EXPECT_EQ(output.compare(""), 0); - EXPECT_TRUE(Truncated("\xf8\x80\x80\x80\xbf", 5, &output)); - EXPECT_EQ(output.compare(""), 0); - EXPECT_TRUE(Truncated("\xfc\x80\x80\x80\xa0\xa5", 6, &output)); - EXPECT_EQ(output.compare(""), 0); - - // Beyond U+10FFFF (the upper limit of Unicode codespace) - EXPECT_TRUE(Truncated("\xf4\x90\x80\x80", 4, &output)); - EXPECT_EQ(output.compare(""), 0); - EXPECT_TRUE(Truncated("\xf8\xa0\xbf\x80\xbf", 5, &output)); - EXPECT_EQ(output.compare(""), 0); - EXPECT_TRUE(Truncated("\xfc\x9c\xbf\x80\xbf\x80", 6, &output)); - EXPECT_EQ(output.compare(""), 0); - - // BOMs in UTF-16(BE|LE) and UTF-32(BE|LE) - EXPECT_TRUE(Truncated("\xfe\xff", 2, &output)); - EXPECT_EQ(output.compare(""), 0); - EXPECT_TRUE(Truncated("\xff\xfe", 2, &output)); - EXPECT_EQ(output.compare(""), 0); - - { - const char array[] = "\x00\x00\xfe\xff"; - const std::string array_string(array, arraysize(array)); - EXPECT_TRUE(Truncated(array_string, 4, &output)); - EXPECT_EQ(output.compare(std::string("\x00\x00", 2)), 0); - } - - // Variants on the previous test - { - const char array[] = "\xff\xfe\x00\x00"; - const std::string array_string(array, 4); - EXPECT_FALSE(Truncated(array_string, 4, &output)); - EXPECT_EQ(output.compare(std::string("\xff\xfe\x00\x00", 4)), 0); - } - { - const char array[] = "\xff\x00\x00\xfe"; - const std::string array_string(array, arraysize(array)); - EXPECT_TRUE(Truncated(array_string, 4, &output)); - EXPECT_EQ(output.compare(std::string("\xff\x00\x00", 3)), 0); - } - - // Non-characters : U+xxFFF[EF] where xx is 0x00 through 0x10 and - EXPECT_TRUE(Truncated("\xef\xbf\xbe", 3, &output)); - EXPECT_EQ(output.compare(""), 0); - EXPECT_TRUE(Truncated("\xf0\x8f\xbf\xbe", 4, &output)); - EXPECT_EQ(output.compare(""), 0); - EXPECT_TRUE(Truncated("\xf3\xbf\xbf\xbf", 4, &output)); - EXPECT_EQ(output.compare(""), 0); - EXPECT_TRUE(Truncated("\xef\xb7\x90", 3, &output)); - EXPECT_EQ(output.compare(""), 0); - EXPECT_TRUE(Truncated("\xef\xb7\xaf", 3, &output)); - EXPECT_EQ(output.compare(""), 0); - - // Strings in legacy encodings that are valid in UTF-8, but - // are invalid as UTF-8 in real data. - EXPECT_TRUE(Truncated("caf\xe9", 4, &output)); - EXPECT_EQ(output.compare("caf"), 0); - EXPECT_TRUE(Truncated("\xb0\xa1\xb0\xa2", 4, &output)); - EXPECT_EQ(output.compare(""), 0); - EXPECT_FALSE(Truncated("\xa7\x41\xa6\x6e", 4, &output)); - EXPECT_EQ(output.compare("\xa7\x41\xa6\x6e"), 0); - EXPECT_TRUE(Truncated("\xa7\x41\xa6\x6e\xd9\xee\xe4\xee", 7, - &output)); - EXPECT_EQ(output.compare("\xa7\x41\xa6\x6e"), 0); - - // Testing using the same string as input and output. - EXPECT_FALSE(Truncated(output, 4, &output)); - EXPECT_EQ(output.compare("\xa7\x41\xa6\x6e"), 0); - EXPECT_TRUE(Truncated(output, 3, &output)); - EXPECT_EQ(output.compare("\xa7\x41"), 0); - - // "abc" with U+201[CD] in windows-125[0-8] - EXPECT_TRUE(Truncated("\x93" "abc\x94", 5, &output)); - EXPECT_EQ(output.compare("\x93" "abc"), 0); - - // U+0639 U+064E U+0644 U+064E in ISO-8859-6 - EXPECT_TRUE(Truncated("\xd9\xee\xe4\xee", 4, &output)); - EXPECT_EQ(output.compare(""), 0); - - // U+03B3 U+03B5 U+03B9 U+03AC in ISO-8859-7 - EXPECT_TRUE(Truncated("\xe3\xe5\xe9\xdC", 4, &output)); - EXPECT_EQ(output.compare(""), 0); -} - -TEST(StringUtilTest, TrimWhitespace) { - string16 output; // Allow contents to carry over to next testcase - for (size_t i = 0; i < arraysize(trim_cases); ++i) { - const trim_case& value = trim_cases[i]; - EXPECT_EQ(value.return_value, - TrimWhitespace(WideToUTF16(value.input), value.positions, - &output)); - EXPECT_EQ(WideToUTF16(value.output), output); - } - - // Test that TrimWhitespace() can take the same string for input and output - output = ASCIIToUTF16(" This is a test \r\n"); - EXPECT_EQ(TRIM_ALL, TrimWhitespace(output, TRIM_ALL, &output)); - EXPECT_EQ(ASCIIToUTF16("This is a test"), output); - - // Once more, but with a string of whitespace - output = ASCIIToUTF16(" \r\n"); - EXPECT_EQ(TRIM_ALL, TrimWhitespace(output, TRIM_ALL, &output)); - EXPECT_EQ(string16(), output); - - std::string output_ascii; - for (size_t i = 0; i < arraysize(trim_cases_ascii); ++i) { - const trim_case_ascii& value = trim_cases_ascii[i]; - EXPECT_EQ(value.return_value, - TrimWhitespace(value.input, value.positions, &output_ascii)); - EXPECT_EQ(value.output, output_ascii); - } -} - -static const struct collapse_case { - const wchar_t* input; - const bool trim; - const wchar_t* output; -} collapse_cases[] = { - {L" Google Video ", false, L"Google Video"}, - {L"Google Video", false, L"Google Video"}, - {L"", false, L""}, - {L" ", false, L""}, - {L"\t\rTest String\n", false, L"Test String"}, - {L"\x2002Test String\x00A0\x3000", false, L"Test String"}, - {L" Test \n \t String ", false, L"Test String"}, - {L"\x2002Test\x1680 \x2028 \tString\x00A0\x3000", false, L"Test String"}, - {L" Test String", false, L"Test String"}, - {L"Test String ", false, L"Test String"}, - {L"Test String", false, L"Test String"}, - {L"", true, L""}, - {L"\n", true, L""}, - {L" \r ", true, L""}, - {L"\nFoo", true, L"Foo"}, - {L"\r Foo ", true, L"Foo"}, - {L" Foo bar ", true, L"Foo bar"}, - {L" \tFoo bar \n", true, L"Foo bar"}, - {L" a \r b\n c \r\n d \t\re \t f \n ", true, L"abcde f"}, -}; - -TEST(StringUtilTest, CollapseWhitespace) { - for (size_t i = 0; i < arraysize(collapse_cases); ++i) { - const collapse_case& value = collapse_cases[i]; - EXPECT_EQ(value.output, CollapseWhitespace(value.input, value.trim)); - } -} - -static const struct collapse_case_ascii { - const char* input; - const bool trim; - const char* output; -} collapse_cases_ascii[] = { - {" Google Video ", false, "Google Video"}, - {"Google Video", false, "Google Video"}, - {"", false, ""}, - {" ", false, ""}, - {"\t\rTest String\n", false, "Test String"}, - {" Test \n \t String ", false, "Test String"}, - {" Test String", false, "Test String"}, - {"Test String ", false, "Test String"}, - {"Test String", false, "Test String"}, - {"", true, ""}, - {"\n", true, ""}, - {" \r ", true, ""}, - {"\nFoo", true, "Foo"}, - {"\r Foo ", true, "Foo"}, - {" Foo bar ", true, "Foo bar"}, - {" \tFoo bar \n", true, "Foo bar"}, - {" a \r b\n c \r\n d \t\re \t f \n ", true, "abcde f"}, -}; - -TEST(StringUtilTest, CollapseWhitespaceASCII) { - for (size_t i = 0; i < arraysize(collapse_cases_ascii); ++i) { - const collapse_case_ascii& value = collapse_cases_ascii[i]; - EXPECT_EQ(value.output, CollapseWhitespaceASCII(value.input, value.trim)); - } -} - -TEST(StringUtilTest, ContainsOnlyWhitespaceASCII) { - EXPECT_TRUE(ContainsOnlyWhitespaceASCII(std::string())); - EXPECT_TRUE(ContainsOnlyWhitespaceASCII(" ")); - EXPECT_TRUE(ContainsOnlyWhitespaceASCII("\t")); - EXPECT_TRUE(ContainsOnlyWhitespaceASCII("\t \r \n ")); - EXPECT_FALSE(ContainsOnlyWhitespaceASCII("a")); - EXPECT_FALSE(ContainsOnlyWhitespaceASCII("\thello\r \n ")); -} - -TEST(StringUtilTest, ContainsOnlyWhitespace) { - EXPECT_TRUE(ContainsOnlyWhitespace(string16())); - EXPECT_TRUE(ContainsOnlyWhitespace(ASCIIToUTF16(" "))); - EXPECT_TRUE(ContainsOnlyWhitespace(ASCIIToUTF16("\t"))); - EXPECT_TRUE(ContainsOnlyWhitespace(ASCIIToUTF16("\t \r \n "))); - EXPECT_FALSE(ContainsOnlyWhitespace(ASCIIToUTF16("a"))); - EXPECT_FALSE(ContainsOnlyWhitespace(ASCIIToUTF16("\thello\r \n "))); -} - -TEST(StringUtilTest, IsStringUTF8) { - EXPECT_TRUE(IsStringUTF8("abc")); - EXPECT_TRUE(IsStringUTF8("\xc2\x81")); - EXPECT_TRUE(IsStringUTF8("\xe1\x80\xbf")); - EXPECT_TRUE(IsStringUTF8("\xf1\x80\xa0\xbf")); - EXPECT_TRUE(IsStringUTF8("a\xc2\x81\xe1\x80\xbf\xf1\x80\xa0\xbf")); - EXPECT_TRUE(IsStringUTF8("\xef\xbb\xbf" "abc")); // UTF-8 BOM - - // surrogate code points - EXPECT_FALSE(IsStringUTF8("\xed\xa0\x80\xed\xbf\xbf")); - EXPECT_FALSE(IsStringUTF8("\xed\xa0\x8f")); - EXPECT_FALSE(IsStringUTF8("\xed\xbf\xbf")); - - // overlong sequences - EXPECT_FALSE(IsStringUTF8("\xc0\x80")); // U+0000 - EXPECT_FALSE(IsStringUTF8("\xc1\x80\xc1\x81")); // "AB" - EXPECT_FALSE(IsStringUTF8("\xe0\x80\x80")); // U+0000 - EXPECT_FALSE(IsStringUTF8("\xe0\x82\x80")); // U+0080 - EXPECT_FALSE(IsStringUTF8("\xe0\x9f\xbf")); // U+07ff - EXPECT_FALSE(IsStringUTF8("\xf0\x80\x80\x8D")); // U+000D - EXPECT_FALSE(IsStringUTF8("\xf0\x80\x82\x91")); // U+0091 - EXPECT_FALSE(IsStringUTF8("\xf0\x80\xa0\x80")); // U+0800 - EXPECT_FALSE(IsStringUTF8("\xf0\x8f\xbb\xbf")); // U+FEFF (BOM) - EXPECT_FALSE(IsStringUTF8("\xf8\x80\x80\x80\xbf")); // U+003F - EXPECT_FALSE(IsStringUTF8("\xfc\x80\x80\x80\xa0\xa5")); // U+00A5 - - // Beyond U+10FFFF (the upper limit of Unicode codespace) - EXPECT_FALSE(IsStringUTF8("\xf4\x90\x80\x80")); // U+110000 - EXPECT_FALSE(IsStringUTF8("\xf8\xa0\xbf\x80\xbf")); // 5 bytes - EXPECT_FALSE(IsStringUTF8("\xfc\x9c\xbf\x80\xbf\x80")); // 6 bytes - - // BOMs in UTF-16(BE|LE) and UTF-32(BE|LE) - EXPECT_FALSE(IsStringUTF8("\xfe\xff")); - EXPECT_FALSE(IsStringUTF8("\xff\xfe")); - EXPECT_FALSE(IsStringUTF8(std::string("\x00\x00\xfe\xff", 4))); - EXPECT_FALSE(IsStringUTF8("\xff\xfe\x00\x00")); - - // Non-characters : U+xxFFF[EF] where xx is 0x00 through 0x10 and - EXPECT_FALSE(IsStringUTF8("\xef\xbf\xbe")); // U+FFFE) - EXPECT_FALSE(IsStringUTF8("\xf0\x8f\xbf\xbe")); // U+1FFFE - EXPECT_FALSE(IsStringUTF8("\xf3\xbf\xbf\xbf")); // U+10FFFF - EXPECT_FALSE(IsStringUTF8("\xef\xb7\x90")); // U+FDD0 - EXPECT_FALSE(IsStringUTF8("\xef\xb7\xaf")); // U+FDEF - // Strings in legacy encodings. We can certainly make up strings - // in a legacy encoding that are valid in UTF-8, but in real data, - // most of them are invalid as UTF-8. - EXPECT_FALSE(IsStringUTF8("caf\xe9")); // cafe with U+00E9 in ISO-8859-1 - EXPECT_FALSE(IsStringUTF8("\xb0\xa1\xb0\xa2")); // U+AC00, U+AC001 in EUC-KR - EXPECT_FALSE(IsStringUTF8("\xa7\x41\xa6\x6e")); // U+4F60 U+597D in Big5 - // "abc" with U+201[CD] in windows-125[0-8] - EXPECT_FALSE(IsStringUTF8("\x93" "abc\x94")); - // U+0639 U+064E U+0644 U+064E in ISO-8859-6 - EXPECT_FALSE(IsStringUTF8("\xd9\xee\xe4\xee")); - // U+03B3 U+03B5 U+03B9 U+03AC in ISO-8859-7 - EXPECT_FALSE(IsStringUTF8("\xe3\xe5\xe9\xdC")); - - // Check that we support Embedded Nulls. The first uses the canonical UTF-8 - // representation, and the second uses a 2-byte sequence. The second version - // is invalid UTF-8 since UTF-8 states that the shortest encoding for a - // given codepoint must be used. - static const char kEmbeddedNull[] = "embedded\0null"; - EXPECT_TRUE(IsStringUTF8( - std::string(kEmbeddedNull, sizeof(kEmbeddedNull)))); - EXPECT_FALSE(IsStringUTF8("embedded\xc0\x80U+0000")); -} - -TEST(StringUtilTest, ConvertASCII) { - static const char* char_cases[] = { - "Google Video", - "Hello, world\n", - "0123ABCDwxyz \a\b\t\r\n!+,.~" - }; - - static const wchar_t* const wchar_cases[] = { - L"Google Video", - L"Hello, world\n", - L"0123ABCDwxyz \a\b\t\r\n!+,.~" - }; - - for (size_t i = 0; i < arraysize(char_cases); ++i) { - EXPECT_TRUE(IsStringASCII(char_cases[i])); - std::wstring wide = ASCIIToWide(char_cases[i]); - EXPECT_EQ(wchar_cases[i], wide); - - EXPECT_TRUE(IsStringASCII(wchar_cases[i])); - std::string ascii = WideToASCII(wchar_cases[i]); - EXPECT_EQ(char_cases[i], ascii); - } - - EXPECT_FALSE(IsStringASCII("Google \x80Video")); - EXPECT_FALSE(IsStringASCII(L"Google \x80Video")); - - // Convert empty strings. - std::wstring wempty; - std::string empty; - EXPECT_EQ(empty, WideToASCII(wempty)); - EXPECT_EQ(wempty, ASCIIToWide(empty)); - - // Convert strings with an embedded NUL character. - const char chars_with_nul[] = "test\0string"; - const int length_with_nul = arraysize(chars_with_nul) - 1; - std::string string_with_nul(chars_with_nul, length_with_nul); - std::wstring wide_with_nul = ASCIIToWide(string_with_nul); - EXPECT_EQ(static_cast(length_with_nul), - wide_with_nul.length()); - std::string narrow_with_nul = WideToASCII(wide_with_nul); - EXPECT_EQ(static_cast(length_with_nul), - narrow_with_nul.length()); - EXPECT_EQ(0, string_with_nul.compare(narrow_with_nul)); -} - -TEST(StringUtilTest, ToUpperASCII) { - EXPECT_EQ('C', ToUpperASCII('C')); - EXPECT_EQ('C', ToUpperASCII('c')); - EXPECT_EQ('2', ToUpperASCII('2')); - - EXPECT_EQ(L'C', ToUpperASCII(L'C')); - EXPECT_EQ(L'C', ToUpperASCII(L'c')); - EXPECT_EQ(L'2', ToUpperASCII(L'2')); - - std::string in_place_a("Cc2"); - StringToUpperASCII(&in_place_a); - EXPECT_EQ("CC2", in_place_a); - - std::wstring in_place_w(L"Cc2"); - StringToUpperASCII(&in_place_w); - EXPECT_EQ(L"CC2", in_place_w); - - std::string original_a("Cc2"); - std::string upper_a = StringToUpperASCII(original_a); - EXPECT_EQ("CC2", upper_a); - - std::wstring original_w(L"Cc2"); - std::wstring upper_w = StringToUpperASCII(original_w); - EXPECT_EQ(L"CC2", upper_w); -} - -TEST(StringUtilTest, LowerCaseEqualsASCII) { - static const struct { - const wchar_t* src_w; - const char* src_a; - const char* dst; - } lowercase_cases[] = { - { L"FoO", "FoO", "foo" }, - { L"foo", "foo", "foo" }, - { L"FOO", "FOO", "foo" }, - }; - - for (size_t i = 0; i < ARRAYSIZE_UNSAFE(lowercase_cases); ++i) { - EXPECT_TRUE(LowerCaseEqualsASCII(lowercase_cases[i].src_w, - lowercase_cases[i].dst)); - EXPECT_TRUE(LowerCaseEqualsASCII(lowercase_cases[i].src_a, - lowercase_cases[i].dst)); - } -} - -TEST(StringUtilTest, FormatBytesUnlocalized) { - static const struct { - int64 bytes; - const char* expected; - } cases[] = { - // Expected behavior: we show one post-decimal digit when we have - // under two pre-decimal digits, except in cases where it makes no - // sense (zero or bytes). - // Since we switch units once we cross the 1000 mark, this keeps - // the display of file sizes or bytes consistently around three - // digits. - {0, "0 B"}, - {512, "512 B"}, - {1024*1024, "1.0 MB"}, - {1024*1024*1024, "1.0 GB"}, - {10LL*1024*1024*1024, "10.0 GB"}, - {99LL*1024*1024*1024, "99.0 GB"}, - {105LL*1024*1024*1024, "105 GB"}, - {105LL*1024*1024*1024 + 500LL*1024*1024, "105 GB"}, - {~(1LL<<63), "8192 PB"}, - - {99*1024 + 103, "99.1 kB"}, - {1024*1024 + 103, "1.0 MB"}, - {1024*1024 + 205 * 1024, "1.2 MB"}, - {1024*1024*1024 + (927 * 1024*1024), "1.9 GB"}, - {10LL*1024*1024*1024, "10.0 GB"}, - {100LL*1024*1024*1024, "100 GB"}, - }; - - for (size_t i = 0; i < ARRAYSIZE_UNSAFE(cases); ++i) { - EXPECT_EQ(ASCIIToUTF16(cases[i].expected), - FormatBytesUnlocalized(cases[i].bytes)); - } -} -TEST(StringUtilTest, ReplaceSubstringsAfterOffset) { - static const struct { - const char* str; - string16::size_type start_offset; - const char* find_this; - const char* replace_with; - const char* expected; - } cases[] = { - {"aaa", 0, "a", "b", "bbb"}, - {"abb", 0, "ab", "a", "ab"}, - {"Removing some substrings inging", 0, "ing", "", "Remov some substrs "}, - {"Not found", 0, "x", "0", "Not found"}, - {"Not found again", 5, "x", "0", "Not found again"}, - {" Making it much longer ", 0, " ", "Four score and seven years ago", - "Four score and seven years agoMakingFour score and seven years agoit" - "Four score and seven years agomuchFour score and seven years agolonger" - "Four score and seven years ago"}, - {"Invalid offset", 9999, "t", "foobar", "Invalid offset"}, - {"Replace me only me once", 9, "me ", "", "Replace me only once"}, - {"abababab", 2, "ab", "c", "abccc"}, - }; - - for (size_t i = 0; i < ARRAYSIZE_UNSAFE(cases); i++) { - string16 str = ASCIIToUTF16(cases[i].str); - ReplaceSubstringsAfterOffset(&str, cases[i].start_offset, - ASCIIToUTF16(cases[i].find_this), - ASCIIToUTF16(cases[i].replace_with)); - EXPECT_EQ(ASCIIToUTF16(cases[i].expected), str); - } -} - -TEST(StringUtilTest, ReplaceFirstSubstringAfterOffset) { - static const struct { - const char* str; - string16::size_type start_offset; - const char* find_this; - const char* replace_with; - const char* expected; - } cases[] = { - {"aaa", 0, "a", "b", "baa"}, - {"abb", 0, "ab", "a", "ab"}, - {"Removing some substrings inging", 0, "ing", "", - "Remov some substrings inging"}, - {"Not found", 0, "x", "0", "Not found"}, - {"Not found again", 5, "x", "0", "Not found again"}, - {" Making it much longer ", 0, " ", "Four score and seven years ago", - "Four score and seven years agoMaking it much longer "}, - {"Invalid offset", 9999, "t", "foobar", "Invalid offset"}, - {"Replace me only me once", 4, "me ", "", "Replace only me once"}, - {"abababab", 2, "ab", "c", "abcabab"}, - }; - - for (size_t i = 0; i < ARRAYSIZE_UNSAFE(cases); i++) { - string16 str = ASCIIToUTF16(cases[i].str); - ReplaceFirstSubstringAfterOffset(&str, cases[i].start_offset, - ASCIIToUTF16(cases[i].find_this), - ASCIIToUTF16(cases[i].replace_with)); - EXPECT_EQ(ASCIIToUTF16(cases[i].expected), str); - } -} - -TEST(StringUtilTest, HexDigitToInt) { - EXPECT_EQ(0, HexDigitToInt('0')); - EXPECT_EQ(1, HexDigitToInt('1')); - EXPECT_EQ(2, HexDigitToInt('2')); - EXPECT_EQ(3, HexDigitToInt('3')); - EXPECT_EQ(4, HexDigitToInt('4')); - EXPECT_EQ(5, HexDigitToInt('5')); - EXPECT_EQ(6, HexDigitToInt('6')); - EXPECT_EQ(7, HexDigitToInt('7')); - EXPECT_EQ(8, HexDigitToInt('8')); - EXPECT_EQ(9, HexDigitToInt('9')); - EXPECT_EQ(10, HexDigitToInt('A')); - EXPECT_EQ(11, HexDigitToInt('B')); - EXPECT_EQ(12, HexDigitToInt('C')); - EXPECT_EQ(13, HexDigitToInt('D')); - EXPECT_EQ(14, HexDigitToInt('E')); - EXPECT_EQ(15, HexDigitToInt('F')); - - // Verify the lower case as well. - EXPECT_EQ(10, HexDigitToInt('a')); - EXPECT_EQ(11, HexDigitToInt('b')); - EXPECT_EQ(12, HexDigitToInt('c')); - EXPECT_EQ(13, HexDigitToInt('d')); - EXPECT_EQ(14, HexDigitToInt('e')); - EXPECT_EQ(15, HexDigitToInt('f')); -} - -// This checks where we can use the assignment operator for a va_list. We need -// a way to do this since Visual C doesn't support va_copy, but assignment on -// va_list is not guaranteed to be a copy. See StringAppendVT which uses this -// capability. -static void VariableArgsFunc(const char* format, ...) { - va_list org; - va_start(org, format); - - va_list dup; - GG_VA_COPY(dup, org); - int i1 = va_arg(org, int); - int j1 = va_arg(org, int); - char* s1 = va_arg(org, char*); - double d1 = va_arg(org, double); - va_end(org); - - int i2 = va_arg(dup, int); - int j2 = va_arg(dup, int); - char* s2 = va_arg(dup, char*); - double d2 = va_arg(dup, double); - - EXPECT_EQ(i1, i2); - EXPECT_EQ(j1, j2); - EXPECT_STREQ(s1, s2); - EXPECT_EQ(d1, d2); - - va_end(dup); -} - -TEST(StringUtilTest, VAList) { - VariableArgsFunc("%d %d %s %lf", 45, 92, "This is interesting", 9.21); -} - -// Test for Tokenize -template -void TokenizeTest() { - std::vector r; - size_t size; - - size = Tokenize(STR("This is a string"), STR(" "), &r); - EXPECT_EQ(4U, size); - ASSERT_EQ(4U, r.size()); - EXPECT_EQ(r[0], STR("This")); - EXPECT_EQ(r[1], STR("is")); - EXPECT_EQ(r[2], STR("a")); - EXPECT_EQ(r[3], STR("string")); - r.clear(); - - size = Tokenize(STR("one,two,three"), STR(","), &r); - EXPECT_EQ(3U, size); - ASSERT_EQ(3U, r.size()); - EXPECT_EQ(r[0], STR("one")); - EXPECT_EQ(r[1], STR("two")); - EXPECT_EQ(r[2], STR("three")); - r.clear(); - - size = Tokenize(STR("one,two:three;four"), STR(",:"), &r); - EXPECT_EQ(3U, size); - ASSERT_EQ(3U, r.size()); - EXPECT_EQ(r[0], STR("one")); - EXPECT_EQ(r[1], STR("two")); - EXPECT_EQ(r[2], STR("three;four")); - r.clear(); - - size = Tokenize(STR("one,two:three;four"), STR(";,:"), &r); - EXPECT_EQ(4U, size); - ASSERT_EQ(4U, r.size()); - EXPECT_EQ(r[0], STR("one")); - EXPECT_EQ(r[1], STR("two")); - EXPECT_EQ(r[2], STR("three")); - EXPECT_EQ(r[3], STR("four")); - r.clear(); - - size = Tokenize(STR("one, two, three"), STR(","), &r); - EXPECT_EQ(3U, size); - ASSERT_EQ(3U, r.size()); - EXPECT_EQ(r[0], STR("one")); - EXPECT_EQ(r[1], STR(" two")); - EXPECT_EQ(r[2], STR(" three")); - r.clear(); - - size = Tokenize(STR("one, two, three, "), STR(","), &r); - EXPECT_EQ(4U, size); - ASSERT_EQ(4U, r.size()); - EXPECT_EQ(r[0], STR("one")); - EXPECT_EQ(r[1], STR(" two")); - EXPECT_EQ(r[2], STR(" three")); - EXPECT_EQ(r[3], STR(" ")); - r.clear(); - - size = Tokenize(STR("one, two, three,"), STR(","), &r); - EXPECT_EQ(3U, size); - ASSERT_EQ(3U, r.size()); - EXPECT_EQ(r[0], STR("one")); - EXPECT_EQ(r[1], STR(" two")); - EXPECT_EQ(r[2], STR(" three")); - r.clear(); - - size = Tokenize(STR(), STR(","), &r); - EXPECT_EQ(0U, size); - ASSERT_EQ(0U, r.size()); - r.clear(); - - size = Tokenize(STR(","), STR(","), &r); - EXPECT_EQ(0U, size); - ASSERT_EQ(0U, r.size()); - r.clear(); - - size = Tokenize(STR(",;:."), STR(".:;,"), &r); - EXPECT_EQ(0U, size); - ASSERT_EQ(0U, r.size()); - r.clear(); - - size = Tokenize(STR("\t\ta\t"), STR("\t"), &r); - EXPECT_EQ(1U, size); - ASSERT_EQ(1U, r.size()); - EXPECT_EQ(r[0], STR("a")); - r.clear(); - - size = Tokenize(STR("\ta\t\nb\tcc"), STR("\n"), &r); - EXPECT_EQ(2U, size); - ASSERT_EQ(2U, r.size()); - EXPECT_EQ(r[0], STR("\ta\t")); - EXPECT_EQ(r[1], STR("b\tcc")); - r.clear(); -} - -TEST(StringUtilTest, TokenizeStdString) { - TokenizeTest(); -} - -TEST(StringUtilTest, TokenizeStringPiece) { - TokenizeTest(); -} - -// Test for JoinString -TEST(StringUtilTest, JoinString) { - std::vector in; - EXPECT_EQ("", JoinString(in, ',')); - - in.push_back("a"); - EXPECT_EQ("a", JoinString(in, ',')); - - in.push_back("b"); - in.push_back("c"); - EXPECT_EQ("a,b,c", JoinString(in, ',')); - - in.push_back(std::string()); - EXPECT_EQ("a,b,c,", JoinString(in, ',')); - in.push_back(" "); - EXPECT_EQ("a|b|c|| ", JoinString(in, '|')); -} - -// Test for JoinString overloaded with std::string separator -TEST(StringUtilTest, JoinStringWithString) { - std::string separator(", "); - std::vector parts; - EXPECT_EQ(std::string(), JoinString(parts, separator)); - - parts.push_back("a"); - EXPECT_EQ("a", JoinString(parts, separator)); - - parts.push_back("b"); - parts.push_back("c"); - EXPECT_EQ("a, b, c", JoinString(parts, separator)); - - parts.push_back(std::string()); - EXPECT_EQ("a, b, c, ", JoinString(parts, separator)); - parts.push_back(" "); - EXPECT_EQ("a|b|c|| ", JoinString(parts, "|")); -} - -// Test for JoinString overloaded with string16 separator -TEST(StringUtilTest, JoinStringWithString16) { - string16 separator = ASCIIToUTF16(", "); - std::vector parts; - EXPECT_EQ(string16(), JoinString(parts, separator)); - - parts.push_back(ASCIIToUTF16("a")); - EXPECT_EQ(ASCIIToUTF16("a"), JoinString(parts, separator)); - - parts.push_back(ASCIIToUTF16("b")); - parts.push_back(ASCIIToUTF16("c")); - EXPECT_EQ(ASCIIToUTF16("a, b, c"), JoinString(parts, separator)); - - parts.push_back(ASCIIToUTF16("")); - EXPECT_EQ(ASCIIToUTF16("a, b, c, "), JoinString(parts, separator)); - parts.push_back(ASCIIToUTF16(" ")); - EXPECT_EQ(ASCIIToUTF16("a|b|c|| "), JoinString(parts, ASCIIToUTF16("|"))); -} - -TEST(StringUtilTest, StartsWith) { - EXPECT_TRUE(StartsWithASCII("javascript:url", "javascript", true)); - EXPECT_FALSE(StartsWithASCII("JavaScript:url", "javascript", true)); - EXPECT_TRUE(StartsWithASCII("javascript:url", "javascript", false)); - EXPECT_TRUE(StartsWithASCII("JavaScript:url", "javascript", false)); - EXPECT_FALSE(StartsWithASCII("java", "javascript", true)); - EXPECT_FALSE(StartsWithASCII("java", "javascript", false)); - EXPECT_FALSE(StartsWithASCII(std::string(), "javascript", false)); - EXPECT_FALSE(StartsWithASCII(std::string(), "javascript", true)); - EXPECT_TRUE(StartsWithASCII("java", std::string(), false)); - EXPECT_TRUE(StartsWithASCII("java", std::string(), true)); - - EXPECT_TRUE(StartsWith(L"javascript:url", L"javascript", true)); - EXPECT_FALSE(StartsWith(L"JavaScript:url", L"javascript", true)); - EXPECT_TRUE(StartsWith(L"javascript:url", L"javascript", false)); - EXPECT_TRUE(StartsWith(L"JavaScript:url", L"javascript", false)); - EXPECT_FALSE(StartsWith(L"java", L"javascript", true)); - EXPECT_FALSE(StartsWith(L"java", L"javascript", false)); - EXPECT_FALSE(StartsWith(std::wstring(), L"javascript", false)); - EXPECT_FALSE(StartsWith(std::wstring(), L"javascript", true)); - EXPECT_TRUE(StartsWith(L"java", std::wstring(), false)); - EXPECT_TRUE(StartsWith(L"java", std::wstring(), true)); -} - -TEST(StringUtilTest, EndsWith) { - EXPECT_TRUE(EndsWith(L"Foo.plugin", L".plugin", true)); - EXPECT_FALSE(EndsWith(L"Foo.Plugin", L".plugin", true)); - EXPECT_TRUE(EndsWith(L"Foo.plugin", L".plugin", false)); - EXPECT_TRUE(EndsWith(L"Foo.Plugin", L".plugin", false)); - EXPECT_FALSE(EndsWith(L".plug", L".plugin", true)); - EXPECT_FALSE(EndsWith(L".plug", L".plugin", false)); - EXPECT_FALSE(EndsWith(L"Foo.plugin Bar", L".plugin", true)); - EXPECT_FALSE(EndsWith(L"Foo.plugin Bar", L".plugin", false)); - EXPECT_FALSE(EndsWith(std::wstring(), L".plugin", false)); - EXPECT_FALSE(EndsWith(std::wstring(), L".plugin", true)); - EXPECT_TRUE(EndsWith(L"Foo.plugin", std::wstring(), false)); - EXPECT_TRUE(EndsWith(L"Foo.plugin", std::wstring(), true)); - EXPECT_TRUE(EndsWith(L".plugin", L".plugin", false)); - EXPECT_TRUE(EndsWith(L".plugin", L".plugin", true)); - EXPECT_TRUE(EndsWith(std::wstring(), std::wstring(), false)); - EXPECT_TRUE(EndsWith(std::wstring(), std::wstring(), true)); -} - -TEST(StringUtilTest, GetStringFWithOffsets) { - std::vector subst; - subst.push_back(ASCIIToUTF16("1")); - subst.push_back(ASCIIToUTF16("2")); - std::vector offsets; - - ReplaceStringPlaceholders(ASCIIToUTF16("Hello, $1. Your number is $2."), - subst, - &offsets); - EXPECT_EQ(2U, offsets.size()); - EXPECT_EQ(7U, offsets[0]); - EXPECT_EQ(25U, offsets[1]); - offsets.clear(); - - ReplaceStringPlaceholders(ASCIIToUTF16("Hello, $2. Your number is $1."), - subst, - &offsets); - EXPECT_EQ(2U, offsets.size()); - EXPECT_EQ(25U, offsets[0]); - EXPECT_EQ(7U, offsets[1]); - offsets.clear(); -} - -TEST(StringUtilTest, ReplaceStringPlaceholdersTooFew) { - // Test whether replacestringplaceholders works as expected when there - // are fewer inputs than outputs. - std::vector subst; - subst.push_back(ASCIIToUTF16("9a")); - subst.push_back(ASCIIToUTF16("8b")); - subst.push_back(ASCIIToUTF16("7c")); - - string16 formatted = - ReplaceStringPlaceholders( - ASCIIToUTF16("$1a,$2b,$3c,$4d,$5e,$6f,$1g,$2h,$3i"), subst, NULL); - - EXPECT_EQ(formatted, ASCIIToUTF16("9aa,8bb,7cc,d,e,f,9ag,8bh,7ci")); -} - -TEST(StringUtilTest, ReplaceStringPlaceholders) { - std::vector subst; - subst.push_back(ASCIIToUTF16("9a")); - subst.push_back(ASCIIToUTF16("8b")); - subst.push_back(ASCIIToUTF16("7c")); - subst.push_back(ASCIIToUTF16("6d")); - subst.push_back(ASCIIToUTF16("5e")); - subst.push_back(ASCIIToUTF16("4f")); - subst.push_back(ASCIIToUTF16("3g")); - subst.push_back(ASCIIToUTF16("2h")); - subst.push_back(ASCIIToUTF16("1i")); - - string16 formatted = - ReplaceStringPlaceholders( - ASCIIToUTF16("$1a,$2b,$3c,$4d,$5e,$6f,$7g,$8h,$9i"), subst, NULL); - - EXPECT_EQ(formatted, ASCIIToUTF16("9aa,8bb,7cc,6dd,5ee,4ff,3gg,2hh,1ii")); -} - -TEST(StringUtilTest, ReplaceStringPlaceholdersMoreThan9Replacements) { - std::vector subst; - subst.push_back(ASCIIToUTF16("9a")); - subst.push_back(ASCIIToUTF16("8b")); - subst.push_back(ASCIIToUTF16("7c")); - subst.push_back(ASCIIToUTF16("6d")); - subst.push_back(ASCIIToUTF16("5e")); - subst.push_back(ASCIIToUTF16("4f")); - subst.push_back(ASCIIToUTF16("3g")); - subst.push_back(ASCIIToUTF16("2h")); - subst.push_back(ASCIIToUTF16("1i")); - subst.push_back(ASCIIToUTF16("0j")); - subst.push_back(ASCIIToUTF16("-1k")); - subst.push_back(ASCIIToUTF16("-2l")); - subst.push_back(ASCIIToUTF16("-3m")); - subst.push_back(ASCIIToUTF16("-4n")); - - string16 formatted = - ReplaceStringPlaceholders( - ASCIIToUTF16("$1a,$2b,$3c,$4d,$5e,$6f,$7g,$8h,$9i," - "$10j,$11k,$12l,$13m,$14n,$1"), subst, NULL); - - EXPECT_EQ(formatted, ASCIIToUTF16("9aa,8bb,7cc,6dd,5ee,4ff,3gg,2hh," - "1ii,0jj,-1kk,-2ll,-3mm,-4nn,9a")); -} - -TEST(StringUtilTest, StdStringReplaceStringPlaceholders) { - std::vector subst; - subst.push_back("9a"); - subst.push_back("8b"); - subst.push_back("7c"); - subst.push_back("6d"); - subst.push_back("5e"); - subst.push_back("4f"); - subst.push_back("3g"); - subst.push_back("2h"); - subst.push_back("1i"); - - std::string formatted = - ReplaceStringPlaceholders( - "$1a,$2b,$3c,$4d,$5e,$6f,$7g,$8h,$9i", subst, NULL); - - EXPECT_EQ(formatted, "9aa,8bb,7cc,6dd,5ee,4ff,3gg,2hh,1ii"); -} - -TEST(StringUtilTest, ReplaceStringPlaceholdersConsecutiveDollarSigns) { - std::vector subst; - subst.push_back("a"); - subst.push_back("b"); - subst.push_back("c"); - EXPECT_EQ(ReplaceStringPlaceholders("$$1 $$$2 $$$$3", subst, NULL), - "$1 $$2 $$$3"); -} - -TEST(StringUtilTest, MatchPatternTest) { - EXPECT_TRUE(MatchPattern("www.google.com", "*.com")); - EXPECT_TRUE(MatchPattern("www.google.com", "*")); - EXPECT_FALSE(MatchPattern("www.google.com", "www*.g*.org")); - EXPECT_TRUE(MatchPattern("Hello", "H?l?o")); - EXPECT_FALSE(MatchPattern("www.google.com", "http://*)")); - EXPECT_FALSE(MatchPattern("www.msn.com", "*.COM")); - EXPECT_TRUE(MatchPattern("Hello*1234", "He??o\\*1*")); - EXPECT_FALSE(MatchPattern("", "*.*")); - EXPECT_TRUE(MatchPattern("", "*")); - EXPECT_TRUE(MatchPattern("", "?")); - EXPECT_TRUE(MatchPattern("", "")); - EXPECT_FALSE(MatchPattern("Hello", "")); - EXPECT_TRUE(MatchPattern("Hello*", "Hello*")); - // Stop after a certain recursion depth. - EXPECT_FALSE(MatchPattern("123456789012345678", "?????????????????*")); - - // Test UTF8 matching. - EXPECT_TRUE(MatchPattern("heart: \xe2\x99\xa0", "*\xe2\x99\xa0")); - EXPECT_TRUE(MatchPattern("heart: \xe2\x99\xa0.", "heart: ?.")); - EXPECT_TRUE(MatchPattern("hearts: \xe2\x99\xa0\xe2\x99\xa0", "*")); - // Invalid sequences should be handled as a single invalid character. - EXPECT_TRUE(MatchPattern("invalid: \xef\xbf\xbe", "invalid: ?")); - // If the pattern has invalid characters, it shouldn't match anything. - EXPECT_FALSE(MatchPattern("\xf4\x90\x80\x80", "\xf4\x90\x80\x80")); - - // Test UTF16 character matching. - EXPECT_TRUE(MatchPattern(UTF8ToUTF16("www.google.com"), - UTF8ToUTF16("*.com"))); - EXPECT_TRUE(MatchPattern(UTF8ToUTF16("Hello*1234"), - UTF8ToUTF16("He??o\\*1*"))); - - // This test verifies that consecutive wild cards are collapsed into 1 - // wildcard (when this doesn't occur, MatchPattern reaches it's maximum - // recursion depth). - EXPECT_TRUE(MatchPattern(UTF8ToUTF16("Hello"), - UTF8ToUTF16("He********************************o"))); -} - -TEST(StringUtilTest, LcpyTest) { - // Test the normal case where we fit in our buffer. - { - char dst[10]; - wchar_t wdst[10]; - EXPECT_EQ(7U, base::strlcpy(dst, "abcdefg", arraysize(dst))); - EXPECT_EQ(0, memcmp(dst, "abcdefg", 8)); - EXPECT_EQ(7U, base::wcslcpy(wdst, L"abcdefg", arraysize(wdst))); - EXPECT_EQ(0, memcmp(wdst, L"abcdefg", sizeof(wchar_t) * 8)); - } - - // Test dst_size == 0, nothing should be written to |dst| and we should - // have the equivalent of strlen(src). - { - char dst[2] = {1, 2}; - wchar_t wdst[2] = {1, 2}; - EXPECT_EQ(7U, base::strlcpy(dst, "abcdefg", 0)); - EXPECT_EQ(1, dst[0]); - EXPECT_EQ(2, dst[1]); - EXPECT_EQ(7U, base::wcslcpy(wdst, L"abcdefg", 0)); -#if defined(WCHAR_T_IS_UNSIGNED) - EXPECT_EQ(1U, wdst[0]); - EXPECT_EQ(2U, wdst[1]); -#else - EXPECT_EQ(1, wdst[0]); - EXPECT_EQ(2, wdst[1]); -#endif - } - - // Test the case were we _just_ competely fit including the null. - { - char dst[8]; - wchar_t wdst[8]; - EXPECT_EQ(7U, base::strlcpy(dst, "abcdefg", arraysize(dst))); - EXPECT_EQ(0, memcmp(dst, "abcdefg", 8)); - EXPECT_EQ(7U, base::wcslcpy(wdst, L"abcdefg", arraysize(wdst))); - EXPECT_EQ(0, memcmp(wdst, L"abcdefg", sizeof(wchar_t) * 8)); - } - - // Test the case were we we are one smaller, so we can't fit the null. - { - char dst[7]; - wchar_t wdst[7]; - EXPECT_EQ(7U, base::strlcpy(dst, "abcdefg", arraysize(dst))); - EXPECT_EQ(0, memcmp(dst, "abcdef", 7)); - EXPECT_EQ(7U, base::wcslcpy(wdst, L"abcdefg", arraysize(wdst))); - EXPECT_EQ(0, memcmp(wdst, L"abcdef", sizeof(wchar_t) * 7)); - } - - // Test the case were we are just too small. - { - char dst[3]; - wchar_t wdst[3]; - EXPECT_EQ(7U, base::strlcpy(dst, "abcdefg", arraysize(dst))); - EXPECT_EQ(0, memcmp(dst, "ab", 3)); - EXPECT_EQ(7U, base::wcslcpy(wdst, L"abcdefg", arraysize(wdst))); - EXPECT_EQ(0, memcmp(wdst, L"ab", sizeof(wchar_t) * 3)); - } -} - -TEST(StringUtilTest, WprintfFormatPortabilityTest) { - static const struct { - const wchar_t* input; - bool portable; - } cases[] = { - { L"%ls", true }, - { L"%s", false }, - { L"%S", false }, - { L"%lS", false }, - { L"Hello, %s", false }, - { L"%lc", true }, - { L"%c", false }, - { L"%C", false }, - { L"%lC", false }, - { L"%ls %s", false }, - { L"%s %ls", false }, - { L"%s %ls %s", false }, - { L"%f", true }, - { L"%f %F", false }, - { L"%d %D", false }, - { L"%o %O", false }, - { L"%u %U", false }, - { L"%f %d %o %u", true }, - { L"%-8d (%02.1f%)", true }, - { L"% 10s", false }, - { L"% 10ls", true } - }; - for (size_t i = 0; i < ARRAYSIZE_UNSAFE(cases); ++i) - EXPECT_EQ(cases[i].portable, base::IsWprintfFormatPortable(cases[i].input)); -} - -TEST(StringUtilTest, RemoveChars) { - const char* kRemoveChars = "-/+*"; - std::string input = "A-+bc/d!*"; - EXPECT_TRUE(RemoveChars(input, kRemoveChars, &input)); - EXPECT_EQ("Abcd!", input); - - // No characters match kRemoveChars. - EXPECT_FALSE(RemoveChars(input, kRemoveChars, &input)); - EXPECT_EQ("Abcd!", input); - - // Empty string. - input.clear(); - EXPECT_FALSE(RemoveChars(input, kRemoveChars, &input)); - EXPECT_EQ(std::string(), input); -} - -TEST(StringUtilTest, ReplaceChars) { - struct TestData { - const char* input; - const char* replace_chars; - const char* replace_with; - const char* output; - bool result; - } cases[] = { - { "", "", "", "", false }, - { "test", "", "", "test", false }, - { "test", "", "!", "test", false }, - { "test", "z", "!", "test", false }, - { "test", "e", "!", "t!st", true }, - { "test", "e", "!?", "t!?st", true }, - { "test", "ez", "!", "t!st", true }, - { "test", "zed", "!?", "t!?st", true }, - { "test", "t", "!?", "!?es!?", true }, - { "test", "et", "!>", "!>!>s!>", true }, - { "test", "zest", "!", "!!!!", true }, - { "test", "szt", "!", "!e!!", true }, - { "test", "t", "test", "testestest", true }, - }; - - for (size_t i = 0; i < ARRAYSIZE_UNSAFE(cases); ++i) { - std::string output; - bool result = ReplaceChars(cases[i].input, - cases[i].replace_chars, - cases[i].replace_with, - &output); - EXPECT_EQ(cases[i].result, result); - EXPECT_EQ(cases[i].output, output); - } -} - -TEST(StringUtilTest, ContainsOnlyChars) { - // Providing an empty list of characters should return false but for the empty - // string. - EXPECT_TRUE(ContainsOnlyChars(std::string(), std::string())); - EXPECT_FALSE(ContainsOnlyChars("Hello", std::string())); - - EXPECT_TRUE(ContainsOnlyChars(std::string(), "1234")); - EXPECT_TRUE(ContainsOnlyChars("1", "1234")); - EXPECT_TRUE(ContainsOnlyChars("1", "4321")); - EXPECT_TRUE(ContainsOnlyChars("123", "4321")); - EXPECT_FALSE(ContainsOnlyChars("123a", "4321")); -} - -class WriteIntoTest : public testing::Test { - protected: - static void WritesCorrectly(size_t num_chars) { - std::string buffer; - char kOriginal[] = "supercali"; - strncpy(WriteInto(&buffer, num_chars + 1), kOriginal, num_chars); - // Using std::string(buffer.c_str()) instead of |buffer| truncates the - // string at the first \0. - EXPECT_EQ(std::string(kOriginal, - std::min(num_chars, arraysize(kOriginal) - 1)), - std::string(buffer.c_str())); - EXPECT_EQ(num_chars, buffer.size()); - } -}; - -TEST_F(WriteIntoTest, WriteInto) { - // Validate that WriteInto reserves enough space and - // sizes a string correctly. - WritesCorrectly(1); - WritesCorrectly(2); - WritesCorrectly(5000); - - // Validate that WriteInto doesn't modify other strings - // when using a Copy-on-Write implementation. - const char kLive[] = "live"; - const char kDead[] = "dead"; - const std::string live = kLive; - std::string dead = live; - strncpy(WriteInto(&dead, 5), kDead, 4); - EXPECT_EQ(kDead, dead); - EXPECT_EQ(4u, dead.size()); - EXPECT_EQ(kLive, live); - EXPECT_EQ(4u, live.size()); -} - -} // namespace base diff --git a/base/strings/string_util_win.h b/base/strings/string_util_win.h deleted file mode 100644 index 602ba27378..0000000000 --- a/base/strings/string_util_win.h +++ /dev/null @@ -1,61 +0,0 @@ -// Copyright 2013 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef BASE_STRINGS_STRING_UTIL_WIN_H_ -#define BASE_STRINGS_STRING_UTIL_WIN_H_ - -#include -#include -#include -#include - -#include "base/logging.h" - -namespace base { - -// Chromium code style is to not use malloc'd strings; this is only for use -// for interaction with APIs that require it. -inline char* strdup(const char* str) { - return _strdup(str); -} - -inline int strcasecmp(const char* s1, const char* s2) { - return _stricmp(s1, s2); -} - -inline int strncasecmp(const char* s1, const char* s2, size_t count) { - return _strnicmp(s1, s2, count); -} - -inline int strncmp16(const char16* s1, const char16* s2, size_t count) { - return ::wcsncmp(s1, s2, count); -} - -inline int vsnprintf(char* buffer, size_t size, - const char* format, va_list arguments) { - int length = _vsprintf_p(buffer, size, format, arguments); - if (length < 0) { - if (size > 0) - buffer[0] = 0; - return _vscprintf_p(format, arguments); - } - return length; -} - -inline int vswprintf(wchar_t* buffer, size_t size, - const wchar_t* format, va_list arguments) { - DCHECK(IsWprintfFormatPortable(format)); - - int length = _vswprintf_p(buffer, size, format, arguments); - if (length < 0) { - if (size > 0) - buffer[0] = 0; - return _vscwprintf_p(format, arguments); - } - return length; -} - -} // namespace base - -#endif // BASE_STRINGS_STRING_UTIL_WIN_H_ diff --git a/base/strings/stringize_macros.h b/base/strings/stringize_macros.h deleted file mode 100644 index d4e27071e4..0000000000 --- a/base/strings/stringize_macros.h +++ /dev/null @@ -1,31 +0,0 @@ -// Copyright (c) 2010 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. -// -// This file defines preprocessor macros for stringizing preprocessor -// symbols (or their output) and manipulating preprocessor symbols -// that define strings. - -#ifndef BASE_STRINGS_STRINGIZE_MACROS_H_ -#define BASE_STRINGS_STRINGIZE_MACROS_H_ - -#include "build/build_config.h" - -// This is not very useful as it does not expand defined symbols if -// called directly. Use its counterpart without the _NO_EXPANSION -// suffix, below. -#define STRINGIZE_NO_EXPANSION(x) #x - -// Use this to quote the provided parameter, first expanding it if it -// is a preprocessor symbol. -// -// For example, if: -// #define A FOO -// #define B(x) myobj->FunctionCall(x) -// -// Then: -// STRINGIZE(A) produces "FOO" -// STRINGIZE(B(y)) produces "myobj->FunctionCall(y)" -#define STRINGIZE(x) STRINGIZE_NO_EXPANSION(x) - -#endif // BASE_STRINGS_STRINGIZE_MACROS_H_ diff --git a/base/strings/stringize_macros_unittest.cc b/base/strings/stringize_macros_unittest.cc deleted file mode 100644 index d7f9e560ae..0000000000 --- a/base/strings/stringize_macros_unittest.cc +++ /dev/null @@ -1,29 +0,0 @@ -// Copyright (c) 2010 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "base/strings/stringize_macros.h" - -#include "testing/gtest/include/gtest/gtest.h" - -// Macros as per documentation in header file. -#define PREPROCESSOR_UTIL_UNITTEST_A FOO -#define PREPROCESSOR_UTIL_UNITTEST_B(x) myobj->FunctionCall(x) -#define PREPROCESSOR_UTIL_UNITTEST_C "foo" - -TEST(StringizeTest, Ansi) { - EXPECT_STREQ( - "PREPROCESSOR_UTIL_UNITTEST_A", - STRINGIZE_NO_EXPANSION(PREPROCESSOR_UTIL_UNITTEST_A)); - EXPECT_STREQ( - "PREPROCESSOR_UTIL_UNITTEST_B(y)", - STRINGIZE_NO_EXPANSION(PREPROCESSOR_UTIL_UNITTEST_B(y))); - EXPECT_STREQ( - "PREPROCESSOR_UTIL_UNITTEST_C", - STRINGIZE_NO_EXPANSION(PREPROCESSOR_UTIL_UNITTEST_C)); - - EXPECT_STREQ("FOO", STRINGIZE(PREPROCESSOR_UTIL_UNITTEST_A)); - EXPECT_STREQ("myobj->FunctionCall(y)", - STRINGIZE(PREPROCESSOR_UTIL_UNITTEST_B(y))); - EXPECT_STREQ("\"foo\"", STRINGIZE(PREPROCESSOR_UTIL_UNITTEST_C)); -} diff --git a/base/strings/stringprintf.cc b/base/strings/stringprintf.cc deleted file mode 100644 index fe23daaa35..0000000000 --- a/base/strings/stringprintf.cc +++ /dev/null @@ -1,186 +0,0 @@ -// Copyright 2013 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "base/strings/stringprintf.h" - -#include - -#include "base/scoped_clear_errno.h" -#include "base/strings/string_util.h" -#include "base/strings/utf_string_conversions.h" - -namespace base { - -namespace { - -// Overloaded wrappers around vsnprintf and vswprintf. The buf_size parameter -// is the size of the buffer. These return the number of characters in the -// formatted string excluding the NUL terminator. If the buffer is not -// large enough to accommodate the formatted string without truncation, they -// return the number of characters that would be in the fully-formatted string -// (vsnprintf, and vswprintf on Windows), or -1 (vswprintf on POSIX platforms). -inline int vsnprintfT(char* buffer, - size_t buf_size, - const char* format, - va_list argptr) { - return base::vsnprintf(buffer, buf_size, format, argptr); -} - -#if !defined(OS_ANDROID) -inline int vsnprintfT(wchar_t* buffer, - size_t buf_size, - const wchar_t* format, - va_list argptr) { - return base::vswprintf(buffer, buf_size, format, argptr); -} -#endif - -// Templatized backend for StringPrintF/StringAppendF. This does not finalize -// the va_list, the caller is expected to do that. -template -static void StringAppendVT(StringType* dst, - const typename StringType::value_type* format, - va_list ap) { - // First try with a small fixed size buffer. - // This buffer size should be kept in sync with StringUtilTest.GrowBoundary - // and StringUtilTest.StringPrintfBounds. - typename StringType::value_type stack_buf[1024]; - - va_list ap_copy; - GG_VA_COPY(ap_copy, ap); - -#if !defined(OS_WIN) - ScopedClearErrno clear_errno; -#endif - int result = vsnprintfT(stack_buf, arraysize(stack_buf), format, ap_copy); - va_end(ap_copy); - - if (result >= 0 && result < static_cast(arraysize(stack_buf))) { - // It fit. - dst->append(stack_buf, result); - return; - } - - // Repeatedly increase buffer size until it fits. - int mem_length = arraysize(stack_buf); - while (true) { - if (result < 0) { -#if !defined(OS_WIN) - // On Windows, vsnprintfT always returns the number of characters in a - // fully-formatted string, so if we reach this point, something else is - // wrong and no amount of buffer-doubling is going to fix it. - if (errno != 0 && errno != EOVERFLOW) -#endif - { - // If an error other than overflow occurred, it's never going to work. - DLOG(WARNING) << "Unable to printf the requested string due to error."; - return; - } - // Try doubling the buffer size. - mem_length *= 2; - } else { - // We need exactly "result + 1" characters. - mem_length = result + 1; - } - - if (mem_length > 32 * 1024 * 1024) { - // That should be plenty, don't try anything larger. This protects - // against huge allocations when using vsnprintfT implementations that - // return -1 for reasons other than overflow without setting errno. - DLOG(WARNING) << "Unable to printf the requested string due to size."; - return; - } - - std::vector mem_buf(mem_length); - - // NOTE: You can only use a va_list once. Since we're in a while loop, we - // need to make a new copy each time so we don't use up the original. - GG_VA_COPY(ap_copy, ap); - result = vsnprintfT(&mem_buf[0], mem_length, format, ap_copy); - va_end(ap_copy); - - if ((result >= 0) && (result < mem_length)) { - // It fit. - dst->append(&mem_buf[0], result); - return; - } - } -} - -} // namespace - -std::string StringPrintf(const char* format, ...) { - va_list ap; - va_start(ap, format); - std::string result; - StringAppendV(&result, format, ap); - va_end(ap); - return result; -} - -#if !defined(OS_ANDROID) -std::wstring StringPrintf(const wchar_t* format, ...) { - va_list ap; - va_start(ap, format); - std::wstring result; - StringAppendV(&result, format, ap); - va_end(ap); - return result; -} -#endif - -std::string StringPrintV(const char* format, va_list ap) { - std::string result; - StringAppendV(&result, format, ap); - return result; -} - -const std::string& SStringPrintf(std::string* dst, const char* format, ...) { - va_list ap; - va_start(ap, format); - dst->clear(); - StringAppendV(dst, format, ap); - va_end(ap); - return *dst; -} - -#if !defined(OS_ANDROID) -const std::wstring& SStringPrintf(std::wstring* dst, - const wchar_t* format, ...) { - va_list ap; - va_start(ap, format); - dst->clear(); - StringAppendV(dst, format, ap); - va_end(ap); - return *dst; -} -#endif - -void StringAppendF(std::string* dst, const char* format, ...) { - va_list ap; - va_start(ap, format); - StringAppendV(dst, format, ap); - va_end(ap); -} - -#if !defined(OS_ANDROID) -void StringAppendF(std::wstring* dst, const wchar_t* format, ...) { - va_list ap; - va_start(ap, format); - StringAppendV(dst, format, ap); - va_end(ap); -} -#endif - -void StringAppendV(std::string* dst, const char* format, va_list ap) { - StringAppendVT(dst, format, ap); -} - -#if !defined(OS_ANDROID) -void StringAppendV(std::wstring* dst, const wchar_t* format, va_list ap) { - StringAppendVT(dst, format, ap); -} -#endif - -} // namespace base diff --git a/base/strings/stringprintf.h b/base/strings/stringprintf.h deleted file mode 100644 index 3c0e399c0a..0000000000 --- a/base/strings/stringprintf.h +++ /dev/null @@ -1,62 +0,0 @@ -// Copyright 2013 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef BASE_STRINGS_STRINGPRINTF_H_ -#define BASE_STRINGS_STRINGPRINTF_H_ - -#include // va_list - -#include - -#include "base/base_export.h" -#include "base/compiler_specific.h" - -namespace base { - -// Return a C++ string given printf-like input. -BASE_EXPORT std::string StringPrintf(const char* format, ...) - PRINTF_FORMAT(1, 2); -// OS_ANDROID's libc does not support wchar_t, so several overloads are omitted. -#if !defined(OS_ANDROID) -BASE_EXPORT std::wstring StringPrintf(const wchar_t* format, ...) - WPRINTF_FORMAT(1, 2); -#endif - -// Return a C++ string given vprintf-like input. -BASE_EXPORT std::string StringPrintV(const char* format, va_list ap) - PRINTF_FORMAT(1, 0); - -// Store result into a supplied string and return it. -BASE_EXPORT const std::string& SStringPrintf(std::string* dst, - const char* format, ...) - PRINTF_FORMAT(2, 3); -#if !defined(OS_ANDROID) -BASE_EXPORT const std::wstring& SStringPrintf(std::wstring* dst, - const wchar_t* format, ...) - WPRINTF_FORMAT(2, 3); -#endif - -// Append result to a supplied string. -BASE_EXPORT void StringAppendF(std::string* dst, const char* format, ...) - PRINTF_FORMAT(2, 3); -#if !defined(OS_ANDROID) -// TODO(evanm): this is only used in a few places in the code; -// replace with string16 version. -BASE_EXPORT void StringAppendF(std::wstring* dst, const wchar_t* format, ...) - WPRINTF_FORMAT(2, 3); -#endif - -// Lower-level routine that takes a va_list and appends to a specified -// string. All other routines are just convenience wrappers around it. -BASE_EXPORT void StringAppendV(std::string* dst, const char* format, va_list ap) - PRINTF_FORMAT(2, 0); -#if !defined(OS_ANDROID) -BASE_EXPORT void StringAppendV(std::wstring* dst, - const wchar_t* format, va_list ap) - WPRINTF_FORMAT(2, 0); -#endif - -} // namespace base - -#endif // BASE_STRINGS_STRINGPRINTF_H_ diff --git a/base/strings/stringprintf_unittest.cc b/base/strings/stringprintf_unittest.cc deleted file mode 100644 index a1bf2da426..0000000000 --- a/base/strings/stringprintf_unittest.cc +++ /dev/null @@ -1,188 +0,0 @@ -// Copyright 2013 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "base/strings/stringprintf.h" - -#include - -#include "base/basictypes.h" -#include "testing/gtest/include/gtest/gtest.h" - -namespace base { - -namespace { - -// A helper for the StringAppendV test that follows. -// -// Just forwards its args to StringAppendV. -static void StringAppendVTestHelper(std::string* out, const char* format, ...) { - va_list ap; - va_start(ap, format); - StringAppendV(out, format, ap); - va_end(ap); -} - -} // namespace - -TEST(StringPrintfTest, StringPrintfEmpty) { - EXPECT_EQ("", StringPrintf("%s", "")); -} - -TEST(StringPrintfTest, StringPrintfMisc) { - EXPECT_EQ("123hello w", StringPrintf("%3d%2s %1c", 123, "hello", 'w')); -#if !defined(OS_ANDROID) - EXPECT_EQ(L"123hello w", StringPrintf(L"%3d%2ls %1lc", 123, L"hello", 'w')); -#endif -} - -TEST(StringPrintfTest, StringAppendfEmptyString) { - std::string value("Hello"); - StringAppendF(&value, "%s", ""); - EXPECT_EQ("Hello", value); - -#if !defined(OS_ANDROID) - std::wstring valuew(L"Hello"); - StringAppendF(&valuew, L"%ls", L""); - EXPECT_EQ(L"Hello", valuew); -#endif -} - -TEST(StringPrintfTest, StringAppendfString) { - std::string value("Hello"); - StringAppendF(&value, " %s", "World"); - EXPECT_EQ("Hello World", value); - -#if !defined(OS_ANDROID) - std::wstring valuew(L"Hello"); - StringAppendF(&valuew, L" %ls", L"World"); - EXPECT_EQ(L"Hello World", valuew); -#endif -} - -TEST(StringPrintfTest, StringAppendfInt) { - std::string value("Hello"); - StringAppendF(&value, " %d", 123); - EXPECT_EQ("Hello 123", value); - -#if !defined(OS_ANDROID) - std::wstring valuew(L"Hello"); - StringAppendF(&valuew, L" %d", 123); - EXPECT_EQ(L"Hello 123", valuew); -#endif -} - -// Make sure that lengths exactly around the initial buffer size are handled -// correctly. -TEST(StringPrintfTest, StringPrintfBounds) { - const int kSrcLen = 1026; - char src[kSrcLen]; - for (size_t i = 0; i < arraysize(src); i++) - src[i] = 'A'; - - wchar_t srcw[kSrcLen]; - for (size_t i = 0; i < arraysize(srcw); i++) - srcw[i] = 'A'; - - for (int i = 1; i < 3; i++) { - src[kSrcLen - i] = 0; - std::string out; - SStringPrintf(&out, "%s", src); - EXPECT_STREQ(src, out.c_str()); - -#if !defined(OS_ANDROID) - srcw[kSrcLen - i] = 0; - std::wstring outw; - SStringPrintf(&outw, L"%ls", srcw); - EXPECT_STREQ(srcw, outw.c_str()); -#endif - } -} - -// Test very large sprintfs that will cause the buffer to grow. -TEST(StringPrintfTest, Grow) { - char src[1026]; - for (size_t i = 0; i < arraysize(src); i++) - src[i] = 'A'; - src[1025] = 0; - - const char* fmt = "%sB%sB%sB%sB%sB%sB%s"; - - std::string out; - SStringPrintf(&out, fmt, src, src, src, src, src, src, src); - - const int kRefSize = 320000; - char* ref = new char[kRefSize]; -#if defined(OS_WIN) - sprintf_s(ref, kRefSize, fmt, src, src, src, src, src, src, src); -#elif defined(OS_POSIX) - snprintf(ref, kRefSize, fmt, src, src, src, src, src, src, src); -#endif - - EXPECT_STREQ(ref, out.c_str()); - delete[] ref; -} - -TEST(StringPrintfTest, StringAppendV) { - std::string out; - StringAppendVTestHelper(&out, "%d foo %s", 1, "bar"); - EXPECT_EQ("1 foo bar", out); -} - -// Test the boundary condition for the size of the string_util's -// internal buffer. -TEST(StringPrintfTest, GrowBoundary) { - const int string_util_buf_len = 1024; - // Our buffer should be one larger than the size of StringAppendVT's stack - // buffer. - const int buf_len = string_util_buf_len + 1; - char src[buf_len + 1]; // Need extra one for NULL-terminator. - for (int i = 0; i < buf_len; ++i) - src[i] = 'a'; - src[buf_len] = 0; - - std::string out; - SStringPrintf(&out, "%s", src); - - EXPECT_STREQ(src, out.c_str()); -} - -// TODO(evanm): what's the proper cross-platform test here? -#if defined(OS_WIN) -// sprintf in Visual Studio fails when given U+FFFF. This tests that the -// failure case is gracefuly handled. -TEST(StringPrintfTest, Invalid) { - wchar_t invalid[2]; - invalid[0] = 0xffff; - invalid[1] = 0; - - std::wstring out; - SStringPrintf(&out, L"%ls", invalid); - EXPECT_STREQ(L"", out.c_str()); -} -#endif - -// Test that the positional parameters work. -TEST(StringPrintfTest, PositionalParameters) { - std::string out; - SStringPrintf(&out, "%1$s %1$s", "test"); - EXPECT_STREQ("test test", out.c_str()); - -#if defined(OS_WIN) - std::wstring wout; - SStringPrintf(&wout, L"%1$ls %1$ls", L"test"); - EXPECT_STREQ(L"test test", wout.c_str()); -#endif -} - -// Test that StringPrintf and StringAppendV do not change errno. -TEST(StringPrintfTest, StringPrintfErrno) { - errno = 1; - EXPECT_EQ("", StringPrintf("%s", "")); - EXPECT_EQ(1, errno); - std::string out; - StringAppendVTestHelper(&out, "%d foo %s", 1, "bar"); - EXPECT_EQ(1, errno); -} - -} // namespace base diff --git a/base/strings/sys_string_conversions.h b/base/strings/sys_string_conversions.h deleted file mode 100644 index 42f2389a8b..0000000000 --- a/base/strings/sys_string_conversions.h +++ /dev/null @@ -1,83 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef BASE_STRINGS_SYS_STRING_CONVERSIONS_H_ -#define BASE_STRINGS_SYS_STRING_CONVERSIONS_H_ - -// Provides system-dependent string type conversions for cases where it's -// necessary to not use ICU. Generally, you should not need this in Chrome, -// but it is used in some shared code. Dependencies should be minimal. - -#include - -#include "base/base_export.h" -#include "base/basictypes.h" -#include "base/strings/string16.h" -#include "base/strings/string_piece.h" - -#if defined(OS_MACOSX) -#include -#ifdef __OBJC__ -@class NSString; -#else -class NSString; -#endif -#endif // OS_MACOSX - -namespace base { - -// Converts between wide and UTF-8 representations of a string. On error, the -// result is system-dependent. -BASE_EXPORT std::string SysWideToUTF8(const std::wstring& wide); -BASE_EXPORT std::wstring SysUTF8ToWide(const StringPiece& utf8); - -// Converts between wide and the system multi-byte representations of a string. -// DANGER: This will lose information and can change (on Windows, this can -// change between reboots). -BASE_EXPORT std::string SysWideToNativeMB(const std::wstring& wide); -BASE_EXPORT std::wstring SysNativeMBToWide(const StringPiece& native_mb); - -// Windows-specific ------------------------------------------------------------ - -#if defined(OS_WIN) - -// Converts between 8-bit and wide strings, using the given code page. The -// code page identifier is one accepted by the Windows function -// MultiByteToWideChar(). -BASE_EXPORT std::wstring SysMultiByteToWide(const StringPiece& mb, - uint32 code_page); -BASE_EXPORT std::string SysWideToMultiByte(const std::wstring& wide, - uint32 code_page); - -#endif // defined(OS_WIN) - -// Mac-specific ---------------------------------------------------------------- - -#if defined(OS_MACOSX) - -// Converts between STL strings and CFStringRefs/NSStrings. - -// Creates a string, and returns it with a refcount of 1. You are responsible -// for releasing it. Returns NULL on failure. -BASE_EXPORT CFStringRef SysUTF8ToCFStringRef(const std::string& utf8); -BASE_EXPORT CFStringRef SysUTF16ToCFStringRef(const string16& utf16); - -// Same, but returns an autoreleased NSString. -BASE_EXPORT NSString* SysUTF8ToNSString(const std::string& utf8); -BASE_EXPORT NSString* SysUTF16ToNSString(const string16& utf16); - -// Converts a CFStringRef to an STL string. Returns an empty string on failure. -BASE_EXPORT std::string SysCFStringRefToUTF8(CFStringRef ref); -BASE_EXPORT string16 SysCFStringRefToUTF16(CFStringRef ref); - -// Same, but accepts NSString input. Converts nil NSString* to the appropriate -// string type of length 0. -BASE_EXPORT std::string SysNSStringToUTF8(NSString* ref); -BASE_EXPORT string16 SysNSStringToUTF16(NSString* ref); - -#endif // defined(OS_MACOSX) - -} // namespace base - -#endif // BASE_STRINGS_SYS_STRING_CONVERSIONS_H_ diff --git a/base/strings/sys_string_conversions_mac.mm b/base/strings/sys_string_conversions_mac.mm deleted file mode 100644 index 9479e787c0..0000000000 --- a/base/strings/sys_string_conversions_mac.mm +++ /dev/null @@ -1,186 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "base/strings/sys_string_conversions.h" - -#import - -#include - -#include "base/mac/foundation_util.h" -#include "base/mac/scoped_cftyperef.h" -#include "base/strings/string_piece.h" - -namespace base { - -namespace { - -// Convert the supplied CFString into the specified encoding, and return it as -// an STL string of the template type. Returns an empty string on failure. -// -// Do not assert in this function since it is used by the asssertion code! -template -static StringType CFStringToSTLStringWithEncodingT(CFStringRef cfstring, - CFStringEncoding encoding) { - CFIndex length = CFStringGetLength(cfstring); - if (length == 0) - return StringType(); - - CFRange whole_string = CFRangeMake(0, length); - CFIndex out_size; - CFIndex converted = CFStringGetBytes(cfstring, - whole_string, - encoding, - 0, // lossByte - false, // isExternalRepresentation - NULL, // buffer - 0, // maxBufLen - &out_size); - if (converted == 0 || out_size == 0) - return StringType(); - - // out_size is the number of UInt8-sized units needed in the destination. - // A buffer allocated as UInt8 units might not be properly aligned to - // contain elements of StringType::value_type. Use a container for the - // proper value_type, and convert out_size by figuring the number of - // value_type elements per UInt8. Leave room for a NUL terminator. - typename StringType::size_type elements = - out_size * sizeof(UInt8) / sizeof(typename StringType::value_type) + 1; - - std::vector out_buffer(elements); - converted = CFStringGetBytes(cfstring, - whole_string, - encoding, - 0, // lossByte - false, // isExternalRepresentation - reinterpret_cast(&out_buffer[0]), - out_size, - NULL); // usedBufLen - if (converted == 0) - return StringType(); - - out_buffer[elements - 1] = '\0'; - return StringType(&out_buffer[0], elements - 1); -} - -// Given an STL string |in| with an encoding specified by |in_encoding|, -// convert it to |out_encoding| and return it as an STL string of the -// |OutStringType| template type. Returns an empty string on failure. -// -// Do not assert in this function since it is used by the asssertion code! -template -static OutStringType STLStringToSTLStringWithEncodingsT( - const InStringType& in, - CFStringEncoding in_encoding, - CFStringEncoding out_encoding) { - typename InStringType::size_type in_length = in.length(); - if (in_length == 0) - return OutStringType(); - - base::ScopedCFTypeRef cfstring(CFStringCreateWithBytesNoCopy( - NULL, - reinterpret_cast(in.data()), - in_length * sizeof(typename InStringType::value_type), - in_encoding, - false, - kCFAllocatorNull)); - if (!cfstring) - return OutStringType(); - - return CFStringToSTLStringWithEncodingT(cfstring, - out_encoding); -} - -// Given an STL string |in| with an encoding specified by |in_encoding|, -// return it as a CFStringRef. Returns NULL on failure. -template -static CFStringRef STLStringToCFStringWithEncodingsT( - const StringType& in, - CFStringEncoding in_encoding) { - typename StringType::size_type in_length = in.length(); - if (in_length == 0) - return CFSTR(""); - - return CFStringCreateWithBytes(kCFAllocatorDefault, - reinterpret_cast(in.data()), - in_length * - sizeof(typename StringType::value_type), - in_encoding, - false); -} - -// Specify the byte ordering explicitly, otherwise CFString will be confused -// when strings don't carry BOMs, as they typically won't. -static const CFStringEncoding kNarrowStringEncoding = kCFStringEncodingUTF8; -#ifdef __BIG_ENDIAN__ -static const CFStringEncoding kMediumStringEncoding = kCFStringEncodingUTF16BE; -static const CFStringEncoding kWideStringEncoding = kCFStringEncodingUTF32BE; -#elif defined(__LITTLE_ENDIAN__) -static const CFStringEncoding kMediumStringEncoding = kCFStringEncodingUTF16LE; -static const CFStringEncoding kWideStringEncoding = kCFStringEncodingUTF32LE; -#endif // __LITTLE_ENDIAN__ - -} // namespace - -// Do not assert in this function since it is used by the asssertion code! -std::string SysWideToUTF8(const std::wstring& wide) { - return STLStringToSTLStringWithEncodingsT( - wide, kWideStringEncoding, kNarrowStringEncoding); -} - -// Do not assert in this function since it is used by the asssertion code! -std::wstring SysUTF8ToWide(const StringPiece& utf8) { - return STLStringToSTLStringWithEncodingsT( - utf8, kNarrowStringEncoding, kWideStringEncoding); -} - -std::string SysWideToNativeMB(const std::wstring& wide) { - return SysWideToUTF8(wide); -} - -std::wstring SysNativeMBToWide(const StringPiece& native_mb) { - return SysUTF8ToWide(native_mb); -} - -CFStringRef SysUTF8ToCFStringRef(const std::string& utf8) { - return STLStringToCFStringWithEncodingsT(utf8, kNarrowStringEncoding); -} - -CFStringRef SysUTF16ToCFStringRef(const string16& utf16) { - return STLStringToCFStringWithEncodingsT(utf16, kMediumStringEncoding); -} - -NSString* SysUTF8ToNSString(const std::string& utf8) { - return (NSString*)base::mac::CFTypeRefToNSObjectAutorelease( - SysUTF8ToCFStringRef(utf8)); -} - -NSString* SysUTF16ToNSString(const string16& utf16) { - return (NSString*)base::mac::CFTypeRefToNSObjectAutorelease( - SysUTF16ToCFStringRef(utf16)); -} - -std::string SysCFStringRefToUTF8(CFStringRef ref) { - return CFStringToSTLStringWithEncodingT(ref, - kNarrowStringEncoding); -} - -string16 SysCFStringRefToUTF16(CFStringRef ref) { - return CFStringToSTLStringWithEncodingT(ref, - kMediumStringEncoding); -} - -std::string SysNSStringToUTF8(NSString* nsstring) { - if (!nsstring) - return std::string(); - return SysCFStringRefToUTF8(reinterpret_cast(nsstring)); -} - -string16 SysNSStringToUTF16(NSString* nsstring) { - if (!nsstring) - return string16(); - return SysCFStringRefToUTF16(reinterpret_cast(nsstring)); -} - -} // namespace base diff --git a/base/strings/sys_string_conversions_mac_unittest.mm b/base/strings/sys_string_conversions_mac_unittest.mm deleted file mode 100644 index 4750a9a8b5..0000000000 --- a/base/strings/sys_string_conversions_mac_unittest.mm +++ /dev/null @@ -1,21 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#import - -#include "base/strings/string16.h" -#include "base/strings/sys_string_conversions.h" -#include "testing/gtest/include/gtest/gtest.h" - -namespace base { - -TEST(SysStrings, ConversionsFromNSString) { - EXPECT_STREQ("Hello, world!", SysNSStringToUTF8(@"Hello, world!").c_str()); - - // Conversions should be able to handle a NULL value without crashing. - EXPECT_STREQ("", SysNSStringToUTF8(nil).c_str()); - EXPECT_EQ(string16(), SysNSStringToUTF16(nil)); -} - -} // namespace base diff --git a/base/strings/sys_string_conversions_posix.cc b/base/strings/sys_string_conversions_posix.cc deleted file mode 100644 index 1e926bb549..0000000000 --- a/base/strings/sys_string_conversions_posix.cc +++ /dev/null @@ -1,161 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "base/strings/sys_string_conversions.h" - -#include - -#include "base/strings/string_piece.h" -#include "base/strings/utf_string_conversions.h" - -namespace base { - -std::string SysWideToUTF8(const std::wstring& wide) { - // In theory this should be using the system-provided conversion rather - // than our ICU, but this will do for now. - return WideToUTF8(wide); -} -std::wstring SysUTF8ToWide(const StringPiece& utf8) { - // In theory this should be using the system-provided conversion rather - // than our ICU, but this will do for now. - std::wstring out; - UTF8ToWide(utf8.data(), utf8.size(), &out); - return out; -} - -#if defined(OS_CHROMEOS) || defined(OS_ANDROID) -// TODO(port): Consider reverting the OS_ANDROID when we have wcrtomb() -// support and a better understanding of what calls these routines. - -// ChromeOS always runs in UTF-8 locale. -std::string SysWideToNativeMB(const std::wstring& wide) { - return WideToUTF8(wide); -} - -std::wstring SysNativeMBToWide(const StringPiece& native_mb) { - return SysUTF8ToWide(native_mb); -} - -#else - -std::string SysWideToNativeMB(const std::wstring& wide) { - mbstate_t ps; - - // Calculate the number of multi-byte characters. We walk through the string - // without writing the output, counting the number of multi-byte characters. - size_t num_out_chars = 0; - memset(&ps, 0, sizeof(ps)); - for (size_t i = 0; i < wide.size(); ++i) { - const wchar_t src = wide[i]; - // Use a temp buffer since calling wcrtomb with an output of NULL does not - // calculate the output length. - char buf[16]; - // Skip NULLs to avoid wcrtomb's special handling of them. - size_t res = src ? wcrtomb(buf, src, &ps) : 0; - switch (res) { - // Handle any errors and return an empty string. - case static_cast(-1): - return std::string(); - break; - case 0: - // We hit an embedded null byte, keep going. - ++num_out_chars; - break; - default: - num_out_chars += res; - break; - } - } - - if (num_out_chars == 0) - return std::string(); - - std::string out; - out.resize(num_out_chars); - - // We walk the input string again, with |i| tracking the index of the - // wide input, and |j| tracking the multi-byte output. - memset(&ps, 0, sizeof(ps)); - for (size_t i = 0, j = 0; i < wide.size(); ++i) { - const wchar_t src = wide[i]; - // We don't want wcrtomb to do its funkiness for embedded NULLs. - size_t res = src ? wcrtomb(&out[j], src, &ps) : 0; - switch (res) { - // Handle any errors and return an empty string. - case static_cast(-1): - return std::string(); - break; - case 0: - // We hit an embedded null byte, keep going. - ++j; // Output is already zeroed. - break; - default: - j += res; - break; - } - } - - return out; -} - -std::wstring SysNativeMBToWide(const StringPiece& native_mb) { - mbstate_t ps; - - // Calculate the number of wide characters. We walk through the string - // without writing the output, counting the number of wide characters. - size_t num_out_chars = 0; - memset(&ps, 0, sizeof(ps)); - for (size_t i = 0; i < native_mb.size(); ) { - const char* src = native_mb.data() + i; - size_t res = mbrtowc(NULL, src, native_mb.size() - i, &ps); - switch (res) { - // Handle any errors and return an empty string. - case static_cast(-2): - case static_cast(-1): - return std::wstring(); - break; - case 0: - // We hit an embedded null byte, keep going. - i += 1; // Fall through. - default: - i += res; - ++num_out_chars; - break; - } - } - - if (num_out_chars == 0) - return std::wstring(); - - std::wstring out; - out.resize(num_out_chars); - - memset(&ps, 0, sizeof(ps)); // Clear the shift state. - // We walk the input string again, with |i| tracking the index of the - // multi-byte input, and |j| tracking the wide output. - for (size_t i = 0, j = 0; i < native_mb.size(); ++j) { - const char* src = native_mb.data() + i; - wchar_t* dst = &out[j]; - size_t res = mbrtowc(dst, src, native_mb.size() - i, &ps); - switch (res) { - // Handle any errors and return an empty string. - case static_cast(-2): - case static_cast(-1): - return std::wstring(); - break; - case 0: - i += 1; // Skip null byte. - break; - default: - i += res; - break; - } - } - - return out; -} - -#endif // OS_CHROMEOS - -} // namespace base diff --git a/base/strings/sys_string_conversions_unittest.cc b/base/strings/sys_string_conversions_unittest.cc deleted file mode 100644 index d2d38e40cc..0000000000 --- a/base/strings/sys_string_conversions_unittest.cc +++ /dev/null @@ -1,187 +0,0 @@ -// Copyright (c) 2011 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include - -#include "base/basictypes.h" -#include "base/strings/string_piece.h" -#include "base/strings/sys_string_conversions.h" -#include "base/strings/utf_string_conversions.h" -#include "base/test/scoped_locale.h" -#include "testing/gtest/include/gtest/gtest.h" - -#ifdef WCHAR_T_IS_UTF32 -static const std::wstring kSysWideOldItalicLetterA = L"\x10300"; -#else -static const std::wstring kSysWideOldItalicLetterA = L"\xd800\xdf00"; -#endif - -namespace base { - -TEST(SysStrings, SysWideToUTF8) { - EXPECT_EQ("Hello, world", SysWideToUTF8(L"Hello, world")); - EXPECT_EQ("\xe4\xbd\xa0\xe5\xa5\xbd", SysWideToUTF8(L"\x4f60\x597d")); - - // >16 bits - EXPECT_EQ("\xF0\x90\x8C\x80", SysWideToUTF8(kSysWideOldItalicLetterA)); - - // Error case. When Windows finds a UTF-16 character going off the end of - // a string, it just converts that literal value to UTF-8, even though this - // is invalid. - // - // This is what XP does, but Vista has different behavior, so we don't bother - // verifying it: - // EXPECT_EQ("\xE4\xBD\xA0\xED\xA0\x80zyxw", - // SysWideToUTF8(L"\x4f60\xd800zyxw")); - - // Test embedded NULLs. - std::wstring wide_null(L"a"); - wide_null.push_back(0); - wide_null.push_back('b'); - - std::string expected_null("a"); - expected_null.push_back(0); - expected_null.push_back('b'); - - EXPECT_EQ(expected_null, SysWideToUTF8(wide_null)); -} - -TEST(SysStrings, SysUTF8ToWide) { - EXPECT_EQ(L"Hello, world", SysUTF8ToWide("Hello, world")); - EXPECT_EQ(L"\x4f60\x597d", SysUTF8ToWide("\xe4\xbd\xa0\xe5\xa5\xbd")); - // >16 bits - EXPECT_EQ(kSysWideOldItalicLetterA, SysUTF8ToWide("\xF0\x90\x8C\x80")); - - // Error case. When Windows finds an invalid UTF-8 character, it just skips - // it. This seems weird because it's inconsistent with the reverse conversion. - // - // This is what XP does, but Vista has different behavior, so we don't bother - // verifying it: - // EXPECT_EQ(L"\x4f60zyxw", SysUTF8ToWide("\xe4\xbd\xa0\xe5\xa5zyxw")); - - // Test embedded NULLs. - std::string utf8_null("a"); - utf8_null.push_back(0); - utf8_null.push_back('b'); - - std::wstring expected_null(L"a"); - expected_null.push_back(0); - expected_null.push_back('b'); - - EXPECT_EQ(expected_null, SysUTF8ToWide(utf8_null)); -} - -#if defined(OS_LINUX) // Tests depend on setting a specific Linux locale. - -TEST(SysStrings, SysWideToNativeMB) { - ScopedLocale locale("en_US.utf-8"); - EXPECT_EQ("Hello, world", SysWideToNativeMB(L"Hello, world")); - EXPECT_EQ("\xe4\xbd\xa0\xe5\xa5\xbd", SysWideToNativeMB(L"\x4f60\x597d")); - - // >16 bits - EXPECT_EQ("\xF0\x90\x8C\x80", SysWideToNativeMB(kSysWideOldItalicLetterA)); - - // Error case. When Windows finds a UTF-16 character going off the end of - // a string, it just converts that literal value to UTF-8, even though this - // is invalid. - // - // This is what XP does, but Vista has different behavior, so we don't bother - // verifying it: - // EXPECT_EQ("\xE4\xBD\xA0\xED\xA0\x80zyxw", - // SysWideToNativeMB(L"\x4f60\xd800zyxw")); - - // Test embedded NULLs. - std::wstring wide_null(L"a"); - wide_null.push_back(0); - wide_null.push_back('b'); - - std::string expected_null("a"); - expected_null.push_back(0); - expected_null.push_back('b'); - - EXPECT_EQ(expected_null, SysWideToNativeMB(wide_null)); -} - -// We assume the test is running in a UTF8 locale. -TEST(SysStrings, SysNativeMBToWide) { - ScopedLocale locale("en_US.utf-8"); - EXPECT_EQ(L"Hello, world", SysNativeMBToWide("Hello, world")); - EXPECT_EQ(L"\x4f60\x597d", SysNativeMBToWide("\xe4\xbd\xa0\xe5\xa5\xbd")); - // >16 bits - EXPECT_EQ(kSysWideOldItalicLetterA, SysNativeMBToWide("\xF0\x90\x8C\x80")); - - // Error case. When Windows finds an invalid UTF-8 character, it just skips - // it. This seems weird because it's inconsistent with the reverse conversion. - // - // This is what XP does, but Vista has different behavior, so we don't bother - // verifying it: - // EXPECT_EQ(L"\x4f60zyxw", SysNativeMBToWide("\xe4\xbd\xa0\xe5\xa5zyxw")); - - // Test embedded NULLs. - std::string utf8_null("a"); - utf8_null.push_back(0); - utf8_null.push_back('b'); - - std::wstring expected_null(L"a"); - expected_null.push_back(0); - expected_null.push_back('b'); - - EXPECT_EQ(expected_null, SysNativeMBToWide(utf8_null)); -} - -static const wchar_t* const kConvertRoundtripCases[] = { - L"Google Video", - // "网页 图片 资讯更多 »" - L"\x7f51\x9875\x0020\x56fe\x7247\x0020\x8d44\x8baf\x66f4\x591a\x0020\x00bb", - // "Παγκόσμιος Ιστός" - L"\x03a0\x03b1\x03b3\x03ba\x03cc\x03c3\x03bc\x03b9" - L"\x03bf\x03c2\x0020\x0399\x03c3\x03c4\x03cc\x03c2", - // "Поиск страниц на русском" - L"\x041f\x043e\x0438\x0441\x043a\x0020\x0441\x0442" - L"\x0440\x0430\x043d\x0438\x0446\x0020\x043d\x0430" - L"\x0020\x0440\x0443\x0441\x0441\x043a\x043e\x043c", - // "전체서비스" - L"\xc804\xccb4\xc11c\xbe44\xc2a4", - - // Test characters that take more than 16 bits. This will depend on whether - // wchar_t is 16 or 32 bits. -#if defined(WCHAR_T_IS_UTF16) - L"\xd800\xdf00", - // ????? (Mathematical Alphanumeric Symbols (U+011d40 - U+011d44 : A,B,C,D,E) - L"\xd807\xdd40\xd807\xdd41\xd807\xdd42\xd807\xdd43\xd807\xdd44", -#elif defined(WCHAR_T_IS_UTF32) - L"\x10300", - // ????? (Mathematical Alphanumeric Symbols (U+011d40 - U+011d44 : A,B,C,D,E) - L"\x11d40\x11d41\x11d42\x11d43\x11d44", -#endif -}; - - -TEST(SysStrings, SysNativeMBAndWide) { - ScopedLocale locale("en_US.utf-8"); - for (size_t i = 0; i < arraysize(kConvertRoundtripCases); ++i) { - std::wstring wide = kConvertRoundtripCases[i]; - std::wstring trip = SysNativeMBToWide(SysWideToNativeMB(wide)); - EXPECT_EQ(wide.size(), trip.size()); - EXPECT_EQ(wide, trip); - } - - // We assume our test is running in UTF-8, so double check through ICU. - for (size_t i = 0; i < arraysize(kConvertRoundtripCases); ++i) { - std::wstring wide = kConvertRoundtripCases[i]; - std::wstring trip = SysNativeMBToWide(WideToUTF8(wide)); - EXPECT_EQ(wide.size(), trip.size()); - EXPECT_EQ(wide, trip); - } - - for (size_t i = 0; i < arraysize(kConvertRoundtripCases); ++i) { - std::wstring wide = kConvertRoundtripCases[i]; - std::wstring trip = UTF8ToWide(SysWideToNativeMB(wide)); - EXPECT_EQ(wide.size(), trip.size()); - EXPECT_EQ(wide, trip); - } -} -#endif // OS_LINUX - -} // namespace base diff --git a/base/strings/sys_string_conversions_win.cc b/base/strings/sys_string_conversions_win.cc deleted file mode 100644 index 94d4466223..0000000000 --- a/base/strings/sys_string_conversions_win.cc +++ /dev/null @@ -1,70 +0,0 @@ -// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "base/strings/sys_string_conversions.h" - -#include - -#include "base/strings/string_piece.h" - -namespace base { - -// Do not assert in this function since it is used by the asssertion code! -std::string SysWideToUTF8(const std::wstring& wide) { - return SysWideToMultiByte(wide, CP_UTF8); -} - -// Do not assert in this function since it is used by the asssertion code! -std::wstring SysUTF8ToWide(const StringPiece& utf8) { - return SysMultiByteToWide(utf8, CP_UTF8); -} - -std::string SysWideToNativeMB(const std::wstring& wide) { - return SysWideToMultiByte(wide, CP_ACP); -} - -std::wstring SysNativeMBToWide(const StringPiece& native_mb) { - return SysMultiByteToWide(native_mb, CP_ACP); -} - -// Do not assert in this function since it is used by the asssertion code! -std::wstring SysMultiByteToWide(const StringPiece& mb, uint32 code_page) { - if (mb.empty()) - return std::wstring(); - - int mb_length = static_cast(mb.length()); - // Compute the length of the buffer. - int charcount = MultiByteToWideChar(code_page, 0, - mb.data(), mb_length, NULL, 0); - if (charcount == 0) - return std::wstring(); - - std::wstring wide; - wide.resize(charcount); - MultiByteToWideChar(code_page, 0, mb.data(), mb_length, &wide[0], charcount); - - return wide; -} - -// Do not assert in this function since it is used by the asssertion code! -std::string SysWideToMultiByte(const std::wstring& wide, uint32 code_page) { - int wide_length = static_cast(wide.length()); - if (wide_length == 0) - return std::string(); - - // Compute the length of the buffer we'll need. - int charcount = WideCharToMultiByte(code_page, 0, wide.data(), wide_length, - NULL, 0, NULL, NULL); - if (charcount == 0) - return std::string(); - - std::string mb; - mb.resize(charcount); - WideCharToMultiByte(code_page, 0, wide.data(), wide_length, - &mb[0], charcount, NULL, NULL); - - return mb; -} - -} // namespace base diff --git a/base/strings/utf_offset_string_conversions.cc b/base/strings/utf_offset_string_conversions.cc deleted file mode 100644 index bb402e4d24..0000000000 --- a/base/strings/utf_offset_string_conversions.cc +++ /dev/null @@ -1,166 +0,0 @@ -// Copyright (c) 2011 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "base/strings/utf_offset_string_conversions.h" - -#include - -#include "base/memory/scoped_ptr.h" -#include "base/strings/string_piece.h" -#include "base/strings/utf_string_conversion_utils.h" - -namespace base { - -// Converts the given source Unicode character type to the given destination -// Unicode character type as a STL string. The given input buffer and size -// determine the source, and the given output STL string will be replaced by -// the result. -template -bool ConvertUnicode(const SrcChar* src, - size_t src_len, - DestStdString* output, - std::vector* offsets_for_adjustment) { - if (offsets_for_adjustment) { - std::for_each(offsets_for_adjustment->begin(), - offsets_for_adjustment->end(), - LimitOffset(src_len)); - } - - // ICU requires 32-bit numbers. - bool success = true; - OffsetAdjuster offset_adjuster(offsets_for_adjustment); - int32 src_len32 = static_cast(src_len); - for (int32 i = 0; i < src_len32; i++) { - uint32 code_point; - size_t original_i = i; - size_t chars_written = 0; - if (ReadUnicodeCharacter(src, src_len32, &i, &code_point)) { - chars_written = WriteUnicodeCharacter(code_point, output); - } else { - chars_written = WriteUnicodeCharacter(0xFFFD, output); - success = false; - } - if (offsets_for_adjustment) { - // NOTE: ReadUnicodeCharacter() adjusts |i| to point _at_ the last - // character read, not after it (so that incrementing it in the loop - // increment will place it at the right location), so we need to account - // for that in determining the amount that was read. - offset_adjuster.Add(OffsetAdjuster::Adjustment(original_i, - i - original_i + 1, chars_written)); - } - } - return success; -} - -bool UTF8ToUTF16AndAdjustOffset(const char* src, - size_t src_len, - string16* output, - size_t* offset_for_adjustment) { - std::vector offsets; - if (offset_for_adjustment) - offsets.push_back(*offset_for_adjustment); - PrepareForUTF16Or32Output(src, src_len, output); - bool ret = ConvertUnicode(src, src_len, output, &offsets); - if (offset_for_adjustment) - *offset_for_adjustment = offsets[0]; - return ret; -} - -bool UTF8ToUTF16AndAdjustOffsets(const char* src, - size_t src_len, - string16* output, - std::vector* offsets_for_adjustment) { - PrepareForUTF16Or32Output(src, src_len, output); - return ConvertUnicode(src, src_len, output, offsets_for_adjustment); -} - -string16 UTF8ToUTF16AndAdjustOffset(const base::StringPiece& utf8, - size_t* offset_for_adjustment) { - std::vector offsets; - if (offset_for_adjustment) - offsets.push_back(*offset_for_adjustment); - string16 result; - UTF8ToUTF16AndAdjustOffsets(utf8.data(), utf8.length(), &result, - &offsets); - if (offset_for_adjustment) - *offset_for_adjustment = offsets[0]; - return result; -} - -string16 UTF8ToUTF16AndAdjustOffsets( - const base::StringPiece& utf8, - std::vector* offsets_for_adjustment) { - string16 result; - UTF8ToUTF16AndAdjustOffsets(utf8.data(), utf8.length(), &result, - offsets_for_adjustment); - return result; -} - -std::string UTF16ToUTF8AndAdjustOffset( - const base::StringPiece16& utf16, - size_t* offset_for_adjustment) { - std::vector offsets; - if (offset_for_adjustment) - offsets.push_back(*offset_for_adjustment); - std::string result = UTF16ToUTF8AndAdjustOffsets(utf16, &offsets); - if (offset_for_adjustment) - *offset_for_adjustment = offsets[0]; - return result; -} - -std::string UTF16ToUTF8AndAdjustOffsets( - const base::StringPiece16& utf16, - std::vector* offsets_for_adjustment) { - std::string result; - PrepareForUTF8Output(utf16.data(), utf16.length(), &result); - ConvertUnicode(utf16.data(), utf16.length(), &result, offsets_for_adjustment); - return result; -} - -OffsetAdjuster::Adjustment::Adjustment(size_t original_offset, - size_t original_length, - size_t output_length) - : original_offset(original_offset), - original_length(original_length), - output_length(output_length) { -} - -OffsetAdjuster::OffsetAdjuster(std::vector* offsets_for_adjustment) - : offsets_for_adjustment_(offsets_for_adjustment) { -} - -OffsetAdjuster::~OffsetAdjuster() { - if (!offsets_for_adjustment_ || adjustments_.empty()) - return; - for (std::vector::iterator i(offsets_for_adjustment_->begin()); - i != offsets_for_adjustment_->end(); ++i) - AdjustOffset(i); -} - -void OffsetAdjuster::Add(const Adjustment& adjustment) { - adjustments_.push_back(adjustment); -} - -void OffsetAdjuster::AdjustOffset(std::vector::iterator offset) { - if (*offset == string16::npos) - return; - size_t adjustment = 0; - for (std::vector::const_iterator i = adjustments_.begin(); - i != adjustments_.end(); ++i) { - if (*offset == i->original_offset && i->output_length == 0) { - *offset = string16::npos; - return; - } - if (*offset <= i->original_offset) - break; - if (*offset < (i->original_offset + i->original_length)) { - *offset = string16::npos; - return; - } - adjustment += (i->original_length - i->output_length); - } - *offset -= adjustment; -} - -} // namespace base diff --git a/base/strings/utf_offset_string_conversions.h b/base/strings/utf_offset_string_conversions.h deleted file mode 100644 index 1b615f4449..0000000000 --- a/base/strings/utf_offset_string_conversions.h +++ /dev/null @@ -1,93 +0,0 @@ -// Copyright (c) 2011 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef BASE_STRINGS_UTF_OFFSET_STRING_CONVERSIONS_H_ -#define BASE_STRINGS_UTF_OFFSET_STRING_CONVERSIONS_H_ - -#include -#include - -#include "base/base_export.h" -#include "base/strings/string16.h" -#include "base/strings/string_piece.h" - -namespace base { - -// Like the conversions in utf_string_conversions.h, but also takes one or more -// offsets (|offset[s]_for_adjustment|) into the source strings, each offset -// will be adjusted to point at the same logical place in the result strings. -// If this isn't possible because an offset points past the end of the source -// strings or into the middle of a multibyte sequence, the offending offset will -// be set to string16::npos. |offset[s]_for_adjustment| may be NULL. -BASE_EXPORT bool UTF8ToUTF16AndAdjustOffset(const char* src, - size_t src_len, - string16* output, - size_t* offset_for_adjustment); -BASE_EXPORT bool UTF8ToUTF16AndAdjustOffsets( - const char* src, - size_t src_len, - string16* output, - std::vector* offsets_for_adjustment); - -BASE_EXPORT string16 UTF8ToUTF16AndAdjustOffset(const base::StringPiece& utf8, - size_t* offset_for_adjustment); -BASE_EXPORT string16 UTF8ToUTF16AndAdjustOffsets( - const base::StringPiece& utf8, - std::vector* offsets_for_adjustment); - -BASE_EXPORT std::string UTF16ToUTF8AndAdjustOffset( - const base::StringPiece16& utf16, - size_t* offset_for_adjustment); -BASE_EXPORT std::string UTF16ToUTF8AndAdjustOffsets( - const base::StringPiece16& utf16, - std::vector* offsets_for_adjustment); - -// Limiting function callable by std::for_each which will replace any value -// which is equal to or greater than |limit| with npos. -template -struct LimitOffset { - explicit LimitOffset(size_t limit) - : limit_(limit) {} - - void operator()(size_t& offset) { - if (offset >= limit_) - offset = T::npos; - } - - size_t limit_; -}; - -// Stack object which, on destruction, will update a vector of offsets based on -// any supplied adjustments. To use, declare one of these, providing the -// address of the offset vector to adjust. Then Add() any number of Adjustments -// (each Adjustment gives the |original_offset| of a substring and the lengths -// of the substring before and after transforming). When the OffsetAdjuster -// goes out of scope, all the offsets in the provided vector will be updated. -class BASE_EXPORT OffsetAdjuster { - public: - struct BASE_EXPORT Adjustment { - Adjustment(size_t original_offset, - size_t original_length, - size_t output_length); - - size_t original_offset; - size_t original_length; - size_t output_length; - }; - - explicit OffsetAdjuster(std::vector* offsets_for_adjustment); - ~OffsetAdjuster(); - - void Add(const Adjustment& adjustment); - - private: - void AdjustOffset(std::vector::iterator offset); - - std::vector* offsets_for_adjustment_; - std::vector adjustments_; -}; - -} // namespace base - -#endif // BASE_STRINGS_UTF_OFFSET_STRING_CONVERSIONS_H_ diff --git a/base/strings/utf_offset_string_conversions_unittest.cc b/base/strings/utf_offset_string_conversions_unittest.cc deleted file mode 100644 index 5545c0d22e..0000000000 --- a/base/strings/utf_offset_string_conversions_unittest.cc +++ /dev/null @@ -1,154 +0,0 @@ -// Copyright (c) 2011 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include - -#include "base/logging.h" -#include "base/strings/string_piece.h" -#include "base/strings/utf_offset_string_conversions.h" -#include "testing/gtest/include/gtest/gtest.h" - -namespace base { - -namespace { - -static const size_t kNpos = string16::npos; - -} // namespace - -TEST(UTFOffsetStringConversionsTest, AdjustOffset) { - struct UTF8ToUTF16Case { - const char* utf8; - size_t input_offset; - size_t output_offset; - } utf8_to_utf16_cases[] = { - {"", 0, kNpos}, - {"\xe4\xbd\xa0\xe5\xa5\xbd", 1, kNpos}, - {"\xe4\xbd\xa0\xe5\xa5\xbd", 3, 1}, - {"\xed\xb0\x80z", 3, 1}, - {"A\xF0\x90\x8C\x80z", 1, 1}, - {"A\xF0\x90\x8C\x80z", 2, kNpos}, - {"A\xF0\x90\x8C\x80z", 5, 3}, - }; - for (size_t i = 0; i < ARRAYSIZE_UNSAFE(utf8_to_utf16_cases); ++i) { - size_t offset = utf8_to_utf16_cases[i].input_offset; - UTF8ToUTF16AndAdjustOffset(utf8_to_utf16_cases[i].utf8, &offset); - EXPECT_EQ(utf8_to_utf16_cases[i].output_offset, offset); - } - - struct UTF16ToUTF8Case { - char16 utf16[10]; - size_t input_offset; - size_t output_offset; - } utf16_to_utf8_cases[] = { - {{}, 0, kNpos}, - // Converted to 3-byte utf-8 sequences - {{0x5909, 0x63DB}, 2, kNpos}, - {{0x5909, 0x63DB}, 1, 3}, - // Converted to 2-byte utf-8 sequences - {{'A', 0x00bc, 0x00be, 'z'}, 1, 1}, - {{'A', 0x00bc, 0x00be, 'z'}, 2, 3}, - {{'A', 0x00bc, 0x00be, 'z'}, 3, 5}, - // Surrogate pair - {{'A', 0xd800, 0xdf00, 'z'}, 1, 1}, - {{'A', 0xd800, 0xdf00, 'z'}, 2, kNpos}, - {{'A', 0xd800, 0xdf00, 'z'}, 3, 5}, - }; - for (size_t i = 0; i < ARRAYSIZE_UNSAFE(utf16_to_utf8_cases); ++i) { - size_t offset = utf16_to_utf8_cases[i].input_offset; - UTF16ToUTF8AndAdjustOffset(utf16_to_utf8_cases[i].utf16, &offset); - EXPECT_EQ(utf16_to_utf8_cases[i].output_offset, offset); - } -} - -TEST(UTFOffsetStringConversionsTest, LimitOffsets) { - const size_t kLimit = 10; - const size_t kItems = 20; - std::vector size_ts; - for (size_t t = 0; t < kItems; ++t) - size_ts.push_back(t); - std::for_each(size_ts.begin(), size_ts.end(), - LimitOffset(kLimit)); - size_t unlimited_count = 0; - for (std::vector::iterator ti = size_ts.begin(); ti != size_ts.end(); - ++ti) { - if (*ti < kLimit && *ti != kNpos) - ++unlimited_count; - } - EXPECT_EQ(10U, unlimited_count); - - // Reverse the values in the vector and try again. - size_ts.clear(); - for (size_t t = kItems; t > 0; --t) - size_ts.push_back(t - 1); - std::for_each(size_ts.begin(), size_ts.end(), - LimitOffset(kLimit)); - unlimited_count = 0; - for (std::vector::iterator ti = size_ts.begin(); ti != size_ts.end(); - ++ti) { - if (*ti < kLimit && *ti != kNpos) - ++unlimited_count; - } - EXPECT_EQ(10U, unlimited_count); -} - -TEST(UTFOffsetStringConversionsTest, AdjustOffsets) { - // Imagine we have strings as shown in the following cases where the - // X's represent encoded characters. - // 1: abcXXXdef ==> abcXdef - { - std::vector offsets; - for (size_t t = 0; t < 9; ++t) - offsets.push_back(t); - { - OffsetAdjuster offset_adjuster(&offsets); - offset_adjuster.Add(OffsetAdjuster::Adjustment(3, 3, 1)); - } - size_t expected_1[] = {0, 1, 2, 3, kNpos, kNpos, 4, 5, 6}; - EXPECT_EQ(offsets.size(), arraysize(expected_1)); - for (size_t i = 0; i < arraysize(expected_1); ++i) - EXPECT_EQ(expected_1[i], offsets[i]); - } - - // 2: XXXaXXXXbcXXXXXXXdefXXX ==> XaXXbcXXXXdefX - { - std::vector offsets; - for (size_t t = 0; t < 23; ++t) - offsets.push_back(t); - { - OffsetAdjuster offset_adjuster(&offsets); - offset_adjuster.Add(OffsetAdjuster::Adjustment(0, 3, 1)); - offset_adjuster.Add(OffsetAdjuster::Adjustment(4, 4, 2)); - offset_adjuster.Add(OffsetAdjuster::Adjustment(10, 7, 4)); - offset_adjuster.Add(OffsetAdjuster::Adjustment(20, 3, 1)); - } - size_t expected_2[] = {0, kNpos, kNpos, 1, 2, kNpos, kNpos, kNpos, 4, 5, 6, - kNpos, kNpos, kNpos, kNpos, kNpos, kNpos, 10, 11, 12, - 13, kNpos, kNpos}; - EXPECT_EQ(offsets.size(), arraysize(expected_2)); - for (size_t i = 0; i < arraysize(expected_2); ++i) - EXPECT_EQ(expected_2[i], offsets[i]); - } - - // 3: XXXaXXXXbcdXXXeXX ==> aXXXXbcdXXXe - { - std::vector offsets; - for (size_t t = 0; t < 17; ++t) - offsets.push_back(t); - { - OffsetAdjuster offset_adjuster(&offsets); - offset_adjuster.Add(OffsetAdjuster::Adjustment(0, 3, 0)); - offset_adjuster.Add(OffsetAdjuster::Adjustment(4, 4, 4)); - offset_adjuster.Add(OffsetAdjuster::Adjustment(11, 3, 3)); - offset_adjuster.Add(OffsetAdjuster::Adjustment(15, 2, 0)); - } - size_t expected_3[] = {kNpos, kNpos, kNpos, 0, 1, kNpos, kNpos, kNpos, 5, 6, - 7, 8, kNpos, kNpos, 11, kNpos, kNpos}; - EXPECT_EQ(offsets.size(), arraysize(expected_3)); - for (size_t i = 0; i < arraysize(expected_3); ++i) - EXPECT_EQ(expected_3[i], offsets[i]); - } -} - -} // namaspace base diff --git a/base/strings/utf_string_conversion_utils.cc b/base/strings/utf_string_conversion_utils.cc deleted file mode 100644 index 09a003d1b9..0000000000 --- a/base/strings/utf_string_conversion_utils.cc +++ /dev/null @@ -1,148 +0,0 @@ -// Copyright (c) 2009 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "base/strings/utf_string_conversion_utils.h" - -#include "base/third_party/icu/icu_utf.h" - -namespace base { - -// ReadUnicodeCharacter -------------------------------------------------------- - -bool ReadUnicodeCharacter(const char* src, - int32 src_len, - int32* char_index, - uint32* code_point_out) { - // U8_NEXT expects to be able to use -1 to signal an error, so we must - // use a signed type for code_point. But this function returns false - // on error anyway, so code_point_out is unsigned. - int32 code_point; - CBU8_NEXT(src, *char_index, src_len, code_point); - *code_point_out = static_cast(code_point); - - // The ICU macro above moves to the next char, we want to point to the last - // char consumed. - (*char_index)--; - - // Validate the decoded value. - return IsValidCodepoint(code_point); -} - -bool ReadUnicodeCharacter(const char16* src, - int32 src_len, - int32* char_index, - uint32* code_point) { - if (CBU16_IS_SURROGATE(src[*char_index])) { - if (!CBU16_IS_SURROGATE_LEAD(src[*char_index]) || - *char_index + 1 >= src_len || - !CBU16_IS_TRAIL(src[*char_index + 1])) { - // Invalid surrogate pair. - return false; - } - - // Valid surrogate pair. - *code_point = CBU16_GET_SUPPLEMENTARY(src[*char_index], - src[*char_index + 1]); - (*char_index)++; - } else { - // Not a surrogate, just one 16-bit word. - *code_point = src[*char_index]; - } - - return IsValidCodepoint(*code_point); -} - -#if defined(WCHAR_T_IS_UTF32) -bool ReadUnicodeCharacter(const wchar_t* src, - int32 src_len, - int32* char_index, - uint32* code_point) { - // Conversion is easy since the source is 32-bit. - *code_point = src[*char_index]; - - // Validate the value. - return IsValidCodepoint(*code_point); -} -#endif // defined(WCHAR_T_IS_UTF32) - -// WriteUnicodeCharacter ------------------------------------------------------- - -size_t WriteUnicodeCharacter(uint32 code_point, std::string* output) { - if (code_point <= 0x7f) { - // Fast path the common case of one byte. - output->push_back(code_point); - return 1; - } - - - // CBU8_APPEND_UNSAFE can append up to 4 bytes. - size_t char_offset = output->length(); - size_t original_char_offset = char_offset; - output->resize(char_offset + CBU8_MAX_LENGTH); - - CBU8_APPEND_UNSAFE(&(*output)[0], char_offset, code_point); - - // CBU8_APPEND_UNSAFE will advance our pointer past the inserted character, so - // it will represent the new length of the string. - output->resize(char_offset); - return char_offset - original_char_offset; -} - -size_t WriteUnicodeCharacter(uint32 code_point, string16* output) { - if (CBU16_LENGTH(code_point) == 1) { - // Thie code point is in the Basic Multilingual Plane (BMP). - output->push_back(static_cast(code_point)); - return 1; - } - // Non-BMP characters use a double-character encoding. - size_t char_offset = output->length(); - output->resize(char_offset + CBU16_MAX_LENGTH); - CBU16_APPEND_UNSAFE(&(*output)[0], char_offset, code_point); - return CBU16_MAX_LENGTH; -} - -// Generalized Unicode converter ----------------------------------------------- - -template -void PrepareForUTF8Output(const CHAR* src, - size_t src_len, - std::string* output) { - output->clear(); - if (src_len == 0) - return; - if (src[0] < 0x80) { - // Assume that the entire input will be ASCII. - output->reserve(src_len); - } else { - // Assume that the entire input is non-ASCII and will have 3 bytes per char. - output->reserve(src_len * 3); - } -} - -// Instantiate versions we know callers will need. -template void PrepareForUTF8Output(const wchar_t*, size_t, std::string*); -template void PrepareForUTF8Output(const char16*, size_t, std::string*); - -template -void PrepareForUTF16Or32Output(const char* src, - size_t src_len, - STRING* output) { - output->clear(); - if (src_len == 0) - return; - if (static_cast(src[0]) < 0x80) { - // Assume the input is all ASCII, which means 1:1 correspondence. - output->reserve(src_len); - } else { - // Otherwise assume that the UTF-8 sequences will have 2 bytes for each - // character. - output->reserve(src_len / 2); - } -} - -// Instantiate versions we know callers will need. -template void PrepareForUTF16Or32Output(const char*, size_t, std::wstring*); -template void PrepareForUTF16Or32Output(const char*, size_t, string16*); - -} // namespace base diff --git a/base/strings/utf_string_conversion_utils.h b/base/strings/utf_string_conversion_utils.h deleted file mode 100644 index 22abbbc9e7..0000000000 --- a/base/strings/utf_string_conversion_utils.h +++ /dev/null @@ -1,97 +0,0 @@ -// Copyright (c) 2011 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef BASE_STRINGS_UTF_STRING_CONVERSION_UTILS_H_ -#define BASE_STRINGS_UTF_STRING_CONVERSION_UTILS_H_ - -// This should only be used by the various UTF string conversion files. - -#include "base/base_export.h" -#include "base/strings/string16.h" - -namespace base { - -inline bool IsValidCodepoint(uint32 code_point) { - // Excludes the surrogate code points ([0xD800, 0xDFFF]) and - // codepoints larger than 0x10FFFF (the highest codepoint allowed). - // Non-characters and unassigned codepoints are allowed. - return code_point < 0xD800u || - (code_point >= 0xE000u && code_point <= 0x10FFFFu); -} - -inline bool IsValidCharacter(uint32 code_point) { - // Excludes non-characters (U+FDD0..U+FDEF, and all codepoints ending in - // 0xFFFE or 0xFFFF) from the set of valid code points. - return code_point < 0xD800u || (code_point >= 0xE000u && - code_point < 0xFDD0u) || (code_point > 0xFDEFu && - code_point <= 0x10FFFFu && (code_point & 0xFFFEu) != 0xFFFEu); -} - -// ReadUnicodeCharacter -------------------------------------------------------- - -// Reads a UTF-8 stream, placing the next code point into the given output -// |*code_point|. |src| represents the entire string to read, and |*char_index| -// is the character offset within the string to start reading at. |*char_index| -// will be updated to index the last character read, such that incrementing it -// (as in a for loop) will take the reader to the next character. -// -// Returns true on success. On false, |*code_point| will be invalid. -BASE_EXPORT bool ReadUnicodeCharacter(const char* src, - int32 src_len, - int32* char_index, - uint32* code_point_out); - -// Reads a UTF-16 character. The usage is the same as the 8-bit version above. -BASE_EXPORT bool ReadUnicodeCharacter(const char16* src, - int32 src_len, - int32* char_index, - uint32* code_point); - -#if defined(WCHAR_T_IS_UTF32) -// Reads UTF-32 character. The usage is the same as the 8-bit version above. -BASE_EXPORT bool ReadUnicodeCharacter(const wchar_t* src, - int32 src_len, - int32* char_index, - uint32* code_point); -#endif // defined(WCHAR_T_IS_UTF32) - -// WriteUnicodeCharacter ------------------------------------------------------- - -// Appends a UTF-8 character to the given 8-bit string. Returns the number of -// bytes written. -// TODO(brettw) Bug 79631: This function should not be exposed. -BASE_EXPORT size_t WriteUnicodeCharacter(uint32 code_point, - std::string* output); - -// Appends the given code point as a UTF-16 character to the given 16-bit -// string. Returns the number of 16-bit values written. -BASE_EXPORT size_t WriteUnicodeCharacter(uint32 code_point, string16* output); - -#if defined(WCHAR_T_IS_UTF32) -// Appends the given UTF-32 character to the given 32-bit string. Returns the -// number of 32-bit values written. -inline size_t WriteUnicodeCharacter(uint32 code_point, std::wstring* output) { - // This is the easy case, just append the character. - output->push_back(code_point); - return 1; -} -#endif // defined(WCHAR_T_IS_UTF32) - -// Generalized Unicode converter ----------------------------------------------- - -// Guesses the length of the output in UTF-8 in bytes, clears that output -// string, and reserves that amount of space. We assume that the input -// character types are unsigned, which will be true for UTF-16 and -32 on our -// systems. -template -void PrepareForUTF8Output(const CHAR* src, size_t src_len, std::string* output); - -// Prepares an output buffer (containing either UTF-16 or -32 data) given some -// UTF-8 input that will be converted to it. See PrepareForUTF8Output(). -template -void PrepareForUTF16Or32Output(const char* src, size_t src_len, STRING* output); - -} // namespace base - -#endif // BASE_STRINGS_UTF_STRING_CONVERSION_UTILS_H_ diff --git a/base/strings/utf_string_conversions.cc b/base/strings/utf_string_conversions.cc deleted file mode 100644 index c3ea4f253e..0000000000 --- a/base/strings/utf_string_conversions.cc +++ /dev/null @@ -1,185 +0,0 @@ -// Copyright (c) 2010 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "base/strings/utf_string_conversions.h" - -#include "base/strings/string_piece.h" -#include "base/strings/string_util.h" -#include "base/strings/utf_string_conversion_utils.h" - -namespace base { - -namespace { - -// Generalized Unicode converter ----------------------------------------------- - -// Converts the given source Unicode character type to the given destination -// Unicode character type as a STL string. The given input buffer and size -// determine the source, and the given output STL string will be replaced by -// the result. -template -bool ConvertUnicode(const SRC_CHAR* src, - size_t src_len, - DEST_STRING* output) { - // ICU requires 32-bit numbers. - bool success = true; - int32 src_len32 = static_cast(src_len); - for (int32 i = 0; i < src_len32; i++) { - uint32 code_point; - if (ReadUnicodeCharacter(src, src_len32, &i, &code_point)) { - WriteUnicodeCharacter(code_point, output); - } else { - WriteUnicodeCharacter(0xFFFD, output); - success = false; - } - } - - return success; -} - -} // namespace - -// UTF-8 <-> Wide -------------------------------------------------------------- - -bool WideToUTF8(const wchar_t* src, size_t src_len, std::string* output) { - PrepareForUTF8Output(src, src_len, output); - return ConvertUnicode(src, src_len, output); -} - -std::string WideToUTF8(const std::wstring& wide) { - std::string ret; - // Ignore the success flag of this call, it will do the best it can for - // invalid input, which is what we want here. - WideToUTF8(wide.data(), wide.length(), &ret); - return ret; -} - -bool UTF8ToWide(const char* src, size_t src_len, std::wstring* output) { - PrepareForUTF16Or32Output(src, src_len, output); - return ConvertUnicode(src, src_len, output); -} - -std::wstring UTF8ToWide(const StringPiece& utf8) { - std::wstring ret; - UTF8ToWide(utf8.data(), utf8.length(), &ret); - return ret; -} - -// UTF-16 <-> Wide ------------------------------------------------------------- - -#if defined(WCHAR_T_IS_UTF16) - -// When wide == UTF-16, then conversions are a NOP. -bool WideToUTF16(const wchar_t* src, size_t src_len, string16* output) { - output->assign(src, src_len); - return true; -} - -string16 WideToUTF16(const std::wstring& wide) { - return wide; -} - -bool UTF16ToWide(const char16* src, size_t src_len, std::wstring* output) { - output->assign(src, src_len); - return true; -} - -std::wstring UTF16ToWide(const string16& utf16) { - return utf16; -} - -#elif defined(WCHAR_T_IS_UTF32) - -bool WideToUTF16(const wchar_t* src, size_t src_len, string16* output) { - output->clear(); - // Assume that normally we won't have any non-BMP characters so the counts - // will be the same. - output->reserve(src_len); - return ConvertUnicode(src, src_len, output); -} - -string16 WideToUTF16(const std::wstring& wide) { - string16 ret; - WideToUTF16(wide.data(), wide.length(), &ret); - return ret; -} - -bool UTF16ToWide(const char16* src, size_t src_len, std::wstring* output) { - output->clear(); - // Assume that normally we won't have any non-BMP characters so the counts - // will be the same. - output->reserve(src_len); - return ConvertUnicode(src, src_len, output); -} - -std::wstring UTF16ToWide(const string16& utf16) { - std::wstring ret; - UTF16ToWide(utf16.data(), utf16.length(), &ret); - return ret; -} - -#endif // defined(WCHAR_T_IS_UTF32) - -// UTF16 <-> UTF8 -------------------------------------------------------------- - -#if defined(WCHAR_T_IS_UTF32) - -bool UTF8ToUTF16(const char* src, size_t src_len, string16* output) { - PrepareForUTF16Or32Output(src, src_len, output); - return ConvertUnicode(src, src_len, output); -} - -string16 UTF8ToUTF16(const StringPiece& utf8) { - string16 ret; - // Ignore the success flag of this call, it will do the best it can for - // invalid input, which is what we want here. - UTF8ToUTF16(utf8.data(), utf8.length(), &ret); - return ret; -} - -bool UTF16ToUTF8(const char16* src, size_t src_len, std::string* output) { - PrepareForUTF8Output(src, src_len, output); - return ConvertUnicode(src, src_len, output); -} - -std::string UTF16ToUTF8(const string16& utf16) { - std::string ret; - // Ignore the success flag of this call, it will do the best it can for - // invalid input, which is what we want here. - UTF16ToUTF8(utf16.data(), utf16.length(), &ret); - return ret; -} - -#elif defined(WCHAR_T_IS_UTF16) -// Easy case since we can use the "wide" versions we already wrote above. - -bool UTF8ToUTF16(const char* src, size_t src_len, string16* output) { - return UTF8ToWide(src, src_len, output); -} - -string16 UTF8ToUTF16(const StringPiece& utf8) { - return UTF8ToWide(utf8); -} - -bool UTF16ToUTF8(const char16* src, size_t src_len, std::string* output) { - return WideToUTF8(src, src_len, output); -} - -std::string UTF16ToUTF8(const string16& utf16) { - return WideToUTF8(utf16); -} - -#endif - -std::wstring ASCIIToWide(const StringPiece& ascii) { - DCHECK(IsStringASCII(ascii)) << ascii; - return std::wstring(ascii.begin(), ascii.end()); -} - -string16 ASCIIToUTF16(const StringPiece& ascii) { - DCHECK(IsStringASCII(ascii)) << ascii; - return string16(ascii.begin(), ascii.end()); -} - -} // namespace base diff --git a/base/strings/utf_string_conversions.h b/base/strings/utf_string_conversions.h deleted file mode 100644 index 3461aa491d..0000000000 --- a/base/strings/utf_string_conversions.h +++ /dev/null @@ -1,72 +0,0 @@ -// Copyright (c) 2011 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef BASE_STRINGS_UTF_STRING_CONVERSIONS_H_ -#define BASE_STRINGS_UTF_STRING_CONVERSIONS_H_ - -#include - -#include "base/base_export.h" -#include "base/strings/string16.h" -#include "base/strings/string_piece.h" - -namespace base { - -// These convert between UTF-8, -16, and -32 strings. They are potentially slow, -// so avoid unnecessary conversions. The low-level versions return a boolean -// indicating whether the conversion was 100% valid. In this case, it will still -// do the best it can and put the result in the output buffer. The versions that -// return strings ignore this error and just return the best conversion -// possible. -BASE_EXPORT bool WideToUTF8(const wchar_t* src, size_t src_len, - std::string* output); -BASE_EXPORT std::string WideToUTF8(const std::wstring& wide); -BASE_EXPORT bool UTF8ToWide(const char* src, size_t src_len, - std::wstring* output); -BASE_EXPORT std::wstring UTF8ToWide(const StringPiece& utf8); - -BASE_EXPORT bool WideToUTF16(const wchar_t* src, size_t src_len, - string16* output); -BASE_EXPORT string16 WideToUTF16(const std::wstring& wide); -BASE_EXPORT bool UTF16ToWide(const char16* src, size_t src_len, - std::wstring* output); -BASE_EXPORT std::wstring UTF16ToWide(const string16& utf16); - -BASE_EXPORT bool UTF8ToUTF16(const char* src, size_t src_len, string16* output); -BASE_EXPORT string16 UTF8ToUTF16(const StringPiece& utf8); -BASE_EXPORT bool UTF16ToUTF8(const char16* src, size_t src_len, - std::string* output); -BASE_EXPORT std::string UTF16ToUTF8(const string16& utf16); - -// We are trying to get rid of wstring as much as possible, but it's too big -// a mess to do it all at once. These conversions should be used when we -// really should just be passing a string16 around, but we haven't finished -// porting whatever module uses wstring and the conversion is being used as a -// stopcock. This makes it easy to grep for the ones that should be removed. -#if defined(OS_WIN) -# define WideToUTF16Hack -# define UTF16ToWideHack -#else -# define WideToUTF16Hack WideToUTF16 -# define UTF16ToWideHack UTF16ToWide -#endif - -// These convert an ASCII string, typically a hardcoded constant, to a -// UTF16/Wide string. -BASE_EXPORT std::wstring ASCIIToWide(const StringPiece& ascii); -BASE_EXPORT string16 ASCIIToUTF16(const StringPiece& ascii); - -} // namespace base - -// TODO(brettw) remove these when callers are fixed up. -using base::WideToUTF8; -using base::UTF8ToWide; -using base::WideToUTF16; -using base::UTF16ToWide; -using base::UTF8ToUTF16; -using base::UTF16ToUTF8; -using base::ASCIIToWide; -using base::ASCIIToUTF16; - -#endif // BASE_STRINGS_UTF_STRING_CONVERSIONS_H_ diff --git a/base/strings/utf_string_conversions_unittest.cc b/base/strings/utf_string_conversions_unittest.cc deleted file mode 100644 index 08009c4f38..0000000000 --- a/base/strings/utf_string_conversions_unittest.cc +++ /dev/null @@ -1,211 +0,0 @@ -// Copyright (c) 2010 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "base/basictypes.h" -#include "base/logging.h" -#include "base/strings/string_piece.h" -#include "base/strings/string_util.h" -#include "base/strings/utf_string_conversions.h" -#include "testing/gtest/include/gtest/gtest.h" - -namespace base { - -namespace { - -const wchar_t* const kConvertRoundtripCases[] = { - L"Google Video", - // "网页 图片 资讯更多 »" - L"\x7f51\x9875\x0020\x56fe\x7247\x0020\x8d44\x8baf\x66f4\x591a\x0020\x00bb", - // "Παγκόσμιος Ιστός" - L"\x03a0\x03b1\x03b3\x03ba\x03cc\x03c3\x03bc\x03b9" - L"\x03bf\x03c2\x0020\x0399\x03c3\x03c4\x03cc\x03c2", - // "Поиск страниц на русском" - L"\x041f\x043e\x0438\x0441\x043a\x0020\x0441\x0442" - L"\x0440\x0430\x043d\x0438\x0446\x0020\x043d\x0430" - L"\x0020\x0440\x0443\x0441\x0441\x043a\x043e\x043c", - // "전체서비스" - L"\xc804\xccb4\xc11c\xbe44\xc2a4", - - // Test characters that take more than 16 bits. This will depend on whether - // wchar_t is 16 or 32 bits. -#if defined(WCHAR_T_IS_UTF16) - L"\xd800\xdf00", - // ????? (Mathematical Alphanumeric Symbols (U+011d40 - U+011d44 : A,B,C,D,E) - L"\xd807\xdd40\xd807\xdd41\xd807\xdd42\xd807\xdd43\xd807\xdd44", -#elif defined(WCHAR_T_IS_UTF32) - L"\x10300", - // ????? (Mathematical Alphanumeric Symbols (U+011d40 - U+011d44 : A,B,C,D,E) - L"\x11d40\x11d41\x11d42\x11d43\x11d44", -#endif -}; - -} // namespace - -TEST(UTFStringConversionsTest, ConvertUTF8AndWide) { - // we round-trip all the wide strings through UTF-8 to make sure everything - // agrees on the conversion. This uses the stream operators to test them - // simultaneously. - for (size_t i = 0; i < arraysize(kConvertRoundtripCases); ++i) { - std::ostringstream utf8; - utf8 << WideToUTF8(kConvertRoundtripCases[i]); - std::wostringstream wide; - wide << UTF8ToWide(utf8.str()); - - EXPECT_EQ(kConvertRoundtripCases[i], wide.str()); - } -} - -TEST(UTFStringConversionsTest, ConvertUTF8AndWideEmptyString) { - // An empty std::wstring should be converted to an empty std::string, - // and vice versa. - std::wstring wempty; - std::string empty; - EXPECT_EQ(empty, WideToUTF8(wempty)); - EXPECT_EQ(wempty, UTF8ToWide(empty)); -} - -TEST(UTFStringConversionsTest, ConvertUTF8ToWide) { - struct UTF8ToWideCase { - const char* utf8; - const wchar_t* wide; - bool success; - } convert_cases[] = { - // Regular UTF-8 input. - {"\xe4\xbd\xa0\xe5\xa5\xbd", L"\x4f60\x597d", true}, - // Non-character is passed through. - {"\xef\xbf\xbfHello", L"\xffffHello", true}, - // Truncated UTF-8 sequence. - {"\xe4\xa0\xe5\xa5\xbd", L"\xfffd\x597d", false}, - // Truncated off the end. - {"\xe5\xa5\xbd\xe4\xa0", L"\x597d\xfffd", false}, - // Non-shortest-form UTF-8. - {"\xf0\x84\xbd\xa0\xe5\xa5\xbd", L"\xfffd\x597d", false}, - // This UTF-8 character decodes to a UTF-16 surrogate, which is illegal. - {"\xed\xb0\x80", L"\xfffd", false}, - // Non-BMP characters. The second is a non-character regarded as valid. - // The result will either be in UTF-16 or UTF-32. -#if defined(WCHAR_T_IS_UTF16) - {"A\xF0\x90\x8C\x80z", L"A\xd800\xdf00z", true}, - {"A\xF4\x8F\xBF\xBEz", L"A\xdbff\xdffez", true}, -#elif defined(WCHAR_T_IS_UTF32) - {"A\xF0\x90\x8C\x80z", L"A\x10300z", true}, - {"A\xF4\x8F\xBF\xBEz", L"A\x10fffez", true}, -#endif - }; - - for (size_t i = 0; i < ARRAYSIZE_UNSAFE(convert_cases); i++) { - std::wstring converted; - EXPECT_EQ(convert_cases[i].success, - UTF8ToWide(convert_cases[i].utf8, - strlen(convert_cases[i].utf8), - &converted)); - std::wstring expected(convert_cases[i].wide); - EXPECT_EQ(expected, converted); - } - - // Manually test an embedded NULL. - std::wstring converted; - EXPECT_TRUE(UTF8ToWide("\00Z\t", 3, &converted)); - ASSERT_EQ(3U, converted.length()); - EXPECT_EQ(static_cast(0), converted[0]); - EXPECT_EQ('Z', converted[1]); - EXPECT_EQ('\t', converted[2]); - - // Make sure that conversion replaces, not appends. - EXPECT_TRUE(UTF8ToWide("B", 1, &converted)); - ASSERT_EQ(1U, converted.length()); - EXPECT_EQ('B', converted[0]); -} - -#if defined(WCHAR_T_IS_UTF16) -// This test is only valid when wchar_t == UTF-16. -TEST(UTFStringConversionsTest, ConvertUTF16ToUTF8) { - struct WideToUTF8Case { - const wchar_t* utf16; - const char* utf8; - bool success; - } convert_cases[] = { - // Regular UTF-16 input. - {L"\x4f60\x597d", "\xe4\xbd\xa0\xe5\xa5\xbd", true}, - // Test a non-BMP character. - {L"\xd800\xdf00", "\xF0\x90\x8C\x80", true}, - // Non-characters are passed through. - {L"\xffffHello", "\xEF\xBF\xBFHello", true}, - {L"\xdbff\xdffeHello", "\xF4\x8F\xBF\xBEHello", true}, - // The first character is a truncated UTF-16 character. - {L"\xd800\x597d", "\xef\xbf\xbd\xe5\xa5\xbd", false}, - // Truncated at the end. - {L"\x597d\xd800", "\xe5\xa5\xbd\xef\xbf\xbd", false}, - }; - - for (int i = 0; i < arraysize(convert_cases); i++) { - std::string converted; - EXPECT_EQ(convert_cases[i].success, - WideToUTF8(convert_cases[i].utf16, - wcslen(convert_cases[i].utf16), - &converted)); - std::string expected(convert_cases[i].utf8); - EXPECT_EQ(expected, converted); - } -} - -#elif defined(WCHAR_T_IS_UTF32) -// This test is only valid when wchar_t == UTF-32. -TEST(UTFStringConversionsTest, ConvertUTF32ToUTF8) { - struct WideToUTF8Case { - const wchar_t* utf32; - const char* utf8; - bool success; - } convert_cases[] = { - // Regular 16-bit input. - {L"\x4f60\x597d", "\xe4\xbd\xa0\xe5\xa5\xbd", true}, - // Test a non-BMP character. - {L"A\x10300z", "A\xF0\x90\x8C\x80z", true}, - // Non-characters are passed through. - {L"\xffffHello", "\xEF\xBF\xBFHello", true}, - {L"\x10fffeHello", "\xF4\x8F\xBF\xBEHello", true}, - // Invalid Unicode code points. - {L"\xfffffffHello", "\xEF\xBF\xBDHello", false}, - // The first character is a truncated UTF-16 character. - {L"\xd800\x597d", "\xef\xbf\xbd\xe5\xa5\xbd", false}, - {L"\xdc01Hello", "\xef\xbf\xbdHello", false}, - }; - - for (size_t i = 0; i < ARRAYSIZE_UNSAFE(convert_cases); i++) { - std::string converted; - EXPECT_EQ(convert_cases[i].success, - WideToUTF8(convert_cases[i].utf32, - wcslen(convert_cases[i].utf32), - &converted)); - std::string expected(convert_cases[i].utf8); - EXPECT_EQ(expected, converted); - } -} -#endif // defined(WCHAR_T_IS_UTF32) - -TEST(UTFStringConversionsTest, ConvertMultiString) { - static wchar_t wmulti[] = { - L'f', L'o', L'o', L'\0', - L'b', L'a', L'r', L'\0', - L'b', L'a', L'z', L'\0', - L'\0' - }; - static char multi[] = { - 'f', 'o', 'o', '\0', - 'b', 'a', 'r', '\0', - 'b', 'a', 'z', '\0', - '\0' - }; - std::wstring wmultistring; - memcpy(WriteInto(&wmultistring, arraysize(wmulti)), wmulti, sizeof(wmulti)); - EXPECT_EQ(arraysize(wmulti) - 1, wmultistring.length()); - std::string expected; - memcpy(WriteInto(&expected, arraysize(multi)), multi, sizeof(multi)); - EXPECT_EQ(arraysize(multi) - 1, expected.length()); - const std::string& converted = WideToUTF8(wmultistring); - EXPECT_EQ(arraysize(multi) - 1, converted.length()); - EXPECT_EQ(expected, converted); -} - -} // base diff --git a/base/supports_user_data.cc b/base/supports_user_data.cc deleted file mode 100644 index 2a0263ed0d..0000000000 --- a/base/supports_user_data.cc +++ /dev/null @@ -1,40 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "base/supports_user_data.h" - -namespace base { - -SupportsUserData::SupportsUserData() { - // Harmless to construct on a different thread to subsequent usage. - thread_checker_.DetachFromThread(); -} - -SupportsUserData::Data* SupportsUserData::GetUserData(const void* key) const { - DCHECK(thread_checker_.CalledOnValidThread()); - DataMap::const_iterator found = user_data_.find(key); - if (found != user_data_.end()) - return found->second.get(); - return NULL; -} - -void SupportsUserData::SetUserData(const void* key, Data* data) { - DCHECK(thread_checker_.CalledOnValidThread()); - user_data_[key] = linked_ptr(data); -} - -void SupportsUserData::RemoveUserData(const void* key) { - DCHECK(thread_checker_.CalledOnValidThread()); - user_data_.erase(key); -} - -void SupportsUserData::DetachUserDataThread() { - thread_checker_.DetachFromThread(); -} - -SupportsUserData::~SupportsUserData() { - DCHECK(thread_checker_.CalledOnValidThread() || user_data_.empty()); -} - -} // namespace base diff --git a/base/supports_user_data.h b/base/supports_user_data.h deleted file mode 100644 index 77367553da..0000000000 --- a/base/supports_user_data.h +++ /dev/null @@ -1,81 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef BASE_SUPPORTS_USER_DATA_H_ -#define BASE_SUPPORTS_USER_DATA_H_ - -#include - -#include "base/base_export.h" -#include "base/memory/linked_ptr.h" -#include "base/memory/ref_counted.h" -#include "base/threading/thread_checker.h" - -namespace base { - -// This is a helper for classes that want to allow users to stash random data by -// key. At destruction all the objects will be destructed. -class BASE_EXPORT SupportsUserData { - public: - SupportsUserData(); - - // Derive from this class and add your own data members to associate extra - // information with this object. Alternatively, add this as a public base - // class to any class with a virtual destructor. - class BASE_EXPORT Data { - public: - virtual ~Data() {} - }; - - // The user data allows the clients to associate data with this object. - // Multiple user data values can be stored under different keys. - // This object will TAKE OWNERSHIP of the given data pointer, and will - // delete the object if it is changed or the object is destroyed. - Data* GetUserData(const void* key) const; - void SetUserData(const void* key, Data* data); - void RemoveUserData(const void* key); - - // SupportsUserData is not thread-safe, and on debug build will assert it is - // only used on one thread. Calling this method allows the caller to hand - // the SupportsUserData instance across threads. Use only if you are taking - // full control of the synchronization of that hand over. - void DetachUserDataThread(); - - protected: - virtual ~SupportsUserData(); - - private: - typedef std::map > DataMap; - - // Externally-defined data accessible by key. - DataMap user_data_; - // Guards usage of |user_data_| - ThreadChecker thread_checker_; - - DISALLOW_COPY_AND_ASSIGN(SupportsUserData); -}; - -// Adapter class that releases a refcounted object when the -// SupportsUserData::Data object is deleted. -template -class UserDataAdapter : public base::SupportsUserData::Data { - public: - static T* Get(SupportsUserData* supports_user_data, const char* key) { - UserDataAdapter* data = - static_cast(supports_user_data->GetUserData(key)); - return data ? static_cast(data->object_.get()) : NULL; - } - - UserDataAdapter(T* object) : object_(object) {} - T* release() { return object_.release(); } - - private: - scoped_refptr object_; - - DISALLOW_COPY_AND_ASSIGN(UserDataAdapter); -}; - -} // namespace base - -#endif // BASE_SUPPORTS_USER_DATA_H_ diff --git a/base/sync_socket.h b/base/sync_socket.h deleted file mode 100644 index 8ba3f6c265..0000000000 --- a/base/sync_socket.h +++ /dev/null @@ -1,130 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef BASE_SYNC_SOCKET_H_ -#define BASE_SYNC_SOCKET_H_ - -// A socket abstraction used for sending and receiving plain -// data. Because the receiving is blocking, they can be used to perform -// rudimentary cross-process synchronization with low latency. - -#include "base/basictypes.h" -#if defined(OS_WIN) -#include -#endif -#include - -#include "base/base_export.h" -#include "base/compiler_specific.h" -#include "base/synchronization/waitable_event.h" - -namespace base { - -class BASE_EXPORT SyncSocket { - public: -#if defined(OS_WIN) - typedef HANDLE Handle; -#else - typedef int Handle; -#endif - static const Handle kInvalidHandle; - - SyncSocket(); - - // Creates a SyncSocket from a Handle. Used in transport. - explicit SyncSocket(Handle handle) : handle_(handle) {} - virtual ~SyncSocket(); - - // Initializes and connects a pair of sockets. - // |socket_a| and |socket_b| must not hold a valid handle. Upon successful - // return, the sockets will both be valid and connected. - static bool CreatePair(SyncSocket* socket_a, SyncSocket* socket_b); - - // Closes the SyncSocket. Returns true on success, false on failure. - virtual bool Close(); - - // Sends the message to the remote peer of the SyncSocket. - // Note it is not safe to send messages from the same socket handle by - // multiple threads simultaneously. - // buffer is a pointer to the data to send. - // length is the length of the data to send (must be non-zero). - // Returns the number of bytes sent, or 0 upon failure. - virtual size_t Send(const void* buffer, size_t length); - - // Receives a message from an SyncSocket. - // buffer is a pointer to the buffer to receive data. - // length is the number of bytes of data to receive (must be non-zero). - // Returns the number of bytes received, or 0 upon failure. - virtual size_t Receive(void* buffer, size_t length); - - // Returns the number of bytes available. If non-zero, Receive() will not - // not block when called. NOTE: Some implementations cannot reliably - // determine the number of bytes available so avoid using the returned - // size as a promise and simply test against zero. - size_t Peek(); - - // Extracts the contained handle. Used for transferring between - // processes. - Handle handle() const { return handle_; } - - protected: - Handle handle_; - - private: - DISALLOW_COPY_AND_ASSIGN(SyncSocket); -}; - -// Derives from SyncSocket and adds support for shutting down the socket from -// another thread while a blocking Receive or Send is being done from the -// thread that owns the socket. -class BASE_EXPORT CancelableSyncSocket : public SyncSocket { - public: - CancelableSyncSocket(); - explicit CancelableSyncSocket(Handle handle); - virtual ~CancelableSyncSocket() {} - - // Initializes a pair of cancelable sockets. See documentation for - // SyncSocket::CreatePair for more details. - static bool CreatePair(CancelableSyncSocket* socket_a, - CancelableSyncSocket* socket_b); - - // A way to shut down a socket even if another thread is currently performing - // a blocking Receive or Send. - bool Shutdown(); - -#if defined(OS_WIN) - // Since the Linux and Mac implementations actually use a socket, shutting - // them down from another thread is pretty simple - we can just call - // shutdown(). However, the Windows implementation relies on named pipes - // and there isn't a way to cancel a blocking synchronous Read that is - // supported on -#include -#include -#include - -#include "base/logging.h" - - -namespace base { - -const SyncSocket::Handle SyncSocket::kInvalidHandle = -1; - -SyncSocket::SyncSocket() : handle_(kInvalidHandle) { -} - -SyncSocket::~SyncSocket() { -} - -// static -bool SyncSocket::CreatePair(SyncSocket* socket_a, SyncSocket* socket_b) { - return false; -} - -bool SyncSocket::Close() { - if (handle_ != kInvalidHandle) { - if (close(handle_) < 0) - DPLOG(ERROR) << "close"; - handle_ = -1; - } - return true; -} - -size_t SyncSocket::Send(const void* buffer, size_t length) { - // Not implemented since it's not needed by any client code yet. - return -1; -} - -size_t SyncSocket::Receive(void* buffer, size_t length) { - return read(handle_, buffer, length); -} - -size_t SyncSocket::Peek() { - return -1; -} - -CancelableSyncSocket::CancelableSyncSocket() { -} - -CancelableSyncSocket::CancelableSyncSocket(Handle handle) - : SyncSocket(handle) { -} - -size_t CancelableSyncSocket::Send(const void* buffer, size_t length) { - return -1; -} - -bool CancelableSyncSocket::Shutdown() { - return false; -} - -// static -bool CancelableSyncSocket::CreatePair(CancelableSyncSocket* socket_a, - CancelableSyncSocket* socket_b) { - return SyncSocket::CreatePair(socket_a, socket_b); -} - -} // namespace base diff --git a/base/sync_socket_posix.cc b/base/sync_socket_posix.cc deleted file mode 100644 index 257916df33..0000000000 --- a/base/sync_socket_posix.cc +++ /dev/null @@ -1,154 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "base/sync_socket.h" - -#include -#include -#include -#include -#include -#include -#include - -#if defined(OS_SOLARIS) -#include -#endif - -#include "base/file_util.h" -#include "base/logging.h" - - -namespace base { - -namespace { -// To avoid users sending negative message lengths to Send/Receive -// we clamp message lengths, which are size_t, to no more than INT_MAX. -const size_t kMaxMessageLength = static_cast(INT_MAX); - -} // namespace - -const SyncSocket::Handle SyncSocket::kInvalidHandle = -1; - -SyncSocket::SyncSocket() : handle_(kInvalidHandle) {} - -SyncSocket::~SyncSocket() { - Close(); -} - -// static -bool SyncSocket::CreatePair(SyncSocket* socket_a, SyncSocket* socket_b) { - DCHECK(socket_a != socket_b); - DCHECK(socket_a->handle_ == kInvalidHandle); - DCHECK(socket_b->handle_ == kInvalidHandle); - -#if defined(OS_MACOSX) - int nosigpipe = 1; -#endif // defined(OS_MACOSX) - - Handle handles[2] = { kInvalidHandle, kInvalidHandle }; - if (socketpair(AF_UNIX, SOCK_STREAM, 0, handles) != 0) - goto cleanup; - -#if defined(OS_MACOSX) - // On OSX an attempt to read or write to a closed socket may generate a - // SIGPIPE rather than returning -1. setsockopt will shut this off. - if (0 != setsockopt(handles[0], SOL_SOCKET, SO_NOSIGPIPE, - &nosigpipe, sizeof nosigpipe) || - 0 != setsockopt(handles[1], SOL_SOCKET, SO_NOSIGPIPE, - &nosigpipe, sizeof nosigpipe)) { - goto cleanup; - } -#endif - - // Copy the handles out for successful return. - socket_a->handle_ = handles[0]; - socket_b->handle_ = handles[1]; - - return true; - - cleanup: - if (handles[0] != kInvalidHandle) { - if (HANDLE_EINTR(close(handles[0])) < 0) - DPLOG(ERROR) << "close"; - } - if (handles[1] != kInvalidHandle) { - if (HANDLE_EINTR(close(handles[1])) < 0) - DPLOG(ERROR) << "close"; - } - - return false; -} - -bool SyncSocket::Close() { - if (handle_ == kInvalidHandle) { - return false; - } - int retval = HANDLE_EINTR(close(handle_)); - if (retval < 0) - DPLOG(ERROR) << "close"; - handle_ = kInvalidHandle; - return (retval == 0); -} - -size_t SyncSocket::Send(const void* buffer, size_t length) { - DCHECK_LE(length, kMaxMessageLength); - const char* charbuffer = static_cast(buffer); - int len = file_util::WriteFileDescriptor(handle_, charbuffer, length); - - return (len == -1) ? 0 : static_cast(len); -} - -size_t SyncSocket::Receive(void* buffer, size_t length) { - DCHECK_LE(length, kMaxMessageLength); - char* charbuffer = static_cast(buffer); - if (file_util::ReadFromFD(handle_, charbuffer, length)) - return length; - return 0; -} - -size_t SyncSocket::Peek() { - int number_chars; - if (-1 == ioctl(handle_, FIONREAD, &number_chars)) { - // If there is an error in ioctl, signal that the channel would block. - return 0; - } - return (size_t) number_chars; -} - -CancelableSyncSocket::CancelableSyncSocket() {} -CancelableSyncSocket::CancelableSyncSocket(Handle handle) - : SyncSocket(handle) { -} - -bool CancelableSyncSocket::Shutdown() { - return HANDLE_EINTR(shutdown(handle(), SHUT_RDWR)) >= 0; -} - -size_t CancelableSyncSocket::Send(const void* buffer, size_t length) { - long flags = 0; - flags = fcntl(handle_, F_GETFL, NULL); - if (flags != -1 && (flags & O_NONBLOCK) == 0) { - // Set the socket to non-blocking mode for sending if its original mode - // is blocking. - fcntl(handle_, F_SETFL, flags | O_NONBLOCK); - } - - size_t len = SyncSocket::Send(buffer, length); - - if (flags != -1 && (flags & O_NONBLOCK) == 0) { - // Restore the original flags. - fcntl(handle_, F_SETFL, flags); - } - - return len; -} - -// static -bool CancelableSyncSocket::CreatePair(CancelableSyncSocket* socket_a, - CancelableSyncSocket* socket_b) { - return SyncSocket::CreatePair(socket_a, socket_b); -} - -} // namespace base diff --git a/base/sync_socket_win.cc b/base/sync_socket_win.cc deleted file mode 100644 index 99a6afea3e..0000000000 --- a/base/sync_socket_win.cc +++ /dev/null @@ -1,273 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "base/sync_socket.h" - -#include "base/logging.h" -#include "base/win/scoped_handle.h" - -namespace base { - -using win::ScopedHandle; - -namespace { -// IMPORTANT: do not change how this name is generated because it will break -// in sandboxed scenarios as we might have by-name policies that allow pipe -// creation. Also keep the secure random number generation. -const wchar_t kPipeNameFormat[] = L"\\\\.\\pipe\\chrome.sync.%u.%u.%lu"; -const size_t kPipePathMax = arraysize(kPipeNameFormat) + (3 * 10) + 1; - -// To avoid users sending negative message lengths to Send/Receive -// we clamp message lengths, which are size_t, to no more than INT_MAX. -const size_t kMaxMessageLength = static_cast(INT_MAX); - -const int kOutBufferSize = 4096; -const int kInBufferSize = 4096; -const int kDefaultTimeoutMilliSeconds = 1000; - -bool CreatePairImpl(HANDLE* socket_a, HANDLE* socket_b, bool overlapped) { - DCHECK(socket_a != socket_b); - DCHECK(*socket_a == SyncSocket::kInvalidHandle); - DCHECK(*socket_b == SyncSocket::kInvalidHandle); - - wchar_t name[kPipePathMax]; - ScopedHandle handle_a; - DWORD flags = PIPE_ACCESS_DUPLEX | FILE_FLAG_FIRST_PIPE_INSTANCE; - if (overlapped) - flags |= FILE_FLAG_OVERLAPPED; - - do { - unsigned int rnd_name; - if (rand_s(&rnd_name) != 0) - return false; - - swprintf(name, kPipePathMax, - kPipeNameFormat, - GetCurrentProcessId(), - GetCurrentThreadId(), - rnd_name); - - handle_a.Set(CreateNamedPipeW( - name, - flags, - PIPE_TYPE_BYTE | PIPE_READMODE_BYTE, - 1, - kOutBufferSize, - kInBufferSize, - kDefaultTimeoutMilliSeconds, - NULL)); - } while (!handle_a.IsValid() && - (GetLastError() == ERROR_PIPE_BUSY)); - - if (!handle_a.IsValid()) { - NOTREACHED(); - return false; - } - - // The SECURITY_ANONYMOUS flag means that the server side (handle_a) cannot - // impersonate the client (handle_b). This allows us not to care which side - // ends up in which side of a privilege boundary. - flags = SECURITY_SQOS_PRESENT | SECURITY_ANONYMOUS; - if (overlapped) - flags |= FILE_FLAG_OVERLAPPED; - - ScopedHandle handle_b(CreateFileW(name, - GENERIC_READ | GENERIC_WRITE, - 0, // no sharing. - NULL, // default security attributes. - OPEN_EXISTING, // opens existing pipe. - flags, - NULL)); // no template file. - if (!handle_b.IsValid()) { - DPLOG(ERROR) << "CreateFileW failed"; - return false; - } - - if (!ConnectNamedPipe(handle_a, NULL)) { - DWORD error = GetLastError(); - if (error != ERROR_PIPE_CONNECTED) { - DPLOG(ERROR) << "ConnectNamedPipe failed"; - return false; - } - } - - *socket_a = handle_a.Take(); - *socket_b = handle_b.Take(); - - return true; -} - -// Inline helper to avoid having the cast everywhere. -DWORD GetNextChunkSize(size_t current_pos, size_t max_size) { - // The following statement is for 64 bit portability. - return static_cast(((max_size - current_pos) <= UINT_MAX) ? - (max_size - current_pos) : UINT_MAX); -} - -// Template function that supports calling ReadFile or WriteFile in an -// overlapped fashion and waits for IO completion. The function also waits -// on an event that can be used to cancel the operation. If the operation -// is cancelled, the function returns and closes the relevant socket object. -template -size_t CancelableFileOperation(Function operation, HANDLE file, - BufferType* buffer, size_t length, - base::WaitableEvent* io_event, - base::WaitableEvent* cancel_event, - CancelableSyncSocket* socket, - DWORD timeout_in_ms) { - // The buffer must be byte size or the length check won't make much sense. - COMPILE_ASSERT(sizeof(buffer[0]) == sizeof(char), incorrect_buffer_type); - DCHECK_LE(length, kMaxMessageLength); - - OVERLAPPED ol = {0}; - ol.hEvent = io_event->handle(); - size_t count = 0; - while (count < length) { - DWORD chunk = GetNextChunkSize(count, length); - // This is either the ReadFile or WriteFile call depending on whether - // we're receiving or sending data. - DWORD len = 0; - BOOL ok = operation(file, static_cast(buffer) + count, chunk, - &len, &ol); - if (!ok) { - if (::GetLastError() == ERROR_IO_PENDING) { - HANDLE events[] = { io_event->handle(), cancel_event->handle() }; - int wait_result = WaitForMultipleObjects( - arraysize(events), events, FALSE, timeout_in_ms); - if (wait_result == (WAIT_OBJECT_0 + 0)) { - GetOverlappedResult(file, &ol, &len, TRUE); - } else if (wait_result == (WAIT_OBJECT_0 + 1)) { - VLOG(1) << "Shutdown was signaled. Closing socket."; - CancelIo(file); - socket->Close(); - count = 0; - break; - } else { - // Timeout happened. - DCHECK_EQ(WAIT_TIMEOUT, wait_result); - if (!CancelIo(file)){ - DLOG(WARNING) << "CancelIo() failed"; - } - break; - } - } else { - break; - } - } - - count += len; - - // Quit the operation if we can't write/read anymore. - if (len != chunk) - break; - } - - return (count > 0) ? count : 0; -} - -} // namespace - -#if defined(COMPONENT_BUILD) -const SyncSocket::Handle SyncSocket::kInvalidHandle = INVALID_HANDLE_VALUE; -#endif - -SyncSocket::SyncSocket() : handle_(kInvalidHandle) {} - -SyncSocket::~SyncSocket() { - Close(); -} - -// static -bool SyncSocket::CreatePair(SyncSocket* socket_a, SyncSocket* socket_b) { - return CreatePairImpl(&socket_a->handle_, &socket_b->handle_, false); -} - -bool SyncSocket::Close() { - if (handle_ == kInvalidHandle) - return false; - - BOOL retval = CloseHandle(handle_); - handle_ = kInvalidHandle; - return retval ? true : false; -} - -size_t SyncSocket::Send(const void* buffer, size_t length) { - DCHECK_LE(length, kMaxMessageLength); - size_t count = 0; - while (count < length) { - DWORD len; - DWORD chunk = GetNextChunkSize(count, length); - if (WriteFile(handle_, static_cast(buffer) + count, - chunk, &len, NULL) == FALSE) { - return (0 < count) ? count : 0; - } - count += len; - } - return count; -} - -size_t SyncSocket::Receive(void* buffer, size_t length) { - DCHECK_LE(length, kMaxMessageLength); - size_t count = 0; - while (count < length) { - DWORD len; - DWORD chunk = GetNextChunkSize(count, length); - if (ReadFile(handle_, static_cast(buffer) + count, - chunk, &len, NULL) == FALSE) { - return (0 < count) ? count : 0; - } - count += len; - } - return count; -} - -size_t SyncSocket::Peek() { - DWORD available = 0; - PeekNamedPipe(handle_, NULL, 0, NULL, &available, NULL); - return available; -} - -CancelableSyncSocket::CancelableSyncSocket() - : shutdown_event_(true, false), file_operation_(true, false) { -} - -CancelableSyncSocket::CancelableSyncSocket(Handle handle) - : SyncSocket(handle), shutdown_event_(true, false), - file_operation_(true, false) { -} - -bool CancelableSyncSocket::Shutdown() { - // This doesn't shut down the pipe immediately, but subsequent Receive or Send - // methods will fail straight away. - shutdown_event_.Signal(); - return true; -} - -bool CancelableSyncSocket::Close() { - bool ret = SyncSocket::Close(); - shutdown_event_.Reset(); - return ret; -} - -size_t CancelableSyncSocket::Send(const void* buffer, size_t length) { - static const DWORD kWaitTimeOutInMs = 500; - return CancelableFileOperation( - &WriteFile, handle_, reinterpret_cast(buffer), - length, &file_operation_, &shutdown_event_, this, kWaitTimeOutInMs); -} - -size_t CancelableSyncSocket::Receive(void* buffer, size_t length) { - return CancelableFileOperation(&ReadFile, handle_, - reinterpret_cast(buffer), length, &file_operation_, - &shutdown_event_, this, INFINITE); -} - -// static -bool CancelableSyncSocket::CreatePair(CancelableSyncSocket* socket_a, - CancelableSyncSocket* socket_b) { - return CreatePairImpl(&socket_a->handle_, &socket_b->handle_, true); -} - - -} // namespace base diff --git a/base/synchronization/cancellation_flag.cc b/base/synchronization/cancellation_flag.cc deleted file mode 100644 index ad3b551169..0000000000 --- a/base/synchronization/cancellation_flag.cc +++ /dev/null @@ -1,22 +0,0 @@ -// Copyright (c) 2011 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "base/synchronization/cancellation_flag.h" - -#include "base/logging.h" - -namespace base { - -void CancellationFlag::Set() { -#if !defined(NDEBUG) - DCHECK_EQ(set_on_, PlatformThread::CurrentId()); -#endif - base::subtle::Release_Store(&flag_, 1); -} - -bool CancellationFlag::IsSet() const { - return base::subtle::Acquire_Load(&flag_) != 0; -} - -} // namespace base diff --git a/base/synchronization/cancellation_flag.h b/base/synchronization/cancellation_flag.h deleted file mode 100644 index 51a4def1eb..0000000000 --- a/base/synchronization/cancellation_flag.h +++ /dev/null @@ -1,43 +0,0 @@ -// Copyright (c) 2011 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef BASE_SYNCHRONIZATION_CANCELLATION_FLAG_H_ -#define BASE_SYNCHRONIZATION_CANCELLATION_FLAG_H_ - -#include "base/base_export.h" -#include "base/atomicops.h" -#include "base/threading/platform_thread.h" - -namespace base { - -// CancellationFlag allows one thread to cancel jobs executed on some worker -// thread. Calling Set() from one thread and IsSet() from a number of threads -// is thread-safe. -// -// This class IS NOT intended for synchronization between threads. -class BASE_EXPORT CancellationFlag { - public: - CancellationFlag() : flag_(false) { -#if !defined(NDEBUG) - set_on_ = PlatformThread::CurrentId(); -#endif - } - ~CancellationFlag() {} - - // Set the flag. May only be called on the thread which owns the object. - void Set(); - bool IsSet() const; // Returns true iff the flag was set. - - private: - base::subtle::Atomic32 flag_; -#if !defined(NDEBUG) - PlatformThreadId set_on_; -#endif - - DISALLOW_COPY_AND_ASSIGN(CancellationFlag); -}; - -} // namespace base - -#endif // BASE_SYNCHRONIZATION_CANCELLATION_FLAG_H_ diff --git a/base/synchronization/cancellation_flag_unittest.cc b/base/synchronization/cancellation_flag_unittest.cc deleted file mode 100644 index 02b08b6a9d..0000000000 --- a/base/synchronization/cancellation_flag_unittest.cc +++ /dev/null @@ -1,64 +0,0 @@ -// Copyright (c) 2011 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -// Tests of CancellationFlag class. - -#include "base/synchronization/cancellation_flag.h" - -#include "base/bind.h" -#include "base/logging.h" -#include "base/message_loop/message_loop.h" -#include "base/synchronization/spin_wait.h" -#include "base/threading/thread.h" -#include "base/time/time.h" -#include "testing/gtest/include/gtest/gtest.h" -#include "testing/platform_test.h" - -namespace base { - -namespace { - -//------------------------------------------------------------------------------ -// Define our test class. -//------------------------------------------------------------------------------ - -void CancelHelper(CancellationFlag* flag) { -#if GTEST_HAS_DEATH_TEST - ASSERT_DEBUG_DEATH(flag->Set(), ""); -#endif -} - -TEST(CancellationFlagTest, SimpleSingleThreadedTest) { - CancellationFlag flag; - ASSERT_FALSE(flag.IsSet()); - flag.Set(); - ASSERT_TRUE(flag.IsSet()); -} - -TEST(CancellationFlagTest, DoubleSetTest) { - CancellationFlag flag; - ASSERT_FALSE(flag.IsSet()); - flag.Set(); - ASSERT_TRUE(flag.IsSet()); - flag.Set(); - ASSERT_TRUE(flag.IsSet()); -} - -TEST(CancellationFlagTest, SetOnDifferentThreadDeathTest) { - // Checks that Set() can't be called from any other thread. - // CancellationFlag should die on a DCHECK if Set() is called from - // other thread. - ::testing::FLAGS_gtest_death_test_style = "threadsafe"; - Thread t("CancellationFlagTest.SetOnDifferentThreadDeathTest"); - ASSERT_TRUE(t.Start()); - ASSERT_TRUE(t.message_loop()); - ASSERT_TRUE(t.IsRunning()); - - CancellationFlag flag; - t.message_loop()->PostTask(FROM_HERE, base::Bind(&CancelHelper, &flag)); -} - -} // namespace - -} // namespace base diff --git a/base/synchronization/condition_variable.h b/base/synchronization/condition_variable.h deleted file mode 100644 index 4f744f80b2..0000000000 --- a/base/synchronization/condition_variable.h +++ /dev/null @@ -1,118 +0,0 @@ -// Copyright (c) 2011 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -// ConditionVariable wraps pthreads condition variable synchronization or, on -// Windows, simulates it. This functionality is very helpful for having -// several threads wait for an event, as is common with a thread pool managed -// by a master. The meaning of such an event in the (worker) thread pool -// scenario is that additional tasks are now available for processing. It is -// used in Chrome in the DNS prefetching system to notify worker threads that -// a queue now has items (tasks) which need to be tended to. A related use -// would have a pool manager waiting on a ConditionVariable, waiting for a -// thread in the pool to announce (signal) that there is now more room in a -// (bounded size) communications queue for the manager to deposit tasks, or, -// as a second example, that the queue of tasks is completely empty and all -// workers are waiting. -// -// USAGE NOTE 1: spurious signal events are possible with this and -// most implementations of condition variables. As a result, be -// *sure* to retest your condition before proceeding. The following -// is a good example of doing this correctly: -// -// while (!work_to_be_done()) Wait(...); -// -// In contrast do NOT do the following: -// -// if (!work_to_be_done()) Wait(...); // Don't do this. -// -// Especially avoid the above if you are relying on some other thread only -// issuing a signal up *if* there is work-to-do. There can/will -// be spurious signals. Recheck state on waiting thread before -// assuming the signal was intentional. Caveat caller ;-). -// -// USAGE NOTE 2: Broadcast() frees up all waiting threads at once, -// which leads to contention for the locks they all held when they -// called Wait(). This results in POOR performance. A much better -// approach to getting a lot of threads out of Wait() is to have each -// thread (upon exiting Wait()) call Signal() to free up another -// Wait'ing thread. Look at condition_variable_unittest.cc for -// both examples. -// -// Broadcast() can be used nicely during teardown, as it gets the job -// done, and leaves no sleeping threads... and performance is less -// critical at that point. -// -// The semantics of Broadcast() are carefully crafted so that *all* -// threads that were waiting when the request was made will indeed -// get signaled. Some implementations mess up, and don't signal them -// all, while others allow the wait to be effectively turned off (for -// a while while waiting threads come around). This implementation -// appears correct, as it will not "lose" any signals, and will guarantee -// that all threads get signaled by Broadcast(). -// -// This implementation offers support for "performance" in its selection of -// which thread to revive. Performance, in direct contrast with "fairness," -// assures that the thread that most recently began to Wait() is selected by -// Signal to revive. Fairness would (if publicly supported) assure that the -// thread that has Wait()ed the longest is selected. The default policy -// may improve performance, as the selected thread may have a greater chance of -// having some of its stack data in various CPU caches. -// -// For a discussion of the many very subtle implementation details, see the FAQ -// at the end of condition_variable_win.cc. - -#ifndef BASE_SYNCHRONIZATION_CONDITION_VARIABLE_H_ -#define BASE_SYNCHRONIZATION_CONDITION_VARIABLE_H_ - -#include "build/build_config.h" - -#if defined(OS_POSIX) -#include -#endif - -#include "base/base_export.h" -#include "base/basictypes.h" -#include "base/synchronization/lock.h" - -namespace base { - -class ConditionVarImpl; -class TimeDelta; - -class BASE_EXPORT ConditionVariable { - public: - // Construct a cv for use with ONLY one user lock. - explicit ConditionVariable(Lock* user_lock); - - ~ConditionVariable(); - - // Wait() releases the caller's critical section atomically as it starts to - // sleep, and the reacquires it when it is signaled. - void Wait(); - void TimedWait(const TimeDelta& max_time); - - // Broadcast() revives all waiting threads. - void Broadcast(); - // Signal() revives one waiting thread. - void Signal(); - - private: - -#if defined(OS_WIN) - ConditionVarImpl* impl_; -#elif defined(OS_POSIX) - pthread_cond_t condition_; - pthread_mutex_t* user_mutex_; -#if !defined(NDEBUG) - base::Lock* user_lock_; // Needed to adjust shadow lock state on wait. -#endif - -#endif - - DISALLOW_COPY_AND_ASSIGN(ConditionVariable); -}; - -} // namespace base - -#endif // BASE_SYNCHRONIZATION_CONDITION_VARIABLE_H_ diff --git a/base/synchronization/condition_variable_posix.cc b/base/synchronization/condition_variable_posix.cc deleted file mode 100644 index 93b35ed354..0000000000 --- a/base/synchronization/condition_variable_posix.cc +++ /dev/null @@ -1,80 +0,0 @@ -// Copyright (c) 2011 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "base/synchronization/condition_variable.h" - -#include -#include - -#include "base/logging.h" -#include "base/synchronization/lock.h" -#include "base/threading/thread_restrictions.h" -#include "base/time/time.h" - -namespace base { - -ConditionVariable::ConditionVariable(Lock* user_lock) - : user_mutex_(user_lock->lock_.os_lock()) -#if !defined(NDEBUG) - , user_lock_(user_lock) -#endif -{ - int rv = pthread_cond_init(&condition_, NULL); - DCHECK_EQ(0, rv); -} - -ConditionVariable::~ConditionVariable() { - int rv = pthread_cond_destroy(&condition_); - DCHECK_EQ(0, rv); -} - -void ConditionVariable::Wait() { - base::ThreadRestrictions::AssertWaitAllowed(); -#if !defined(NDEBUG) - user_lock_->CheckHeldAndUnmark(); -#endif - int rv = pthread_cond_wait(&condition_, user_mutex_); - DCHECK_EQ(0, rv); -#if !defined(NDEBUG) - user_lock_->CheckUnheldAndMark(); -#endif -} - -void ConditionVariable::TimedWait(const TimeDelta& max_time) { - base::ThreadRestrictions::AssertWaitAllowed(); - int64 usecs = max_time.InMicroseconds(); - - // The timeout argument to pthread_cond_timedwait is in absolute time. - struct timeval now; - gettimeofday(&now, NULL); - - struct timespec abstime; - abstime.tv_sec = now.tv_sec + (usecs / Time::kMicrosecondsPerSecond); - abstime.tv_nsec = (now.tv_usec + (usecs % Time::kMicrosecondsPerSecond)) * - Time::kNanosecondsPerMicrosecond; - abstime.tv_sec += abstime.tv_nsec / Time::kNanosecondsPerSecond; - abstime.tv_nsec %= Time::kNanosecondsPerSecond; - DCHECK_GE(abstime.tv_sec, now.tv_sec); // Overflow paranoia - -#if !defined(NDEBUG) - user_lock_->CheckHeldAndUnmark(); -#endif - int rv = pthread_cond_timedwait(&condition_, user_mutex_, &abstime); - DCHECK(rv == 0 || rv == ETIMEDOUT); -#if !defined(NDEBUG) - user_lock_->CheckUnheldAndMark(); -#endif -} - -void ConditionVariable::Broadcast() { - int rv = pthread_cond_broadcast(&condition_); - DCHECK_EQ(0, rv); -} - -void ConditionVariable::Signal() { - int rv = pthread_cond_signal(&condition_); - DCHECK_EQ(0, rv); -} - -} // namespace base diff --git a/base/synchronization/condition_variable_unittest.cc b/base/synchronization/condition_variable_unittest.cc deleted file mode 100644 index 4230e63549..0000000000 --- a/base/synchronization/condition_variable_unittest.cc +++ /dev/null @@ -1,715 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -// Multi-threaded tests of ConditionVariable class. - -#include -#include -#include - -#include "base/logging.h" -#include "base/memory/scoped_ptr.h" -#include "base/synchronization/condition_variable.h" -#include "base/synchronization/lock.h" -#include "base/synchronization/spin_wait.h" -#include "base/threading/platform_thread.h" -#include "base/threading/thread_collision_warner.h" -#include "base/time/time.h" -#include "testing/gtest/include/gtest/gtest.h" -#include "testing/platform_test.h" - -namespace base { - -namespace { -//------------------------------------------------------------------------------ -// Define our test class, with several common variables. -//------------------------------------------------------------------------------ - -class ConditionVariableTest : public PlatformTest { - public: - const TimeDelta kZeroMs; - const TimeDelta kTenMs; - const TimeDelta kThirtyMs; - const TimeDelta kFortyFiveMs; - const TimeDelta kSixtyMs; - const TimeDelta kOneHundredMs; - - ConditionVariableTest() - : kZeroMs(TimeDelta::FromMilliseconds(0)), - kTenMs(TimeDelta::FromMilliseconds(10)), - kThirtyMs(TimeDelta::FromMilliseconds(30)), - kFortyFiveMs(TimeDelta::FromMilliseconds(45)), - kSixtyMs(TimeDelta::FromMilliseconds(60)), - kOneHundredMs(TimeDelta::FromMilliseconds(100)) { - } -}; - -//------------------------------------------------------------------------------ -// Define a class that will control activities an several multi-threaded tests. -// The general structure of multi-threaded tests is that a test case will -// construct an instance of a WorkQueue. The WorkQueue will spin up some -// threads and control them throughout their lifetime, as well as maintaining -// a central repository of the work thread's activity. Finally, the WorkQueue -// will command the the worker threads to terminate. At that point, the test -// cases will validate that the WorkQueue has records showing that the desired -// activities were performed. -//------------------------------------------------------------------------------ - -// Callers are responsible for synchronizing access to the following class. -// The WorkQueue::lock_, as accessed via WorkQueue::lock(), should be used for -// all synchronized access. -class WorkQueue : public PlatformThread::Delegate { - public: - explicit WorkQueue(int thread_count); - virtual ~WorkQueue(); - - // PlatformThread::Delegate interface. - virtual void ThreadMain() OVERRIDE; - - //---------------------------------------------------------------------------- - // Worker threads only call the following methods. - // They should use the lock to get exclusive access. - int GetThreadId(); // Get an ID assigned to a thread.. - bool EveryIdWasAllocated() const; // Indicates that all IDs were handed out. - TimeDelta GetAnAssignment(int thread_id); // Get a work task duration. - void WorkIsCompleted(int thread_id); - - int task_count() const; - bool allow_help_requests() const; // Workers can signal more workers. - bool shutdown() const; // Check if shutdown has been requested. - - void thread_shutting_down(); - - - //---------------------------------------------------------------------------- - // Worker threads can call them but not needed to acquire a lock. - Lock* lock(); - - ConditionVariable* work_is_available(); - ConditionVariable* all_threads_have_ids(); - ConditionVariable* no_more_tasks(); - - //---------------------------------------------------------------------------- - // The rest of the methods are for use by the controlling master thread (the - // test case code). - void ResetHistory(); - int GetMinCompletionsByWorkerThread() const; - int GetMaxCompletionsByWorkerThread() const; - int GetNumThreadsTakingAssignments() const; - int GetNumThreadsCompletingTasks() const; - int GetNumberOfCompletedTasks() const; - TimeDelta GetWorkTime() const; - - void SetWorkTime(TimeDelta delay); - void SetTaskCount(int count); - void SetAllowHelp(bool allow); - - // The following must be called without locking, and will spin wait until the - // threads are all in a wait state. - void SpinUntilAllThreadsAreWaiting(); - void SpinUntilTaskCountLessThan(int task_count); - - // Caller must acquire lock before calling. - void SetShutdown(); - - // Compares the |shutdown_task_count_| to the |thread_count| and returns true - // if they are equal. This check will acquire the |lock_| so the caller - // should not hold the lock when calling this method. - bool ThreadSafeCheckShutdown(int thread_count); - - private: - // Both worker threads and controller use the following to synchronize. - Lock lock_; - ConditionVariable work_is_available_; // To tell threads there is work. - - // Conditions to notify the controlling process (if it is interested). - ConditionVariable all_threads_have_ids_; // All threads are running. - ConditionVariable no_more_tasks_; // Task count is zero. - - const int thread_count_; - int waiting_thread_count_; - scoped_ptr thread_handles_; - std::vector assignment_history_; // Number of assignment per worker. - std::vector completion_history_; // Number of completions per worker. - int thread_started_counter_; // Used to issue unique id to workers. - int shutdown_task_count_; // Number of tasks told to shutdown - int task_count_; // Number of assignment tasks waiting to be processed. - TimeDelta worker_delay_; // Time each task takes to complete. - bool allow_help_requests_; // Workers can signal more workers. - bool shutdown_; // Set when threads need to terminate. - - DFAKE_MUTEX(locked_methods_); -}; - -//------------------------------------------------------------------------------ -// The next section contains the actual tests. -//------------------------------------------------------------------------------ - -TEST_F(ConditionVariableTest, StartupShutdownTest) { - Lock lock; - - // First try trivial startup/shutdown. - { - ConditionVariable cv1(&lock); - } // Call for cv1 destruction. - - // Exercise with at least a few waits. - ConditionVariable cv(&lock); - - lock.Acquire(); - cv.TimedWait(kTenMs); // Wait for 10 ms. - cv.TimedWait(kTenMs); // Wait for 10 ms. - lock.Release(); - - lock.Acquire(); - cv.TimedWait(kTenMs); // Wait for 10 ms. - cv.TimedWait(kTenMs); // Wait for 10 ms. - cv.TimedWait(kTenMs); // Wait for 10 ms. - lock.Release(); -} // Call for cv destruction. - -TEST_F(ConditionVariableTest, TimeoutTest) { - Lock lock; - ConditionVariable cv(&lock); - lock.Acquire(); - - TimeTicks start = TimeTicks::Now(); - const TimeDelta WAIT_TIME = TimeDelta::FromMilliseconds(300); - // Allow for clocking rate granularity. - const TimeDelta FUDGE_TIME = TimeDelta::FromMilliseconds(50); - - cv.TimedWait(WAIT_TIME + FUDGE_TIME); - TimeDelta duration = TimeTicks::Now() - start; - // We can't use EXPECT_GE here as the TimeDelta class does not support the - // required stream conversion. - EXPECT_TRUE(duration >= WAIT_TIME); - - lock.Release(); -} - - -// Suddenly got flaky on Win, see http://crbug.com/10607 (starting at -// comment #15) -#if defined(OS_WIN) -#define MAYBE_MultiThreadConsumerTest DISABLED_MultiThreadConsumerTest -#else -#define MAYBE_MultiThreadConsumerTest MultiThreadConsumerTest -#endif -// Test serial task servicing, as well as two parallel task servicing methods. -TEST_F(ConditionVariableTest, MAYBE_MultiThreadConsumerTest) { - const int kThreadCount = 10; - WorkQueue queue(kThreadCount); // Start the threads. - - const int kTaskCount = 10; // Number of tasks in each mini-test here. - - Time start_time; // Used to time task processing. - - { - base::AutoLock auto_lock(*queue.lock()); - while (!queue.EveryIdWasAllocated()) - queue.all_threads_have_ids()->Wait(); - } - - // If threads aren't in a wait state, they may start to gobble up tasks in - // parallel, short-circuiting (breaking) this test. - queue.SpinUntilAllThreadsAreWaiting(); - - { - // Since we have no tasks yet, all threads should be waiting by now. - base::AutoLock auto_lock(*queue.lock()); - EXPECT_EQ(0, queue.GetNumThreadsTakingAssignments()); - EXPECT_EQ(0, queue.GetNumThreadsCompletingTasks()); - EXPECT_EQ(0, queue.task_count()); - EXPECT_EQ(0, queue.GetMaxCompletionsByWorkerThread()); - EXPECT_EQ(0, queue.GetMinCompletionsByWorkerThread()); - EXPECT_EQ(0, queue.GetNumberOfCompletedTasks()); - - // Set up to make each task include getting help from another worker, so - // so that the work gets done in paralell. - queue.ResetHistory(); - queue.SetTaskCount(kTaskCount); - queue.SetWorkTime(kThirtyMs); - queue.SetAllowHelp(true); - - start_time = Time::Now(); - } - - queue.work_is_available()->Signal(); // But each worker can signal another. - // Wait till we at least start to handle tasks (and we're not all waiting). - queue.SpinUntilTaskCountLessThan(kTaskCount); - // Wait to allow the all workers to get done. - queue.SpinUntilAllThreadsAreWaiting(); - - { - // Wait until all work tasks have at least been assigned. - base::AutoLock auto_lock(*queue.lock()); - while (queue.task_count()) - queue.no_more_tasks()->Wait(); - - // To avoid racy assumptions, we'll just assert that at least 2 threads - // did work. We know that the first worker should have gone to sleep, and - // hence a second worker should have gotten an assignment. - EXPECT_LE(2, queue.GetNumThreadsTakingAssignments()); - EXPECT_EQ(kTaskCount, queue.GetNumberOfCompletedTasks()); - - // Try to ask all workers to help, and only a few will do the work. - queue.ResetHistory(); - queue.SetTaskCount(3); - queue.SetWorkTime(kThirtyMs); - queue.SetAllowHelp(false); - } - queue.work_is_available()->Broadcast(); // Make them all try. - // Wait till we at least start to handle tasks (and we're not all waiting). - queue.SpinUntilTaskCountLessThan(3); - // Wait to allow the 3 workers to get done. - queue.SpinUntilAllThreadsAreWaiting(); - - { - base::AutoLock auto_lock(*queue.lock()); - EXPECT_EQ(3, queue.GetNumThreadsTakingAssignments()); - EXPECT_EQ(3, queue.GetNumThreadsCompletingTasks()); - EXPECT_EQ(0, queue.task_count()); - EXPECT_EQ(1, queue.GetMaxCompletionsByWorkerThread()); - EXPECT_EQ(0, queue.GetMinCompletionsByWorkerThread()); - EXPECT_EQ(3, queue.GetNumberOfCompletedTasks()); - - // Set up to make each task get help from another worker. - queue.ResetHistory(); - queue.SetTaskCount(3); - queue.SetWorkTime(kThirtyMs); - queue.SetAllowHelp(true); // Allow (unnecessary) help requests. - } - queue.work_is_available()->Broadcast(); // Signal all threads. - // Wait till we at least start to handle tasks (and we're not all waiting). - queue.SpinUntilTaskCountLessThan(3); - // Wait to allow the 3 workers to get done. - queue.SpinUntilAllThreadsAreWaiting(); - - { - base::AutoLock auto_lock(*queue.lock()); - EXPECT_EQ(3, queue.GetNumThreadsTakingAssignments()); - EXPECT_EQ(3, queue.GetNumThreadsCompletingTasks()); - EXPECT_EQ(0, queue.task_count()); - EXPECT_EQ(1, queue.GetMaxCompletionsByWorkerThread()); - EXPECT_EQ(0, queue.GetMinCompletionsByWorkerThread()); - EXPECT_EQ(3, queue.GetNumberOfCompletedTasks()); - - // Set up to make each task get help from another worker. - queue.ResetHistory(); - queue.SetTaskCount(20); // 2 tasks per thread. - queue.SetWorkTime(kThirtyMs); - queue.SetAllowHelp(true); - } - queue.work_is_available()->Signal(); // But each worker can signal another. - // Wait till we at least start to handle tasks (and we're not all waiting). - queue.SpinUntilTaskCountLessThan(20); - // Wait to allow the 10 workers to get done. - queue.SpinUntilAllThreadsAreWaiting(); // Should take about 60 ms. - - { - base::AutoLock auto_lock(*queue.lock()); - EXPECT_EQ(10, queue.GetNumThreadsTakingAssignments()); - EXPECT_EQ(10, queue.GetNumThreadsCompletingTasks()); - EXPECT_EQ(0, queue.task_count()); - EXPECT_EQ(20, queue.GetNumberOfCompletedTasks()); - - // Same as last test, but with Broadcast(). - queue.ResetHistory(); - queue.SetTaskCount(20); // 2 tasks per thread. - queue.SetWorkTime(kThirtyMs); - queue.SetAllowHelp(true); - } - queue.work_is_available()->Broadcast(); - // Wait till we at least start to handle tasks (and we're not all waiting). - queue.SpinUntilTaskCountLessThan(20); - // Wait to allow the 10 workers to get done. - queue.SpinUntilAllThreadsAreWaiting(); // Should take about 60 ms. - - { - base::AutoLock auto_lock(*queue.lock()); - EXPECT_EQ(10, queue.GetNumThreadsTakingAssignments()); - EXPECT_EQ(10, queue.GetNumThreadsCompletingTasks()); - EXPECT_EQ(0, queue.task_count()); - EXPECT_EQ(20, queue.GetNumberOfCompletedTasks()); - - queue.SetShutdown(); - } - queue.work_is_available()->Broadcast(); // Force check for shutdown. - - SPIN_FOR_TIMEDELTA_OR_UNTIL_TRUE(TimeDelta::FromMinutes(1), - queue.ThreadSafeCheckShutdown(kThreadCount)); -} - -TEST_F(ConditionVariableTest, LargeFastTaskTest) { - const int kThreadCount = 200; - WorkQueue queue(kThreadCount); // Start the threads. - - Lock private_lock; // Used locally for master to wait. - base::AutoLock private_held_lock(private_lock); - ConditionVariable private_cv(&private_lock); - - { - base::AutoLock auto_lock(*queue.lock()); - while (!queue.EveryIdWasAllocated()) - queue.all_threads_have_ids()->Wait(); - } - - // Wait a bit more to allow threads to reach their wait state. - queue.SpinUntilAllThreadsAreWaiting(); - - { - // Since we have no tasks, all threads should be waiting by now. - base::AutoLock auto_lock(*queue.lock()); - EXPECT_EQ(0, queue.GetNumThreadsTakingAssignments()); - EXPECT_EQ(0, queue.GetNumThreadsCompletingTasks()); - EXPECT_EQ(0, queue.task_count()); - EXPECT_EQ(0, queue.GetMaxCompletionsByWorkerThread()); - EXPECT_EQ(0, queue.GetMinCompletionsByWorkerThread()); - EXPECT_EQ(0, queue.GetNumberOfCompletedTasks()); - - // Set up to make all workers do (an average of) 20 tasks. - queue.ResetHistory(); - queue.SetTaskCount(20 * kThreadCount); - queue.SetWorkTime(kFortyFiveMs); - queue.SetAllowHelp(false); - } - queue.work_is_available()->Broadcast(); // Start up all threads. - // Wait until we've handed out all tasks. - { - base::AutoLock auto_lock(*queue.lock()); - while (queue.task_count() != 0) - queue.no_more_tasks()->Wait(); - } - - // Wait till the last of the tasks complete. - queue.SpinUntilAllThreadsAreWaiting(); - - { - // With Broadcast(), every thread should have participated. - // but with racing.. they may not all have done equal numbers of tasks. - base::AutoLock auto_lock(*queue.lock()); - EXPECT_EQ(kThreadCount, queue.GetNumThreadsTakingAssignments()); - EXPECT_EQ(kThreadCount, queue.GetNumThreadsCompletingTasks()); - EXPECT_EQ(0, queue.task_count()); - EXPECT_LE(20, queue.GetMaxCompletionsByWorkerThread()); - EXPECT_EQ(20 * kThreadCount, queue.GetNumberOfCompletedTasks()); - - // Set up to make all workers do (an average of) 4 tasks. - queue.ResetHistory(); - queue.SetTaskCount(kThreadCount * 4); - queue.SetWorkTime(kFortyFiveMs); - queue.SetAllowHelp(true); // Might outperform Broadcast(). - } - queue.work_is_available()->Signal(); // Start up one thread. - - // Wait until we've handed out all tasks - { - base::AutoLock auto_lock(*queue.lock()); - while (queue.task_count() != 0) - queue.no_more_tasks()->Wait(); - } - - // Wait till the last of the tasks complete. - queue.SpinUntilAllThreadsAreWaiting(); - - { - // With Signal(), every thread should have participated. - // but with racing.. they may not all have done four tasks. - base::AutoLock auto_lock(*queue.lock()); - EXPECT_EQ(kThreadCount, queue.GetNumThreadsTakingAssignments()); - EXPECT_EQ(kThreadCount, queue.GetNumThreadsCompletingTasks()); - EXPECT_EQ(0, queue.task_count()); - EXPECT_LE(4, queue.GetMaxCompletionsByWorkerThread()); - EXPECT_EQ(4 * kThreadCount, queue.GetNumberOfCompletedTasks()); - - queue.SetShutdown(); - } - queue.work_is_available()->Broadcast(); // Force check for shutdown. - - // Wait for shutdowns to complete. - SPIN_FOR_TIMEDELTA_OR_UNTIL_TRUE(TimeDelta::FromMinutes(1), - queue.ThreadSafeCheckShutdown(kThreadCount)); -} - -//------------------------------------------------------------------------------ -// Finally we provide the implementation for the methods in the WorkQueue class. -//------------------------------------------------------------------------------ - -WorkQueue::WorkQueue(int thread_count) - : lock_(), - work_is_available_(&lock_), - all_threads_have_ids_(&lock_), - no_more_tasks_(&lock_), - thread_count_(thread_count), - waiting_thread_count_(0), - thread_handles_(new PlatformThreadHandle[thread_count]), - assignment_history_(thread_count), - completion_history_(thread_count), - thread_started_counter_(0), - shutdown_task_count_(0), - task_count_(0), - allow_help_requests_(false), - shutdown_(false) { - EXPECT_GE(thread_count_, 1); - ResetHistory(); - SetTaskCount(0); - SetWorkTime(TimeDelta::FromMilliseconds(30)); - - for (int i = 0; i < thread_count_; ++i) { - PlatformThreadHandle pth; - EXPECT_TRUE(PlatformThread::Create(0, this, &pth)); - thread_handles_[i] = pth; - } -} - -WorkQueue::~WorkQueue() { - { - base::AutoLock auto_lock(lock_); - SetShutdown(); - } - work_is_available_.Broadcast(); // Tell them all to terminate. - - for (int i = 0; i < thread_count_; ++i) { - PlatformThread::Join(thread_handles_[i]); - } - EXPECT_EQ(0, waiting_thread_count_); -} - -int WorkQueue::GetThreadId() { - DFAKE_SCOPED_RECURSIVE_LOCK(locked_methods_); - DCHECK(!EveryIdWasAllocated()); - return thread_started_counter_++; // Give out Unique IDs. -} - -bool WorkQueue::EveryIdWasAllocated() const { - DFAKE_SCOPED_RECURSIVE_LOCK(locked_methods_); - return thread_count_ == thread_started_counter_; -} - -TimeDelta WorkQueue::GetAnAssignment(int thread_id) { - DFAKE_SCOPED_RECURSIVE_LOCK(locked_methods_); - DCHECK_LT(0, task_count_); - assignment_history_[thread_id]++; - if (0 == --task_count_) { - no_more_tasks_.Signal(); - } - return worker_delay_; -} - -void WorkQueue::WorkIsCompleted(int thread_id) { - DFAKE_SCOPED_RECURSIVE_LOCK(locked_methods_); - completion_history_[thread_id]++; -} - -int WorkQueue::task_count() const { - DFAKE_SCOPED_RECURSIVE_LOCK(locked_methods_); - return task_count_; -} - -bool WorkQueue::allow_help_requests() const { - DFAKE_SCOPED_RECURSIVE_LOCK(locked_methods_); - return allow_help_requests_; -} - -bool WorkQueue::shutdown() const { - lock_.AssertAcquired(); - DFAKE_SCOPED_RECURSIVE_LOCK(locked_methods_); - return shutdown_; -} - -// Because this method is called from the test's main thread we need to actually -// take the lock. Threads will call the thread_shutting_down() method with the -// lock already acquired. -bool WorkQueue::ThreadSafeCheckShutdown(int thread_count) { - bool all_shutdown; - base::AutoLock auto_lock(lock_); - { - // Declare in scope so DFAKE is guranteed to be destroyed before AutoLock. - DFAKE_SCOPED_RECURSIVE_LOCK(locked_methods_); - all_shutdown = (shutdown_task_count_ == thread_count); - } - return all_shutdown; -} - -void WorkQueue::thread_shutting_down() { - lock_.AssertAcquired(); - DFAKE_SCOPED_RECURSIVE_LOCK(locked_methods_); - shutdown_task_count_++; -} - -Lock* WorkQueue::lock() { - return &lock_; -} - -ConditionVariable* WorkQueue::work_is_available() { - return &work_is_available_; -} - -ConditionVariable* WorkQueue::all_threads_have_ids() { - return &all_threads_have_ids_; -} - -ConditionVariable* WorkQueue::no_more_tasks() { - return &no_more_tasks_; -} - -void WorkQueue::ResetHistory() { - for (int i = 0; i < thread_count_; ++i) { - assignment_history_[i] = 0; - completion_history_[i] = 0; - } -} - -int WorkQueue::GetMinCompletionsByWorkerThread() const { - int minumum = completion_history_[0]; - for (int i = 0; i < thread_count_; ++i) - minumum = std::min(minumum, completion_history_[i]); - return minumum; -} - -int WorkQueue::GetMaxCompletionsByWorkerThread() const { - int maximum = completion_history_[0]; - for (int i = 0; i < thread_count_; ++i) - maximum = std::max(maximum, completion_history_[i]); - return maximum; -} - -int WorkQueue::GetNumThreadsTakingAssignments() const { - int count = 0; - for (int i = 0; i < thread_count_; ++i) - if (assignment_history_[i]) - count++; - return count; -} - -int WorkQueue::GetNumThreadsCompletingTasks() const { - int count = 0; - for (int i = 0; i < thread_count_; ++i) - if (completion_history_[i]) - count++; - return count; -} - -int WorkQueue::GetNumberOfCompletedTasks() const { - int total = 0; - for (int i = 0; i < thread_count_; ++i) - total += completion_history_[i]; - return total; -} - -TimeDelta WorkQueue::GetWorkTime() const { - return worker_delay_; -} - -void WorkQueue::SetWorkTime(TimeDelta delay) { - worker_delay_ = delay; -} - -void WorkQueue::SetTaskCount(int count) { - task_count_ = count; -} - -void WorkQueue::SetAllowHelp(bool allow) { - allow_help_requests_ = allow; -} - -void WorkQueue::SetShutdown() { - lock_.AssertAcquired(); - shutdown_ = true; -} - -void WorkQueue::SpinUntilAllThreadsAreWaiting() { - while (true) { - { - base::AutoLock auto_lock(lock_); - if (waiting_thread_count_ == thread_count_) - break; - } - PlatformThread::Sleep(TimeDelta::FromMilliseconds(30)); - } -} - -void WorkQueue::SpinUntilTaskCountLessThan(int task_count) { - while (true) { - { - base::AutoLock auto_lock(lock_); - if (task_count_ < task_count) - break; - } - PlatformThread::Sleep(TimeDelta::FromMilliseconds(30)); - } -} - - -//------------------------------------------------------------------------------ -// Define the standard worker task. Several tests will spin out many of these -// threads. -//------------------------------------------------------------------------------ - -// The multithread tests involve several threads with a task to perform as -// directed by an instance of the class WorkQueue. -// The task is to: -// a) Check to see if there are more tasks (there is a task counter). -// a1) Wait on condition variable if there are no tasks currently. -// b) Call a function to see what should be done. -// c) Do some computation based on the number of milliseconds returned in (b). -// d) go back to (a). - -// WorkQueue::ThreadMain() implements the above task for all threads. -// It calls the controlling object to tell the creator about progress, and to -// ask about tasks. - -void WorkQueue::ThreadMain() { - int thread_id; - { - base::AutoLock auto_lock(lock_); - thread_id = GetThreadId(); - if (EveryIdWasAllocated()) - all_threads_have_ids()->Signal(); // Tell creator we're ready. - } - - Lock private_lock; // Used to waste time on "our work". - while (1) { // This is the main consumer loop. - TimeDelta work_time; - bool could_use_help; - { - base::AutoLock auto_lock(lock_); - while (0 == task_count() && !shutdown()) { - ++waiting_thread_count_; - work_is_available()->Wait(); - --waiting_thread_count_; - } - if (shutdown()) { - // Ack the notification of a shutdown message back to the controller. - thread_shutting_down(); - return; // Terminate. - } - // Get our task duration from the queue. - work_time = GetAnAssignment(thread_id); - could_use_help = (task_count() > 0) && allow_help_requests(); - } // Release lock - - // Do work (outside of locked region. - if (could_use_help) - work_is_available()->Signal(); // Get help from other threads. - - if (work_time > TimeDelta::FromMilliseconds(0)) { - // We could just sleep(), but we'll instead further exercise the - // condition variable class, and do a timed wait. - base::AutoLock auto_lock(private_lock); - ConditionVariable private_cv(&private_lock); - private_cv.TimedWait(work_time); // Unsynchronized waiting. - } - - { - base::AutoLock auto_lock(lock_); - // Send notification that we completed our "work." - WorkIsCompleted(thread_id); - } - } -} - -} // namespace - -} // namespace base diff --git a/base/synchronization/condition_variable_win.cc b/base/synchronization/condition_variable_win.cc deleted file mode 100644 index bf0d5f3de7..0000000000 --- a/base/synchronization/condition_variable_win.cc +++ /dev/null @@ -1,669 +0,0 @@ -// Copyright (c) 2011 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "base/synchronization/condition_variable.h" - -#include -#include - -#include "base/compiler_specific.h" -#include "base/logging.h" -#include "base/synchronization/lock.h" -#include "base/threading/thread_restrictions.h" -#include "base/time/time.h" - -namespace { -// We can't use the linker supported delay-load for kernel32 so all this -// cruft here is to manually late-bind the needed functions. -typedef void (WINAPI *InitializeConditionVariableFn)(PCONDITION_VARIABLE); -typedef BOOL (WINAPI *SleepConditionVariableCSFn)(PCONDITION_VARIABLE, - PCRITICAL_SECTION, DWORD); -typedef void (WINAPI *WakeConditionVariableFn)(PCONDITION_VARIABLE); -typedef void (WINAPI *WakeAllConditionVariableFn)(PCONDITION_VARIABLE); - -InitializeConditionVariableFn initialize_condition_variable_fn; -SleepConditionVariableCSFn sleep_condition_variable_fn; -WakeConditionVariableFn wake_condition_variable_fn; -WakeAllConditionVariableFn wake_all_condition_variable_fn; - -bool BindVistaCondVarFunctions() { - HMODULE kernel32 = GetModuleHandleA("kernel32.dll"); - initialize_condition_variable_fn = - reinterpret_cast( - GetProcAddress(kernel32, "InitializeConditionVariable")); - if (!initialize_condition_variable_fn) - return false; - sleep_condition_variable_fn = - reinterpret_cast( - GetProcAddress(kernel32, "SleepConditionVariableCS")); - if (!sleep_condition_variable_fn) - return false; - wake_condition_variable_fn = - reinterpret_cast( - GetProcAddress(kernel32, "WakeConditionVariable")); - if (!wake_condition_variable_fn) - return false; - wake_all_condition_variable_fn = - reinterpret_cast( - GetProcAddress(kernel32, "WakeAllConditionVariable")); - if (!wake_all_condition_variable_fn) - return false; - return true; -} - -} // namespace. - -namespace base { -// Abstract base class of the pimpl idiom. -class ConditionVarImpl { - public: - virtual ~ConditionVarImpl() {}; - virtual void Wait() = 0; - virtual void TimedWait(const TimeDelta& max_time) = 0; - virtual void Broadcast() = 0; - virtual void Signal() = 0; -}; - -/////////////////////////////////////////////////////////////////////////////// -// Windows Vista and Win7 implementation. -/////////////////////////////////////////////////////////////////////////////// - -class WinVistaCondVar: public ConditionVarImpl { - public: - WinVistaCondVar(Lock* user_lock); - ~WinVistaCondVar() {}; - // Overridden from ConditionVarImpl. - virtual void Wait() OVERRIDE; - virtual void TimedWait(const TimeDelta& max_time) OVERRIDE; - virtual void Broadcast() OVERRIDE; - virtual void Signal() OVERRIDE; - - private: - base::Lock& user_lock_; - CONDITION_VARIABLE cv_; -}; - -WinVistaCondVar::WinVistaCondVar(Lock* user_lock) - : user_lock_(*user_lock) { - initialize_condition_variable_fn(&cv_); - DCHECK(user_lock); -} - -void WinVistaCondVar::Wait() { - TimedWait(TimeDelta::FromMilliseconds(INFINITE)); -} - -void WinVistaCondVar::TimedWait(const TimeDelta& max_time) { - base::ThreadRestrictions::AssertWaitAllowed(); - DWORD timeout = static_cast(max_time.InMilliseconds()); - CRITICAL_SECTION* cs = user_lock_.lock_.os_lock(); - -#if !defined(NDEBUG) - user_lock_.CheckHeldAndUnmark(); -#endif - - if (FALSE == sleep_condition_variable_fn(&cv_, cs, timeout)) { - DCHECK(GetLastError() != WAIT_TIMEOUT); - } - -#if !defined(NDEBUG) - user_lock_.CheckUnheldAndMark(); -#endif -} - -void WinVistaCondVar::Broadcast() { - wake_all_condition_variable_fn(&cv_); -} - -void WinVistaCondVar::Signal() { - wake_condition_variable_fn(&cv_); -} - -/////////////////////////////////////////////////////////////////////////////// -// Windows XP implementation. -/////////////////////////////////////////////////////////////////////////////// - -class WinXPCondVar : public ConditionVarImpl { - public: - WinXPCondVar(Lock* user_lock); - ~WinXPCondVar(); - // Overridden from ConditionVarImpl. - virtual void Wait() OVERRIDE; - virtual void TimedWait(const TimeDelta& max_time) OVERRIDE; - virtual void Broadcast() OVERRIDE; - virtual void Signal() OVERRIDE; - - // Define Event class that is used to form circularly linked lists. - // The list container is an element with NULL as its handle_ value. - // The actual list elements have a non-zero handle_ value. - // All calls to methods MUST be done under protection of a lock so that links - // can be validated. Without the lock, some links might asynchronously - // change, and the assertions would fail (as would list change operations). - class Event { - public: - // Default constructor with no arguments creates a list container. - Event(); - ~Event(); - - // InitListElement transitions an instance from a container, to an element. - void InitListElement(); - - // Methods for use on lists. - bool IsEmpty() const; - void PushBack(Event* other); - Event* PopFront(); - Event* PopBack(); - - // Methods for use on list elements. - // Accessor method. - HANDLE handle() const; - // Pull an element from a list (if it's in one). - Event* Extract(); - - // Method for use on a list element or on a list. - bool IsSingleton() const; - - private: - // Provide pre/post conditions to validate correct manipulations. - bool ValidateAsDistinct(Event* other) const; - bool ValidateAsItem() const; - bool ValidateAsList() const; - bool ValidateLinks() const; - - HANDLE handle_; - Event* next_; - Event* prev_; - DISALLOW_COPY_AND_ASSIGN(Event); - }; - - // Note that RUNNING is an unlikely number to have in RAM by accident. - // This helps with defensive destructor coding in the face of user error. - enum RunState { SHUTDOWN = 0, RUNNING = 64213 }; - - // Internal implementation methods supporting Wait(). - Event* GetEventForWaiting(); - void RecycleEvent(Event* used_event); - - RunState run_state_; - - // Private critical section for access to member data. - base::Lock internal_lock_; - - // Lock that is acquired before calling Wait(). - base::Lock& user_lock_; - - // Events that threads are blocked on. - Event waiting_list_; - - // Free list for old events. - Event recycling_list_; - int recycling_list_size_; - - // The number of allocated, but not yet deleted events. - int allocation_counter_; -}; - -WinXPCondVar::WinXPCondVar(Lock* user_lock) - : user_lock_(*user_lock), - run_state_(RUNNING), - allocation_counter_(0), - recycling_list_size_(0) { - DCHECK(user_lock); -} - -WinXPCondVar::~WinXPCondVar() { - AutoLock auto_lock(internal_lock_); - run_state_ = SHUTDOWN; // Prevent any more waiting. - - DCHECK_EQ(recycling_list_size_, allocation_counter_); - if (recycling_list_size_ != allocation_counter_) { // Rare shutdown problem. - // There are threads of execution still in this->TimedWait() and yet the - // caller has instigated the destruction of this instance :-/. - // A common reason for such "overly hasty" destruction is that the caller - // was not willing to wait for all the threads to terminate. Such hasty - // actions are a violation of our usage contract, but we'll give the - // waiting thread(s) one last chance to exit gracefully (prior to our - // destruction). - // Note: waiting_list_ *might* be empty, but recycling is still pending. - AutoUnlock auto_unlock(internal_lock_); - Broadcast(); // Make sure all waiting threads have been signaled. - Sleep(10); // Give threads a chance to grab internal_lock_. - // All contained threads should be blocked on user_lock_ by now :-). - } // Reacquire internal_lock_. - - DCHECK_EQ(recycling_list_size_, allocation_counter_); -} - -void WinXPCondVar::Wait() { - // Default to "wait forever" timing, which means have to get a Signal() - // or Broadcast() to come out of this wait state. - TimedWait(TimeDelta::FromMilliseconds(INFINITE)); -} - -void WinXPCondVar::TimedWait(const TimeDelta& max_time) { - base::ThreadRestrictions::AssertWaitAllowed(); - Event* waiting_event; - HANDLE handle; - { - AutoLock auto_lock(internal_lock_); - if (RUNNING != run_state_) return; // Destruction in progress. - waiting_event = GetEventForWaiting(); - handle = waiting_event->handle(); - DCHECK(handle); - } // Release internal_lock. - - { - AutoUnlock unlock(user_lock_); // Release caller's lock - WaitForSingleObject(handle, static_cast(max_time.InMilliseconds())); - // Minimize spurious signal creation window by recycling asap. - AutoLock auto_lock(internal_lock_); - RecycleEvent(waiting_event); - // Release internal_lock_ - } // Reacquire callers lock to depth at entry. -} - -// Broadcast() is guaranteed to signal all threads that were waiting (i.e., had -// a cv_event internally allocated for them) before Broadcast() was called. -void WinXPCondVar::Broadcast() { - std::stack handles; // See FAQ-question-10. - { - AutoLock auto_lock(internal_lock_); - if (waiting_list_.IsEmpty()) - return; - while (!waiting_list_.IsEmpty()) - // This is not a leak from waiting_list_. See FAQ-question 12. - handles.push(waiting_list_.PopBack()->handle()); - } // Release internal_lock_. - while (!handles.empty()) { - SetEvent(handles.top()); - handles.pop(); - } -} - -// Signal() will select one of the waiting threads, and signal it (signal its -// cv_event). For better performance we signal the thread that went to sleep -// most recently (LIFO). If we want fairness, then we wake the thread that has -// been sleeping the longest (FIFO). -void WinXPCondVar::Signal() { - HANDLE handle; - { - AutoLock auto_lock(internal_lock_); - if (waiting_list_.IsEmpty()) - return; // No one to signal. - // Only performance option should be used. - // This is not a leak from waiting_list. See FAQ-question 12. - handle = waiting_list_.PopBack()->handle(); // LIFO. - } // Release internal_lock_. - SetEvent(handle); -} - -// GetEventForWaiting() provides a unique cv_event for any caller that needs to -// wait. This means that (worst case) we may over time create as many cv_event -// objects as there are threads simultaneously using this instance's Wait() -// functionality. -WinXPCondVar::Event* WinXPCondVar::GetEventForWaiting() { - // We hold internal_lock, courtesy of Wait(). - Event* cv_event; - if (0 == recycling_list_size_) { - DCHECK(recycling_list_.IsEmpty()); - cv_event = new Event(); - cv_event->InitListElement(); - allocation_counter_++; - DCHECK(cv_event->handle()); - } else { - cv_event = recycling_list_.PopFront(); - recycling_list_size_--; - } - waiting_list_.PushBack(cv_event); - return cv_event; -} - -// RecycleEvent() takes a cv_event that was previously used for Wait()ing, and -// recycles it for use in future Wait() calls for this or other threads. -// Note that there is a tiny chance that the cv_event is still signaled when we -// obtain it, and that can cause spurious signals (if/when we re-use the -// cv_event), but such is quite rare (see FAQ-question-5). -void WinXPCondVar::RecycleEvent(Event* used_event) { - // We hold internal_lock, courtesy of Wait(). - // If the cv_event timed out, then it is necessary to remove it from - // waiting_list_. If it was selected by Broadcast() or Signal(), then it is - // already gone. - used_event->Extract(); // Possibly redundant - recycling_list_.PushBack(used_event); - recycling_list_size_++; -} -//------------------------------------------------------------------------------ -// The next section provides the implementation for the private Event class. -//------------------------------------------------------------------------------ - -// Event provides a doubly-linked-list of events for use exclusively by the -// ConditionVariable class. - -// This custom container was crafted because no simple combination of STL -// classes appeared to support the functionality required. The specific -// unusual requirement for a linked-list-class is support for the Extract() -// method, which can remove an element from a list, potentially for insertion -// into a second list. Most critically, the Extract() method is idempotent, -// turning the indicated element into an extracted singleton whether it was -// contained in a list or not. This functionality allows one (or more) of -// threads to do the extraction. The iterator that identifies this extractable -// element (in this case, a pointer to the list element) can be used after -// arbitrary manipulation of the (possibly) enclosing list container. In -// general, STL containers do not provide iterators that can be used across -// modifications (insertions/extractions) of the enclosing containers, and -// certainly don't provide iterators that can be used if the identified -// element is *deleted* (removed) from the container. - -// It is possible to use multiple redundant containers, such as an STL list, -// and an STL map, to achieve similar container semantics. This container has -// only O(1) methods, while the corresponding (multiple) STL container approach -// would have more complex O(log(N)) methods (yeah... N isn't that large). -// Multiple containers also makes correctness more difficult to assert, as -// data is redundantly stored and maintained, which is generally evil. - -WinXPCondVar::Event::Event() : handle_(0) { - next_ = prev_ = this; // Self referencing circular. -} - -WinXPCondVar::Event::~Event() { - if (0 == handle_) { - // This is the list holder - while (!IsEmpty()) { - Event* cv_event = PopFront(); - DCHECK(cv_event->ValidateAsItem()); - delete cv_event; - } - } - DCHECK(IsSingleton()); - if (0 != handle_) { - int ret_val = CloseHandle(handle_); - DCHECK(ret_val); - } -} - -// Change a container instance permanently into an element of a list. -void WinXPCondVar::Event::InitListElement() { - DCHECK(!handle_); - handle_ = CreateEvent(NULL, false, false, NULL); - DCHECK(handle_); -} - -// Methods for use on lists. -bool WinXPCondVar::Event::IsEmpty() const { - DCHECK(ValidateAsList()); - return IsSingleton(); -} - -void WinXPCondVar::Event::PushBack(Event* other) { - DCHECK(ValidateAsList()); - DCHECK(other->ValidateAsItem()); - DCHECK(other->IsSingleton()); - // Prepare other for insertion. - other->prev_ = prev_; - other->next_ = this; - // Cut into list. - prev_->next_ = other; - prev_ = other; - DCHECK(ValidateAsDistinct(other)); -} - -WinXPCondVar::Event* WinXPCondVar::Event::PopFront() { - DCHECK(ValidateAsList()); - DCHECK(!IsSingleton()); - return next_->Extract(); -} - -WinXPCondVar::Event* WinXPCondVar::Event::PopBack() { - DCHECK(ValidateAsList()); - DCHECK(!IsSingleton()); - return prev_->Extract(); -} - -// Methods for use on list elements. -// Accessor method. -HANDLE WinXPCondVar::Event::handle() const { - DCHECK(ValidateAsItem()); - return handle_; -} - -// Pull an element from a list (if it's in one). -WinXPCondVar::Event* WinXPCondVar::Event::Extract() { - DCHECK(ValidateAsItem()); - if (!IsSingleton()) { - // Stitch neighbors together. - next_->prev_ = prev_; - prev_->next_ = next_; - // Make extractee into a singleton. - prev_ = next_ = this; - } - DCHECK(IsSingleton()); - return this; -} - -// Method for use on a list element or on a list. -bool WinXPCondVar::Event::IsSingleton() const { - DCHECK(ValidateLinks()); - return next_ == this; -} - -// Provide pre/post conditions to validate correct manipulations. -bool WinXPCondVar::Event::ValidateAsDistinct(Event* other) const { - return ValidateLinks() && other->ValidateLinks() && (this != other); -} - -bool WinXPCondVar::Event::ValidateAsItem() const { - return (0 != handle_) && ValidateLinks(); -} - -bool WinXPCondVar::Event::ValidateAsList() const { - return (0 == handle_) && ValidateLinks(); -} - -bool WinXPCondVar::Event::ValidateLinks() const { - // Make sure both of our neighbors have links that point back to us. - // We don't do the O(n) check and traverse the whole loop, and instead only - // do a local check to (and returning from) our immediate neighbors. - return (next_->prev_ == this) && (prev_->next_ == this); -} - - -/* -FAQ On WinXPCondVar subtle implementation details: - -1) What makes this problem subtle? Please take a look at "Strategies -for Implementing POSIX Condition Variables on Win32" by Douglas -C. Schmidt and Irfan Pyarali. -http://www.cs.wustl.edu/~schmidt/win32-cv-1.html It includes -discussions of numerous flawed strategies for implementing this -functionality. I'm not convinced that even the final proposed -implementation has semantics that are as nice as this implementation -(especially with regard to Broadcast() and the impact on threads that -try to Wait() after a Broadcast() has been called, but before all the -original waiting threads have been signaled). - -2) Why can't you use a single wait_event for all threads that call -Wait()? See FAQ-question-1, or consider the following: If a single -event were used, then numerous threads calling Wait() could release -their cs locks, and be preempted just before calling -WaitForSingleObject(). If a call to Broadcast() was then presented on -a second thread, it would be impossible to actually signal all -waiting(?) threads. Some number of SetEvent() calls *could* be made, -but there could be no guarantee that those led to to more than one -signaled thread (SetEvent()'s may be discarded after the first!), and -there could be no guarantee that the SetEvent() calls didn't just -awaken "other" threads that hadn't even started waiting yet (oops). -Without any limit on the number of requisite SetEvent() calls, the -system would be forced to do many such calls, allowing many new waits -to receive spurious signals. - -3) How does this implementation cause spurious signal events? The -cause in this implementation involves a race between a signal via -time-out and a signal via Signal() or Broadcast(). The series of -actions leading to this are: - -a) Timer fires, and a waiting thread exits the line of code: - - WaitForSingleObject(waiting_event, max_time.InMilliseconds()); - -b) That thread (in (a)) is randomly pre-empted after the above line, -leaving the waiting_event reset (unsignaled) and still in the -waiting_list_. - -c) A call to Signal() (or Broadcast()) on a second thread proceeds, and -selects the waiting cv_event (identified in step (b)) as the event to revive -via a call to SetEvent(). - -d) The Signal() method (step c) calls SetEvent() on waiting_event (step b). - -e) The waiting cv_event (step b) is now signaled, but no thread is -waiting on it. - -f) When that waiting_event (step b) is reused, it will immediately -be signaled (spuriously). - - -4) Why do you recycle events, and cause spurious signals? First off, -the spurious events are very rare. They can only (I think) appear -when the race described in FAQ-question-3 takes place. This should be -very rare. Most(?) uses will involve only timer expiration, or only -Signal/Broadcast() actions. When both are used, it will be rare that -the race will appear, and it would require MANY Wait() and signaling -activities. If this implementation did not recycle events, then it -would have to create and destroy events for every call to Wait(). -That allocation/deallocation and associated construction/destruction -would be costly (per wait), and would only be a rare benefit (when the -race was "lost" and a spurious signal took place). That would be bad -(IMO) optimization trade-off. Finally, such spurious events are -allowed by the specification of condition variables (such as -implemented in Vista), and hence it is better if any user accommodates -such spurious events (see usage note in condition_variable.h). - -5) Why don't you reset events when you are about to recycle them, or -about to reuse them, so that the spurious signals don't take place? -The thread described in FAQ-question-3 step c may be pre-empted for an -arbitrary length of time before proceeding to step d. As a result, -the wait_event may actually be re-used *before* step (e) is reached. -As a result, calling reset would not help significantly. - -6) How is it that the callers lock is released atomically with the -entry into a wait state? We commit to the wait activity when we -allocate the wait_event for use in a given call to Wait(). This -allocation takes place before the caller's lock is released (and -actually before our internal_lock_ is released). That allocation is -the defining moment when "the wait state has been entered," as that -thread *can* now be signaled by a call to Broadcast() or Signal(). -Hence we actually "commit to wait" before releasing the lock, making -the pair effectively atomic. - -8) Why do you need to lock your data structures during waiting, as the -caller is already in possession of a lock? We need to Acquire() and -Release() our internal lock during Signal() and Broadcast(). If we tried -to use a callers lock for this purpose, we might conflict with their -external use of the lock. For example, the caller may use to consistently -hold a lock on one thread while calling Signal() on another, and that would -block Signal(). - -9) Couldn't a more efficient implementation be provided if you -preclude using more than one external lock in conjunction with a -single ConditionVariable instance? Yes, at least it could be viewed -as a simpler API (since you don't have to reiterate the lock argument -in each Wait() call). One of the constructors now takes a specific -lock as an argument, and a there are corresponding Wait() calls that -don't specify a lock now. It turns that the resulting implmentation -can't be made more efficient, as the internal lock needs to be used by -Signal() and Broadcast(), to access internal data structures. As a -result, I was not able to utilize the user supplied lock (which is -being used by the user elsewhere presumably) to protect the private -member access. - -9) Since you have a second lock, how can be be sure that there is no -possible deadlock scenario? Our internal_lock_ is always the last -lock acquired, and the first one released, and hence a deadlock (due -to critical section problems) is impossible as a consequence of our -lock. - -10) When doing a Broadcast(), why did you copy all the events into -an STL queue, rather than making a linked-loop, and iterating over it? -The iterating during Broadcast() is done so outside the protection -of the internal lock. As a result, other threads, such as the thread -wherein a related event is waiting, could asynchronously manipulate -the links around a cv_event. As a result, the link structure cannot -be used outside a lock. Broadcast() could iterate over waiting -events by cycling in-and-out of the protection of the internal_lock, -but that appears more expensive than copying the list into an STL -stack. - -11) Why did the lock.h file need to be modified so much for this -change? Central to a Condition Variable is the atomic release of a -lock during a Wait(). This places Wait() functionality exactly -mid-way between the two classes, Lock and Condition Variable. Given -that there can be nested Acquire()'s of locks, and Wait() had to -Release() completely a held lock, it was necessary to augment the Lock -class with a recursion counter. Even more subtle is the fact that the -recursion counter (in a Lock) must be protected, as many threads can -access it asynchronously. As a positive fallout of this, there are -now some DCHECKS to be sure no one Release()s a Lock more than they -Acquire()ed it, and there is ifdef'ed functionality that can detect -nested locks (legal under windows, but not under Posix). - -12) Why is it that the cv_events removed from list in Broadcast() and Signal() -are not leaked? How are they recovered?? The cv_events that appear to leak are -taken from the waiting_list_. For each element in that list, there is currently -a thread in or around the WaitForSingleObject() call of Wait(), and those -threads have references to these otherwise leaked events. They are passed as -arguments to be recycled just aftre returning from WaitForSingleObject(). - -13) Why did you use a custom container class (the linked list), when STL has -perfectly good containers, such as an STL list? The STL list, as with any -container, does not guarantee the utility of an iterator across manipulation -(such as insertions and deletions) of the underlying container. The custom -double-linked-list container provided that assurance. I don't believe any -combination of STL containers provided the services that were needed at the same -O(1) efficiency as the custom linked list. The unusual requirement -for the container class is that a reference to an item within a container (an -iterator) needed to be maintained across an arbitrary manipulation of the -container. This requirement exposes itself in the Wait() method, where a -waiting_event must be selected prior to the WaitForSingleObject(), and then it -must be used as part of recycling to remove the related instance from the -waiting_list. A hash table (STL map) could be used, but I was embarrased to -use a complex and relatively low efficiency container when a doubly linked list -provided O(1) performance in all required operations. Since other operations -to provide performance-and/or-fairness required queue (FIFO) and list (LIFO) -containers, I would also have needed to use an STL list/queue as well as an STL -map. In the end I decided it would be "fun" to just do it right, and I -put so many assertions (DCHECKs) into the container class that it is trivial to -code review and validate its correctness. - -*/ - -ConditionVariable::ConditionVariable(Lock* user_lock) - : impl_(NULL) { - static bool use_vista_native_cv = BindVistaCondVarFunctions(); - if (use_vista_native_cv) - impl_= new WinVistaCondVar(user_lock); - else - impl_ = new WinXPCondVar(user_lock); -} - -ConditionVariable::~ConditionVariable() { - delete impl_; -} - -void ConditionVariable::Wait() { - impl_->Wait(); -} - -void ConditionVariable::TimedWait(const TimeDelta& max_time) { - impl_->TimedWait(max_time); -} - -void ConditionVariable::Broadcast() { - impl_->Broadcast(); -} - -void ConditionVariable::Signal() { - impl_->Signal(); -} - -} // namespace base diff --git a/base/synchronization/lock.cc b/base/synchronization/lock.cc deleted file mode 100644 index 49efbe9265..0000000000 --- a/base/synchronization/lock.cc +++ /dev/null @@ -1,48 +0,0 @@ -// Copyright (c) 2011 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -// This file is used for debugging assertion support. The Lock class -// is functionally a wrapper around the LockImpl class, so the only -// real intelligence in the class is in the debugging logic. - -#if !defined(NDEBUG) - -#include "base/synchronization/lock.h" -#include "base/logging.h" - -namespace base { - -const PlatformThreadId kNoThreadId = static_cast(0); - -Lock::Lock() : lock_() { - owned_by_thread_ = false; - owning_thread_id_ = kNoThreadId; -} - -Lock::~Lock() { - DCHECK(!owned_by_thread_); - DCHECK_EQ(kNoThreadId, owning_thread_id_); -} - -void Lock::AssertAcquired() const { - DCHECK(owned_by_thread_); - DCHECK_EQ(owning_thread_id_, PlatformThread::CurrentId()); -} - -void Lock::CheckHeldAndUnmark() { - DCHECK(owned_by_thread_); - DCHECK_EQ(owning_thread_id_, PlatformThread::CurrentId()); - owned_by_thread_ = false; - owning_thread_id_ = kNoThreadId; -} - -void Lock::CheckUnheldAndMark() { - DCHECK(!owned_by_thread_); - owned_by_thread_ = true; - owning_thread_id_ = PlatformThread::CurrentId(); -} - -} // namespace base - -#endif // NDEBUG diff --git a/base/synchronization/lock.h b/base/synchronization/lock.h deleted file mode 100644 index 7e8ffe7b74..0000000000 --- a/base/synchronization/lock.h +++ /dev/null @@ -1,140 +0,0 @@ -// Copyright (c) 2011 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef BASE_SYNCHRONIZATION_LOCK_H_ -#define BASE_SYNCHRONIZATION_LOCK_H_ - -#include "base/base_export.h" -#include "base/synchronization/lock_impl.h" -#include "base/threading/platform_thread.h" - -namespace base { - -// A convenient wrapper for an OS specific critical section. The only real -// intelligence in this class is in debug mode for the support for the -// AssertAcquired() method. -class BASE_EXPORT Lock { - public: -#if defined(NDEBUG) // Optimized wrapper implementation - Lock() : lock_() {} - ~Lock() {} - void Acquire() { lock_.Lock(); } - void Release() { lock_.Unlock(); } - - // If the lock is not held, take it and return true. If the lock is already - // held by another thread, immediately return false. This must not be called - // by a thread already holding the lock (what happens is undefined and an - // assertion may fail). - bool Try() { return lock_.Try(); } - - // Null implementation if not debug. - void AssertAcquired() const {} -#else - Lock(); - ~Lock(); - - // NOTE: Although windows critical sections support recursive locks, we do not - // allow this, and we will commonly fire a DCHECK() if a thread attempts to - // acquire the lock a second time (while already holding it). - void Acquire() { - lock_.Lock(); - CheckUnheldAndMark(); - } - void Release() { - CheckHeldAndUnmark(); - lock_.Unlock(); - } - - bool Try() { - bool rv = lock_.Try(); - if (rv) { - CheckUnheldAndMark(); - } - return rv; - } - - void AssertAcquired() const; -#endif // NDEBUG - -#if defined(OS_POSIX) - // The posix implementation of ConditionVariable needs to be able - // to see our lock and tweak our debugging counters, as it releases - // and acquires locks inside of pthread_cond_{timed,}wait. - friend class ConditionVariable; -#elif defined(OS_WIN) - // The Windows Vista implementation of ConditionVariable needs the - // native handle of the critical section. - friend class WinVistaCondVar; -#endif - - private: -#if !defined(NDEBUG) - // Members and routines taking care of locks assertions. - // Note that this checks for recursive locks and allows them - // if the variable is set. This is allowed by the underlying implementation - // on windows but not on Posix, so we're doing unneeded checks on Posix. - // It's worth it to share the code. - void CheckHeldAndUnmark(); - void CheckUnheldAndMark(); - - // All private data is implicitly protected by lock_. - // Be VERY careful to only access members under that lock. - - // Determines validity of owning_thread_id_. Needed as we don't have - // a null owning_thread_id_ value. - bool owned_by_thread_; - base::PlatformThreadId owning_thread_id_; -#endif // NDEBUG - - // Platform specific underlying lock implementation. - internal::LockImpl lock_; - - DISALLOW_COPY_AND_ASSIGN(Lock); -}; - -// A helper class that acquires the given Lock while the AutoLock is in scope. -class AutoLock { - public: - struct AlreadyAcquired {}; - - explicit AutoLock(Lock& lock) : lock_(lock) { - lock_.Acquire(); - } - - AutoLock(Lock& lock, const AlreadyAcquired&) : lock_(lock) { - lock_.AssertAcquired(); - } - - ~AutoLock() { - lock_.AssertAcquired(); - lock_.Release(); - } - - private: - Lock& lock_; - DISALLOW_COPY_AND_ASSIGN(AutoLock); -}; - -// AutoUnlock is a helper that will Release() the |lock| argument in the -// constructor, and re-Acquire() it in the destructor. -class AutoUnlock { - public: - explicit AutoUnlock(Lock& lock) : lock_(lock) { - // We require our caller to have the lock. - lock_.AssertAcquired(); - lock_.Release(); - } - - ~AutoUnlock() { - lock_.Acquire(); - } - - private: - Lock& lock_; - DISALLOW_COPY_AND_ASSIGN(AutoUnlock); -}; - -} // namespace base - -#endif // BASE_SYNCHRONIZATION_LOCK_H_ diff --git a/base/synchronization/lock_impl.h b/base/synchronization/lock_impl.h deleted file mode 100644 index 0b04167b9d..0000000000 --- a/base/synchronization/lock_impl.h +++ /dev/null @@ -1,61 +0,0 @@ -// Copyright (c) 2011 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef BASE_SYNCHRONIZATION_LOCK_IMPL_H_ -#define BASE_SYNCHRONIZATION_LOCK_IMPL_H_ - -#include "build/build_config.h" - -#if defined(OS_WIN) -#include -#elif defined(OS_POSIX) -#include -#endif - -#include "base/base_export.h" -#include "base/basictypes.h" - -namespace base { -namespace internal { - -// This class implements the underlying platform-specific spin-lock mechanism -// used for the Lock class. Most users should not use LockImpl directly, but -// should instead use Lock. -class BASE_EXPORT LockImpl { - public: -#if defined(OS_WIN) - typedef CRITICAL_SECTION OSLockType; -#elif defined(OS_POSIX) - typedef pthread_mutex_t OSLockType; -#endif - - LockImpl(); - ~LockImpl(); - - // If the lock is not held, take it and return true. If the lock is already - // held by something else, immediately return false. - bool Try(); - - // Take the lock, blocking until it is available if necessary. - void Lock(); - - // Release the lock. This must only be called by the lock's holder: after - // a successful call to Try, or a call to Lock. - void Unlock(); - - // Return the native underlying lock. - // TODO(awalker): refactor lock and condition variables so that this is - // unnecessary. - OSLockType* os_lock() { return &os_lock_; } - - private: - OSLockType os_lock_; - - DISALLOW_COPY_AND_ASSIGN(LockImpl); -}; - -} // namespace internal -} // namespace base - -#endif // BASE_SYNCHRONIZATION_LOCK_IMPL_H_ diff --git a/base/synchronization/lock_impl_posix.cc b/base/synchronization/lock_impl_posix.cc deleted file mode 100644 index 86158767ea..0000000000 --- a/base/synchronization/lock_impl_posix.cc +++ /dev/null @@ -1,55 +0,0 @@ -// Copyright (c) 2011 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "base/synchronization/lock_impl.h" - -#include -#include - -#include "base/logging.h" - -namespace base { -namespace internal { - -LockImpl::LockImpl() { -#ifndef NDEBUG - // In debug, setup attributes for lock error checking. - pthread_mutexattr_t mta; - int rv = pthread_mutexattr_init(&mta); - DCHECK_EQ(rv, 0) << ". " << strerror(rv); - rv = pthread_mutexattr_settype(&mta, PTHREAD_MUTEX_ERRORCHECK); - DCHECK_EQ(rv, 0) << ". " << strerror(rv); - rv = pthread_mutex_init(&os_lock_, &mta); - DCHECK_EQ(rv, 0) << ". " << strerror(rv); - rv = pthread_mutexattr_destroy(&mta); - DCHECK_EQ(rv, 0) << ". " << strerror(rv); -#else - // In release, go with the default lock attributes. - pthread_mutex_init(&os_lock_, NULL); -#endif -} - -LockImpl::~LockImpl() { - int rv = pthread_mutex_destroy(&os_lock_); - DCHECK_EQ(rv, 0) << ". " << strerror(rv); -} - -bool LockImpl::Try() { - int rv = pthread_mutex_trylock(&os_lock_); - DCHECK(rv == 0 || rv == EBUSY) << ". " << strerror(rv); - return rv == 0; -} - -void LockImpl::Lock() { - int rv = pthread_mutex_lock(&os_lock_); - DCHECK_EQ(rv, 0) << ". " << strerror(rv); -} - -void LockImpl::Unlock() { - int rv = pthread_mutex_unlock(&os_lock_); - DCHECK_EQ(rv, 0) << ". " << strerror(rv); -} - -} // namespace internal -} // namespace base diff --git a/base/synchronization/lock_impl_win.cc b/base/synchronization/lock_impl_win.cc deleted file mode 100644 index bb8a23d898..0000000000 --- a/base/synchronization/lock_impl_win.cc +++ /dev/null @@ -1,36 +0,0 @@ -// Copyright (c) 2011 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "base/synchronization/lock_impl.h" - -namespace base { -namespace internal { - -LockImpl::LockImpl() { - // The second parameter is the spin count, for short-held locks it avoid the - // contending thread from going to sleep which helps performance greatly. - ::InitializeCriticalSectionAndSpinCount(&os_lock_, 2000); -} - -LockImpl::~LockImpl() { - ::DeleteCriticalSection(&os_lock_); -} - -bool LockImpl::Try() { - if (::TryEnterCriticalSection(&os_lock_) != FALSE) { - return true; - } - return false; -} - -void LockImpl::Lock() { - ::EnterCriticalSection(&os_lock_); -} - -void LockImpl::Unlock() { - ::LeaveCriticalSection(&os_lock_); -} - -} // namespace internal -} // namespace base diff --git a/base/synchronization/lock_unittest.cc b/base/synchronization/lock_unittest.cc deleted file mode 100644 index 161447557f..0000000000 --- a/base/synchronization/lock_unittest.cc +++ /dev/null @@ -1,216 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "base/synchronization/lock.h" - -#include - -#include "base/compiler_specific.h" -#include "base/threading/platform_thread.h" -#include "testing/gtest/include/gtest/gtest.h" - -namespace base { - -// Basic test to make sure that Acquire()/Release()/Try() don't crash ---------- - -class BasicLockTestThread : public PlatformThread::Delegate { - public: - explicit BasicLockTestThread(Lock* lock) : lock_(lock), acquired_(0) {} - - virtual void ThreadMain() OVERRIDE { - for (int i = 0; i < 10; i++) { - lock_->Acquire(); - acquired_++; - lock_->Release(); - } - for (int i = 0; i < 10; i++) { - lock_->Acquire(); - acquired_++; - PlatformThread::Sleep(TimeDelta::FromMilliseconds(rand() % 20)); - lock_->Release(); - } - for (int i = 0; i < 10; i++) { - if (lock_->Try()) { - acquired_++; - PlatformThread::Sleep(TimeDelta::FromMilliseconds(rand() % 20)); - lock_->Release(); - } - } - } - - int acquired() const { return acquired_; } - - private: - Lock* lock_; - int acquired_; - - DISALLOW_COPY_AND_ASSIGN(BasicLockTestThread); -}; - -TEST(LockTest, Basic) { - Lock lock; - BasicLockTestThread thread(&lock); - PlatformThreadHandle handle; - - ASSERT_TRUE(PlatformThread::Create(0, &thread, &handle)); - - int acquired = 0; - for (int i = 0; i < 5; i++) { - lock.Acquire(); - acquired++; - lock.Release(); - } - for (int i = 0; i < 10; i++) { - lock.Acquire(); - acquired++; - PlatformThread::Sleep(TimeDelta::FromMilliseconds(rand() % 20)); - lock.Release(); - } - for (int i = 0; i < 10; i++) { - if (lock.Try()) { - acquired++; - PlatformThread::Sleep(TimeDelta::FromMilliseconds(rand() % 20)); - lock.Release(); - } - } - for (int i = 0; i < 5; i++) { - lock.Acquire(); - acquired++; - PlatformThread::Sleep(TimeDelta::FromMilliseconds(rand() % 20)); - lock.Release(); - } - - PlatformThread::Join(handle); - - EXPECT_GE(acquired, 20); - EXPECT_GE(thread.acquired(), 20); -} - -// Test that Try() works as expected ------------------------------------------- - -class TryLockTestThread : public PlatformThread::Delegate { - public: - explicit TryLockTestThread(Lock* lock) : lock_(lock), got_lock_(false) {} - - virtual void ThreadMain() OVERRIDE { - got_lock_ = lock_->Try(); - if (got_lock_) - lock_->Release(); - } - - bool got_lock() const { return got_lock_; } - - private: - Lock* lock_; - bool got_lock_; - - DISALLOW_COPY_AND_ASSIGN(TryLockTestThread); -}; - -TEST(LockTest, TryLock) { - Lock lock; - - ASSERT_TRUE(lock.Try()); - // We now have the lock.... - - // This thread will not be able to get the lock. - { - TryLockTestThread thread(&lock); - PlatformThreadHandle handle; - - ASSERT_TRUE(PlatformThread::Create(0, &thread, &handle)); - - PlatformThread::Join(handle); - - ASSERT_FALSE(thread.got_lock()); - } - - lock.Release(); - - // This thread will.... - { - TryLockTestThread thread(&lock); - PlatformThreadHandle handle; - - ASSERT_TRUE(PlatformThread::Create(0, &thread, &handle)); - - PlatformThread::Join(handle); - - ASSERT_TRUE(thread.got_lock()); - // But it released it.... - ASSERT_TRUE(lock.Try()); - } - - lock.Release(); -} - -// Tests that locks actually exclude ------------------------------------------- - -class MutexLockTestThread : public PlatformThread::Delegate { - public: - MutexLockTestThread(Lock* lock, int* value) : lock_(lock), value_(value) {} - - // Static helper which can also be called from the main thread. - static void DoStuff(Lock* lock, int* value) { - for (int i = 0; i < 40; i++) { - lock->Acquire(); - int v = *value; - PlatformThread::Sleep(TimeDelta::FromMilliseconds(rand() % 10)); - *value = v + 1; - lock->Release(); - } - } - - virtual void ThreadMain() OVERRIDE { - DoStuff(lock_, value_); - } - - private: - Lock* lock_; - int* value_; - - DISALLOW_COPY_AND_ASSIGN(MutexLockTestThread); -}; - -TEST(LockTest, MutexTwoThreads) { - Lock lock; - int value = 0; - - MutexLockTestThread thread(&lock, &value); - PlatformThreadHandle handle; - - ASSERT_TRUE(PlatformThread::Create(0, &thread, &handle)); - - MutexLockTestThread::DoStuff(&lock, &value); - - PlatformThread::Join(handle); - - EXPECT_EQ(2 * 40, value); -} - -TEST(LockTest, MutexFourThreads) { - Lock lock; - int value = 0; - - MutexLockTestThread thread1(&lock, &value); - MutexLockTestThread thread2(&lock, &value); - MutexLockTestThread thread3(&lock, &value); - PlatformThreadHandle handle1; - PlatformThreadHandle handle2; - PlatformThreadHandle handle3; - - ASSERT_TRUE(PlatformThread::Create(0, &thread1, &handle1)); - ASSERT_TRUE(PlatformThread::Create(0, &thread2, &handle2)); - ASSERT_TRUE(PlatformThread::Create(0, &thread3, &handle3)); - - MutexLockTestThread::DoStuff(&lock, &value); - - PlatformThread::Join(handle1); - PlatformThread::Join(handle2); - PlatformThread::Join(handle3); - - EXPECT_EQ(4 * 40, value); -} - -} // namespace base diff --git a/base/synchronization/spin_wait.h b/base/synchronization/spin_wait.h deleted file mode 100644 index 9b147cda96..0000000000 --- a/base/synchronization/spin_wait.h +++ /dev/null @@ -1,50 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -// This file provides a macro ONLY for use in testing. -// DO NOT USE IN PRODUCTION CODE. There are much better ways to wait. - -// This code is very helpful in testing multi-threaded code, without depending -// on almost any primitives. This is especially helpful if you are testing -// those primitive multi-threaded constructs. - -// We provide a simple one argument spin wait (for 1 second), and a generic -// spin wait (for longer periods of time). - -#ifndef BASE_SYNCHRONIZATION_SPIN_WAIT_H_ -#define BASE_SYNCHRONIZATION_SPIN_WAIT_H_ - -#include "base/threading/platform_thread.h" -#include "base/time/time.h" - -// Provide a macro that will wait no longer than 1 second for an asynchronous -// change is the value of an expression. -// A typical use would be: -// -// SPIN_FOR_1_SECOND_OR_UNTIL_TRUE(0 == f(x)); -// -// The expression will be evaluated repeatedly until it is true, or until -// the time (1 second) expires. -// Since tests generally have a 5 second watch dog timer, this spin loop is -// typically used to get the padding needed on a given test platform to assure -// that the test passes, even if load varies, and external events vary. - -#define SPIN_FOR_1_SECOND_OR_UNTIL_TRUE(expression) \ - SPIN_FOR_TIMEDELTA_OR_UNTIL_TRUE(base::TimeDelta::FromSeconds(1), \ - (expression)) - -#define SPIN_FOR_TIMEDELTA_OR_UNTIL_TRUE(delta, expression) do { \ - base::TimeTicks start = base::TimeTicks::Now(); \ - const base::TimeDelta kTimeout = delta; \ - while (!(expression)) { \ - if (kTimeout < base::TimeTicks::Now() - start) { \ - EXPECT_LE((base::TimeTicks::Now() - start).InMilliseconds(), \ - kTimeout.InMilliseconds()) << "Timed out"; \ - break; \ - } \ - base::PlatformThread::Sleep(base::TimeDelta::FromMilliseconds(50)); \ - } \ - } while (0) - -#endif // BASE_SYNCHRONIZATION_SPIN_WAIT_H_ diff --git a/base/synchronization/waitable_event.h b/base/synchronization/waitable_event.h deleted file mode 100644 index 26e27791b6..0000000000 --- a/base/synchronization/waitable_event.h +++ /dev/null @@ -1,182 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef BASE_SYNCHRONIZATION_WAITABLE_EVENT_H_ -#define BASE_SYNCHRONIZATION_WAITABLE_EVENT_H_ - -#include "base/base_export.h" -#include "base/basictypes.h" - -#if defined(OS_WIN) -#include -#endif - -#if defined(OS_POSIX) -#include -#include -#include "base/memory/ref_counted.h" -#include "base/synchronization/lock.h" -#endif - -namespace base { - -// This replaces INFINITE from Win32 -static const int kNoTimeout = -1; - -class TimeDelta; - -// A WaitableEvent can be a useful thread synchronization tool when you want to -// allow one thread to wait for another thread to finish some work. For -// non-Windows systems, this can only be used from within a single address -// space. -// -// Use a WaitableEvent when you would otherwise use a Lock+ConditionVariable to -// protect a simple boolean value. However, if you find yourself using a -// WaitableEvent in conjunction with a Lock to wait for a more complex state -// change (e.g., for an item to be added to a queue), then you should probably -// be using a ConditionVariable instead of a WaitableEvent. -// -// NOTE: On Windows, this class provides a subset of the functionality afforded -// by a Windows event object. This is intentional. If you are writing Windows -// specific code and you need other features of a Windows event, then you might -// be better off just using an Windows event directly. -class BASE_EXPORT WaitableEvent { - public: - // If manual_reset is true, then to set the event state to non-signaled, a - // consumer must call the Reset method. If this parameter is false, then the - // system automatically resets the event state to non-signaled after a single - // waiting thread has been released. - WaitableEvent(bool manual_reset, bool initially_signaled); - -#if defined(OS_WIN) - // Create a WaitableEvent from an Event HANDLE which has already been - // created. This objects takes ownership of the HANDLE and will close it when - // deleted. - explicit WaitableEvent(HANDLE event_handle); - - // Releases ownership of the handle from this object. - HANDLE Release(); -#endif - - ~WaitableEvent(); - - // Put the event in the un-signaled state. - void Reset(); - - // Put the event in the signaled state. Causing any thread blocked on Wait - // to be woken up. - void Signal(); - - // Returns true if the event is in the signaled state, else false. If this - // is not a manual reset event, then this test will cause a reset. - bool IsSignaled(); - - // Wait indefinitely for the event to be signaled. - void Wait(); - - // Wait up until max_time has passed for the event to be signaled. Returns - // true if the event was signaled. If this method returns false, then it - // does not necessarily mean that max_time was exceeded. - bool TimedWait(const TimeDelta& max_time); - -#if defined(OS_WIN) - HANDLE handle() const { return handle_; } -#endif - - // Wait, synchronously, on multiple events. - // waitables: an array of WaitableEvent pointers - // count: the number of elements in @waitables - // - // returns: the index of a WaitableEvent which has been signaled. - // - // You MUST NOT delete any of the WaitableEvent objects while this wait is - // happening. - static size_t WaitMany(WaitableEvent** waitables, size_t count); - - // For asynchronous waiting, see WaitableEventWatcher - - // This is a private helper class. It's here because it's used by friends of - // this class (such as WaitableEventWatcher) to be able to enqueue elements - // of the wait-list - class Waiter { - public: - // Signal the waiter to wake up. - // - // Consider the case of a Waiter which is in multiple WaitableEvent's - // wait-lists. Each WaitableEvent is automatic-reset and two of them are - // signaled at the same time. Now, each will wake only the first waiter in - // the wake-list before resetting. However, if those two waiters happen to - // be the same object (as can happen if another thread didn't have a chance - // to dequeue the waiter from the other wait-list in time), two auto-resets - // will have happened, but only one waiter has been signaled! - // - // Because of this, a Waiter may "reject" a wake by returning false. In - // this case, the auto-reset WaitableEvent shouldn't act as if anything has - // been notified. - virtual bool Fire(WaitableEvent* signaling_event) = 0; - - // Waiters may implement this in order to provide an extra condition for - // two Waiters to be considered equal. In WaitableEvent::Dequeue, if the - // pointers match then this function is called as a final check. See the - // comments in ~Handle for why. - virtual bool Compare(void* tag) = 0; - - protected: - virtual ~Waiter() {} - }; - - private: - friend class WaitableEventWatcher; - -#if defined(OS_WIN) - HANDLE handle_; -#else - // On Windows, one can close a HANDLE which is currently being waited on. The - // MSDN documentation says that the resulting behaviour is 'undefined', but - // it doesn't crash. However, if we were to include the following members - // directly then, on POSIX, one couldn't use WaitableEventWatcher to watch an - // event which gets deleted. This mismatch has bitten us several times now, - // so we have a kernel of the WaitableEvent, which is reference counted. - // WaitableEventWatchers may then take a reference and thus match the Windows - // behaviour. - struct WaitableEventKernel : - public RefCountedThreadSafe { - public: - WaitableEventKernel(bool manual_reset, bool initially_signaled); - - bool Dequeue(Waiter* waiter, void* tag); - - base::Lock lock_; - const bool manual_reset_; - bool signaled_; - std::list waiters_; - - private: - friend class RefCountedThreadSafe; - ~WaitableEventKernel(); - }; - - typedef std::pair WaiterAndIndex; - - // When dealing with arrays of WaitableEvent*, we want to sort by the address - // of the WaitableEvent in order to have a globally consistent locking order. - // In that case we keep them, in sorted order, in an array of pairs where the - // second element is the index of the WaitableEvent in the original, - // unsorted, array. - static size_t EnqueueMany(WaiterAndIndex* waitables, - size_t count, Waiter* waiter); - - bool SignalAll(); - bool SignalOne(); - void Enqueue(Waiter* waiter); - - scoped_refptr kernel_; -#endif - - DISALLOW_COPY_AND_ASSIGN(WaitableEvent); -}; - -} // namespace base - -#endif // BASE_SYNCHRONIZATION_WAITABLE_EVENT_H_ diff --git a/base/synchronization/waitable_event_posix.cc b/base/synchronization/waitable_event_posix.cc deleted file mode 100644 index 714c111e19..0000000000 --- a/base/synchronization/waitable_event_posix.cc +++ /dev/null @@ -1,407 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include -#include - -#include "base/logging.h" -#include "base/synchronization/waitable_event.h" -#include "base/synchronization/condition_variable.h" -#include "base/synchronization/lock.h" -#include "base/threading/thread_restrictions.h" - -// ----------------------------------------------------------------------------- -// A WaitableEvent on POSIX is implemented as a wait-list. Currently we don't -// support cross-process events (where one process can signal an event which -// others are waiting on). Because of this, we can avoid having one thread per -// listener in several cases. -// -// The WaitableEvent maintains a list of waiters, protected by a lock. Each -// waiter is either an async wait, in which case we have a Task and the -// MessageLoop to run it on, or a blocking wait, in which case we have the -// condition variable to signal. -// -// Waiting involves grabbing the lock and adding oneself to the wait list. Async -// waits can be canceled, which means grabbing the lock and removing oneself -// from the list. -// -// Waiting on multiple events is handled by adding a single, synchronous wait to -// the wait-list of many events. An event passes a pointer to itself when -// firing a waiter and so we can store that pointer to find out which event -// triggered. -// ----------------------------------------------------------------------------- - -namespace base { - -// ----------------------------------------------------------------------------- -// This is just an abstract base class for waking the two types of waiters -// ----------------------------------------------------------------------------- -WaitableEvent::WaitableEvent(bool manual_reset, bool initially_signaled) - : kernel_(new WaitableEventKernel(manual_reset, initially_signaled)) { -} - -WaitableEvent::~WaitableEvent() { -} - -void WaitableEvent::Reset() { - base::AutoLock locked(kernel_->lock_); - kernel_->signaled_ = false; -} - -void WaitableEvent::Signal() { - base::AutoLock locked(kernel_->lock_); - - if (kernel_->signaled_) - return; - - if (kernel_->manual_reset_) { - SignalAll(); - kernel_->signaled_ = true; - } else { - // In the case of auto reset, if no waiters were woken, we remain - // signaled. - if (!SignalOne()) - kernel_->signaled_ = true; - } -} - -bool WaitableEvent::IsSignaled() { - base::AutoLock locked(kernel_->lock_); - - const bool result = kernel_->signaled_; - if (result && !kernel_->manual_reset_) - kernel_->signaled_ = false; - return result; -} - -// ----------------------------------------------------------------------------- -// Synchronous waits - -// ----------------------------------------------------------------------------- -// This is a synchronous waiter. The thread is waiting on the given condition -// variable and the fired flag in this object. -// ----------------------------------------------------------------------------- -class SyncWaiter : public WaitableEvent::Waiter { - public: - SyncWaiter() - : fired_(false), - signaling_event_(NULL), - lock_(), - cv_(&lock_) { - } - - virtual bool Fire(WaitableEvent* signaling_event) OVERRIDE { - base::AutoLock locked(lock_); - - if (fired_) - return false; - - fired_ = true; - signaling_event_ = signaling_event; - - cv_.Broadcast(); - - // Unlike AsyncWaiter objects, SyncWaiter objects are stack-allocated on - // the blocking thread's stack. There is no |delete this;| in Fire. The - // SyncWaiter object is destroyed when it goes out of scope. - - return true; - } - - WaitableEvent* signaling_event() const { - return signaling_event_; - } - - // --------------------------------------------------------------------------- - // These waiters are always stack allocated and don't delete themselves. Thus - // there's no problem and the ABA tag is the same as the object pointer. - // --------------------------------------------------------------------------- - virtual bool Compare(void* tag) OVERRIDE { - return this == tag; - } - - // --------------------------------------------------------------------------- - // Called with lock held. - // --------------------------------------------------------------------------- - bool fired() const { - return fired_; - } - - // --------------------------------------------------------------------------- - // During a TimedWait, we need a way to make sure that an auto-reset - // WaitableEvent doesn't think that this event has been signaled between - // unlocking it and removing it from the wait-list. Called with lock held. - // --------------------------------------------------------------------------- - void Disable() { - fired_ = true; - } - - base::Lock* lock() { - return &lock_; - } - - base::ConditionVariable* cv() { - return &cv_; - } - - private: - bool fired_; - WaitableEvent* signaling_event_; // The WaitableEvent which woke us - base::Lock lock_; - base::ConditionVariable cv_; -}; - -void WaitableEvent::Wait() { - bool result = TimedWait(TimeDelta::FromSeconds(-1)); - DCHECK(result) << "TimedWait() should never fail with infinite timeout"; -} - -bool WaitableEvent::TimedWait(const TimeDelta& max_time) { - base::ThreadRestrictions::AssertWaitAllowed(); - const Time end_time(Time::Now() + max_time); - const bool finite_time = max_time.ToInternalValue() >= 0; - - kernel_->lock_.Acquire(); - if (kernel_->signaled_) { - if (!kernel_->manual_reset_) { - // In this case we were signaled when we had no waiters. Now that - // someone has waited upon us, we can automatically reset. - kernel_->signaled_ = false; - } - - kernel_->lock_.Release(); - return true; - } - - SyncWaiter sw; - sw.lock()->Acquire(); - - Enqueue(&sw); - kernel_->lock_.Release(); - // We are violating locking order here by holding the SyncWaiter lock but not - // the WaitableEvent lock. However, this is safe because we don't lock @lock_ - // again before unlocking it. - - for (;;) { - const Time current_time(Time::Now()); - - if (sw.fired() || (finite_time && current_time >= end_time)) { - const bool return_value = sw.fired(); - - // We can't acquire @lock_ before releasing the SyncWaiter lock (because - // of locking order), however, in between the two a signal could be fired - // and @sw would accept it, however we will still return false, so the - // signal would be lost on an auto-reset WaitableEvent. Thus we call - // Disable which makes sw::Fire return false. - sw.Disable(); - sw.lock()->Release(); - - kernel_->lock_.Acquire(); - kernel_->Dequeue(&sw, &sw); - kernel_->lock_.Release(); - - return return_value; - } - - if (finite_time) { - const TimeDelta max_wait(end_time - current_time); - sw.cv()->TimedWait(max_wait); - } else { - sw.cv()->Wait(); - } - } -} - -// ----------------------------------------------------------------------------- -// Synchronous waiting on multiple objects. - -static bool // StrictWeakOrdering -cmp_fst_addr(const std::pair &a, - const std::pair &b) { - return a.first < b.first; -} - -// static -size_t WaitableEvent::WaitMany(WaitableEvent** raw_waitables, - size_t count) { - base::ThreadRestrictions::AssertWaitAllowed(); - DCHECK(count) << "Cannot wait on no events"; - - // We need to acquire the locks in a globally consistent order. Thus we sort - // the array of waitables by address. We actually sort a pairs so that we can - // map back to the original index values later. - std::vector > waitables; - waitables.reserve(count); - for (size_t i = 0; i < count; ++i) - waitables.push_back(std::make_pair(raw_waitables[i], i)); - - DCHECK_EQ(count, waitables.size()); - - sort(waitables.begin(), waitables.end(), cmp_fst_addr); - - // The set of waitables must be distinct. Since we have just sorted by - // address, we can check this cheaply by comparing pairs of consecutive - // elements. - for (size_t i = 0; i < waitables.size() - 1; ++i) { - DCHECK(waitables[i].first != waitables[i+1].first); - } - - SyncWaiter sw; - - const size_t r = EnqueueMany(&waitables[0], count, &sw); - if (r) { - // One of the events is already signaled. The SyncWaiter has not been - // enqueued anywhere. EnqueueMany returns the count of remaining waitables - // when the signaled one was seen, so the index of the signaled event is - // @count - @r. - return waitables[count - r].second; - } - - // At this point, we hold the locks on all the WaitableEvents and we have - // enqueued our waiter in them all. - sw.lock()->Acquire(); - // Release the WaitableEvent locks in the reverse order - for (size_t i = 0; i < count; ++i) { - waitables[count - (1 + i)].first->kernel_->lock_.Release(); - } - - for (;;) { - if (sw.fired()) - break; - - sw.cv()->Wait(); - } - sw.lock()->Release(); - - // The address of the WaitableEvent which fired is stored in the SyncWaiter. - WaitableEvent *const signaled_event = sw.signaling_event(); - // This will store the index of the raw_waitables which fired. - size_t signaled_index = 0; - - // Take the locks of each WaitableEvent in turn (except the signaled one) and - // remove our SyncWaiter from the wait-list - for (size_t i = 0; i < count; ++i) { - if (raw_waitables[i] != signaled_event) { - raw_waitables[i]->kernel_->lock_.Acquire(); - // There's no possible ABA issue with the address of the SyncWaiter here - // because it lives on the stack. Thus the tag value is just the pointer - // value again. - raw_waitables[i]->kernel_->Dequeue(&sw, &sw); - raw_waitables[i]->kernel_->lock_.Release(); - } else { - signaled_index = i; - } - } - - return signaled_index; -} - -// ----------------------------------------------------------------------------- -// If return value == 0: -// The locks of the WaitableEvents have been taken in order and the Waiter has -// been enqueued in the wait-list of each. None of the WaitableEvents are -// currently signaled -// else: -// None of the WaitableEvent locks are held. The Waiter has not been enqueued -// in any of them and the return value is the index of the first WaitableEvent -// which was signaled, from the end of the array. -// ----------------------------------------------------------------------------- -// static -size_t WaitableEvent::EnqueueMany - (std::pair* waitables, - size_t count, Waiter* waiter) { - if (!count) - return 0; - - waitables[0].first->kernel_->lock_.Acquire(); - if (waitables[0].first->kernel_->signaled_) { - if (!waitables[0].first->kernel_->manual_reset_) - waitables[0].first->kernel_->signaled_ = false; - waitables[0].first->kernel_->lock_.Release(); - return count; - } - - const size_t r = EnqueueMany(waitables + 1, count - 1, waiter); - if (r) { - waitables[0].first->kernel_->lock_.Release(); - } else { - waitables[0].first->Enqueue(waiter); - } - - return r; -} - -// ----------------------------------------------------------------------------- - - -// ----------------------------------------------------------------------------- -// Private functions... - -WaitableEvent::WaitableEventKernel::WaitableEventKernel(bool manual_reset, - bool initially_signaled) - : manual_reset_(manual_reset), - signaled_(initially_signaled) { -} - -WaitableEvent::WaitableEventKernel::~WaitableEventKernel() { -} - -// ----------------------------------------------------------------------------- -// Wake all waiting waiters. Called with lock held. -// ----------------------------------------------------------------------------- -bool WaitableEvent::SignalAll() { - bool signaled_at_least_one = false; - - for (std::list::iterator - i = kernel_->waiters_.begin(); i != kernel_->waiters_.end(); ++i) { - if ((*i)->Fire(this)) - signaled_at_least_one = true; - } - - kernel_->waiters_.clear(); - return signaled_at_least_one; -} - -// --------------------------------------------------------------------------- -// Try to wake a single waiter. Return true if one was woken. Called with lock -// held. -// --------------------------------------------------------------------------- -bool WaitableEvent::SignalOne() { - for (;;) { - if (kernel_->waiters_.empty()) - return false; - - const bool r = (*kernel_->waiters_.begin())->Fire(this); - kernel_->waiters_.pop_front(); - if (r) - return true; - } -} - -// ----------------------------------------------------------------------------- -// Add a waiter to the list of those waiting. Called with lock held. -// ----------------------------------------------------------------------------- -void WaitableEvent::Enqueue(Waiter* waiter) { - kernel_->waiters_.push_back(waiter); -} - -// ----------------------------------------------------------------------------- -// Remove a waiter from the list of those waiting. Return true if the waiter was -// actually removed. Called with lock held. -// ----------------------------------------------------------------------------- -bool WaitableEvent::WaitableEventKernel::Dequeue(Waiter* waiter, void* tag) { - for (std::list::iterator - i = waiters_.begin(); i != waiters_.end(); ++i) { - if (*i == waiter && (*i)->Compare(tag)) { - waiters_.erase(i); - return true; - } - } - - return false; -} - -// ----------------------------------------------------------------------------- - -} // namespace base diff --git a/base/synchronization/waitable_event_unittest.cc b/base/synchronization/waitable_event_unittest.cc deleted file mode 100644 index b66f6e8720..0000000000 --- a/base/synchronization/waitable_event_unittest.cc +++ /dev/null @@ -1,108 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "base/synchronization/waitable_event.h" - -#include "base/compiler_specific.h" -#include "base/threading/platform_thread.h" -#include "base/time/time.h" -#include "testing/gtest/include/gtest/gtest.h" - -namespace base { - -TEST(WaitableEventTest, ManualBasics) { - WaitableEvent event(true, false); - - EXPECT_FALSE(event.IsSignaled()); - - event.Signal(); - EXPECT_TRUE(event.IsSignaled()); - EXPECT_TRUE(event.IsSignaled()); - - event.Reset(); - EXPECT_FALSE(event.IsSignaled()); - EXPECT_FALSE(event.TimedWait(TimeDelta::FromMilliseconds(10))); - - event.Signal(); - event.Wait(); - EXPECT_TRUE(event.TimedWait(TimeDelta::FromMilliseconds(10))); -} - -TEST(WaitableEventTest, AutoBasics) { - WaitableEvent event(false, false); - - EXPECT_FALSE(event.IsSignaled()); - - event.Signal(); - EXPECT_TRUE(event.IsSignaled()); - EXPECT_FALSE(event.IsSignaled()); - - event.Reset(); - EXPECT_FALSE(event.IsSignaled()); - EXPECT_FALSE(event.TimedWait(TimeDelta::FromMilliseconds(10))); - - event.Signal(); - event.Wait(); - EXPECT_FALSE(event.TimedWait(TimeDelta::FromMilliseconds(10))); - - event.Signal(); - EXPECT_TRUE(event.TimedWait(TimeDelta::FromMilliseconds(10))); -} - -TEST(WaitableEventTest, WaitManyShortcut) { - WaitableEvent* ev[5]; - for (unsigned i = 0; i < 5; ++i) - ev[i] = new WaitableEvent(false, false); - - ev[3]->Signal(); - EXPECT_EQ(WaitableEvent::WaitMany(ev, 5), 3u); - - ev[3]->Signal(); - EXPECT_EQ(WaitableEvent::WaitMany(ev, 5), 3u); - - ev[4]->Signal(); - EXPECT_EQ(WaitableEvent::WaitMany(ev, 5), 4u); - - ev[0]->Signal(); - EXPECT_EQ(WaitableEvent::WaitMany(ev, 5), 0u); - - for (unsigned i = 0; i < 5; ++i) - delete ev[i]; -} - -class WaitableEventSignaler : public PlatformThread::Delegate { - public: - WaitableEventSignaler(double seconds, WaitableEvent* ev) - : seconds_(seconds), - ev_(ev) { - } - - virtual void ThreadMain() OVERRIDE { - PlatformThread::Sleep(TimeDelta::FromSeconds(static_cast(seconds_))); - ev_->Signal(); - } - - private: - const double seconds_; - WaitableEvent *const ev_; -}; - -TEST(WaitableEventTest, WaitMany) { - WaitableEvent* ev[5]; - for (unsigned i = 0; i < 5; ++i) - ev[i] = new WaitableEvent(false, false); - - WaitableEventSignaler signaler(0.1, ev[2]); - PlatformThreadHandle thread; - PlatformThread::Create(0, &signaler, &thread); - - EXPECT_EQ(WaitableEvent::WaitMany(ev, 5), 2u); - - PlatformThread::Join(thread); - - for (unsigned i = 0; i < 5; ++i) - delete ev[i]; -} - -} // namespace base diff --git a/base/synchronization/waitable_event_watcher.h b/base/synchronization/waitable_event_watcher.h deleted file mode 100644 index ede2835490..0000000000 --- a/base/synchronization/waitable_event_watcher.h +++ /dev/null @@ -1,114 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef BASE_SYNCHRONIZATION_WAITABLE_EVENT_WATCHER_H_ -#define BASE_SYNCHRONIZATION_WAITABLE_EVENT_WATCHER_H_ - -#include "base/base_export.h" -#include "build/build_config.h" - -#if defined(OS_WIN) -#include "base/win/object_watcher.h" -#else -#include "base/callback.h" -#include "base/message_loop/message_loop.h" -#include "base/synchronization/waitable_event.h" -#endif - -namespace base { - -class Flag; -class AsyncWaiter; -class AsyncCallbackTask; -class WaitableEvent; - -// This class provides a way to wait on a WaitableEvent asynchronously. -// -// Each instance of this object can be waiting on a single WaitableEvent. When -// the waitable event is signaled, a callback is made in the thread of a given -// MessageLoop. This callback can be deleted by deleting the waiter. -// -// Typical usage: -// -// class MyClass { -// public: -// void DoStuffWhenSignaled(WaitableEvent *waitable_event) { -// watcher_.StartWatching(waitable_event, -// base::Bind(&MyClass::OnWaitableEventSignaled, this); -// } -// private: -// void OnWaitableEventSignaled(WaitableEvent* waitable_event) { -// // OK, time to do stuff! -// } -// base::WaitableEventWatcher watcher_; -// }; -// -// In the above example, MyClass wants to "do stuff" when waitable_event -// becomes signaled. WaitableEventWatcher makes this task easy. When MyClass -// goes out of scope, the watcher_ will be destroyed, and there is no need to -// worry about OnWaitableEventSignaled being called on a deleted MyClass -// pointer. -// -// BEWARE: With automatically reset WaitableEvents, a signal may be lost if it -// occurs just before a WaitableEventWatcher is deleted. There is currently no -// safe way to stop watching an automatic reset WaitableEvent without possibly -// missing a signal. -// -// NOTE: you /are/ allowed to delete the WaitableEvent while still waiting on -// it with a Watcher. It will act as if the event was never signaled. - -class BASE_EXPORT WaitableEventWatcher -#if defined(OS_WIN) - : public win::ObjectWatcher::Delegate { -#else - : public MessageLoop::DestructionObserver { -#endif - public: - typedef Callback EventCallback; - WaitableEventWatcher(); - virtual ~WaitableEventWatcher(); - - // When @event is signaled, the given callback is called on the thread of the - // current message loop when StartWatching is called. - bool StartWatching(WaitableEvent* event, const EventCallback& callback); - - // Cancel the current watch. Must be called from the same thread which - // started the watch. - // - // Does nothing if no event is being watched, nor if the watch has completed. - // The callback will *not* be called for the current watch after this - // function returns. Since the callback runs on the same thread as this - // function, it cannot be called during this function either. - void StopWatching(); - - // Return the currently watched event, or NULL if no object is currently being - // watched. - WaitableEvent* GetWatchedEvent(); - - // Return the callback that will be invoked when the event is - // signaled. - const EventCallback& callback() const { return callback_; } - - private: -#if defined(OS_WIN) - virtual void OnObjectSignaled(HANDLE h) OVERRIDE; - win::ObjectWatcher watcher_; -#else - // Implementation of MessageLoop::DestructionObserver - virtual void WillDestroyCurrentMessageLoop() OVERRIDE; - - MessageLoop* message_loop_; - scoped_refptr cancel_flag_; - AsyncWaiter* waiter_; - base::Closure internal_callback_; - scoped_refptr kernel_; -#endif - - WaitableEvent* event_; - EventCallback callback_; -}; - -} // namespace base - -#endif // BASE_SYNCHRONIZATION_WAITABLE_EVENT_WATCHER_H_ diff --git a/base/synchronization/waitable_event_watcher_posix.cc b/base/synchronization/waitable_event_watcher_posix.cc deleted file mode 100644 index 54e01f8864..0000000000 --- a/base/synchronization/waitable_event_watcher_posix.cc +++ /dev/null @@ -1,271 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "base/synchronization/waitable_event_watcher.h" - -#include "base/bind.h" -#include "base/location.h" -#include "base/message_loop/message_loop.h" -#include "base/synchronization/lock.h" -#include "base/synchronization/waitable_event.h" - -namespace base { - -// ----------------------------------------------------------------------------- -// WaitableEventWatcher (async waits). -// -// The basic design is that we add an AsyncWaiter to the wait-list of the event. -// That AsyncWaiter has a pointer to MessageLoop, and a Task to be posted to it. -// The MessageLoop ends up running the task, which calls the delegate. -// -// Since the wait can be canceled, we have a thread-safe Flag object which is -// set when the wait has been canceled. At each stage in the above, we check the -// flag before going onto the next stage. Since the wait may only be canceled in -// the MessageLoop which runs the Task, we are assured that the delegate cannot -// be called after canceling... - -// ----------------------------------------------------------------------------- -// A thread-safe, reference-counted, write-once flag. -// ----------------------------------------------------------------------------- -class Flag : public RefCountedThreadSafe { - public: - Flag() { flag_ = false; } - - void Set() { - AutoLock locked(lock_); - flag_ = true; - } - - bool value() const { - AutoLock locked(lock_); - return flag_; - } - - private: - friend class RefCountedThreadSafe; - ~Flag() {} - - mutable Lock lock_; - bool flag_; - - DISALLOW_COPY_AND_ASSIGN(Flag); -}; - -// ----------------------------------------------------------------------------- -// This is an asynchronous waiter which posts a task to a MessageLoop when -// fired. An AsyncWaiter may only be in a single wait-list. -// ----------------------------------------------------------------------------- -class AsyncWaiter : public WaitableEvent::Waiter { - public: - AsyncWaiter(MessageLoop* message_loop, - const base::Closure& callback, - Flag* flag) - : message_loop_(message_loop), - callback_(callback), - flag_(flag) { } - - virtual bool Fire(WaitableEvent* event) OVERRIDE { - // Post the callback if we haven't been cancelled. - if (!flag_->value()) { - message_loop_->PostTask(FROM_HERE, callback_); - } - - // We are removed from the wait-list by the WaitableEvent itself. It only - // remains to delete ourselves. - delete this; - - // We can always return true because an AsyncWaiter is never in two - // different wait-lists at the same time. - return true; - } - - // See StopWatching for discussion - virtual bool Compare(void* tag) OVERRIDE { - return tag == flag_.get(); - } - - private: - MessageLoop *const message_loop_; - base::Closure callback_; - scoped_refptr flag_; -}; - -// ----------------------------------------------------------------------------- -// For async waits we need to make a callback in a MessageLoop thread. We do -// this by posting a callback, which calls the delegate and keeps track of when -// the event is canceled. -// ----------------------------------------------------------------------------- -void AsyncCallbackHelper(Flag* flag, - const WaitableEventWatcher::EventCallback& callback, - WaitableEvent* event) { - // Runs in MessageLoop thread. - if (!flag->value()) { - // This is to let the WaitableEventWatcher know that the event has occured - // because it needs to be able to return NULL from GetWatchedObject - flag->Set(); - callback.Run(event); - } -} - -WaitableEventWatcher::WaitableEventWatcher() - : message_loop_(NULL), - cancel_flag_(NULL), - waiter_(NULL), - event_(NULL) { -} - -WaitableEventWatcher::~WaitableEventWatcher() { - StopWatching(); -} - -// ----------------------------------------------------------------------------- -// The Handle is how the user cancels a wait. After deleting the Handle we -// insure that the delegate cannot be called. -// ----------------------------------------------------------------------------- -bool WaitableEventWatcher::StartWatching( - WaitableEvent* event, - const EventCallback& callback) { - MessageLoop *const current_ml = MessageLoop::current(); - DCHECK(current_ml) << "Cannot create WaitableEventWatcher without a " - "current MessageLoop"; - - // A user may call StartWatching from within the callback function. In this - // case, we won't know that we have finished watching, expect that the Flag - // will have been set in AsyncCallbackHelper(). - if (cancel_flag_.get() && cancel_flag_->value()) { - if (message_loop_) { - message_loop_->RemoveDestructionObserver(this); - message_loop_ = NULL; - } - - cancel_flag_ = NULL; - } - - DCHECK(!cancel_flag_.get()) << "StartWatching called while still watching"; - - cancel_flag_ = new Flag; - callback_ = callback; - internal_callback_ = - base::Bind(&AsyncCallbackHelper, cancel_flag_, callback_, event); - WaitableEvent::WaitableEventKernel* kernel = event->kernel_.get(); - - AutoLock locked(kernel->lock_); - - event_ = event; - - if (kernel->signaled_) { - if (!kernel->manual_reset_) - kernel->signaled_ = false; - - // No hairpinning - we can't call the delegate directly here. We have to - // enqueue a task on the MessageLoop as normal. - current_ml->PostTask(FROM_HERE, internal_callback_); - return true; - } - - message_loop_ = current_ml; - current_ml->AddDestructionObserver(this); - - kernel_ = kernel; - waiter_ = new AsyncWaiter(current_ml, internal_callback_, cancel_flag_.get()); - event->Enqueue(waiter_); - - return true; -} - -void WaitableEventWatcher::StopWatching() { - callback_.Reset(); - - if (message_loop_) { - message_loop_->RemoveDestructionObserver(this); - message_loop_ = NULL; - } - - if (!cancel_flag_.get()) // if not currently watching... - return; - - if (cancel_flag_->value()) { - // In this case, the event has fired, but we haven't figured that out yet. - // The WaitableEvent may have been deleted too. - cancel_flag_ = NULL; - return; - } - - if (!kernel_.get()) { - // We have no kernel. This means that we never enqueued a Waiter on an - // event because the event was already signaled when StartWatching was - // called. - // - // In this case, a task was enqueued on the MessageLoop and will run. - // We set the flag in case the task hasn't yet run. The flag will stop the - // delegate getting called. If the task has run then we have the last - // reference to the flag and it will be deleted immedately after. - cancel_flag_->Set(); - cancel_flag_ = NULL; - return; - } - - AutoLock locked(kernel_->lock_); - // We have a lock on the kernel. No one else can signal the event while we - // have it. - - // We have a possible ABA issue here. If Dequeue was to compare only the - // pointer values then it's possible that the AsyncWaiter could have been - // fired, freed and the memory reused for a different Waiter which was - // enqueued in the same wait-list. We would think that that waiter was our - // AsyncWaiter and remove it. - // - // To stop this, Dequeue also takes a tag argument which is passed to the - // virtual Compare function before the two are considered a match. So we need - // a tag which is good for the lifetime of this handle: the Flag. Since we - // have a reference to the Flag, its memory cannot be reused while this object - // still exists. So if we find a waiter with the correct pointer value, and - // which shares a Flag pointer, we have a real match. - if (kernel_->Dequeue(waiter_, cancel_flag_.get())) { - // Case 2: the waiter hasn't been signaled yet; it was still on the wait - // list. We've removed it, thus we can delete it and the task (which cannot - // have been enqueued with the MessageLoop because the waiter was never - // signaled) - delete waiter_; - internal_callback_.Reset(); - cancel_flag_ = NULL; - return; - } - - // Case 3: the waiter isn't on the wait-list, thus it was signaled. It may - // not have run yet, so we set the flag to tell it not to bother enqueuing the - // task on the MessageLoop, but to delete it instead. The Waiter deletes - // itself once run. - cancel_flag_->Set(); - cancel_flag_ = NULL; - - // If the waiter has already run then the task has been enqueued. If the Task - // hasn't yet run, the flag will stop the delegate from getting called. (This - // is thread safe because one may only delete a Handle from the MessageLoop - // thread.) - // - // If the delegate has already been called then we have nothing to do. The - // task has been deleted by the MessageLoop. -} - -WaitableEvent* WaitableEventWatcher::GetWatchedEvent() { - if (!cancel_flag_.get()) - return NULL; - - if (cancel_flag_->value()) - return NULL; - - return event_; -} - -// ----------------------------------------------------------------------------- -// This is called when the MessageLoop which the callback will be run it is -// deleted. We need to cancel the callback as if we had been deleted, but we -// will still be deleted at some point in the future. -// ----------------------------------------------------------------------------- -void WaitableEventWatcher::WillDestroyCurrentMessageLoop() { - StopWatching(); -} - -} // namespace base diff --git a/base/synchronization/waitable_event_watcher_unittest.cc b/base/synchronization/waitable_event_watcher_unittest.cc deleted file mode 100644 index 5319d1efba..0000000000 --- a/base/synchronization/waitable_event_watcher_unittest.cc +++ /dev/null @@ -1,176 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "base/synchronization/waitable_event_watcher.h" - -#include "base/bind.h" -#include "base/callback.h" -#include "base/message_loop/message_loop.h" -#include "base/run_loop.h" -#include "base/synchronization/waitable_event.h" -#include "base/threading/platform_thread.h" -#include "testing/gtest/include/gtest/gtest.h" - -namespace base { - -namespace { - -// The message loops on which each waitable event timer should be tested. -const MessageLoop::Type testing_message_loops[] = { - MessageLoop::TYPE_DEFAULT, - MessageLoop::TYPE_IO, -#if !defined(OS_IOS) // iOS does not allow direct running of the UI loop. - MessageLoop::TYPE_UI, -#endif -}; - -const int kNumTestingMessageLoops = arraysize(testing_message_loops); - -void QuitWhenSignaled(WaitableEvent* event) { - MessageLoop::current()->QuitWhenIdle(); -} - -class DecrementCountContainer { - public: - explicit DecrementCountContainer(int* counter) : counter_(counter) { - } - void OnWaitableEventSignaled(WaitableEvent* object) { - --(*counter_); - } - private: - int* counter_; -}; - -void RunTest_BasicSignal(MessageLoop::Type message_loop_type) { - MessageLoop message_loop(message_loop_type); - - // A manual-reset event that is not yet signaled. - WaitableEvent event(true, false); - - WaitableEventWatcher watcher; - EXPECT_TRUE(watcher.GetWatchedEvent() == NULL); - - watcher.StartWatching(&event, Bind(&QuitWhenSignaled)); - EXPECT_EQ(&event, watcher.GetWatchedEvent()); - - event.Signal(); - - MessageLoop::current()->Run(); - - EXPECT_TRUE(watcher.GetWatchedEvent() == NULL); -} - -void RunTest_BasicCancel(MessageLoop::Type message_loop_type) { - MessageLoop message_loop(message_loop_type); - - // A manual-reset event that is not yet signaled. - WaitableEvent event(true, false); - - WaitableEventWatcher watcher; - - watcher.StartWatching(&event, Bind(&QuitWhenSignaled)); - - watcher.StopWatching(); -} - -void RunTest_CancelAfterSet(MessageLoop::Type message_loop_type) { - MessageLoop message_loop(message_loop_type); - - // A manual-reset event that is not yet signaled. - WaitableEvent event(true, false); - - WaitableEventWatcher watcher; - - int counter = 1; - DecrementCountContainer delegate(&counter); - WaitableEventWatcher::EventCallback callback = - Bind(&DecrementCountContainer::OnWaitableEventSignaled, - Unretained(&delegate)); - watcher.StartWatching(&event, callback); - - event.Signal(); - - // Let the background thread do its business - base::PlatformThread::Sleep(base::TimeDelta::FromMilliseconds(30)); - - watcher.StopWatching(); - - RunLoop().RunUntilIdle(); - - // Our delegate should not have fired. - EXPECT_EQ(1, counter); -} - -void RunTest_OutlivesMessageLoop(MessageLoop::Type message_loop_type) { - // Simulate a MessageLoop that dies before an WaitableEventWatcher. This - // ordinarily doesn't happen when people use the Thread class, but it can - // happen when people use the Singleton pattern or atexit. - WaitableEvent event(true, false); - { - WaitableEventWatcher watcher; - { - MessageLoop message_loop(message_loop_type); - - watcher.StartWatching(&event, Bind(&QuitWhenSignaled)); - } - } -} - -void RunTest_DeleteUnder(MessageLoop::Type message_loop_type) { - // Delete the WaitableEvent out from under the Watcher. This is explictly - // allowed by the interface. - - MessageLoop message_loop(message_loop_type); - - { - WaitableEventWatcher watcher; - - WaitableEvent* event = new WaitableEvent(false, false); - - watcher.StartWatching(event, Bind(&QuitWhenSignaled)); - delete event; - } -} - -} // namespace - -//----------------------------------------------------------------------------- - -TEST(WaitableEventWatcherTest, BasicSignal) { - for (int i = 0; i < kNumTestingMessageLoops; i++) { - RunTest_BasicSignal(testing_message_loops[i]); - } -} - -TEST(WaitableEventWatcherTest, BasicCancel) { - for (int i = 0; i < kNumTestingMessageLoops; i++) { - RunTest_BasicCancel(testing_message_loops[i]); - } -} - -TEST(WaitableEventWatcherTest, CancelAfterSet) { - for (int i = 0; i < kNumTestingMessageLoops; i++) { - RunTest_CancelAfterSet(testing_message_loops[i]); - } -} - -TEST(WaitableEventWatcherTest, OutlivesMessageLoop) { - for (int i = 0; i < kNumTestingMessageLoops; i++) { - RunTest_OutlivesMessageLoop(testing_message_loops[i]); - } -} - -#if defined(OS_WIN) -// Crashes sometimes on vista. http://crbug.com/62119 -#define MAYBE_DeleteUnder DISABLED_DeleteUnder -#else -#define MAYBE_DeleteUnder DeleteUnder -#endif -TEST(WaitableEventWatcherTest, MAYBE_DeleteUnder) { - for (int i = 0; i < kNumTestingMessageLoops; i++) { - RunTest_DeleteUnder(testing_message_loops[i]); - } -} - -} // namespace base diff --git a/base/synchronization/waitable_event_watcher_win.cc b/base/synchronization/waitable_event_watcher_win.cc deleted file mode 100644 index 46d47ac581..0000000000 --- a/base/synchronization/waitable_event_watcher_win.cc +++ /dev/null @@ -1,48 +0,0 @@ -// Copyright (c) 2011 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "base/synchronization/waitable_event_watcher.h" - -#include "base/compiler_specific.h" -#include "base/synchronization/waitable_event.h" -#include "base/win/object_watcher.h" - -namespace base { - -WaitableEventWatcher::WaitableEventWatcher() - : event_(NULL) { -} - -WaitableEventWatcher::~WaitableEventWatcher() { -} - -bool WaitableEventWatcher::StartWatching( - WaitableEvent* event, - const EventCallback& callback) { - callback_ = callback; - event_ = event; - return watcher_.StartWatching(event->handle(), this); -} - -void WaitableEventWatcher::StopWatching() { - callback_.Reset(); - event_ = NULL; - watcher_.StopWatching(); -} - -WaitableEvent* WaitableEventWatcher::GetWatchedEvent() { - return event_; -} - -void WaitableEventWatcher::OnObjectSignaled(HANDLE h) { - WaitableEvent* event = event_; - EventCallback callback = callback_; - event_ = NULL; - callback_.Reset(); - DCHECK(event); - - callback.Run(event); -} - -} // namespace base diff --git a/base/synchronization/waitable_event_win.cc b/base/synchronization/waitable_event_win.cc deleted file mode 100644 index 8259cb74cf..0000000000 --- a/base/synchronization/waitable_event_win.cc +++ /dev/null @@ -1,102 +0,0 @@ -// Copyright (c) 2011 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "base/synchronization/waitable_event.h" - -#include -#include - -#include "base/logging.h" -#include "base/threading/thread_restrictions.h" -#include "base/time/time.h" - -namespace base { - -WaitableEvent::WaitableEvent(bool manual_reset, bool signaled) - : handle_(CreateEvent(NULL, manual_reset, signaled, NULL)) { - // We're probably going to crash anyways if this is ever NULL, so we might as - // well make our stack reports more informative by crashing here. - CHECK(handle_); -} - -WaitableEvent::WaitableEvent(HANDLE handle) - : handle_(handle) { - CHECK(handle) << "Tried to create WaitableEvent from NULL handle"; -} - -WaitableEvent::~WaitableEvent() { - CloseHandle(handle_); -} - -HANDLE WaitableEvent::Release() { - HANDLE rv = handle_; - handle_ = INVALID_HANDLE_VALUE; - return rv; -} - -void WaitableEvent::Reset() { - ResetEvent(handle_); -} - -void WaitableEvent::Signal() { - SetEvent(handle_); -} - -bool WaitableEvent::IsSignaled() { - return TimedWait(TimeDelta::FromMilliseconds(0)); -} - -void WaitableEvent::Wait() { - base::ThreadRestrictions::AssertWaitAllowed(); - DWORD result = WaitForSingleObject(handle_, INFINITE); - // It is most unexpected that this should ever fail. Help consumers learn - // about it if it should ever fail. - DCHECK_EQ(WAIT_OBJECT_0, result) << "WaitForSingleObject failed"; -} - -bool WaitableEvent::TimedWait(const TimeDelta& max_time) { - base::ThreadRestrictions::AssertWaitAllowed(); - DCHECK(max_time >= TimeDelta::FromMicroseconds(0)); - // Be careful here. TimeDelta has a precision of microseconds, but this API - // is in milliseconds. If there are 5.5ms left, should the delay be 5 or 6? - // It should be 6 to avoid returning too early. - double timeout = ceil(max_time.InMillisecondsF()); - DWORD result = WaitForSingleObject(handle_, static_cast(timeout)); - switch (result) { - case WAIT_OBJECT_0: - return true; - case WAIT_TIMEOUT: - return false; - } - // It is most unexpected that this should ever fail. Help consumers learn - // about it if it should ever fail. - NOTREACHED() << "WaitForSingleObject failed"; - return false; -} - -// static -size_t WaitableEvent::WaitMany(WaitableEvent** events, size_t count) { - base::ThreadRestrictions::AssertWaitAllowed(); - HANDLE handles[MAXIMUM_WAIT_OBJECTS]; - CHECK_LE(count, MAXIMUM_WAIT_OBJECTS) - << "Can only wait on " << MAXIMUM_WAIT_OBJECTS << " with WaitMany"; - - for (size_t i = 0; i < count; ++i) - handles[i] = events[i]->handle(); - - // The cast is safe because count is small - see the CHECK above. - DWORD result = - WaitForMultipleObjects(static_cast(count), - handles, - FALSE, // don't wait for all the objects - INFINITE); // no timeout - if (result >= WAIT_OBJECT_0 + count) { - DLOG_GETLASTERROR(FATAL) << "WaitForMultipleObjects failed"; - return 0; - } - - return result - WAIT_OBJECT_0; -} - -} // namespace base diff --git a/base/sys_byteorder.h b/base/sys_byteorder.h deleted file mode 100644 index 97e33acfda..0000000000 --- a/base/sys_byteorder.h +++ /dev/null @@ -1,147 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -// This header defines cross-platform ByteSwap() implementations for 16, 32 and -// 64-bit values, and NetToHostXX() / HostToNextXX() functions equivalent to -// the traditional ntohX() and htonX() functions. -// Use the functions defined here rather than using the platform-specific -// functions directly. - -#ifndef BASE_SYS_BYTEORDER_H_ -#define BASE_SYS_BYTEORDER_H_ - -#include "base/basictypes.h" -#include "build/build_config.h" - -#if defined(OS_WIN) -#include -#else -#include -#endif - -// Include headers to provide byteswap for all platforms. -#if defined(COMPILER_MSVC) -#include -#elif defined(OS_MACOSX) -#include -#elif defined(OS_OPENBSD) -#include -#else -#include -#endif - - -namespace base { - -// Returns a value with all bytes in |x| swapped, i.e. reverses the endianness. -inline uint16 ByteSwap(uint16 x) { -#if defined(COMPILER_MSVC) - return _byteswap_ushort(x); -#elif defined(OS_MACOSX) - return OSSwapInt16(x); -#elif defined(OS_OPENBSD) - return swap16(x); -#else - return bswap_16(x); -#endif -} -inline uint32 ByteSwap(uint32 x) { -#if defined(COMPILER_MSVC) - return _byteswap_ulong(x); -#elif defined(OS_MACOSX) - return OSSwapInt32(x); -#elif defined(OS_OPENBSD) - return swap32(x); -#else - return bswap_32(x); -#endif -} -inline uint64 ByteSwap(uint64 x) { -#if defined(COMPILER_MSVC) - return _byteswap_uint64(x); -#elif defined(OS_MACOSX) - return OSSwapInt64(x); -#elif defined(OS_OPENBSD) - return swap64(x); -#else - return bswap_64(x); -#endif -} - -// Converts the bytes in |x| from host order (endianness) to little endian, and -// returns the result. -inline uint16 ByteSwapToLE16(uint16 x) { -#if defined(ARCH_CPU_LITTLE_ENDIAN) - return x; -#else - return ByteSwap(x); -#endif -} -inline uint32 ByteSwapToLE32(uint32 x) { -#if defined(ARCH_CPU_LITTLE_ENDIAN) - return x; -#else - return ByteSwap(x); -#endif -} -inline uint64 ByteSwapToLE64(uint64 x) { -#if defined(ARCH_CPU_LITTLE_ENDIAN) - return x; -#else - return ByteSwap(x); -#endif -} - -// Converts the bytes in |x| from network to host order (endianness), and -// returns the result. -inline uint16 NetToHost16(uint16 x) { -#if defined(ARCH_CPU_LITTLE_ENDIAN) - return ByteSwap(x); -#else - return x; -#endif -} -inline uint32 NetToHost32(uint32 x) { -#if defined(ARCH_CPU_LITTLE_ENDIAN) - return ByteSwap(x); -#else - return x; -#endif -} -inline uint64 NetToHost64(uint64 x) { -#if defined(ARCH_CPU_LITTLE_ENDIAN) - return ByteSwap(x); -#else - return x; -#endif -} - -// Converts the bytes in |x| from host to network order (endianness), and -// returns the result. -inline uint16 HostToNet16(uint16 x) { -#if defined(ARCH_CPU_LITTLE_ENDIAN) - return ByteSwap(x); -#else - return x; -#endif -} -inline uint32 HostToNet32(uint32 x) { -#if defined(ARCH_CPU_LITTLE_ENDIAN) - return ByteSwap(x); -#else - return x; -#endif -} -inline uint64 HostToNet64(uint64 x) { -#if defined(ARCH_CPU_LITTLE_ENDIAN) - return ByteSwap(x); -#else - return x; -#endif -} - -} // namespace base - - -#endif // BASE_SYS_BYTEORDER_H_ diff --git a/base/sys_info.cc b/base/sys_info.cc deleted file mode 100644 index d43e9320bc..0000000000 --- a/base/sys_info.cc +++ /dev/null @@ -1,20 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "base/sys_info.h" - -#include "base/time/time.h" - -namespace base { - -// static -int64 SysInfo::Uptime() { - // This code relies on an implementation detail of TimeTicks::Now() - that - // its return value happens to coincide with the system uptime value in - // microseconds, on Win/Mac/iOS/Linux/ChromeOS and Android. - int64 uptime_in_microseconds = TimeTicks::Now().ToInternalValue(); - return uptime_in_microseconds / 1000; -} - -} // namespace base diff --git a/base/sys_info.h b/base/sys_info.h deleted file mode 100644 index 38462ed111..0000000000 --- a/base/sys_info.h +++ /dev/null @@ -1,113 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef BASE_SYS_INFO_H_ -#define BASE_SYS_INFO_H_ - -#include - -#include "base/base_export.h" -#include "base/basictypes.h" -#include "base/files/file_path.h" -#include "build/build_config.h" - -namespace base { - -class BASE_EXPORT SysInfo { - public: - // Return the number of logical processors/cores on the current machine. - static int NumberOfProcessors(); - - // Return the number of bytes of physical memory on the current machine. - static int64 AmountOfPhysicalMemory(); - - // Return the number of bytes of current available physical memory on the - // machine. - static int64 AmountOfAvailablePhysicalMemory(); - - // Return the number of megabytes of physical memory on the current machine. - static int AmountOfPhysicalMemoryMB() { - return static_cast(AmountOfPhysicalMemory() / 1024 / 1024); - } - - // Return the available disk space in bytes on the volume containing |path|, - // or -1 on failure. - static int64 AmountOfFreeDiskSpace(const FilePath& path); - - // Returns system uptime in milliseconds. - static int64 Uptime(); - - // Returns the name of the host operating system. - static std::string OperatingSystemName(); - - // Returns the version of the host operating system. - static std::string OperatingSystemVersion(); - - // Retrieves detailed numeric values for the OS version. - // TODO(port): Implement a Linux version of this method and enable the - // corresponding unit test. - // DON'T USE THIS ON THE MAC OR WINDOWS to determine the current OS release - // for OS version-specific feature checks and workarounds. If you must use - // an OS version check instead of a feature check, use the base::mac::IsOS* - // family from base/mac/mac_util.h, or base::win::GetVersion from - // base/win/windows_version.h. - static void OperatingSystemVersionNumbers(int32* major_version, - int32* minor_version, - int32* bugfix_version); - - // Returns the architecture of the running operating system. - // Exact return value may differ across platforms. - // e.g. a 32-bit x86 kernel on a 64-bit capable CPU will return "x86", - // whereas a x86-64 kernel on the same CPU will return "x86_64" - static std::string OperatingSystemArchitecture(); - - // Avoid using this. Use base/cpu.h to get information about the CPU instead. - // http://crbug.com/148884 - // Returns the CPU model name of the system. If it can not be figured out, - // an empty string is returned. - static std::string CPUModelName(); - - // Return the smallest amount of memory (in bytes) which the VM system will - // allocate. - static size_t VMAllocationGranularity(); - -#if defined(OS_POSIX) && !defined(OS_MACOSX) - // Returns the maximum SysV shared memory segment size. - static size_t MaxSharedMemorySize(); -#endif // defined(OS_POSIX) && !defined(OS_MACOSX) - -#if defined(OS_CHROMEOS) - // Returns the name of the version entry we wish to look up in the - // Linux Standard Base release information file. - static std::string GetLinuxStandardBaseVersionKey(); - - // Parses /etc/lsb-release to get version information for Google Chrome OS. - // Declared here so it can be exposed for unit testing. - static void ParseLsbRelease(const std::string& lsb_release, - int32* major_version, - int32* minor_version, - int32* bugfix_version); - - // Returns the path to the lsb-release file. - static FilePath GetLsbReleaseFilePath(); -#endif // defined(OS_CHROMEOS) - -#if defined(OS_ANDROID) - // Returns the Android build's codename. - static std::string GetAndroidBuildCodename(); - - // Returns the Android build ID. - static std::string GetAndroidBuildID(); - - // Returns the device's name. - static std::string GetDeviceName(); - - static int DalvikHeapSizeMB(); - static int DalvikHeapGrowthLimitMB(); -#endif // defined(OS_ANDROID) -}; - -} // namespace base - -#endif // BASE_SYS_INFO_H_ diff --git a/base/sys_info_android.cc b/base/sys_info_android.cc deleted file mode 100644 index 577ca0e6bd..0000000000 --- a/base/sys_info_android.cc +++ /dev/null @@ -1,167 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "base/sys_info.h" - -#include - -#include "base/logging.h" -#include "base/strings/string_number_conversions.h" -#include "base/strings/string_piece.h" -#include "base/strings/stringprintf.h" - -namespace { - -// Default version of Android to fall back to when actual version numbers -// cannot be acquired. -// TODO(dfalcantara): Keep this reasonably up to date with the latest publicly -// available version of Android. -const int kDefaultAndroidMajorVersion = 4; -const int kDefaultAndroidMinorVersion = 3; -const int kDefaultAndroidBugfixVersion = 0; - -// Parse out the OS version numbers from the system properties. -void ParseOSVersionNumbers(const char* os_version_str, - int32 *major_version, - int32 *minor_version, - int32 *bugfix_version) { - if (os_version_str[0]) { - // Try to parse out the version numbers from the string. - int num_read = sscanf(os_version_str, "%d.%d.%d", major_version, - minor_version, bugfix_version); - - if (num_read > 0) { - // If we don't have a full set of version numbers, make the extras 0. - if (num_read < 2) *minor_version = 0; - if (num_read < 3) *bugfix_version = 0; - return; - } - } - - // For some reason, we couldn't parse the version number string. - *major_version = kDefaultAndroidMajorVersion; - *minor_version = kDefaultAndroidMinorVersion; - *bugfix_version = kDefaultAndroidBugfixVersion; -} - -// Parses a system property (specified with unit 'k','m' or 'g'). -// Returns a value in bytes. -// Returns -1 if the string could not be parsed. -int64 ParseSystemPropertyBytes(const base::StringPiece& str) { - const int64 KB = 1024; - const int64 MB = 1024 * KB; - const int64 GB = 1024 * MB; - if (str.size() == 0u) - return -1; - int64 unit_multiplier = 1; - size_t length = str.size(); - if (str[length - 1] == 'k') { - unit_multiplier = KB; - length--; - } else if (str[length - 1] == 'm') { - unit_multiplier = MB; - length--; - } else if (str[length - 1] == 'g') { - unit_multiplier = GB; - length--; - } - int64 result = 0; - bool parsed = base::StringToInt64(str.substr(0, length), &result); - bool negative = result <= 0; - bool overflow = result >= std::numeric_limits::max() / unit_multiplier; - if (!parsed || negative || overflow) - return -1; - return result * unit_multiplier; -} - -int GetDalvikHeapSizeMB() { - char heap_size_str[PROP_VALUE_MAX]; - __system_property_get("dalvik.vm.heapsize", heap_size_str); - // dalvik.vm.heapsize property is writable by a root user. - // Clamp it to reasonable range as a sanity check, - // a typical android device will never have less than 48MB. - const int64 MB = 1024 * 1024; - int64 result = ParseSystemPropertyBytes(heap_size_str); - if (result == -1) { - // We should consider not exposing these values if they are not reliable. - LOG(ERROR) << "Can't parse dalvik.vm.heapsize: " << heap_size_str; - result = base::SysInfo::AmountOfPhysicalMemoryMB() / 3; - } - result = std::min(std::max(32 * MB, result), 1024 * MB) / MB; - return static_cast(result); -} - -int GetDalvikHeapGrowthLimitMB() { - char heap_size_str[PROP_VALUE_MAX]; - __system_property_get("dalvik.vm.heapgrowthlimit", heap_size_str); - // dalvik.vm.heapgrowthlimit property is writable by a root user. - // Clamp it to reasonable range as a sanity check, - // a typical android device will never have less than 24MB. - const int64 MB = 1024 * 1024; - int64 result = ParseSystemPropertyBytes(heap_size_str); - if (result == -1) { - // We should consider not exposing these values if they are not reliable. - LOG(ERROR) << "Can't parse dalvik.vm.heapgrowthlimit: " << heap_size_str; - result = base::SysInfo::AmountOfPhysicalMemoryMB() / 6; - } - result = std::min(std::max(16 * MB, result), 512 * MB) / MB; - return static_cast(result); -} - -} // anonymous namespace - -namespace base { - -std::string SysInfo::OperatingSystemName() { - return "Android"; -} - -std::string SysInfo::GetAndroidBuildCodename() { - char os_version_codename_str[PROP_VALUE_MAX]; - __system_property_get("ro.build.version.codename", os_version_codename_str); - return std::string(os_version_codename_str); -} - -std::string SysInfo::GetAndroidBuildID() { - char os_build_id_str[PROP_VALUE_MAX]; - __system_property_get("ro.build.id", os_build_id_str); - return std::string(os_build_id_str); -} - -std::string SysInfo::GetDeviceName() { - char device_model_str[PROP_VALUE_MAX]; - __system_property_get("ro.product.model", device_model_str); - return std::string(device_model_str); -} - -std::string SysInfo::OperatingSystemVersion() { - int32 major, minor, bugfix; - OperatingSystemVersionNumbers(&major, &minor, &bugfix); - return StringPrintf("%d.%d.%d", major, minor, bugfix); -} - -void SysInfo::OperatingSystemVersionNumbers(int32* major_version, - int32* minor_version, - int32* bugfix_version) { - // Read the version number string out from the properties. - char os_version_str[PROP_VALUE_MAX]; - __system_property_get("ro.build.version.release", os_version_str); - - // Parse out the numbers. - ParseOSVersionNumbers(os_version_str, major_version, minor_version, - bugfix_version); -} - -int SysInfo::DalvikHeapSizeMB() { - static int heap_size = GetDalvikHeapSizeMB(); - return heap_size; -} - -int SysInfo::DalvikHeapGrowthLimitMB() { - static int heap_growth_limit = GetDalvikHeapGrowthLimitMB(); - return heap_growth_limit; -} - - -} // namespace base diff --git a/base/sys_info_chromeos.cc b/base/sys_info_chromeos.cc deleted file mode 100644 index 1335760d03..0000000000 --- a/base/sys_info_chromeos.cc +++ /dev/null @@ -1,119 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "base/sys_info.h" - -#include "base/basictypes.h" -#include "base/file_util.h" -#include "base/files/file_path.h" -#include "base/lazy_instance.h" -#include "base/strings/string_number_conversions.h" -#include "base/strings/string_piece.h" -#include "base/strings/string_tokenizer.h" -#include "base/threading/thread_restrictions.h" - -namespace base { - -static const char* kLinuxStandardBaseVersionKeys[] = { - "CHROMEOS_RELEASE_VERSION", - "GOOGLE_RELEASE", - "DISTRIB_RELEASE", - NULL -}; - -const char kLinuxStandardBaseReleaseFile[] = "/etc/lsb-release"; - -struct ChromeOSVersionNumbers { - ChromeOSVersionNumbers() - : major_version(0), - minor_version(0), - bugfix_version(0), - parsed(false) { - } - - int32 major_version; - int32 minor_version; - int32 bugfix_version; - bool parsed; -}; - -static LazyInstance - g_chrome_os_version_numbers = LAZY_INSTANCE_INITIALIZER; - -// static -void SysInfo::OperatingSystemVersionNumbers(int32* major_version, - int32* minor_version, - int32* bugfix_version) { - if (!g_chrome_os_version_numbers.Get().parsed) { - // The other implementations of SysInfo don't block on the disk. - // See http://code.google.com/p/chromium/issues/detail?id=60394 - // Perhaps the caller ought to cache this? - // Temporary allowing while we work the bug out. - ThreadRestrictions::ScopedAllowIO allow_io; - - FilePath path(kLinuxStandardBaseReleaseFile); - std::string contents; - if (file_util::ReadFileToString(path, &contents)) { - g_chrome_os_version_numbers.Get().parsed = true; - ParseLsbRelease(contents, - &(g_chrome_os_version_numbers.Get().major_version), - &(g_chrome_os_version_numbers.Get().minor_version), - &(g_chrome_os_version_numbers.Get().bugfix_version)); - } - } - *major_version = g_chrome_os_version_numbers.Get().major_version; - *minor_version = g_chrome_os_version_numbers.Get().minor_version; - *bugfix_version = g_chrome_os_version_numbers.Get().bugfix_version; -} - -// static -std::string SysInfo::GetLinuxStandardBaseVersionKey() { - return std::string(kLinuxStandardBaseVersionKeys[0]); -} - -// static -void SysInfo::ParseLsbRelease(const std::string& lsb_release, - int32* major_version, - int32* minor_version, - int32* bugfix_version) { - size_t version_key_index = std::string::npos; - for (int i = 0; kLinuxStandardBaseVersionKeys[i] != NULL; ++i) { - version_key_index = lsb_release.find(kLinuxStandardBaseVersionKeys[i]); - if (std::string::npos != version_key_index) { - break; - } - } - if (std::string::npos == version_key_index) { - return; - } - - size_t start_index = lsb_release.find_first_of('=', version_key_index); - start_index++; // Move past '='. - size_t length = lsb_release.find_first_of('\n', start_index) - start_index; - std::string version = lsb_release.substr(start_index, length); - StringTokenizer tokenizer(version, "."); - for (int i = 0; i < 3 && tokenizer.GetNext(); ++i) { - if (0 == i) { - StringToInt(StringPiece(tokenizer.token_begin(), - tokenizer.token_end()), - major_version); - *minor_version = *bugfix_version = 0; - } else if (1 == i) { - StringToInt(StringPiece(tokenizer.token_begin(), - tokenizer.token_end()), - minor_version); - } else { // 2 == i - StringToInt(StringPiece(tokenizer.token_begin(), - tokenizer.token_end()), - bugfix_version); - } - } -} - -// static -FilePath SysInfo::GetLsbReleaseFilePath() { - return FilePath(kLinuxStandardBaseReleaseFile); -} - -} // namespace base diff --git a/base/sys_info_freebsd.cc b/base/sys_info_freebsd.cc deleted file mode 100644 index 832b35985b..0000000000 --- a/base/sys_info_freebsd.cc +++ /dev/null @@ -1,36 +0,0 @@ -// Copyright (c) 2011 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "base/sys_info.h" - -#include - -#include "base/logging.h" - -namespace base { - -int64 SysInfo::AmountOfPhysicalMemory() { - int pages, page_size; - size_t size = sizeof(pages); - sysctlbyname("vm.stats.vm.v_page_count", &pages, &size, NULL, 0); - sysctlbyname("vm.stats.vm.v_page_size", &page_size, &size, NULL, 0); - if (pages == -1 || page_size == -1) { - NOTREACHED(); - return 0; - } - return static_cast(pages) * page_size; -} - -// static -size_t SysInfo::MaxSharedMemorySize() { - size_t limit; - size_t size = sizeof(limit); - if (sysctlbyname("kern.ipc.shmmax", &limit, &size, NULL, 0) < 0) { - NOTREACHED(); - return 0; - } - return limit; -} - -} // namespace base diff --git a/base/sys_info_ios.mm b/base/sys_info_ios.mm deleted file mode 100644 index de68fcf37c..0000000000 --- a/base/sys_info_ios.mm +++ /dev/null @@ -1,90 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "base/sys_info.h" - -#import -#include -#include -#include - -#include "base/logging.h" -#include "base/mac/scoped_mach_port.h" -#include "base/mac/scoped_nsautorelease_pool.h" -#include "base/strings/sys_string_conversions.h" - -namespace base { - -// static -std::string SysInfo::OperatingSystemName() { - static dispatch_once_t get_system_name_once; - static std::string* system_name; - dispatch_once(&get_system_name_once, ^{ - base::mac::ScopedNSAutoreleasePool pool; - system_name = new std::string( - SysNSStringToUTF8([[UIDevice currentDevice] systemName])); - }); - // Examples of returned value: 'iPhone OS' on iPad 5.1.1 - // and iPhone 5.1.1. - return *system_name; -} - -// static -std::string SysInfo::OperatingSystemVersion() { - static dispatch_once_t get_system_version_once; - static std::string* system_version; - dispatch_once(&get_system_version_once, ^{ - base::mac::ScopedNSAutoreleasePool pool; - system_version = new std::string( - SysNSStringToUTF8([[UIDevice currentDevice] systemVersion])); - }); - return *system_version; -} - -// static -void SysInfo::OperatingSystemVersionNumbers(int32* major_version, - int32* minor_version, - int32* bugfix_version) { - base::mac::ScopedNSAutoreleasePool pool; - std::string system_version = OperatingSystemVersion(); - if (!system_version.empty()) { - // Try to parse out the version numbers from the string. - int num_read = sscanf(system_version.c_str(), "%d.%d.%d", major_version, - minor_version, bugfix_version); - if (num_read < 1) - *major_version = 0; - if (num_read < 2) - *minor_version = 0; - if (num_read < 3) - *bugfix_version = 0; - } -} - -// static -int64 SysInfo::AmountOfPhysicalMemory() { - struct host_basic_info hostinfo; - mach_msg_type_number_t count = HOST_BASIC_INFO_COUNT; - base::mac::ScopedMachPort host(mach_host_self()); - int result = host_info(host, - HOST_BASIC_INFO, - reinterpret_cast(&hostinfo), - &count); - if (result != KERN_SUCCESS) { - NOTREACHED(); - return 0; - } - DCHECK_EQ(HOST_BASIC_INFO_COUNT, count); - return static_cast(hostinfo.max_mem); -} - -// static -std::string SysInfo::CPUModelName() { - char name[256]; - size_t len = arraysize(name); - if (sysctlbyname("machdep.cpu.brand_string", &name, &len, NULL, 0) == 0) - return name; - return std::string(); -} - -} // namespace base diff --git a/base/sys_info_linux.cc b/base/sys_info_linux.cc deleted file mode 100644 index 58a0aefee6..0000000000 --- a/base/sys_info_linux.cc +++ /dev/null @@ -1,85 +0,0 @@ -// Copyright (c) 2011 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "base/sys_info.h" - -#include - -#include "base/file_util.h" -#include "base/logging.h" -#include "base/strings/string_number_conversions.h" - -namespace { - -int64 AmountOfMemory(int pages_name) { - long pages = sysconf(pages_name); - long page_size = sysconf(_SC_PAGESIZE); - if (pages == -1 || page_size == -1) { - NOTREACHED(); - return 0; - } - return static_cast(pages) * page_size; -} - -} // namespace - -namespace base { - -// static -int64 SysInfo::AmountOfPhysicalMemory() { - return AmountOfMemory(_SC_PHYS_PAGES); -} - -// static -int64 SysInfo::AmountOfAvailablePhysicalMemory() { - return AmountOfMemory(_SC_AVPHYS_PAGES); -} - -// static -size_t SysInfo::MaxSharedMemorySize() { - static int64 limit; - static bool limit_valid = false; - if (!limit_valid) { - std::string contents; - file_util::ReadFileToString(FilePath("/proc/sys/kernel/shmmax"), &contents); - DCHECK(!contents.empty()); - if (!contents.empty() && contents[contents.length() - 1] == '\n') { - contents.erase(contents.length() - 1); - } - if (base::StringToInt64(contents, &limit)) { - DCHECK(limit >= 0); - DCHECK(static_cast(limit) <= std::numeric_limits::max()); - limit_valid = true; - } else { - NOTREACHED(); - return 0; - } - } - return static_cast(limit); -} - -// static -std::string SysInfo::CPUModelName() { -#if defined(OS_CHROMEOS) && defined(ARCH_CPU_ARMEL) - const char kCpuModelPrefix[] = "Hardware"; -#else - const char kCpuModelPrefix[] = "model name"; -#endif - std::string contents; - file_util::ReadFileToString(FilePath("/proc/cpuinfo"), &contents); - DCHECK(!contents.empty()); - if (!contents.empty()) { - std::istringstream iss(contents); - std::string line; - while (std::getline(iss, line)) { - if (line.compare(0, strlen(kCpuModelPrefix), kCpuModelPrefix) == 0) { - size_t pos = line.find(": "); - return line.substr(pos + 2); - } - } - } - return std::string(); -} - -} // namespace base diff --git a/base/sys_info_mac.cc b/base/sys_info_mac.cc deleted file mode 100644 index 2911c7c4ce..0000000000 --- a/base/sys_info_mac.cc +++ /dev/null @@ -1,88 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "base/sys_info.h" - -#include -#include -#include -#include -#include -#include - -#include "base/logging.h" -#include "base/mac/scoped_mach_port.h" -#include "base/strings/stringprintf.h" - -namespace base { - -// static -std::string SysInfo::OperatingSystemName() { - return "Mac OS X"; -} - -// static -std::string SysInfo::OperatingSystemVersion() { - int32 major, minor, bugfix; - OperatingSystemVersionNumbers(&major, &minor, &bugfix); - return base::StringPrintf("%d.%d.%d", major, minor, bugfix); -} - -// static -void SysInfo::OperatingSystemVersionNumbers(int32* major_version, - int32* minor_version, - int32* bugfix_version) { - Gestalt(gestaltSystemVersionMajor, - reinterpret_cast(major_version)); - Gestalt(gestaltSystemVersionMinor, - reinterpret_cast(minor_version)); - Gestalt(gestaltSystemVersionBugFix, - reinterpret_cast(bugfix_version)); -} - -// static -int64 SysInfo::AmountOfPhysicalMemory() { - struct host_basic_info hostinfo; - mach_msg_type_number_t count = HOST_BASIC_INFO_COUNT; - base::mac::ScopedMachPort host(mach_host_self()); - int result = host_info(host, - HOST_BASIC_INFO, - reinterpret_cast(&hostinfo), - &count); - if (result != KERN_SUCCESS) { - NOTREACHED(); - return 0; - } - DCHECK_EQ(HOST_BASIC_INFO_COUNT, count); - return static_cast(hostinfo.max_mem); -} - -// static -int64 SysInfo::AmountOfAvailablePhysicalMemory() { - base::mac::ScopedMachPort host(mach_host_self()); - vm_statistics_data_t vm_info; - mach_msg_type_number_t count = HOST_VM_INFO_COUNT; - - if (host_statistics(host.get(), - HOST_VM_INFO, - reinterpret_cast(&vm_info), - &count) != KERN_SUCCESS) { - NOTREACHED(); - return 0; - } - - return static_cast( - vm_info.free_count - vm_info.speculative_count) * PAGE_SIZE; -} - -// static -std::string SysInfo::CPUModelName() { - char name[256]; - size_t len = arraysize(name); - if (sysctlbyname("machdep.cpu.brand_string", &name, &len, NULL, 0) == 0) - return name; - return std::string(); -} - -} // namespace base diff --git a/base/sys_info_openbsd.cc b/base/sys_info_openbsd.cc deleted file mode 100644 index edbb2c9d86..0000000000 --- a/base/sys_info_openbsd.cc +++ /dev/null @@ -1,75 +0,0 @@ -// Copyright (c) 2011 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "base/sys_info.h" - -#include -#include -#include - -#include "base/logging.h" - -namespace { - -int64 AmountOfMemory(int pages_name) { - long pages = sysconf(pages_name); - long page_size = sysconf(_SC_PAGESIZE); - if (pages == -1 || page_size == -1) { - NOTREACHED(); - return 0; - } - return static_cast(pages) * page_size; -} - -} // namespace - -namespace base { - -// static -int SysInfo::NumberOfProcessors() { - int mib[] = { CTL_HW, HW_NCPU }; - int ncpu; - size_t size = sizeof(ncpu); - if (sysctl(mib, arraysize(mib), &ncpu, &size, NULL, 0) < 0) { - NOTREACHED(); - return 1; - } - return ncpu; -} - -// static -int64 SysInfo::AmountOfPhysicalMemory() { - return AmountOfMemory(_SC_PHYS_PAGES); -} - -// static -int64 SysInfo::AmountOfAvailablePhysicalMemory() { - return AmountOfMemory(_SC_AVPHYS_PAGES); -} - -// static -size_t SysInfo::MaxSharedMemorySize() { - int mib[] = { CTL_KERN, KERN_SHMINFO, KERN_SHMINFO_SHMMAX }; - size_t limit; - size_t size = sizeof(limit); - if (sysctl(mib, arraysize(mib), &limit, &size, NULL, 0) < 0) { - NOTREACHED(); - return 0; - } - return limit; -} - -// static -std::string SysInfo::CPUModelName() { - int mib[] = { CTL_HW, HW_MODEL }; - char name[256]; - size_t len = arraysize(name); - if (sysctl(mib, arraysize(mib), name, &len, NULL, 0) < 0) { - NOTREACHED(); - return std::string(); - } - return name; -} - -} // namespace base diff --git a/base/sys_info_posix.cc b/base/sys_info_posix.cc deleted file mode 100644 index bbb1662559..0000000000 --- a/base/sys_info_posix.cc +++ /dev/null @@ -1,97 +0,0 @@ -// Copyright (c) 2011 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "base/sys_info.h" - -#include -#include -#include -#include -#include - -#include "base/basictypes.h" -#include "base/file_util.h" -#include "base/logging.h" -#include "base/strings/utf_string_conversions.h" -#include "base/threading/thread_restrictions.h" - -#if defined(OS_ANDROID) -#include -#define statvfs statfs // Android uses a statvfs-like statfs struct and call. -#else -#include -#endif - -namespace base { - -#if !defined(OS_OPENBSD) -int SysInfo::NumberOfProcessors() { - // It seems that sysconf returns the number of "logical" processors on both - // Mac and Linux. So we get the number of "online logical" processors. - long res = sysconf(_SC_NPROCESSORS_ONLN); - if (res == -1) { - NOTREACHED(); - return 1; - } - - return static_cast(res); -} -#endif - -// static -int64 SysInfo::AmountOfFreeDiskSpace(const FilePath& path) { - base::ThreadRestrictions::AssertIOAllowed(); - - struct statvfs stats; - if (HANDLE_EINTR(statvfs(path.value().c_str(), &stats)) != 0) - return -1; - return static_cast(stats.f_bavail) * stats.f_frsize; -} - -#if !defined(OS_MACOSX) && !defined(OS_ANDROID) -// static -std::string SysInfo::OperatingSystemName() { - struct utsname info; - if (uname(&info) < 0) { - NOTREACHED(); - return std::string(); - } - return std::string(info.sysname); -} -#endif - -#if !defined(OS_MACOSX) && !defined(OS_ANDROID) -// static -std::string SysInfo::OperatingSystemVersion() { - struct utsname info; - if (uname(&info) < 0) { - NOTREACHED(); - return std::string(); - } - return std::string(info.release); -} -#endif - -// static -std::string SysInfo::OperatingSystemArchitecture() { - struct utsname info; - if (uname(&info) < 0) { - NOTREACHED(); - return std::string(); - } - std::string arch(info.machine); - if (arch == "i386" || arch == "i486" || arch == "i586" || arch == "i686") { - arch = "x86"; - } else if (arch == "amd64") { - arch = "x86_64"; - } - return arch; -} - -// static -size_t SysInfo::VMAllocationGranularity() { - return getpagesize(); -} - -} // namespace base diff --git a/base/sys_info_unittest.cc b/base/sys_info_unittest.cc deleted file mode 100644 index 8153f2b357..0000000000 --- a/base/sys_info_unittest.cc +++ /dev/null @@ -1,111 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "base/file_util.h" -#include "base/sys_info.h" -#include "base/threading/platform_thread.h" -#include "testing/gtest/include/gtest/gtest.h" -#include "testing/platform_test.h" - -typedef PlatformTest SysInfoTest; -using base::FilePath; - -#if defined(OS_POSIX) && !defined(OS_MACOSX) && !defined(OS_ANDROID) -TEST_F(SysInfoTest, MaxSharedMemorySize) { - // We aren't actually testing that it's correct, just that it's sane. - EXPECT_GT(base::SysInfo::MaxSharedMemorySize(), 0u); -} -#endif - -TEST_F(SysInfoTest, NumProcs) { - // We aren't actually testing that it's correct, just that it's sane. - EXPECT_GE(base::SysInfo::NumberOfProcessors(), 1); -} - -TEST_F(SysInfoTest, AmountOfMem) { - // We aren't actually testing that it's correct, just that it's sane. - EXPECT_GT(base::SysInfo::AmountOfPhysicalMemory(), 0); - EXPECT_GT(base::SysInfo::AmountOfPhysicalMemoryMB(), 0); -} - -TEST_F(SysInfoTest, AmountOfFreeDiskSpace) { - // We aren't actually testing that it's correct, just that it's sane. - FilePath tmp_path; - ASSERT_TRUE(file_util::GetTempDir(&tmp_path)); - EXPECT_GT(base::SysInfo::AmountOfFreeDiskSpace(tmp_path), 0) - << tmp_path.value(); -} - -#if defined(OS_WIN) || defined(OS_MACOSX) || defined(OS_CHROMEOS) -TEST_F(SysInfoTest, OperatingSystemVersionNumbers) { - int32 os_major_version = -1; - int32 os_minor_version = -1; - int32 os_bugfix_version = -1; - base::SysInfo::OperatingSystemVersionNumbers(&os_major_version, - &os_minor_version, - &os_bugfix_version); - EXPECT_GT(os_major_version, -1); - EXPECT_GT(os_minor_version, -1); - EXPECT_GT(os_bugfix_version, -1); -} -#endif - -TEST_F(SysInfoTest, Uptime) { - int64 up_time_1 = base::SysInfo::Uptime(); - // UpTime() is implemented internally using TimeTicks::Now(), which documents - // system resolution as being 1-15ms. Sleep a little longer than that. - base::PlatformThread::Sleep(base::TimeDelta::FromMilliseconds(20)); - int64 up_time_2 = base::SysInfo::Uptime(); - EXPECT_GT(up_time_1, 0); - EXPECT_GT(up_time_2, up_time_1); -} - -#if defined(OS_CHROMEOS) -TEST_F(SysInfoTest, GoogleChromeOSVersionNumbers) { - int32 os_major_version = -1; - int32 os_minor_version = -1; - int32 os_bugfix_version = -1; - std::string lsb_release("FOO=1234123.34.5\n"); - lsb_release.append(base::SysInfo::GetLinuxStandardBaseVersionKey()); - lsb_release.append("=1.2.3.4\n"); - base::SysInfo::ParseLsbRelease(lsb_release, - &os_major_version, - &os_minor_version, - &os_bugfix_version); - EXPECT_EQ(1, os_major_version); - EXPECT_EQ(2, os_minor_version); - EXPECT_EQ(3, os_bugfix_version); -} - -TEST_F(SysInfoTest, GoogleChromeOSVersionNumbersFirst) { - int32 os_major_version = -1; - int32 os_minor_version = -1; - int32 os_bugfix_version = -1; - std::string lsb_release(base::SysInfo::GetLinuxStandardBaseVersionKey()); - lsb_release.append("=1.2.3.4\n"); - lsb_release.append("FOO=1234123.34.5\n"); - base::SysInfo::ParseLsbRelease(lsb_release, - &os_major_version, - &os_minor_version, - &os_bugfix_version); - EXPECT_EQ(1, os_major_version); - EXPECT_EQ(2, os_minor_version); - EXPECT_EQ(3, os_bugfix_version); -} - -TEST_F(SysInfoTest, GoogleChromeOSNoVersionNumbers) { - int32 os_major_version = -1; - int32 os_minor_version = -1; - int32 os_bugfix_version = -1; - std::string lsb_release("FOO=1234123.34.5\n"); - base::SysInfo::ParseLsbRelease(lsb_release, - &os_major_version, - &os_minor_version, - &os_bugfix_version); - EXPECT_EQ(-1, os_major_version); - EXPECT_EQ(-1, os_minor_version); - EXPECT_EQ(-1, os_bugfix_version); -} - -#endif // OS_CHROMEOS diff --git a/base/sys_info_win.cc b/base/sys_info_win.cc deleted file mode 100644 index 191fd94ff5..0000000000 --- a/base/sys_info_win.cc +++ /dev/null @@ -1,125 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "base/sys_info.h" - -#include - -#include "base/files/file_path.h" -#include "base/logging.h" -#include "base/memory/scoped_ptr.h" -#include "base/strings/stringprintf.h" -#include "base/threading/thread_restrictions.h" -#include "base/win/windows_version.h" - -namespace { - -int64 AmountOfMemory(DWORDLONG MEMORYSTATUSEX::* memory_field) { - MEMORYSTATUSEX memory_info; - memory_info.dwLength = sizeof(memory_info); - if (!GlobalMemoryStatusEx(&memory_info)) { - NOTREACHED(); - return 0; - } - - int64 rv = static_cast(memory_info.*memory_field); - if (rv < 0) - rv = kint64max; - return rv; -} - -} // namespace - -namespace base { - -// static -int SysInfo::NumberOfProcessors() { - return win::OSInfo::GetInstance()->processors(); -} - -// static -int64 SysInfo::AmountOfPhysicalMemory() { - return AmountOfMemory(&MEMORYSTATUSEX::ullTotalPhys); -} - -// static -int64 SysInfo::AmountOfAvailablePhysicalMemory() { - return AmountOfMemory(&MEMORYSTATUSEX::ullAvailPhys); -} - -// static -int64 SysInfo::AmountOfFreeDiskSpace(const FilePath& path) { - base::ThreadRestrictions::AssertIOAllowed(); - - ULARGE_INTEGER available, total, free; - if (!GetDiskFreeSpaceExW(path.value().c_str(), &available, &total, &free)) { - return -1; - } - int64 rv = static_cast(available.QuadPart); - if (rv < 0) - rv = kint64max; - return rv; -} - -// static -std::string SysInfo::OperatingSystemName() { - return "Windows NT"; -} - -// static -std::string SysInfo::OperatingSystemVersion() { - win::OSInfo* os_info = win::OSInfo::GetInstance(); - win::OSInfo::VersionNumber version_number = os_info->version_number(); - std::string version(StringPrintf("%d.%d", version_number.major, - version_number.minor)); - win::OSInfo::ServicePack service_pack = os_info->service_pack(); - if (service_pack.major != 0) { - version += StringPrintf(" SP%d", service_pack.major); - if (service_pack.minor != 0) - version += StringPrintf(".%d", service_pack.minor); - } - return version; -} - -// TODO: Implement OperatingSystemVersionComplete, which would include -// patchlevel/service pack number. -// See chrome/browser/feedback/feedback_util.h, FeedbackUtil::SetOSVersion. - -// static -std::string SysInfo::OperatingSystemArchitecture() { - win::OSInfo::WindowsArchitecture arch = - win::OSInfo::GetInstance()->architecture(); - switch (arch) { - case win::OSInfo::X86_ARCHITECTURE: - return "x86"; - case win::OSInfo::X64_ARCHITECTURE: - return "x86_64"; - case win::OSInfo::IA64_ARCHITECTURE: - return "ia64"; - default: - return ""; - } -} - -// static -std::string SysInfo::CPUModelName() { - return win::OSInfo::GetInstance()->processor_model_name(); -} - -// static -size_t SysInfo::VMAllocationGranularity() { - return win::OSInfo::GetInstance()->allocation_granularity(); -} - -// static -void SysInfo::OperatingSystemVersionNumbers(int32* major_version, - int32* minor_version, - int32* bugfix_version) { - win::OSInfo* os_info = win::OSInfo::GetInstance(); - *major_version = os_info->version_number().major; - *minor_version = os_info->version_number().minor; - *bugfix_version = 0; -} - -} // namespace base diff --git a/base/system_monitor/system_monitor.cc b/base/system_monitor/system_monitor.cc deleted file mode 100644 index 11dd000a16..0000000000 --- a/base/system_monitor/system_monitor.cc +++ /dev/null @@ -1,52 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "base/system_monitor/system_monitor.h" - -#include - -#include "base/logging.h" -#include "base/message_loop/message_loop.h" -#include "base/time/time.h" - -namespace base { - -static SystemMonitor* g_system_monitor = NULL; - -SystemMonitor::SystemMonitor() - : devices_changed_observer_list_( - new ObserverListThreadSafe()) { - DCHECK(!g_system_monitor); - g_system_monitor = this; -} - -SystemMonitor::~SystemMonitor() { - DCHECK_EQ(this, g_system_monitor); - g_system_monitor = NULL; -} - -// static -SystemMonitor* SystemMonitor::Get() { - return g_system_monitor; -} - -void SystemMonitor::ProcessDevicesChanged(DeviceType device_type) { - NotifyDevicesChanged(device_type); -} - -void SystemMonitor::AddDevicesChangedObserver(DevicesChangedObserver* obs) { - devices_changed_observer_list_->AddObserver(obs); -} - -void SystemMonitor::RemoveDevicesChangedObserver(DevicesChangedObserver* obs) { - devices_changed_observer_list_->RemoveObserver(obs); -} - -void SystemMonitor::NotifyDevicesChanged(DeviceType device_type) { - DVLOG(1) << "DevicesChanged with device type " << device_type; - devices_changed_observer_list_->Notify( - &DevicesChangedObserver::OnDevicesChanged, device_type); -} - -} // namespace base diff --git a/base/system_monitor/system_monitor.h b/base/system_monitor/system_monitor.h deleted file mode 100644 index 5dd849f5e3..0000000000 --- a/base/system_monitor/system_monitor.h +++ /dev/null @@ -1,75 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef BASE_SYSTEM_MONITOR_SYSTEM_MONITOR_H_ -#define BASE_SYSTEM_MONITOR_SYSTEM_MONITOR_H_ - -#include "base/base_export.h" -#include "base/basictypes.h" -#include "base/memory/ref_counted.h" -#include "base/observer_list_threadsafe.h" -#include "build/build_config.h" - -namespace base { - -// Class for monitoring various system-related subsystems -// such as power management, network status, etc. -// TODO(mbelshe): Add support beyond just power management. -class BASE_EXPORT SystemMonitor { - public: - // Type of devices whose change need to be monitored, such as add/remove. - enum DeviceType { - DEVTYPE_AUDIO_CAPTURE, // Audio capture device, e.g., microphone. - DEVTYPE_VIDEO_CAPTURE, // Video capture device, e.g., webcam. - DEVTYPE_UNKNOWN, // Other devices. - }; - - // Create SystemMonitor. Only one SystemMonitor instance per application - // is allowed. - SystemMonitor(); - ~SystemMonitor(); - - // Get the application-wide SystemMonitor (if not present, returns NULL). - static SystemMonitor* Get(); - - class BASE_EXPORT DevicesChangedObserver { - public: - // Notification that the devices connected to the system have changed. - // This is only implemented on Windows currently. - virtual void OnDevicesChanged(DeviceType device_type) {} - - protected: - virtual ~DevicesChangedObserver() {} - }; - - // Add a new observer. - // Can be called from any thread. - // Must not be called from within a notification callback. - void AddDevicesChangedObserver(DevicesChangedObserver* obs); - - // Remove an existing observer. - // Can be called from any thread. - // Must not be called from within a notification callback. - void RemoveDevicesChangedObserver(DevicesChangedObserver* obs); - - // The ProcessFoo() style methods are a broken pattern and should not - // be copied. Any significant addition to this class is blocked on - // refactoring to improve the state of affairs. See http://crbug.com/149059 - - // Cross-platform handling of a device change event. - void ProcessDevicesChanged(DeviceType device_type); - - private: - // Functions to trigger notifications. - void NotifyDevicesChanged(DeviceType device_type); - - scoped_refptr > - devices_changed_observer_list_; - - DISALLOW_COPY_AND_ASSIGN(SystemMonitor); -}; - -} // namespace base - -#endif // BASE_SYSTEM_MONITOR_SYSTEM_MONITOR_H_ diff --git a/base/system_monitor/system_monitor_unittest.cc b/base/system_monitor/system_monitor_unittest.cc deleted file mode 100644 index e49405ec45..0000000000 --- a/base/system_monitor/system_monitor_unittest.cc +++ /dev/null @@ -1,54 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "base/system_monitor/system_monitor.h" - -#include "base/message_loop/message_loop.h" -#include "base/run_loop.h" -#include "base/test/mock_devices_changed_observer.h" -#include "testing/gmock/include/gmock/gmock.h" -#include "testing/gtest/include/gtest/gtest.h" - -namespace base { - -namespace { - -class SystemMonitorTest : public testing::Test { - protected: - SystemMonitorTest() { - system_monitor_.reset(new SystemMonitor); - } - virtual ~SystemMonitorTest() {} - - MessageLoop message_loop_; - scoped_ptr system_monitor_; - - DISALLOW_COPY_AND_ASSIGN(SystemMonitorTest); -}; - -TEST_F(SystemMonitorTest, DeviceChangeNotifications) { - const int kObservers = 5; - - testing::Sequence mock_sequencer[kObservers]; - MockDevicesChangedObserver observers[kObservers]; - for (int index = 0; index < kObservers; ++index) { - system_monitor_->AddDevicesChangedObserver(&observers[index]); - - EXPECT_CALL(observers[index], - OnDevicesChanged(SystemMonitor::DEVTYPE_UNKNOWN)) - .Times(3) - .InSequence(mock_sequencer[index]); - } - - system_monitor_->ProcessDevicesChanged(SystemMonitor::DEVTYPE_UNKNOWN); - RunLoop().RunUntilIdle(); - - system_monitor_->ProcessDevicesChanged(SystemMonitor::DEVTYPE_UNKNOWN); - system_monitor_->ProcessDevicesChanged(SystemMonitor::DEVTYPE_UNKNOWN); - RunLoop().RunUntilIdle(); -} - -} // namespace - -} // namespace base diff --git a/base/task_runner.cc b/base/task_runner.cc deleted file mode 100644 index 5860f2820f..0000000000 --- a/base/task_runner.cc +++ /dev/null @@ -1,68 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "base/task_runner.h" - -#include "base/compiler_specific.h" -#include "base/logging.h" -#include "base/threading/post_task_and_reply_impl.h" - -namespace base { - -namespace { - -// TODO(akalin): There's only one other implementation of -// PostTaskAndReplyImpl in WorkerPool. Investigate whether it'll be -// possible to merge the two. -class PostTaskAndReplyTaskRunner : public internal::PostTaskAndReplyImpl { - public: - explicit PostTaskAndReplyTaskRunner(TaskRunner* destination); - - private: - virtual bool PostTask(const tracked_objects::Location& from_here, - const Closure& task) OVERRIDE; - - // Non-owning. - TaskRunner* destination_; -}; - -PostTaskAndReplyTaskRunner::PostTaskAndReplyTaskRunner( - TaskRunner* destination) : destination_(destination) { - DCHECK(destination_); -} - -bool PostTaskAndReplyTaskRunner::PostTask( - const tracked_objects::Location& from_here, - const Closure& task) { - return destination_->PostTask(from_here, task); -} - -} // namespace - -bool TaskRunner::PostTask(const tracked_objects::Location& from_here, - const Closure& task) { - return PostDelayedTask(from_here, task, base::TimeDelta()); -} - -bool TaskRunner::PostTaskAndReply( - const tracked_objects::Location& from_here, - const Closure& task, - const Closure& reply) { - return PostTaskAndReplyTaskRunner(this).PostTaskAndReply( - from_here, task, reply); -} - -TaskRunner::TaskRunner() {} - -TaskRunner::~TaskRunner() {} - -void TaskRunner::OnDestruct() const { - delete this; -} - -void TaskRunnerTraits::Destruct(const TaskRunner* task_runner) { - task_runner->OnDestruct(); -} - -} // namespace base diff --git a/base/task_runner.h b/base/task_runner.h deleted file mode 100644 index 7d07b8ceb0..0000000000 --- a/base/task_runner.h +++ /dev/null @@ -1,153 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef BASE_TASK_RUNNER_H_ -#define BASE_TASK_RUNNER_H_ - -#include "base/base_export.h" -#include "base/basictypes.h" -#include "base/callback_forward.h" -#include "base/memory/ref_counted.h" -#include "base/time/time.h" - -namespace tracked_objects { -class Location; -} // namespace tracked_objects - -namespace base { - -struct TaskRunnerTraits; - -// A TaskRunner is an object that runs posted tasks (in the form of -// Closure objects). The TaskRunner interface provides a way of -// decoupling task posting from the mechanics of how each task will be -// run. TaskRunner provides very weak guarantees as to how posted -// tasks are run (or if they're run at all). In particular, it only -// guarantees: -// -// - Posting a task will not run it synchronously. That is, no -// Post*Task method will call task.Run() directly. -// -// - Increasing the delay can only delay when the task gets run. -// That is, increasing the delay may not affect when the task gets -// run, or it could make it run later than it normally would, but -// it won't make it run earlier than it normally would. -// -// TaskRunner does not guarantee the order in which posted tasks are -// run, whether tasks overlap, or whether they're run on a particular -// thread. Also it does not guarantee a memory model for shared data -// between tasks. (In other words, you should use your own -// synchronization/locking primitives if you need to share data -// between tasks.) -// -// Implementations of TaskRunner should be thread-safe in that all -// methods must be safe to call on any thread. Ownership semantics -// for TaskRunners are in general not clear, which is why the -// interface itself is RefCountedThreadSafe. -// -// Some theoretical implementations of TaskRunner: -// -// - A TaskRunner that uses a thread pool to run posted tasks. -// -// - A TaskRunner that, for each task, spawns a non-joinable thread -// to run that task and immediately quit. -// -// - A TaskRunner that stores the list of posted tasks and has a -// method Run() that runs each runnable task in random order. -class BASE_EXPORT TaskRunner - : public RefCountedThreadSafe { - public: - // Posts the given task to be run. Returns true if the task may be - // run at some point in the future, and false if the task definitely - // will not be run. - // - // Equivalent to PostDelayedTask(from_here, task, 0). - bool PostTask(const tracked_objects::Location& from_here, - const Closure& task); - - // Like PostTask, but tries to run the posted task only after - // |delay_ms| has passed. - // - // It is valid for an implementation to ignore |delay_ms|; that is, - // to have PostDelayedTask behave the same as PostTask. - virtual bool PostDelayedTask(const tracked_objects::Location& from_here, - const Closure& task, - base::TimeDelta delay) = 0; - - // Returns true if the current thread is a thread on which a task - // may be run, and false if no task will be run on the current - // thread. - // - // It is valid for an implementation to always return true, or in - // general to use 'true' as a default value. - virtual bool RunsTasksOnCurrentThread() const = 0; - - // Posts |task| on the current TaskRunner. On completion, |reply| - // is posted to the thread that called PostTaskAndReply(). Both - // |task| and |reply| are guaranteed to be deleted on the thread - // from which PostTaskAndReply() is invoked. This allows objects - // that must be deleted on the originating thread to be bound into - // the |task| and |reply| Closures. In particular, it can be useful - // to use WeakPtr<> in the |reply| Closure so that the reply - // operation can be canceled. See the following pseudo-code: - // - // class DataBuffer : public RefCountedThreadSafe { - // public: - // // Called to add data into a buffer. - // void AddData(void* buf, size_t length); - // ... - // }; - // - // - // class DataLoader : public SupportsWeakPtr { - // public: - // void GetData() { - // scoped_refptr buffer = new DataBuffer(); - // target_thread_.message_loop_proxy()->PostTaskAndReply( - // FROM_HERE, - // base::Bind(&DataBuffer::AddData, buffer), - // base::Bind(&DataLoader::OnDataReceived, AsWeakPtr(), buffer)); - // } - // - // private: - // void OnDataReceived(scoped_refptr buffer) { - // // Do something with buffer. - // } - // }; - // - // - // Things to notice: - // * Results of |task| are shared with |reply| by binding a shared argument - // (a DataBuffer instance). - // * The DataLoader object has no special thread safety. - // * The DataLoader object can be deleted while |task| is still running, - // and the reply will cancel itself safely because it is bound to a - // WeakPtr<>. - bool PostTaskAndReply(const tracked_objects::Location& from_here, - const Closure& task, - const Closure& reply); - - protected: - friend struct TaskRunnerTraits; - - // Only the Windows debug build seems to need this: see - // http://crbug.com/112250. - friend class RefCountedThreadSafe; - - TaskRunner(); - virtual ~TaskRunner(); - - // Called when this object should be destroyed. By default simply - // deletes |this|, but can be overridden to do something else, like - // delete on a certain thread. - virtual void OnDestruct() const; -}; - -struct BASE_EXPORT TaskRunnerTraits { - static void Destruct(const TaskRunner* task_runner); -}; - -} // namespace base - -#endif // BASE_TASK_RUNNER_H_ diff --git a/base/task_runner_util.h b/base/task_runner_util.h deleted file mode 100644 index b6dd0f36d6..0000000000 --- a/base/task_runner_util.h +++ /dev/null @@ -1,71 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef BASE_TASK_RUNNER_UTIL_H_ -#define BASE_TASK_RUNNER_UTIL_H_ - -#include "base/bind.h" -#include "base/bind_helpers.h" -#include "base/callback_internal.h" -#include "base/logging.h" -#include "base/task_runner.h" - -namespace base { - -namespace internal { - -// Adapts a function that produces a result via a return value to -// one that returns via an output parameter. -template -void ReturnAsParamAdapter(const Callback& func, - ReturnType* result) { - *result = func.Run(); -} - -// Adapts a T* result to a callblack that expects a T. -template -void ReplyAdapter(const Callback& callback, - TaskReturnType* result) { - // TODO(ajwong): Remove this conditional and add a DCHECK to enforce that - // |reply| must be non-null in PostTaskAndReplyWithResult() below after - // current code that relies on this API softness has been removed. - // http://crbug.com/162712 - if (!callback.is_null()) - callback.Run(CallbackForward(*result)); -} - -} // namespace internal - -// When you have these methods -// -// R DoWorkAndReturn(); -// void Callback(const R& result); -// -// and want to call them in a PostTaskAndReply kind of fashion where the -// result of DoWorkAndReturn is passed to the Callback, you can use -// PostTaskAndReplyWithResult as in this example: -// -// PostTaskAndReplyWithResult( -// target_thread_.message_loop_proxy(), -// FROM_HERE, -// Bind(&DoWorkAndReturn), -// Bind(&Callback)); -template -bool PostTaskAndReplyWithResult( - TaskRunner* task_runner, - const tracked_objects::Location& from_here, - const Callback& task, - const Callback& reply) { - TaskReturnType* result = new TaskReturnType(); - return task_runner->PostTaskAndReply( - from_here, - base::Bind(&internal::ReturnAsParamAdapter, task, - result), - base::Bind(&internal::ReplyAdapter, reply, - base::Owned(result))); -} - -} // namespace base - -#endif // BASE_TASK_RUNNER_UTIL_H_ diff --git a/base/task_runner_util_unittest.cc b/base/task_runner_util_unittest.cc deleted file mode 100644 index 04743944d6..0000000000 --- a/base/task_runner_util_unittest.cc +++ /dev/null @@ -1,128 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "base/task_runner_util.h" - -#include "base/bind.h" -#include "base/message_loop/message_loop.h" -#include "base/run_loop.h" -#include "testing/gtest/include/gtest/gtest.h" - -namespace base { - -namespace { - -int ReturnFourtyTwo() { - return 42; -} - -void StoreValue(int* destination, int value) { - *destination = value; -} - -void StoreDoubleValue(double* destination, double value) { - *destination = value; -} - -int g_foo_destruct_count = 0; -int g_foo_free_count = 0; - -struct Foo { - ~Foo() { - ++g_foo_destruct_count; - } -}; - -scoped_ptr CreateFoo() { - return scoped_ptr(new Foo); -} - -void ExpectFoo(scoped_ptr foo) { - EXPECT_TRUE(foo.get()); - scoped_ptr local_foo(foo.Pass()); - EXPECT_TRUE(local_foo.get()); - EXPECT_FALSE(foo.get()); -} - -struct FreeFooFunctor { - void operator()(Foo* foo) const { - ++g_foo_free_count; - delete foo; - }; -}; - -scoped_ptr_malloc CreateScopedFoo() { - return scoped_ptr_malloc(new Foo); -} - -void ExpectScopedFoo(scoped_ptr_malloc foo) { - EXPECT_TRUE(foo.get()); - scoped_ptr_malloc local_foo(foo.Pass()); - EXPECT_TRUE(local_foo.get()); - EXPECT_FALSE(foo.get()); -} - -} // namespace - -TEST(TaskRunnerHelpersTest, PostTaskAndReplyWithResult) { - int result = 0; - - MessageLoop message_loop; - PostTaskAndReplyWithResult(message_loop.message_loop_proxy().get(), - FROM_HERE, - Bind(&ReturnFourtyTwo), - Bind(&StoreValue, &result)); - - RunLoop().RunUntilIdle(); - - EXPECT_EQ(42, result); -} - -TEST(TaskRunnerHelpersTest, PostTaskAndReplyWithResultImplicitConvert) { - double result = 0; - - MessageLoop message_loop; - PostTaskAndReplyWithResult(message_loop.message_loop_proxy().get(), - FROM_HERE, - Bind(&ReturnFourtyTwo), - Bind(&StoreDoubleValue, &result)); - - RunLoop().RunUntilIdle(); - - EXPECT_DOUBLE_EQ(42.0, result); -} - -TEST(TaskRunnerHelpersTest, PostTaskAndReplyWithResultPassed) { - g_foo_destruct_count = 0; - g_foo_free_count = 0; - - MessageLoop message_loop; - PostTaskAndReplyWithResult(message_loop.message_loop_proxy().get(), - FROM_HERE, - Bind(&CreateFoo), - Bind(&ExpectFoo)); - - RunLoop().RunUntilIdle(); - - EXPECT_EQ(1, g_foo_destruct_count); - EXPECT_EQ(0, g_foo_free_count); -} - -TEST(TaskRunnerHelpersTest, PostTaskAndReplyWithResultPassedFreeProc) { - g_foo_destruct_count = 0; - g_foo_free_count = 0; - - MessageLoop message_loop; - PostTaskAndReplyWithResult(message_loop.message_loop_proxy().get(), - FROM_HERE, - Bind(&CreateScopedFoo), - Bind(&ExpectScopedFoo)); - - RunLoop().RunUntilIdle(); - - EXPECT_EQ(1, g_foo_destruct_count); - EXPECT_EQ(1, g_foo_free_count); -} - -} // namespace base diff --git a/base/template_util.h b/base/template_util.h deleted file mode 100644 index e21d4dc773..0000000000 --- a/base/template_util.h +++ /dev/null @@ -1,108 +0,0 @@ -// Copyright (c) 2011 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef BASE_TEMPLATE_UTIL_H_ -#define BASE_TEMPLATE_UTIL_H_ - -#include // For size_t. - -#include "build/build_config.h" - -namespace base { - -// template definitions from tr1 - -template -struct integral_constant { - static const T value = v; - typedef T value_type; - typedef integral_constant type; -}; - -template const T integral_constant::value; - -typedef integral_constant true_type; -typedef integral_constant false_type; - -template struct is_pointer : false_type {}; -template struct is_pointer : true_type {}; - -template struct is_same : public false_type {}; -template struct is_same : true_type {}; - -template struct is_array : public false_type {}; -template struct is_array : public true_type {}; -template struct is_array : public true_type {}; - -template struct is_non_const_reference : false_type {}; -template struct is_non_const_reference : true_type {}; -template struct is_non_const_reference : false_type {}; - -template struct is_void : false_type {}; -template <> struct is_void : true_type {}; - -namespace internal { - -// Types YesType and NoType are guaranteed such that sizeof(YesType) < -// sizeof(NoType). -typedef char YesType; - -struct NoType { - YesType dummy[2]; -}; - -// This class is an implementation detail for is_convertible, and you -// don't need to know how it works to use is_convertible. For those -// who care: we declare two different functions, one whose argument is -// of type To and one with a variadic argument list. We give them -// return types of different size, so we can use sizeof to trick the -// compiler into telling us which function it would have chosen if we -// had called it with an argument of type From. See Alexandrescu's -// _Modern C++ Design_ for more details on this sort of trick. - -struct ConvertHelper { - template - static YesType Test(To); - - template - static NoType Test(...); - - template - static From& Create(); -}; - -// Used to determine if a type is a struct/union/class. Inspired by Boost's -// is_class type_trait implementation. -struct IsClassHelper { - template - static YesType Test(void(C::*)(void)); - - template - static NoType Test(...); -}; - -} // namespace internal - -// Inherits from true_type if From is convertible to To, false_type otherwise. -// -// Note that if the type is convertible, this will be a true_type REGARDLESS -// of whether or not the conversion would emit a warning. -template -struct is_convertible - : integral_constant( - internal::ConvertHelper::Create())) == - sizeof(internal::YesType)> { -}; - -template -struct is_class - : integral_constant(0)) == - sizeof(internal::YesType)> { -}; - -} // namespace base - -#endif // BASE_TEMPLATE_UTIL_H_ diff --git a/base/template_util_unittest.cc b/base/template_util_unittest.cc deleted file mode 100644 index 4cfa3e4fb5..0000000000 --- a/base/template_util_unittest.cc +++ /dev/null @@ -1,80 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "base/template_util.h" - -#include "base/basictypes.h" -#include "testing/gtest/include/gtest/gtest.h" - -namespace base { -namespace { - -struct AStruct {}; -class AClass {}; -enum AnEnum {}; - -class Parent {}; -class Child : public Parent {}; - -// is_pointer -COMPILE_ASSERT(!is_pointer::value, IsPointer); -COMPILE_ASSERT(!is_pointer::value, IsPointer); -COMPILE_ASSERT(is_pointer::value, IsPointer); -COMPILE_ASSERT(is_pointer::value, IsPointer); - -// is_array -COMPILE_ASSERT(!is_array::value, IsArray); -COMPILE_ASSERT(!is_array::value, IsArray); -COMPILE_ASSERT(!is_array::value, IsArray); -COMPILE_ASSERT(is_array::value, IsArray); -COMPILE_ASSERT(is_array::value, IsArray); -COMPILE_ASSERT(is_array::value, IsArray); - -// is_non_const_reference -COMPILE_ASSERT(!is_non_const_reference::value, IsNonConstReference); -COMPILE_ASSERT(!is_non_const_reference::value, IsNonConstReference); -COMPILE_ASSERT(is_non_const_reference::value, IsNonConstReference); - -// is_convertible - -// Extra parens needed to make preprocessor macro parsing happy. Otherwise, -// it sees the equivalent of: -// -// (is_convertible < Child), (Parent > ::value) -// -// Silly C++. -COMPILE_ASSERT( (is_convertible::value), IsConvertible); -COMPILE_ASSERT(!(is_convertible::value), IsConvertible); -COMPILE_ASSERT(!(is_convertible::value), IsConvertible); -COMPILE_ASSERT( (is_convertible::value), IsConvertible); -COMPILE_ASSERT( (is_convertible::value), IsConvertible); -COMPILE_ASSERT(!(is_convertible::value), IsConvertible); - -// Array types are an easy corner case. Make sure to test that -// it does indeed compile. -COMPILE_ASSERT(!(is_convertible::value), IsConvertible); -COMPILE_ASSERT(!(is_convertible::value), IsConvertible); -COMPILE_ASSERT( (is_convertible::value), IsConvertible); - -// is_same -COMPILE_ASSERT(!(is_same::value), IsSame); -COMPILE_ASSERT(!(is_same::value), IsSame); -COMPILE_ASSERT( (is_same::value), IsSame); -COMPILE_ASSERT( (is_same::value), IsSame); -COMPILE_ASSERT( (is_same::value), IsSame); -COMPILE_ASSERT( (is_same::value), IsSame); -COMPILE_ASSERT(!(is_same::value), IsSame); - - -// is_class -COMPILE_ASSERT(is_class::value, IsClass); -COMPILE_ASSERT(is_class::value, IsClass); -COMPILE_ASSERT(!is_class::value, IsClass); -COMPILE_ASSERT(!is_class::value, IsClass); -COMPILE_ASSERT(!is_class::value, IsClass); -COMPILE_ASSERT(!is_class::value, IsClass); -COMPILE_ASSERT(!is_class::value, IsClass); - -} // namespace -} // namespace base diff --git a/base/test/OWNERS b/base/test/OWNERS deleted file mode 100644 index 92ecc889fd..0000000000 --- a/base/test/OWNERS +++ /dev/null @@ -1 +0,0 @@ -phajdan.jr@chromium.org diff --git a/base/test/android/OWNERS b/base/test/android/OWNERS deleted file mode 100644 index ebc6e2624f..0000000000 --- a/base/test/android/OWNERS +++ /dev/null @@ -1,3 +0,0 @@ -bulach@chromium.org -joth@chromium.org -yfriedman@chromium.org diff --git a/base/test/android/javatests/src/org/chromium/base/test/util/AdvancedMockContext.java b/base/test/android/javatests/src/org/chromium/base/test/util/AdvancedMockContext.java deleted file mode 100644 index a57a8b0319..0000000000 --- a/base/test/android/javatests/src/org/chromium/base/test/util/AdvancedMockContext.java +++ /dev/null @@ -1,103 +0,0 @@ -// Copyright (c) 2013 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -package org.chromium.base.test.util; - -import android.content.ContentResolver; -import android.content.Context; -import android.content.ContextWrapper; -import android.content.SharedPreferences; -import android.test.mock.MockContentResolver; -import android.test.mock.MockContext; - -import java.util.HashMap; -import java.util.Map; - -/** - * ContextWrapper that adds functionality for SharedPreferences and a way to set and retrieve flags. - */ -public class AdvancedMockContext extends ContextWrapper { - - private final MockContentResolver mMockContentResolver = new MockContentResolver(); - - private final Map mSharedPreferences = - new HashMap(); - - private final Map flags = new HashMap(); - - public AdvancedMockContext(Context base) { - super(base); - } - - public AdvancedMockContext() { - super(new MockContext()); - } - - @Override - public String getPackageName() { - return getBaseContext().getPackageName(); - } - - @Override - public Context getApplicationContext() { - return this; - } - - @Override - public ContentResolver getContentResolver() { - return mMockContentResolver; - } - - public MockContentResolver getMockContentResolver() { - return mMockContentResolver; - } - - @Override - public SharedPreferences getSharedPreferences(String name, int mode) { - synchronized (mSharedPreferences) { - if (!mSharedPreferences.containsKey(name)) { - // Auto-create shared preferences to mimic Android Context behavior - mSharedPreferences.put(name, new InMemorySharedPreferences()); - } - return mSharedPreferences.get(name); - } - } - - public void addSharedPreferences(String name, Map data) { - synchronized (mSharedPreferences) { - mSharedPreferences.put(name, new InMemorySharedPreferences(data)); - } - } - - public void setFlag(String key) { - flags.put(key, true); - } - - public void clearFlag(String key) { - flags.remove(key); - } - - public boolean isFlagSet(String key) { - return flags.containsKey(key) && flags.get(key); - } - - public static class MapBuilder { - - private final Map mData = new HashMap(); - - public static MapBuilder create() { - return new MapBuilder(); - } - - public MapBuilder add(String key, Object value) { - mData.put(key, value); - return this; - } - - public Map build() { - return mData; - } - - } -} diff --git a/base/test/android/javatests/src/org/chromium/base/test/util/DisabledTest.java b/base/test/android/javatests/src/org/chromium/base/test/util/DisabledTest.java deleted file mode 100644 index c2b2ecddcd..0000000000 --- a/base/test/android/javatests/src/org/chromium/base/test/util/DisabledTest.java +++ /dev/null @@ -1,21 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -package org.chromium.base.test.util; - -import java.lang.annotation.ElementType; -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; -import java.lang.annotation.Target; - -/** - * This annotation is for disabled tests. - *

- * Tests with this annotation will not be run on any of the normal bots. - * Please note that they might eventually run on a special bot. - */ -@Target(ElementType.METHOD) -@Retention(RetentionPolicy.RUNTIME) -public @interface DisabledTest { -} diff --git a/base/test/android/javatests/src/org/chromium/base/test/util/EnormousTest.java b/base/test/android/javatests/src/org/chromium/base/test/util/EnormousTest.java deleted file mode 100644 index 9f8fa939e8..0000000000 --- a/base/test/android/javatests/src/org/chromium/base/test/util/EnormousTest.java +++ /dev/null @@ -1,24 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -package org.chromium.base.test.util; - -import java.lang.annotation.ElementType; -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; -import java.lang.annotation.Target; - -/** - * This annotation is for enormous tests. - *

- * Examples of enormous tests are tests that depend on external web sites or - * tests that are long running. - *

- * Such tests are likely NOT reliable enough to run on tree closing bots and - * should only be run on FYI bots. - */ -@Target(ElementType.METHOD) -@Retention(RetentionPolicy.RUNTIME) -public @interface EnormousTest { -} diff --git a/base/test/android/javatests/src/org/chromium/base/test/util/Feature.java b/base/test/android/javatests/src/org/chromium/base/test/util/Feature.java deleted file mode 100644 index aa120ea8f0..0000000000 --- a/base/test/android/javatests/src/org/chromium/base/test/util/Feature.java +++ /dev/null @@ -1,29 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -package org.chromium.base.test.util; - -import java.lang.annotation.ElementType; -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; -import java.lang.annotation.Target; - -/** - * The java instrumentation tests are normally fairly large (in terms of - * dependencies), and the test suite ends up containing a large amount of - * tests that are not trivial to filter / group just by their names. - * Instead, we use this annotation: each test should be annotated as: - * @Feature({"Foo", "Bar"}) - * in order for the test runner scripts to be able to filter and group - * them accordingly (for instance, this enable us to run all tests that exercise - * feature Foo). - */ -@Target(ElementType.METHOD) -@Retention(RetentionPolicy.RUNTIME) -public @interface Feature { - /** - * @return A list of feature names. - */ - public String[] value(); -} diff --git a/base/test/android/javatests/src/org/chromium/base/test/util/InMemorySharedPreferences.java b/base/test/android/javatests/src/org/chromium/base/test/util/InMemorySharedPreferences.java deleted file mode 100644 index c127732769..0000000000 --- a/base/test/android/javatests/src/org/chromium/base/test/util/InMemorySharedPreferences.java +++ /dev/null @@ -1,238 +0,0 @@ -// Copyright (c) 2013 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -package org.chromium.base.test.util; - -import android.content.SharedPreferences; - -import java.util.Collections; -import java.util.HashMap; -import java.util.Map; -import java.util.Set; - -/** - * An implementation of SharedPreferences that can be used in tests. - *

    ZX~{24ZkrfIYg-4-s`Z+~h+DZ^+9cXZNp7kdwQ#p8;ij!(+&V%d ziwDTGEzhrgr}R9$*wyguZMs)d^zWUMP-1^rKaO^AzjMPgv|mAX9icE74~7kLJp5Vs z@v*LNU@NCnX)yr8z1*E9cqB4K!lD5tJtX`x<6b-m@wTA%g$Hbq zDO2@%eU$w}>&Tn~5HC&tMl>!kbin^a54MyZXeE@aP^Cf_Ou|HB%v3aKBu0)LCPrK- zjI`9BJ|Q4efty4M_Pal_lj@sV2{&7!l%_a76ki4K~F-FTDKx3T3W4fR{J-t+5+bG;()YG#cetM6$3ktmHcoY~UVwWA#vO4+Nf(9{&8xb5~l&$1)u)w>6khCR@ zWKpyunY(V6zYwE`&7;HNgCg%Dp%MFT^_y^wA*|tu3rA3MO|R31j0;rMy4r@%Wh#tf zMj^?fU`ql)f=q@aiw^?RDHSKsHgs+Ds-x&eIKD{tFZykoz%KIzf_VLm&I>&D!bGxs zv~_Y<^gsd)rHMlc?ug)#^y&V#=GJcPvxc}gxR)%2Hj%=7AQdALS8OAR92{%oes9fG zxdxd}S-6zJpAX0Ydp12VLA(s|f}ByrDDG8gC@(_?gCK_?Y!)8Fi4u3@;%gOBtNRte z#GH|Av>Sp*F)ZbcgVvJKU_fhCO~`hpuypowgh7OCf%Tln5o^(^l;db%=t>ZL+JD(D zj85nnF@y))UXg_Oi?wY;(W<);#WmOGyRn=e8yZD}<#M3{_IJcJkf9KJSXgrVhE^Us zgItz9BS2KHzUzG7?yROGkF!Ikg2#7qNxHcXCP>nphOiWyz z#)@p?VCyj1DY|AxCxD}*gwV>y$mp9FjfCd3Qbdlj%5lLmuo%wn50pOg1Ad8hR~=zbrNl1taY0~(JRB?FtIq1%&~-M>^-OX`CX3d@gcGym?106F6+GM zvp~GgkBWWM1*a^#C-c>h$-8gnIN$@Kvd!;FMXiP-+Z+D_DL)2*!0O~VW{dAOg3pBx zXb##zrtL_Sj!_6mjqlX4Q+g4=(z3jmqSPp__h{L?;RFoy*;lU zI&3(E_ntR@IIVr*_6B9}@nrNYhcpHklDTlAe_a%YOcwk^_^|L1c!xv$1$5y7NQ%md z)Cw5{{kx+O?G$aA5zy)9FNlD({>@Ry=D%?i`fvP%NP+E0|K%t28<3t30KicF-5WFp zThhJj^;KO*`K|MAU*9h-J?-s~6H$>-BnV0SRKQ?R=i=088Taz%Aj?rP6%*zYsK}JK zQsdM{86~JuH=>f}nW-fgEdV4^h|s^07$ZqT!1rXwxF4Urvyb?^@8g{>LzATss5e=> zXD-`jx6FN4+1N=D5F^EO#+FoojCUUl%^xyY^&E4d!ikST~fF zv^?5#lyR_?c9e2EKIRm5cqN>?aMtDZirZ&D-qiZ?d)@r>jcv0MPB-a14L{;j$lL9` zYjCbxHJu(aM{S!c(9_mWi6B%yKKW67J($V<7+2QH+k6oz{;=8oc3AV+Qxkx{X!(|L z2UdT-17~hF?`5~;=!|rIO||=T7%CjofW2WvL{TIa)$;@6o!h?4WRQwD=!96L_49*h zBUO(bzV!IwZNEB$w>O>F7(UVjH6v=S21}F~4HnKpb*WkgbvXOS51$*btgY9*P69sj z)G@aUjqd&PuWKNW^8OiPW9))7&;{t_05uU_#CnqmX5uVa|#pE<(?6R=ch)CYDl3W(U=nZoo%!D+;+EhJB=2Lz7xbbGFGwayLmNn&M(-xLvd$>DJBtOk-{2roikqM1mxo( ze?cM*~?qo`MvBx@Dl7lg;AqZKfO>{gSDU~ra|w?F-{9mbOZtl>r~{kO2g zh2cjyLjj;CtSgFzLkYvBSYjboMfuKh+0-rgpCz7U=9BU~t|yyIUTNFd(02m*+PR)* zR~6RkxT{Pva~j^BlLZR{CV;C5t~fAnu7zm5qa0Nu2u%nGMiT&ser z7#<*C2easm0xBe$GilBV;fl%}U0gBf5e3EJNEsm1U&UP0n*P}9O%*#KCoQSN0n4S{VLNyg zUz14Qdnwi=z66DA>bBT9^}7+2*$Eq?>(U;P=t##T*}I^VEvX4Zclc+wsGenS2$j|% zRgb!A2}GuHwcHZtkf{_V>F*@tEf$W`X6YaIRcSYGsiV+^ zGe2?@SXj;JJ&8y!B7dweFX{5r1v)cD?tsyY`qWTbT1YPS{H2Gp6_C>xiYl zF?^+8ski6R$8wzutaPx@N0p_u29fK;qLYC8TCa3|Tv_q2?~paD-b{L2 z=(z@l)G###Zd*DQOQ~|5TYNA`#4bQ5moC%tV<8q)(W##sM1mZgl-RKL%_l)wGzP0~ z;6%*%+P}po*1H@1)|asfctd$Sy0kEtL681qC7?fxkyN6Xo}CXyD!b`8y;cRyWtSbD zcckG>ix$n9B3pr)RUzC+VVcE*)sY8)H}CI9lFwN0ZEICewTju8{99@Tm1Z~o>-*B+ zhQ{-pQ&?C${@1;4K~O<#IJvr`U{#m-8fOC)K`0_snv1_VTUrELRL%FC$Te;8`cT_b zqU$v7)@jb#mUYL!;yj*3fYs4pUjMoZu;J?B|MC8I%TV87>-(#N+z8ev*|u}#_Sd1f zCELbSW^2GA`5oRH*(J|?@Y`MFl8^U!n&#so@1l4ABV3T8JT^0P`rYT_O$~eYdyjIS zt;$jNs^!gQQE;by=h;N``Ac|f{i(XRGsKqPrTEi;c@JctsCxFFrB0kB4wqvDH5<4~ z?R$hvj$iAG80&oZU-^tgbW$%}C5uVVxhSSR_y>>Oz95(uhw{BCh3Q{8ZB`U&1`;hxnHb3gpKF*-WH-IJm@Z|GCe`aLr`Se z$H5Q}3KNwm1=6C?rT8L^J5Otsu{rL}b4ivZpKZ4Jj<2JI>%VpL1>0#p5PkWw0nt0B z6*Wc|D^|0vT1!~SQ7uFsAs7?hKZvQX%Bx6`ITY!_Rl@;OBtBUGT=JTB?)B1mik?qy zde8nsj$m=zh;W;dwG#8$`(mGV_N&+aGsvr3%-uf6t4Od!DO#!|@x`wnW$&3yRt7Ny z77m_qal2pipi{j%!oGSEz1!{hIEGcb`emhuz2*2*KVYP<>&VH&j7%m+Q;PU>0T%}A z7ZzeTWPQW)debSw7R;D8L&kfO9P3S>REbPQl|Vnk-olc88Xb(owz}WFHh=qDn+t3c zbFbQ|AG57lhL)}+Jg3+fI!S{l<<6tYQF{+{)1!+c-2$CbB?e_$FY2d6HxngD><<%i z45<-R>7Z+#Z(kHCSn*J!(PzV*rrk~JBx)3g9%D@`1KpSfE&V%Z!bOV7Ms_@jha1J) z)$(N1|mSr=ZYRbn0XW2=d{md1!;6O5Ch(NFmGGdA#xS~L@pooHYzgj_Beqj*I zyoE|;0C7+?hd^|cz(W4ioD30B2!Kci+7o&_Yt-9*vy$uRY?J?F3u8`ivp7NPwAxj@ zMqTxF!`pv*>or?^b>{Tvmj6(}Cc)_B^ zR6p<;f&Kw0UF2K`RjMx_*)hrqH%7nR&ar;+9PL!R@<3sBI2^||?$cOrxAK~KgLF08 zf!}u4l^9xh`qKIHj~NT^{*ugjrs_!PjYr+fRUH5yG<_M_cb+XV2PM5yQMKe!*1eC` zeh%Ayn0Rl??Xo#P=}~l-cr)lRC}$IFa z`0DiM$#=fjeCvJ>Hw=W%fZyhnAwq>+618J(neP;-@+dJKD}Q7<}(0vn9RV zCndb=9Rv5=7we^cnf@>5-!Ab3KCzz>XY_SOF>0%hNzDl2zid;vmfs%DZk-2*Pj6pF zs3b0A`~nSwg9w5WmS6-4`yw3AO~7ZW`&$cUce+Zw+S}@Y#P`V6?bI43R6yTjLh5t+ z6#e%N1JC0HK*PE>?zjUE21L)_IQnDn9<6uuEkn1)yUxd~_qp?84ryi=6|DrRFMkLI zM13yYusS?+NsU&MW{0);9y?1l{+{<^DG8l!DYL~S=GAj9zkn&z_ypjKv{ zpTAKcQ51vz4Z_(2Hp?7+?uENx!sv@*l*l?`l8_7;A)$aFZk-WgUH<^_bpxqn&K_x? zY)%yUkgAyJ_%YuK#=ekHg&%nCJP5U8_2`<#Z8&t~afygdS}4=7wPMJ-Wv4p9gg z9toVI=DE99672Qa=-&~Q$-kGa;es~OI%_#Dj9z+Oos zbRpigBF2b^!Mzd)gG6DXG12kiVJGqF@9QhVn_|3_inLhaBiz_hz?ONmNg})=)=nT^ zUB{|sWp}<8neRmQ-hI}!RRqn4PamH-w*a^!>*6i$k@9E>As~-}dVFTWfqA z)sh)OQpJ~<)4p?tTqsfSV$qg@kLE|4#}lip$JqpeK8==bT1tPIrrS|tO3ldr7nUnQ z0P$A=L2!fFtF1v!NNYNsiHJg|PI-RxTdsJ)hzghO^=OTXMq;IH-lLd71O|ag)0HhS z>w_FH2T2e^L(m<17}u{x+}F=irabEMFS;jPSZRDR3$8Yp-6%}7L!@w)`CkAa-eJzQ z4VYWh)u-=ZrKk_XFL0*`%bJi;8tL$zF5{a7fN?NEi)N)O3ST$*UtWXjZFNGtHw+4d zPymLIBmFg~g7nHIL&Ix2WiEFgIm%pXUr|)c8$E!2KsnU24puQL6gUznxWSCc&raI} zhg2krZ>t(bTnT;PUv^^%aANNq{14U%DUPsI{BXssRU^uofoq;9 z6FIz%#CvI1*iBK&L={8|lmH<_G?gw!(g4u_p9lYq)zgkU$QdZhYqOg`PTUez)FZoO zH9KiHtG*m#!*!CJaYAA)d!(KhuaI>$hLKVkuO00%I7%W=d1@)xIF z6?`^+`=#SJ$}4r=?};LP@oQ!FWF2h4s}d}5Km|1v0JQ~1oNZcUGdVGiiX0drfN5aH zXdcjI9sv~rJ^|Rrl=>PphdLO*&F8orB&*N+*{mBRop115{TCJtNx^bZVCVS ztc*XT$ZWek7OZMs-so{hfO}FS;AwGxJhcd^U5SWplJa%l=E0YVQu>cl=yga-k14k1kJ=GFt#kuy2!!MAi;UX|$TTTBOO=|c2@lbG+uADiyetmP{DaU&B|5w)IDp8zbA#2vH1RP&C zA~P)UG-8ns@v(tFor|Mg9-6#Ox|)UL(r!`;_uD?6EG{=Gl0qG*qpCukXK@3eERPPg zL+BM0Hy3zZUue`=85dX`YA!_1@Dhq-Q^=tK^~iGLoIfq6B#h|e?wVx1Aiqyq!#Keh zmLr8=woE3hg)T3Yco zflqrSCRAml4z1aTa#WZDBA~P&5e>h;R9y%WVsU2ZRHn1+!jOSp^6YlxsbtGUvhrw) z+&k{yp@wuo6#c9k3xxphNJm<87ES@5fzC$rK&Us_X5&&AKxHMB8jWe3oYlsQ=@qy1Bh`8hFP01h|3Ir zF7$IB;^q5a(W-S@L9$>~eZ-U@H5)N|hx)-_C{~91q)9qf*m)ILNZ$@2W@EV+?PrJ) zu_jK+cE=%q6l@b47^45?dOg!aw+&rf{;9eJG1_~CJ9W&3_*~yYl$Sw`grvbElr&nH zBj1204%=LCL>8TGIj%$5qgafMh7FV3G+^oy;8Gal zN`n{UA~+;pDn653kR0|{VUjn)9Khm(h~zd?GQ-K}?XjH>iSM;bZh1W^_K{?eG(UKWtR}4GSEu#AW%@LCmR!b!)W)iT`aa z?P^ayHy8o`LlL)Yw2Vm+%NhWI8XAD8A<|TDC6+&q6p9GLNl6Vr4&XJVTGYz?5)V_3 zbW@rjJ8Ob}G-YR*$h{|)E%L|abVPlo0|sYHBbI;D8|}h-SDoX+_sHl|G#mu{?$Lhu z@?($s?yhDeA>0@A=zRe>ggm|z-w%lmjd0tB7jt0XS%;5M!cH5;^lLG0(~uO12q@AF zpt((M^vVN56G6-sN-!j$B7n6e86ZdQd^7z_rRg=5)q>FD^}t;1{jT`-!JoGKF={7h zJ_+yPw)y_lhcx>8*4z*0xgPfDym-R1SC*RP+CV-eB!V)F$|Ny*Ai$ki2tOBkAQs93 z&t#zl3P9#BYZQ<#fgv&k3Tik}_`L!>Vv$r+6zc0Cew1`iGiKY?t1(ZG`CxU>Wf%gw7oA+|XsbY{yib{q-RV@U>CuS0)KZPno9Wv#_iM>qN7 zDM@>LbzLqh^rU0rflwhLLSkOceUBS$;#?jUfT98_n>I9rz&Abt$>95;x5HKq5yD!< zv(^LtIRHgc1rukT8PYpWKemyl# zi>1A_%$1AluQ*nrEikn^YfzvtqG(Qa1-;~fwim(hey2_o{r;MnAVo)Y=aEOSemO!Q zrD88B$yJVQOSBSRht5Dd7H0~ZToic;xKIDFRwQ7Hom1HzJg?N;?jFM}#0L|rJuDDn8Y+y92 zS+rbiBW-2)Y?P*^RD~qO&55piyIMx_ty9+AW^(uH=MQ1{eU*?JxU*&E)M9oqU69WB;`mD@_5E4~D~jB7n~esRt3;rvZH z-L)4Q&L1>rLO>G3)CJqL?u6VJT`9VF%X**81H17u{0lGT6w;sj?s8H8{uB;eC*NhS zw=}KS->&&WwF^l=*T52wh7P>!#5geN?(%&bGW3St&^9MhOpo-F`u;OF{Jj(H%i0Z~ zW3?UfP29yfD<=#mv!vzDD3ZJ&R7yz($nvulZ*lCf(TP9{fce;ASx}Z{a=v+$#v1tSGBTCpI|1T4<_G%{X=7^j&iHt z^aL1EuI2?bw|oya389EdghAtJoW0L*E!Dy>j3dR^rQd!q^KEi^f|sz|B@XpQEgKKV zbf#BG*tiap!1i74=(0n%Mum@Gm{c-N)(3}Kp_fY;6c?x9UDz&eg1IH?u-s5fX;fs? zuEBy{+ak46jop$?qhXWY6f4NUnYp|IR5K;|JU};+&fA2 ztU8~Y17ww69VMB4^xvaD_in!J-9TGdFxbKQE8|sq3P>8@|X7?r7Oqpe_i*Bi-VZu z5!hNvQY6BOM3Of!I0>wV^>a~bTd)o*fIyD9p ziBxpFuSS}z7Ve3hzji!1F_UF~y0D8#i{ieTL-_@>AYs6T66V7Dp$J0?EW`Xkp+t5< z5Q$c_WPx*{Uj284-zX0U^v8yt^e^jbarBh+@RXDtKN&63MKy*qoFLUl`bL0Wzy^5@ z9c8qfy<`MBh>8`K$q+7~iqR3wHu?^B^b{^=1PovYhz=_zFER%k0HHC^Wt(+FZa=zw zIY^ahv5H8Usg%OM#0g`HTjY{b?ja&r2wpDym|cOJT3GO7rhPQx5m&4h)K}GFfIjU0 zl3zh)2Za8L@O$O54V5&k!)u%1g#qq3k0v!bKl*{8@D240(JXj)XUcdiVI>`fWdSwWc5WSthDFJm)7^02D>l%ojXTy z+tXq;<$}NGW*=f=?7TnkpI-x;g=5wpz9il9pVOX+V@7ZAD(kj2?H|D%#^b9bxu9_Y{iVOn>2}r)XbCd$cporD9@y#GUy6CBUQD?%`Wb0N_6t`Tv#x-TzOT z#s8@R8hkEc@ZTEXPO=;K|L`ow=LcfL!4FGM4*zSL7^C03h~a31hT4PW9~oww z%sf>wJt(_)@Y&Q#yJYpY*@-ct_9kI?3Rr?!HNb$e9~}&-`K1Z(RCI>{4S(n_s49bz zj9a!7Ai4Guzcyt2{MOv@tnF3(u*zNKjBu|)qg)w#sS*%CTS3sL{qT$JeBBFGji297 z$M14O?EIJXey$!9v{Yd8aaf+xUdhh+eAyaGL}90Cm2{i;aSt78R-TKOiu@jQ?$W8miA1upL$XAY_ z8F3nPUE*k%%J<11d+}EaA%$Ru;A}tuxEmjNc&H_9zMA?ZM+7Z04II&wyOgE>WVsX{ zKl4$1_|AlLn^?^}@mzSVyoFqjvl;GlJb@2~sIj^$P`A&}ahPp7L6b4GJ8MY)}bV`f9MkQ)pB2ZcW1uX zMX+u}lbebPQw-3_Jm4D1LDYv~NaGlIO= zMFpd=@OUH%v%hHbI^JIZD5r|U^e5X_8KX$vcmA4NRLzeLna^52bhNCFt`a|6$>}}r zv+!LuL!#;NASAa4i}X8@CGLLerN&gk0cGJNctnwl78Odg*qv0Q*qO~A6^(-FP!V%6 zVTO$M;F9iQCLqd-D8Z7$bV8@F^vPyej7%q<%A0osfrB_SJ3 zg|ns&Mn?GoD;vM(@nDwm(V5B8wxJ6pwp>Ba=(jDjU5xpdDs2IOLa`+JWB8juCC4485ygtW-o#no2O)@*T z9yO+;EHuO)Y>1~Zn1>{^aWAOB0xQ{_5#JbVr68DbkpRq6vAIaFFk}D`Kaf92Q?!1f z_A$ZbI7a(8z)hB39$#O)$dK^xUXb&CFXIF@*vtrPLD zpLAPck0#b6X8~yZ!CAWRT-Iwy&%KiRR6?%D0Rm1B_?;Hpt^%H?4SoD|v-OZai2{Jt z>5^U0Ktn|={GZ&(2T^5upBimZu(e%G9XY8%I(#Ip!bt!k1m#K@ z6l#)cDUZQ;V4HR*pqKHYr0%wTqn_o^6&J)yk5K}p$xOfud8q5Q)zt;NX0{P%VFa6K zPUPy)HAwG(FE@0LUTunGrH~SC(`ANs$aSO4_1hJltd%8l2mlaB4k0fz#U?RPyGVt{ zHJD=#bSVE8UW&@cT+LiP(XD}O%vjFCJlL%TTgDjaAf+(O0!Nb!S8KS5f4=&t?#u#cH~s-N!|Ne(JDk=- zc0bUq(M!FXNmesqyKTGCj|YHC!a~89+`v7wY(xlzWn^?*e0+ysujXI7NdBYowiI_- zxVRJi-MAVj`cc!&E4{dgR*aFZ)eAlOD1#chWlN-$*FXAB!aq3NifV~BMWrwf@DK-? zn+suip*!t&-ahnrvJ1J4>%8G0!Zr3b@;R4jWa0CMTn!f<{JL%WmB|!A5Y&daW!-QF zWZ8ys+0pb8O1-4?xMJbB*n zbg|*=(hmpc76ne~8*Gr#QItR%JryW`tkz|JmjZgH_nusHkrzK48NDfPu(5;j9U%qi zR5{y12w^IUj6aAsiB6bg1Xqj*3s)mw%D_NT5+2@?S*ou29Dlmw%$~7_3v(NHg0=jv zY64;bXdTxfS^X#On75n*@SS@IKoJ`s3G%YMSVJxvtl?C~iz`Ioby>PSlK&7yNKRZO z0)S@NHPRIO-|9Pfxz#b*d~mais{C2F47uPN$=GpsO&NFkyYrz{<5^2>F>A_1>Vj<% zR!t6JT7Q|F<9FfXCk%f}7klbQDZ1Kj1$jUfW0>B7PuWivu` zgr|(~--eH62;aQZcjMtZ#IZ&I5r2TEZ2s^-ngfzae zSFH38QUJI3dNi4xTX$oRB(pAY7`bb|`7_*?5kS5|$y&Fd=G$uM^BD1onfqqymr4S} zLqgemUn`p!vRoUx?Hi(-)|0lZBUm?S2N<0+C)ph^t&TAgg(x#x#yES=sGS`no%?c$`S&2 zA!Ucv+|RhJdyR17U!VOunDJoqGF1&Y`ph9Kkn67`OB+7AIHgpOGg1!>on3Je^C}+T zW-pN>(p9IjHgW1aQN=ND4U`ShQ1ou0Wk(n#QWw1R01RY-Sd{vkY(GfYxIsKv7HEsF zb(&%yD`ZElMbQ!!Mm1)ONuc0_0>6XI$|n+P6tjF@*SltM2c2LRl)L6grWL%LWT+wh zF>FA#3oyf@e+E=8&p4yngcg1hbI%kmm~|D&Czov`ZAj-*4jCUGAO(ix+9yNgMpO_=8JPx2~epd$a<2W|UuT z-jbB&)3zhQ3%qp(h{o*o3xY@mf`oWBv6j1=c7a)A&n|t4&J<|c&9dEYf=?X$t>-eT zyDV#uP2a0sA8ny>;f!U2Loq*bk8C|15m(rOPf!zD<({J30!0^>Rhpse)z?tC#3A{F z*8_y#Y9ofIIrT~QTVp8wzuz@Gho&V_J@%_rX+k9fqa5HY(4f~r@ni*1p~BgX+BT%v zCb-1*(RB|xrUOVrD5r$!chW0A4=0{LI72Sg=e>`Q+>R}9GIUv&8DKV`g^_N9GFriv zbFo$~WWsc2QEOpRpyI^*cLbrgg<4+$)anJlK)-2mgUhWyIm?5sVv(GfLs*{yAoAb~ zi=*0a^j=!D^UDT#)+93YAWxW9(U0<^=CCepz&tYO;;u`zCQez z+aL%%9h+zJ&jI9w~6d?Js%n6}OO>WhftB8AufN@kAi zOL+57r+hmm07UA7ZTt`Jeq7&w|G?PYeA#iynIcgu`@QqjvhG6OPH?n&rl zI2TJMw0QWR;*D$VLkX5^=-&X;Tv>A@@{i*ZXp#iNI^RhL>_7Nb8_yXoorTp=A1{~t zCm|Bha@B)%+0yIHGvacxNNFL&o!-YAs7z07-iMM+0b>eVR{Bq*;f7pas1>sXL70Q< zAc+}9T>SOWN*xlE^lP@Y=J)Z(7#{Vvk6+zzzE}W7VKk0+GM^x)v`uZyvltr7_m>%Y z5&5$S%8Kh}C2+;cGJXhq7@Nj&t&iCXF~8@Xs6C$LaJ(5`;v5PuB1`K(EWDP5>c<1m z%6(+yuLickD7hII#7kZuB%{ppRdtHePhlV^R z%nxOok?qWdlC?MDGx#J9Sda_wxQF^>tD_N>|D_0Zc;W{_{Z<@onn;sQr60-t;%QHc zW6wI7KY88y>=G{Zmwv%`fA@riMJph-``6;d$0XfW%_BP)I(YpIj*LtsIe=o1^c-{6 z9`IlUGnsGfUbOWkat<~>7PLNqyTDTLTTk^^yO1?v*c#H9-Jm{TTJV6NPcDM1Fhkg? z|HM^rsP|a*vC{A?DyxY|hOMvwE@{9!>Fq3-TqihH>+o-N7pkG2=4H+VJWQbJi9va0 zTc3!!fpfEHzUg?<98?afpLlo6;_1sP zX7!lYXYlqT?J=O#DMFVa7dDZ!kAdVi+bRU+b&P!>QeM?f-wzHh|AI`{DE+n67^1)h zi?t4z0QHM^=|OwDgH%jhkB+I%_FR~0fumP~plVku%;n@p&D_Fw-*oISlFVfy%jt#? zPk<2s2a>K%NSuW2*?Z5GwG7m=?iLBLq45Z>vku>UU_LU2FkRygEoiFfp=uHs7HX>y zMyxU^Z1VmXa;u(RsnF9S1K{FCLTp(CZm`8Wu(`S;9x&pHD6nHS_hCx= zYT$-*hls|x$6nU#Pv==@^2bs>@Yz=*Z-tMMQ1n(<*g!)l$nmFjVdW^~$?q)_>Ek@N zb@z*l7|#o!Jsb?pKP~vf%)yc9du?z}qF`nkP#}<= zvWifIbXz1AWG*K6KGsrUo61IIf74|^vx3lYTCJJhgp|NK(@$2ywv+m;17V5MUyeLk zD>R>)S&29bmMiAe!-F%PW5wCV3`!QVB#E(wDRqyqnspz9D&E z1*xGXR$J~<;}fR}$KxKcLrY5}s=!f*CMNyGf^viwjisP10PR!yE0T}FgIEG%;eha1 zwN;_3m{Z{L1!iXi4Xd8$92JRF4N8|ux`ME8T5h3Mk@>dS7!v5(M{^>=B5;1R2o{6& zDMu;n787eJ3BC@S<0qT1$4$;%1j06VDv(9D_lsr_D{E-uSN2vyRYs{{>COC zP=>;T-~dJ07-I9KpUx_d4BWDBBC#*laXyZVE$VL-R!!b+FH75 z#y6>;v_(xMI~a+keq0i1X7==Ky@o0H*g`Pd^4vTk{m!q&0ZtbtP{>&9tNDda_LbzU#L49+H zI7Kw_4Dak?^+6Bv-8zI0PjjdIP1D8wX9a~WTW|w*42rXYfM!L)$SY!{;7@r%WIsrn zoXp$N73vU>$2hZ;t@izgj*||)3nE1L!5D9~?^)?@fr4vl+4GFD1IF}Vo5rTUk_kQ0 zN)<_xaruaxyG@sT2?F00=X}dRM{vdBU0GV!fX}7iH%?+VYtpFZ4REtZ#*a@G7sK-m{umje2+*;%gKH8x94lmDjHOg^1vOCM?fSKOUHUvO=|N^* zRX-3=8BHpZ6bX`+3M~-95Hq`trgyAGAXbJv5h5@aB>GGUNcqu?#0&u%r>xLLI4q~x zSTcT)I5K>sJkKe$QR`ZGRy3*4LYpZOi+=>gQ=?d%#!~A++?Dz@;O~ctb2GdEx^dUB zuZw>N;D>cWU~ZK?NQ~Jr10+_>)WM`dkkq=Nh<5Hy0X2kXFg!!q_c^hqj#hmWP_c@- zZRdP>TnL^r($-eNHtNYT)Q*&p{)vGa8gOyzfWlO7?C4$^oO<>xl4T_{XV{q!Y6HtVlgCn0;q&QrW6>J>gD$T4V zo>7E1rHRU%I$!N%W519iEytdjFjWugvAHbM#g_Z`a>79<%zlmss4o-nq>`<;SEIpL zMyXFzSe&Bg>VstyBS7Y!mie=wo$O+>V5U1bZjCjvvP;{9D>rm%mqZoMK6unmiuqtX zk+0s9A9yu`jcW{0tLUvDGg+j24K^UiNmvcMAWZf9Q|EMFADAS0FSj_@%!xRJ!t#Wk z5Ly0671PNZ7hgY&NhVvEvM;-K&4r(G&&*|$l zDBr58el>7I&yOq8Uzg1}C+c1B>4r}Uw$}zVs)7pBe3L@xhOv{W zU$Ong%UB>o{w3h--o5x>!=66cu66Ao@HZatMkcC}DWc_OC)2IC3J;nVZ^O*lsEDT- z49}X1i^nxt!!8H+HWQI%vxPW!dp!^aC1Z-1e&$jMlveL#(_gq(YV06$*dqh+%3XRV zw2WXlh!=*0M|@}kGM6vnE@dg>#7j>?6X-FqYV236Y8D&qhH_J2#bo9&`9;_-s^Bq6 zy_+HOnyg^->JCF{F79czt~h*qAQ>vV3#W$wMti-slg_pO0H~UUHi%+@)R*_?S-88D zai{l-4*g%!{+8)NRs^oWP~s2cPv(IC1gBPrO<#vE$Z=k@TL@I*brq1al$hBfky`XG z1*>z#^YVeA0>avHGy}q}v2PC!4Pv0}dNNlDKW&0;ww9~f?WdsE*&!owQ&c2Z?De3M zCA%Sv>Ic^$!{zRAcY}e8YRA6yslxDcBYm29D^FKTNj;Q3zi+IKufwUc-!6GZmW ze98Exb|le6qVoa9s88eva_b}=1DeP+0V!ls{AF8N#NzOjs%-4icm|6$8{iC_PT~OL znBDCk>bn~>J||^1W@&~2#d1EUUbq%t?(73&p*SP(dlK?KqFiOxuXu@zL6K zDw9C56x~1HiYt(EQEsPt7AeG7)`|^M@ctMZL)T=xN-am%5ricX^{ikP%-{wupttsF zjw|jGn)&-0?tV}FF};A#Oc+RtImch_ozBdBU7VV^wAl(CXXs z#6vF`4O3tK!0ZG97JGp0y%Mzb53m93MQJ!PK}@TFwYG;jKK+c4IXDkz^JIg z?)+!}t2Aq&yx!LOY?~7>c9)uKdKqdN9|=PVBu+0(;A0-saE9z)BJHMi!Q?)KCe*EI zrW3&vLA`5*(~ex^b==T=a-JqYLn&Se_mVDZ2eKbSqN6OG$FFQZMsGiyG&Ta^ys+`!!Npdm#XuX5iEy%60*50$u~(4o15kN1rH2S&R-SbD+i3@a8!Q zEtbc;IY;SN?B}mFfWSL)aqlJEf4aoUtb%QdUs@>d&B7aAwcf~wX_nywdG4`=@Or$$ zc2z*q3E}zr6y-j|k~JXcNdzFboA<{bSY811a&;9XRu68+aOwJuRtexJ*tElXo_YWT z@8Zhrr}QMn;QYd7a7%we;?&b`O#mYrTjh2*PDqf#Xsx?7^;5X${Thq62*CiEV4EXJ z_Lc^-AKiSY9dKsvJ3lhRpoB$jf8M>0^-dCJvjBonaL2}nAx$m+k>%kW4~ysh70D(i z?A&at-mLrxOZ)Q*wYc^Q>9yUyXmD}18H}-U3x8UBbDmQDCL>K2h|00dgWJ4+FSN6$ zo)xu!V%LMhcN+MW_=Dmonv8h#?mfe_!QAvPAW!WieW}!*M8U6fVybv z{}5@crdunZ(~@K% zUov8kTOXarI<}gakS*v-uJ`+6IcyV8u7M{10M` zZcgbF4C@rFqwtl;7{2Xd$R!?EdBB&FjEzm+--3C-L}lWBAV^drTspfL0Kl&LPd^a2 zJjB$zx7rjVaFxy|CaQq)lew(ZaAjT3;n>YaQ&7avtKL*sbQbE?b)`et_|WF?c6PX1 zO5g)t{iEX-RCnLMNz#etJ?r$iWTD@Gg8F19n^jxgw^Q&qbTXY5X`XgfH%gB1N{dvR zE*6!Vs7+Q138AE2 zg`>;Zpm7{UOb8V^)>5k&BoiR*lm=>&|Jzw+vaMm}YRqQ|xSSP3HnU^>*k!&Qd!VjE z$q@UMi;}^Mo8~bhI${=BG})fq&viN7v)S~u!Lr-<>yI+%{Nr||p$xLnRf5|nl|zn& z9k2D98$inMEv2O&RHDCGHDW4SVvq_sXky-E@GP0jh+6!$Z8y)QKlrD+Nzr}23^M2E zs~w*IdSwFiJ0Le`4TR9yPTH)E{XCPSA%o^iiZbUP^=`@>PKcCH8M;=p>UUzu_I7|` z#T+|J_wn2xstB56^s?iVU|BJ?rEy*_jr=H@pQ6sksbvpZ(GEMC<85$M!(RBUtf(wU zPQKqJlZ_%?H*aoopN<(EciBxn#$9mvi#|IJ(jd&djET@m5*5?t4N-x}$;{1&VWSwW zvHO+X=QS%UI1i^>z$5sfIZTze7hSurM%5o5n%=lW9@wD@MA2rz5i`D_N&?V%_Ue4 z;2@(Kk7&h~G)&wXA z(T7(U@`j|}U`*||tAtSL@($}n2Zg3*HlLNVQhU;Sw4u+V_f|wXkmaZAH<#3GqXrAr zkniL4;m%%xffwnJq1wg)<~@o)krG0nrZ6UE2N!oY9t8TAW^YTglS0*5PzM(s8s&hw z$MdpXCfI8(;DO}B1&ZE7kf$3}-o|Mv4z9NwEpA|87K%tNR6e7=0Lk*JZ%WpN7yvCY zjBQ2pS->lEmS%;|`6F-H#xk*{HR@?{ zqNHcgJqQqIB)lN8s6wUKf+Uzw)Ri?0sUaLr=z;wn=bC<%ioiA?3=^2zCeN{;?ojr< zU$ZN^F1Qn}t_1qn+L+TU3@Nudv>^a>dvP%{jIl4R_JHq+Y2gOU^~!IgA$BPaRUlff z*G9P6c7&8zmIvowEgjo%offdbQa|lOK!E*4jPYt&Jfb6KatvfkWhY7cfe>3x)LLSQp46xRfg}? z|5V827X3XLb(#WB949c#qw^BuHAQ~*E|gtea?Q@Q=1fCeU1t2?@ARSzbSJhx>TnYZ zERmcP&ctpeS-*r=9hzIl*xeB#Ghsm@udw-&eq&`GMb@b0*nzJ2t9L|eK(~4mVwR-y zsT7MAlX^8b1-M(fEFXfWFw@9Ra2isF&6pX1Y$b7ZQzjH6wCRHv{W6KVdl&M7bN%GC z@XaY!&NigxN8h#u_CZSKGUhtSXn$N~GY}d1er)b#+~?%}l@w z_m^OF-D>Q_QD~$eVp>%?OgD*DvPX89eVTO$&|O73sfEQy=+54vD|6)~G#FV(31^?8 z+V_yqh|XV08MJ3GFcjgLA+S0(X>AS<-dq&N{@T~w8BkLlcgps?OW0f*cyut8yz11u zZ@H{945btTwfw58za7vUYFi9;N3Oo|vS>np^yb%A-=zQSpx@1^U~B&=`4+mm~Z6n zNS@Xr2@7>+PwR0}NEvG93f{Bs;%)d5qr4ly{&!9=v5- zyusq-rK`(Img7a-_N~SND|!>S;beg>R5sHGL;G17uZzQrzPlzJ|E8|1JZ|$Yir2sz zX>H=fp58%GWGcvf3x5K;HzKC4gOE=~KN8!aZ0~slwtt{il$z+{09ah1YDUCHoEB18 zi!tr?=p!YD(P|s}f(k2H9q#!3K1sgixSVJMg`)wd`NSwWCi53AUr`Qu{Hje?)OxiK zWVFu(fBSQ{`Ul0v(?9(zp?w6|45(rggk0tr%K}S8-8fm}4o`6{;J70g6jc(!C&`+0Hrl^TW8KgzM?RKFS#Hei#QMx7W2W_ z$&l^KSYLAo$!7ZzRQmhfZq03+C#bl3c*!GB79=W)5Tt$H4pZcFAH{u0Q`8%LQZt%) z!)#-U`YC%tJnesnAcKQSygos1Hb!U?$10$~#K8yThUO{?R9o|u z2XAmgdB0apz`(2NwzP=Sn!zpz_`xpd1+?M~uF7j)zG49YZn`jY2$0EZ0?;M$J)G6L z0?^8Sidnp`Vmje9WE}H;UGFehf5l6LL#=!oX7HGt8kC3DGP!yz%fUC$VOD8`wrM#R z8i-RG^<+>_`z0o1fdgyMv(>Z2Y}Kx(*k0SGT)W@RI&jKh{)m}GoRzb=Kh|{ZiWQLr zRHeVzMpDHXE_NIkEwm3S<^-rB6}%o3(siH*<`>3li@`>5FYLW!utcZ)+8Xwg3%kG+ zZ+9IxHMb#xH=cOvyZ0J1Y}-v1bCoEmM@^Utw%O`N2_la8rsCFDUb4Csegpgd#CmXR zM-ru-v<5!IISurxgd<~rzc_i=ZB{W$Xdv|itx!fX8>*)uoe*L(E@2}!rhK)IcM~yp zb*T05<(X)gjnl()Wek-m9lSo~nZVQi2-MTZ&ETC^K`>~mP_+|<-FY8BzqW#1Xj zq?$#Ex#Kzt-#H6GK0EM7H*the=+y{7t+EY5T3NKC++lh#X{T>Lj0 zjgU7J;j2~hS81mu01!yZNJxYx|MCrD+Q?<~l*FJ*8P?`x#kz4ug)~HJ0$@EsB`t>( zQ{fuDp0@P&glNFA@A-%85D`jmg2I;}BK4SdT2@abE?eE^b$0HCYpW~{&naJa7S})?Mv7?@sy3qo8(r*u`pMjk}@ZiV~63_6R?@J z5jbQ0*FR#6Cn5(l?z^`>>+80y_ag20QEe~YFLL1?>9q^SwN++m<73bCHn*?r(ysFH zs<^uv_I|krtfKSCJ8-9%$ynVG>EloX2;-KiQ~+or=v+X&CIrNitlP%G47j4ypIS@`0160&jHSo33NZ&L-!8FLo6;A=##5JGo#?6*@ zENji>fqD0jUtf1#we{FjI*zn)HXYyk-0x1@#N+2cFlddDg2T!()4Itlt_L(9_D^M- z)uUhz(?6WUgf_;wHX@ucit?iQ)FNR_aO{Ct?%UcabRrP)ezdn)$>L;zp`@{N!tOZ{ z!QE(n+}A>rejjNQ41P<#E5V5(5?NLvGXi)pJqs06r&}{S(Y)}M|=OcHl8D} z(jzCKf1HVS-e%oKqWHFjvS zwyJ1!QpBFHz)d5a|52&Nu$SKXo&KH9?*ntlbe4(lEbN6ugWUHuO7irFTY8}O1#Y*v z1!0oU;lPI~)sr&a)&xP)?vIZe0YG+J8LFAjwU%DTJACACuF-YZWk#)r=MvO%JY3pH zWGdPi8r8DF&|Ov|f$087kv3MsA+UX{vhXk-+Na|K0Zx>MJ31~OgH~OFnY9*=V4G;6WUv6r-^PHFr zceIaR!viXIT_-Cvf2x{&WpwIvs_0w|^9sHs;k`$Vn!ygP1q5}|7>><7?1 z30ZF%kr|9@?1z{Hs=X*oC$dn;UhkoCylwt{r_M@xWi#o#`*(5~u$dnD@%FdMp~p@E z8W5;-VkX-oPNJK+^oesRGM=OtMe{87h&gF+u>q>}?14Rv{$_8nICf zr;r;wm_~tavpR>N#HJ(lui^*&4l^9-PXmUAt7~nAG$pbGKc{?`P zz!da4FNz3T z7Hccx)guhZcnYW)2M)bBQULBZ0D>}F*Ih9YWu239DK{LZ7&nS2JQiHBu*XVj?YaV? zAC>3V1R$l-BJ~wtZ|v@8;2XIGGy|Ug@pzq{1_8nIVVcshP)3Uy9HQA1F^;6bP_o~9 z+(a%bKNhgBJH(JklOA4Ryte|`SlrHaS}$q{a81r59LY++8uX9Mv!|V5W7h;ck{UyQ zh<4^N=CAQLmlc}hwDlYiiWiZ5p8MFQu^4mJv&55e<$MSi>4Ffcxa%urR|27Uj)<&C2x*h;Do$LWIQ8DNy70Baci zI~)|u6KF`Rq$2Dv5rcagPv`1DN`q6_Ndl-M0Sv z!)OL`O|afyurJcdv(4;px-ygeD2jZ5l!!7E83h?upesgB{P4ir+qD;ZI27F?Uyx$O zABQE8kN^$)7EbbdRjWKN`*^4O+KtM8YzRTN8cE#f{sqdQd;`V^tp<9Tf7P+%Pb*V{ zQ9>J5RT)r@E9cJkUw3M~etLit1Gle+s!6hfpJw%TIc@N=;m)Lhby%*r9bOEFi z8@4A341EX&s;lau8VkXc`ersWm)V%RDT*sA=7*wjX?QZAs{EkP- zX@+C8^d)6gJKarDkn2}Ye9K?Wjv6hJwu>u{@5FjbzF;|edG6A->aExXxOo|5QJL54 zbgZf|kn_tO7X<0r<-=?_k(5llJ5+zMmAX-w7*Y)1B3jizlK7dYZS5Y*cw;1iMzi85d@};aATynqbRhj^( zFs&OC7Cwo^g3t1F6@;~Zr$CLZLI!js{uYF<4~rj=&K|fV`8xj`{&(9P=I2CcH~>(s zNOZRqv*Ye__OuS%f2NIpPKCENbaMLX#ANc*JxEQ?n&2CzPn+H+uW*MOUha&u-qobE zQPc&RPO2Hm;Sd1)EC3Hfh?EU`q*>QyHndxDp@l&8`^nh*L&7#YitPY)rVw|4A(@K# zrOH8yaf+yDJKZ^=q*vn;&5deLHMiq084nv{r(;fi%Tigs@4z>fu8z0f8s+iUhvAHY z?-zpY-d@+eeO(eh?lj-#$aA9#QXG`KVii1yIcQYER@pE|^heA`lG*kJlG#~Q zVLl6C6TRC!*)Z)WI?%Sj3kZFPE5^O# zvJ$umKI!HK0n)m$?Fk;yAMqbinvF+RzOBQ_f$~yotnq;}!ohnU65ub)r3(TOvh=Ax zJZ}{rRJ$h<_IonOSGg1D6nEw`IQ?I zN>fzZYam*ZE~sSre-87nfPG}Ae_?UsrF|6)ZiDj}KVC#@5(2;Ro)$4`>aTSozThJr ze$jMWd;fZ>yJY&MC9~NZ_nU9_bwtM-#uRqg?Q)tdh(&J$~0ir)_g_^4hO6;wN_S8GVLef7!HY(^4(%%^X=K@#-z#_O_46k}J=GDL zna}t8{p0ukcw6RbYl8ebS$X15h-xC^hE;p*M59B(pX9-#K3%d{&`W@ohP=W;;xAUU zC7&@vNMB&YKy!nQdi|Zgy$@)7Zi6+M60D}{!*klfHZis;)PR~%gK9={kU64e5}Z5* zD+>o^o&UY+Cf8$uT09gd{W3<5;+`f6SAf&zD^binZ27eU`%_md-(%w!(h8MyOZMQ$ zj;dz8L0{L+>UQ~{P$PhLw=#WLE<4Z^w!U6fP75mV+U1j#5w%E5WJFYA5&BQvZVu7{ z>Js@ka*iyUVnkN=e^5*YFO{6EYOVXe;B44~7v>PlCZL6b*MdT<=2@mTeXlv$vKJGK zK~K~dh9SKaSoAk^p#8XPok7m(!=-ZdkvRPm&dJx!X0ji290`n7cW~U0S{Jsn6c*v_ z30x!S|8xrhpj!}G$_KppK%i`3s66n28pzrVX`*?-2BB?jVsimu=7`j?M$q23lfsN; z{uru@o%vd^TMAi=8RjPg$%r6)qk9#Xxf2YJx$vd&SmWP`=@bmTg0w&vLJ)aIn3Cu9%Xt zp5J{+`-?E=3>g8&e=Zrz3I9sZEuy94-fDJLM1EGdqy8_SOh0&lh>kyBaGGI|6TZ#eV# zBTc8VEKTu=qQQ#kB*^I}K|LqfY7OL-#!mi^yYnr~pSfNB$vmCMe=Ba#&F(J&>(yHJ}bBCV`EMGKk(C@%Y`&+}eHS!^a zX>WcwMy2!5s4FAQ`Y;nr=wTL-df02MuZo=z=1Z88XkC~RnF3BxA_BSlhfp@VP~uuiiqKCFb)Irnkug%{k^Nu;?>7*><5C?xW3V_;CKy zF|Lrja%~k-yD$5YDuuMz+pO6lYCc0PLJuoBP-g8$t%ytH|GCP)CWFp;l9*RJ~ zNdh){D58-E^e74}K#DljB4mAAdw05A7JvC5zXucng{C%2+|?3rsZl_nviJEu-qn$F zobb{rrzwgb9IPU7Pv-^J#lk++BQ7WHrigijbJ~852VaxYk?ABAH75QF!Oh#v1Bdf= zcau57#JdyR+;O|clE^+I!8mCK5fwL?yc=f0P& z#*YprMR&Z)Gzv{h>3e3qk-t({J>F6s_!PC~`)k9{5xeP%OT^}pE@^1qgc*eWNvphf z$|3%zOTFt2{n-`rbH?iqMq|vrhz{dxC(9bTDeJ`_t~Dc+`9=chn!*XEBO$eTPsqnp z58tVpph7)U}HD6N+)pAE9iEWBn9ubNH4q0O3F4G_5`cWw`uaZfP`en0uX{%C|GoA_^K8aV_f~zwlo-|Nw*Bz~C558(#JaVFl#8g* z%cQ&X1`xM8d27(ll8;{oX#dyl?&klL_xqn0wB0= z;hQDlnGGa!ZwcOfP&e?u0p5b_N5KLcTMWe)yFIs3DbAIx3IcKOgIjX5cWs+?u#=I* zcHH)H37f<=&26}yh9_*tZ8f*ugn>ZbfIr1QTHS8PZ8gf^#SyKx;dZpm;PU<_|4t`} zO=52Nmh%K};!c~1&BRW?dv~X;#dZR3&*Uy~n-LnzL-_B4w>_J;rn!A}GtS@Io(*(a UJ4+!j_YpDRS^_F{jK=--Z|F-KRsaA1 diff --git a/build/android/PRESUBMIT.py b/build/android/PRESUBMIT.py deleted file mode 100644 index d8e5ae34bb..0000000000 --- a/build/android/PRESUBMIT.py +++ /dev/null @@ -1,57 +0,0 @@ -# Copyright (c) 2013 The Chromium Authors. All rights reserved. -# Use of this source code is governed by a BSD-style license that can be -# found in the LICENSE file. - -"""Presubmit script for android buildbot. - -See http://dev.chromium.org/developers/how-tos/depottools/presubmit-scripts for -details on the presubmit API built into gcl. -""" - -_DELETIONS_ONLY_FILES = ( - 'build/android/findbugs_filter/findbugs_known_bugs.txt', -) - - -def _CheckDeletionsOnlyFiles(input_api, output_api): - """Check that a certain listed files only have deletions. - """ - warnings = [] - for f in input_api.AffectedFiles(): - if f.LocalPath() in _DELETIONS_ONLY_FILES: - if f.ChangedContents(): - warnings.append(f.LocalPath()) - results = [] - if warnings: - results.append(output_api.PresubmitPromptWarning( - 'Following files should only contain deletions.', warnings)) - return results - - -def CommonChecks(input_api, output_api): - output = [] - - def J(*dirs): - """Returns a path relative to presubmit directory.""" - return input_api.os_path.join(input_api.PresubmitLocalPath(), *dirs) - - output.extend(input_api.canned_checks.RunPylint( - input_api, - output_api, - white_list=[r'PRESUBMIT\.py$', r'buildbot/.*\.py$'], - extra_paths_list=[ - J(), J('..', '..', 'third_party', 'android_testrunner'), - J('buildbot')])) - - output.extend(input_api.canned_checks.RunUnitTestsInDirectory( - input_api, output_api, J('buildbot', 'tests'))) - output.extend(_CheckDeletionsOnlyFiles(input_api, output_api)) - return output - - -def CheckChangeOnUpload(input_api, output_api): - return CommonChecks(input_api, output_api) - - -def CheckChangeOnCommit(input_api, output_api): - return CommonChecks(input_api, output_api) diff --git a/build/android/adb_android_webview_command_line b/build/android/adb_android_webview_command_line deleted file mode 100755 index 947cfb1eed..0000000000 --- a/build/android/adb_android_webview_command_line +++ /dev/null @@ -1,37 +0,0 @@ -#!/bin/bash -# -# Copyright (c) 2013 The Chromium Authors. All rights reserved. -# Use of this source code is governed by a BSD-style license that can be -# found in the LICENSE file. - -# If no flags are given, prints the current content shell flags. -# -# Otherwise, the given flags are used to REPLACE (not modify) the content shell -# flags. For example: -# adb_android_webview_command_line --enable-webgl -# -# To remove all content shell flags, pass an empty string for the flags: -# adb_android_webview_command_line "" - -CMD_LINE_FILE=/data/local/tmp/android-webview-command-line - -if [ $# -eq 0 ] ; then - # If nothing specified, print the command line (stripping off "content_shell") - tempfile=$(tempfile) - adb pull $CMD_LINE_FILE $tempfile 2>/dev/null - if [ $? -eq 0 ] ; then - rm $tempfile - adb shell cat $CMD_LINE_FILE | cut -d " " -f "2-" 2>/dev/null - fi -elif [ $# -eq 1 ] && [ "$1" = '' ] ; then - # If given an empty string, delete the command line. - set -x - adb shell rm $CMD_LINE_FILE >/dev/null -else - # Else set it. - set -x - adb shell "echo 'android_webview $*' > $CMD_LINE_FILE" - # Prevent other apps from modifying flags -- this can create security issues. - adb shell chmod 0664 $CMD_LINE_FILE -fi - diff --git a/build/android/adb_chromium_testshell_command_line b/build/android/adb_chromium_testshell_command_line deleted file mode 100755 index 8c09e3f386..0000000000 --- a/build/android/adb_chromium_testshell_command_line +++ /dev/null @@ -1,37 +0,0 @@ -#!/bin/bash -# -# Copyright (c) 2012 The Chromium Authors. All rights reserved. -# Use of this source code is governed by a BSD-style license that can be -# found in the LICENSE file. - -# If no flags are given, prints the current chromium test shell flags. -# -# Otherwise, the given flags are used to REPLACE (not modify) the chromium -# test shell flags. For example: -# adb_chromium_testshell_command_line --enable-webgl -# -# To remove all chromium test shell flags, pass an empty string for the flags: -# adb_chromium_testshell_command_line "" - -CMD_LINE_FILE=/data/local/tmp/chromium-testshell-command-line - -if [ $# -eq 0 ] ; then - # If nothing specified, print the command line (stripping off "chromium_testshell") - tempfile=$(tempfile) - adb pull $CMD_LINE_FILE $tempfile 2>/dev/null - if [ $? -eq 0 ] ; then - rm $tempfile - adb shell cat $CMD_LINE_FILE | cut -d " " -f "2-" 2>/dev/null - fi -elif [ $# -eq 1 ] && [ "$1" = '' ] ; then - # If given an empty string, delete the command line. - set -x - adb shell rm $CMD_LINE_FILE >/dev/null -else - # Else set it. - set -x - adb shell "echo 'chromium_testshell $*' > $CMD_LINE_FILE" - # Prevent other apps from modifying flags -- this can create security issues. - adb shell chmod 0664 $CMD_LINE_FILE -fi - diff --git a/build/android/adb_content_shell_command_line b/build/android/adb_content_shell_command_line deleted file mode 100755 index f3c1d4f49f..0000000000 --- a/build/android/adb_content_shell_command_line +++ /dev/null @@ -1,37 +0,0 @@ -#!/bin/bash -# -# Copyright (c) 2012 The Chromium Authors. All rights reserved. -# Use of this source code is governed by a BSD-style license that can be -# found in the LICENSE file. - -# If no flags are given, prints the current content shell flags. -# -# Otherwise, the given flags are used to REPLACE (not modify) the content shell -# flags. For example: -# adb_content_shell_command_line --enable-webgl -# -# To remove all content shell flags, pass an empty string for the flags: -# adb_content_shell_command_line "" - -CMD_LINE_FILE=/data/local/tmp/content-shell-command-line - -if [ $# -eq 0 ] ; then - # If nothing specified, print the command line (stripping off "content_shell") - tempfile=$(tempfile) - adb pull $CMD_LINE_FILE $tempfile 2>/dev/null - if [ $? -eq 0 ] ; then - rm $tempfile - adb shell cat $CMD_LINE_FILE | cut -d " " -f "2-" 2>/dev/null - fi -elif [ $# -eq 1 ] && [ "$1" = '' ] ; then - # If given an empty string, delete the command line. - set -x - adb shell rm $CMD_LINE_FILE >/dev/null -else - # Else set it. - set -x - adb shell "echo 'content_shell $*' > $CMD_LINE_FILE" - # Prevent other apps from modifying flags -- this can create security issues. - adb shell chmod 0664 $CMD_LINE_FILE -fi - diff --git a/build/android/adb_device_functions.sh b/build/android/adb_device_functions.sh deleted file mode 100755 index 66cc32fc4e..0000000000 --- a/build/android/adb_device_functions.sh +++ /dev/null @@ -1,139 +0,0 @@ -#!/bin/bash -# -# Copyright (c) 2012 The Chromium Authors. All rights reserved. -# Use of this source code is governed by a BSD-style license that can be -# found in the LICENSE file. -# -# A collection of functions useful for maintaining android devices - - -# Run an adb command on all connected device in parallel. -# Usage: adb_all command line to eval. Quoting is optional. -# -# Examples: -# adb_all install Chrome.apk -# adb_all 'shell cat /path/to/file' -# -adb_all() { - if [[ $# == 0 ]]; then - echo "Usage: adb_all . Quoting is optional." - echo "Example: adb_all install Chrome.apk" - return 1 - fi - local DEVICES=$(adb_get_devices -b) - local NUM_DEVICES=$(echo $DEVICES | wc -w) - if (( $NUM_DEVICES > 1 )); then - echo "Looping over $NUM_DEVICES devices" - fi - _adb_multi "$DEVICES" "$*" -} - - -# Run a command on each connected device. Quoting the command is suggested but -# not required. The script setups up variable DEVICE to correspond to the -# current serial number. Intended for complex one_liners that don't work in -# adb_all -# Usage: adb_device_loop 'command line to eval' -adb_device_loop() { - if [[ $# == 0 ]]; then - echo "Intended for more complex one-liners that cannot be done with" \ - "adb_all." - echo 'Usage: adb_device_loop "echo $DEVICE: $(adb root &&' \ - 'adb shell cat /data/local.prop)"' - return 1 - fi - local DEVICES=$(adb_get_devices) - if [[ -z $DEVICES ]]; then - return - fi - # Do not change DEVICE variable name - part of api - for DEVICE in $DEVICES; do - DEV_TYPE=$(adb -s $DEVICE shell getprop ro.product.device | sed 's/\r//') - echo "Running on $DEVICE ($DEV_TYPE)" - ANDROID_SERIAL=$DEVICE eval "$*" - done -} - -# Erases data from any devices visible on adb. To preserve a device, -# disconnect it or: -# 1) Reboot it into fastboot with 'adb reboot bootloader' -# 2) Run wipe_all_devices to wipe remaining devices -# 3) Restore device it with 'fastboot reboot' -# -# Usage: wipe_all_devices [-f] -# -wipe_all_devices() { - if [[ -z $(which adb) || -z $(which fastboot) ]]; then - echo "aborting: adb and fastboot not in path" - return 1 - elif ! $(groups | grep -q 'plugdev'); then - echo "If fastboot fails, run: 'sudo adduser $(whoami) plugdev'" - fi - - local DEVICES=$(adb_get_devices -b) - - if [[ $1 != '-f' ]]; then - echo "This will ERASE ALL DATA from $(echo $DEVICES | wc -w) device." - read -p "Hit enter to continue" - fi - - _adb_multi "$DEVICES" "reboot bootloader" - # Subshell to isolate job list - ( - for DEVICE in $DEVICES; do - fastboot_erase $DEVICE & - done - wait - ) - - # Reboot devices together - for DEVICE in $DEVICES; do - fastboot -s $DEVICE reboot - done -} - -# Wipe a device in fastboot. -# Usage fastboot_erase [serial] -fastboot_erase() { - if [[ -n $1 ]]; then - echo "Wiping $1" - local SERIAL="-s $1" - else - if [ -z $(fastboot devices) ]; then - echo "No devices in fastboot, aborting." - echo "Check out wipe_all_devices to see if sufficient" - echo "You can put a device in fastboot using adb reboot bootloader" - return 1 - fi - local SERIAL="" - fi - fastboot $SERIAL erase cache - fastboot $SERIAL erase userdata -} - -# Get list of devices connected via adb -# Args: -b block until adb detects a device -adb_get_devices() { - local DEVICES="$(adb devices | grep 'device$')" - if [[ -z $DEVICES && $1 == '-b' ]]; then - echo '- waiting for device -' >&2 - local DEVICES="$(adb wait-for-device devices | grep 'device$')" - fi - echo "$DEVICES" | awk -vORS=' ' '{print $1}' | sed 's/ $/\n/' -} - -################################################### -## HELPER FUNCTIONS -################################################### - -# Run an adb command in parallel over a device list -_adb_multi() { - local DEVICES=$1 - local ADB_ARGS=$2 - ( - for DEVICE in $DEVICES; do - adb -s $DEVICE $ADB_ARGS & - done - wait - ) -} diff --git a/build/android/adb_gdb b/build/android/adb_gdb deleted file mode 100755 index 53e30ac6a8..0000000000 --- a/build/android/adb_gdb +++ /dev/null @@ -1,963 +0,0 @@ -#!/bin/bash -# -# Copyright (c) 2012 The Chromium Authors. All rights reserved. -# Use of this source code is governed by a BSD-style license that can be -# found in the LICENSE file. -# - -# A generic script used to attach to a running Chromium process and -# debug it. Most users should not use this directly, but one of the -# wrapper scripts like adb_gdb_content_shell, or adb_gdb_drt -# -# Use --help to print full usage instructions. -# - -PROGNAME=$(basename "$0") -PROGDIR=$(dirname "$0") - -# Location of Chromium-top-level sources. -CHROMIUM_SRC=$(cd "$PROGDIR"/../.. && pwd 2>/dev/null) - -TMPDIR= -GDBSERVER_PIDFILE= -TARGET_GDBSERVER= - -clean_exit () { - if [ "$TMPDIR" ]; then - GDBSERVER_PID=$(cat $GDBSERVER_PIDFILE 2>/dev/null) - if [ "$GDBSERVER_PID" ]; then - log "Killing background gdbserver process: $GDBSERVER_PID" - kill -9 $GDBSERVER_PID >/dev/null 2>&1 - fi - if [ "$TARGET_GDBSERVER" ]; then - log "Removing target gdbserver binary: $TARGET_GDBSERVER." - "$ADB" shell rm "$TARGET_GDBSERVER" >/dev/null 2>&1 - fi - log "Cleaning up: $TMPDIR" - rm -rf "$TMPDIR" - fi - trap "" EXIT - exit $1 -} - -# Ensure clean exit on Ctrl-C or normal exit. -trap "clean_exit 1" INT HUP QUIT TERM -trap "clean_exit \$?" EXIT - -panic () { - echo "ERROR: $@" >&2 - exit 1 -} - -fail_panic () { - if [ $? != 0 ]; then panic "$@"; fi -} - -log () { - if [ "$VERBOSE" -gt 0 ]; then - echo "$@" - fi -} - -DEFAULT_PULL_LIBS_DIR=/tmp/$USER-adb-gdb-libs - -# NOTE: Allow wrapper scripts to set various default through ADB_GDB_XXX -# environment variables. This is only for cosmetic reasons, i.e. to -# display proper - -# Allow wrapper scripts to set the default activity through -# the ADB_GDB_ACTIVITY variable. Users are still able to change the -# final activity name through --activity= option. -# -# This is only for cosmetic reasons, i.e. to display the proper default -# in the --help output. -# -DEFAULT_ACTIVITY=${ADB_GDB_ACTIVITY:-".Main"} - -# Allow wrapper scripts to set the program name through ADB_GDB_PROGNAME -PROGNAME=${ADB_GDB_PROGNAME:-$(basename "$0")} - -ACTIVITY=$DEFAULT_ACTIVITY -ADB= -ANNOTATE= -# Note: Ignore BUILDTYPE variable, because the Ninja build doesn't use it. -BUILDTYPE= -FORCE= -GDBEXEPOSTFIX=gdb -GDBINIT= -GDBSERVER= -HELP= -NDK_DIR= -NO_PULL_LIBS= -PACKAGE_NAME= -PID= -PROGRAM_NAME="activity" -PULL_LIBS= -PULL_LIBS_DIR= -SANDBOXED= -SANDBOXED_INDEX= -START= -SU_PREFIX= -SYMBOL_DIR= -TARGET_ARCH= -TOOLCHAIN= -VERBOSE=0 - -for opt; do - optarg=$(expr "x$opt" : 'x[^=]*=\(.*\)') - case $opt in - --adb=*) - ADB=$optarg - ;; - --activity=*) - ACTIVITY=$optarg - ;; - --annotate=3) - ANNOTATE=$optarg - ;; - --force) - FORCE=true - ;; - --gdbserver=*) - GDBSERVER=$optarg - ;; - --help|-h|-?) - HELP=true - ;; - --ndk-dir=*) - NDK_DIR=$optarg - ;; - --no-pull-libs) - NO_PULL_LIBS=true - ;; - --package-name=*) - PACKAGE_NAME=$optarg - ;; - --pid=*) - PID=$optarg - ;; - --program-name=*) - PROGRAM_NAME=$optarg - ;; - --pull-libs) - PULL_LIBS=true - ;; - --pull-libs-dir=*) - PULL_LIBS_DIR=$optarg - ;; - --sandboxed) - SANDBOXED=true - ;; - --sandboxed=*) - SANDBOXED=true - SANDBOXED_INDEX=$optarg - ;; - --script=*) - GDBINIT=$optarg - ;; - --start) - START=true - ;; - --su-prefix=*) - SU_PREFIX=$optarg - ;; - --symbol-dir=*) - SYMBOL_DIR=$optarg - ;; - --target-arch=*) - TARGET_ARCH=$optarg - ;; - --toolchain=*) - TOOLCHAIN=$optarg - ;; - --ui) - GDBEXEPOSTFIX=gdbtui - ;; - --verbose) - VERBOSE=$(( $VERBOSE + 1 )) - ;; - --debug) - BUILDTYPE=Debug - ;; - --release) - BUILDTYPE=Release - ;; - -*) - panic "Unknown option $OPT, see --help." >&2 - ;; - *) - if [ "$PACKAGE_NAME" ]; then - panic "You can only provide a single package name as argument!\ - See --help." - fi - PACKAGE_NAME=$opt - ;; - esac -done - -print_help_options () { - cat <] - -Attach gdb to a running Android $PROGRAM_NAME process. - -If provided, must be the name of the Android application's -package name to be debugged. You can also use --package-name= to -specify it. -EOF - fi - - cat < option. - -This script needs several things to work properly. It will try to pick -them up automatically for you though: - - - target gdbserver binary - - host gdb client (e.g. arm-linux-androideabi-gdb) - - directory with symbolic version of $PROGRAM_NAME's shared libraries. - -If you have sourced Chromium's build/android/envsetup.sh, this script will -find all of them automatically. This is the recommended way to use it. - -Otherwise, if you have ANDROID_NDK_ROOT defined in your environment, -the script will use it to find the gdb and gdbserver binaries. You can -also use --ndk-dir= to specify an alternative NDK installation -directory. - -The script tries to find the most recent version of the debug version of -shared libraries under one of the following directories: - - \$CHROMIUM_SRC/out/Release/lib/ (used by Ninja builds) - \$CHROMIUM_SRC/out/Debug/lib/ (used by Ninja builds) - \$CHROMIUM_SRC/out/Release/lib.target/ (used by Make builds) - \$CHROMIUM_SRC/out/Debug/lib.target/ (used by Make builds) - -You can restrict this search by using --release or --debug to specify the -build type, or simply use --symbol-dir= to specify the file manually. - -The script tries to extract the target architecture from your GYP_DEFINES, -but if this fails, will default to 'arm'. Use --target-arch= to force -its value. - -Otherwise, the script will complain, but you can use the --gdbserver, ---gdb and --symbol-lib options to specify everything manually. - -An alternative to --gdb= is to use --toollchain= to specify -the path to the host target-specific cross-toolchain. - -You will also need the 'adb' tool in your path. Otherwise, use the --adb -option. The script will complain if there is more than one device connected -and ANDROID_SERIAL is not defined. - -The first time you use it on a device, the script will pull many system -libraries required by the process into a temporary directory. This -is done to strongly improve the debugging experience, like allowing -readable thread stacks and more. The libraries are copied to the following -directory by default: - - $DEFAULT_PULL_LIBS_DIR/ - -But you can use the --pull-libs-dir= option to specify an -alternative. The script can detect when you change the connected device, -and will re-pull the libraries only in this case. You can however force it -with the --pull-libs option. - -Any local .gdbinit script will be ignored, but it is possible to pass a -gdb command script with the --script= option. Note that its commands -will be passed to gdb after the remote connection and library symbol -loading have completed. - -Valid options: - --help|-h|-? Print this message. - --verbose Increase verbosity. - - --sandboxed Debug first sandboxed process we find. - --sandboxed= Debug specific sandboxed process. - --symbol-dir= Specify directory with symbol shared libraries. - --package-name= Specify package name (alternative to 1st argument). - --program-name= Specify program name (cosmetic only). - --pid= Specify application process pid. - --force Kill any previous debugging session, if any. - --start Start package's activity on device. - --ui Use gdbtui instead of gdb - --activity= Activity name for --start [$DEFAULT_ACTIVITY]. - --annotate= Enable gdb annotation. - --script= Specify extra GDB init script. - - --gdbserver= Specify targer gdbserver binary. - --gdb= Specify host gdb client binary. - --target-arch= Specify NDK target arch. - --adb= Specify host ADB binary. - - --su-prefix= Prepend to 'adb shell' commands that are - run by this script. This can be useful to use - the 'su' program on rooted production devices. - - --pull-libs Force system libraries extraction. - --no-pull-libs Do not extract any system library. - --libs-dir= Specify system libraries extraction directory. - - --debug Use libraries under out/Debug. - --release Use libraries under out/Release. - -EOF - exit 0 -fi - -if [ -z "$PACKAGE_NAME" ]; then - panic "Please specify a package name on the command line. See --help." -fi - -if [ -z "$NDK_DIR" ]; then - if [ -z "$ANDROID_NDK_ROOT" ]; then - panic "Can't find NDK directory, please source \ -build/android/envsetup.sh!" - fi -else - if [ ! -d "$NDK_DIR" ]; then - panic "Invalid directory: $NDK_DIR" - fi - if [ ! -f "$NDK_DIR/ndk-build" ]; then - panic "Not a valid NDK directory: $NDK_DIR" - fi - ANDROID_NDK_ROOT=$NDK_DIR -fi - -if [ "$GDBINIT" -a ! -f "$GDBINIT" ]; then - panic "Unknown --script file: $GDBINIT" -fi - -# Find the target architecture from our $GYP_DEFINES -# This returns an NDK-compatible architecture name. -# out: NDK Architecture name, or empty string. -get_gyp_target_arch () { - local ARCH=$(echo $GYP_DEFINES | tr ' ' '\n' | grep '^target_arch=' |\ - cut -d= -f2) - case $ARCH in - ia32|i?86|x86) echo "x86";; - mips|arm) echo "$ARCH";; - *) echo ""; - esac -} - -if [ -z "$TARGET_ARCH" ]; then - TARGET_ARCH=$(get_gyp_target_arch) - if [ -z "$TARGET_ARCH" ]; then - TARGET_ARCH=arm - fi -else - # Nit: accept Chromium's 'ia32' as a valid target architecture. This - # script prefers the NDK 'x86' name instead because it uses it to find - # NDK-specific files (host gdb) with it. - if [ "$TARGET_ARCH" = "ia32" ]; then - TARGET_ARCH=x86 - log "Auto-config: --arch=$TARGET_ARCH (equivalent to ia32)" - fi -fi - -# Detect the NDK system name, i.e. the name used to identify the host. -# out: NDK system name (e.g. 'linux' or 'darwin') -get_ndk_host_system () { - local HOST_OS - if [ -z "$NDK_HOST_SYSTEM" ]; then - HOST_OS=$(uname -s) - case $HOST_OS in - Linux) NDK_HOST_SYSTEM=linux;; - Darwin) NDK_HOST_SYSTEM=darwin;; - *) panic "You can't run this script on this system: $HOST_OS";; - esac - fi - echo "$NDK_HOST_SYSTEM" -} - -# Detect the NDK host architecture name. -# out: NDK arch name (e.g. 'x86' or 'x86_64') -get_ndk_host_arch () { - local HOST_ARCH HOST_OS - if [ -z "$NDK_HOST_ARCH" ]; then - HOST_OS=$(get_ndk_host_system) - HOST_ARCH=$(uname -p) - case $HOST_ARCH in - i?86) NDK_HOST_ARCH=x86;; - x86_64|amd64) NDK_HOST_ARCH=x86_64;; - *) panic "You can't run this script on this host architecture: $HOST_ARCH";; - esac - # Darwin trick: "uname -p" always returns i386 on 64-bit installations. - if [ "$HOST_OS" = darwin -a "$NDK_HOST_ARCH" = "x86" ]; then - # Use '/usr/bin/file', not just 'file' to avoid buggy MacPorts - # implementations of the tool. See http://b.android.com/53769 - HOST_64BITS=$(/usr/bin/file -L "$SHELL" | grep -e "x86[_-]64") - if [ "$HOST_64BITS" ]; then - NDK_HOST_ARCH=x86_64 - fi - fi - fi - echo "$NDK_HOST_ARCH" -} - -# Convert an NDK architecture name into a GNU configure triplet. -# $1: NDK architecture name (e.g. 'arm') -# Out: Android GNU configure triplet (e.g. 'arm-linux-androideabi') -get_arch_gnu_config () { - case $1 in - arm) - echo "arm-linux-androideabi" - ;; - x86) - echo "i686-linux-android" - ;; - mips) - echo "mipsel-linux-android" - ;; - *) - echo "$ARCH-linux-android" - ;; - esac -} - -# Convert an NDK architecture name into a toolchain name prefix -# $1: NDK architecture name (e.g. 'arm') -# Out: NDK toolchain name prefix (e.g. 'arm-linux-androideabi') -get_arch_toolchain_prefix () { - # Return the configure triplet, except for x86! - if [ "$1" = "x86" ]; then - echo "$1" - else - get_arch_gnu_config $1 - fi -} - -# Find a NDK toolchain prebuilt file or sub-directory. -# This will probe the various arch-specific toolchain directories -# in the NDK for the needed file. -# $1: NDK install path -# $2: NDK architecture name -# $3: prebuilt sub-path to look for. -# Out: file path, or empty if none is found. -get_ndk_toolchain_prebuilt () { - local NDK_DIR="${1%/}" - local ARCH="$2" - local SUBPATH="$3" - local NAME="$(get_arch_toolchain_prefix $ARCH)" - local FILE TARGET - FILE=$NDK_DIR/toolchains/$NAME-4.6/prebuilt/$SUBPATH - if [ ! -f "$FILE" ]; then - FILE=$NDK_DIR/toolchains/$NAME-4.4.3/prebuilt/$SUBPATH - if [ ! -f "$FILE" ]; then - FILE= - fi - fi - echo "$FILE" -} - -# Find the path to an NDK's toolchain full prefix for a given architecture -# $1: NDK install path -# $2: NDK target architecture name -# Out: install path + binary prefix (e.g. -# ".../path/to/bin/arm-linux-androideabi-") -get_ndk_toolchain_fullprefix () { - local NDK_DIR="$1" - local ARCH="$2" - local TARGET NAME HOST_OS HOST_ARCH GCC CONFIG - - # NOTE: This will need to be updated if the NDK changes the names or moves - # the location of its prebuilt toolchains. - # - GCC= - HOST_OS=$(get_ndk_host_system) - HOST_ARCH=$(get_ndk_host_arch) - CONFIG=$(get_arch_gnu_config $ARCH) - GCC=$(get_ndk_toolchain_prebuilt \ - "$NDK_DIR" "$ARCH" "$HOST_OS-$HOST_ARCH/bin/$CONFIG-gcc") - if [ -z "$GCC" -a "$HOST_ARCH" = "x86_64" ]; then - GCC=$(get_ndk_toolchain_prebuilt \ - "$NDK_DIR" "$ARCH" "$HOST_OS-x86/bin/$CONFIG-gcc") - fi - if [ ! -f "$GCC" -a "$ARCH" = "x86" ]; then - # Special case, the x86 toolchain used to be incorrectly - # named i686-android-linux-gcc! - GCC=$(get_ndk_toolchain_prebuilt \ - "$NDK_DIR" "$ARCH" "$HOST_OS-x86/bin/i686-android-linux-gcc") - fi - if [ -z "$GCC" ]; then - panic "Cannot find Android NDK toolchain for '$ARCH' architecture. \ -Please verify your NDK installation!" - fi - echo "${GCC%%gcc}" -} - -# $1: NDK install path -# $2: target architecture. -get_ndk_gdbserver () { - local NDK_DIR="$1" - local ARCH=$2 - local BINARY - - # The location has moved after NDK r8 - BINARY=$NDK_DIR/prebuilt/android-$ARCH/gdbserver/gdbserver - if [ ! -f "$BINARY" ]; then - BINARY=$(get_ndk_toolchain_prebuilt "$NDK_DIR" "$ARCH" gdbserver) - fi - echo "$BINARY" -} - -# Check/probe the path to the Android toolchain installation. Always -# use the NDK versions of gdb and gdbserver. They must match to avoid -# issues when both binaries do not speak the same wire protocol. -# -if [ -z "$TOOLCHAIN" ]; then - ANDROID_TOOLCHAIN=$(get_ndk_toolchain_fullprefix \ - "$ANDROID_NDK_ROOT" "$TARGET_ARCH") - ANDROID_TOOLCHAIN=$(dirname "$ANDROID_TOOLCHAIN") - log "Auto-config: --toolchain=$ANDROID_TOOLCHAIN" -else - # Be flexible, allow one to specify either the install path or the bin - # sub-directory in --toolchain: - # - if [ -d "$TOOLCHAIN/bin" ]; then - TOOLCHAIN=$TOOLCHAIN/bin - fi - ANDROID_TOOLCHAIN=$TOOLCHAIN -fi - -# Cosmetic: Remove trailing directory separator. -ANDROID_TOOLCHAIN=${ANDROID_TOOLCHAIN%/} - -# Find host GDB client binary -GDB=$(which $ANDROID_TOOLCHAIN/*-$GDBEXEPOSTFIX 2>/dev/null | head -1) -if [ -z "$GDB" ]; then - panic "Can't find Android gdb client in your path, check your \ ---toolchain path." -fi -log "Host gdb client: $GDB" - -# Find gdbserver binary, we will later push it to /data/local/tmp -# This ensures that both gdbserver and $GDB talk the same binary protocol, -# otherwise weird problems will appear. -# -if [ -z "$GDBSERVER" ]; then - GDBSERVER=$(get_ndk_gdbserver "$ANDROID_NDK_ROOT" "$TARGET_ARCH") - if [ -z "$GDBSERVER" ]; then - panic "Can't find NDK gdbserver binary. use --gdbserver to specify \ -valid one!" - fi - log "Auto-config: --gdbserver=$GDBSERVER" -fi - - - -# Check that ADB is in our path -if [ -z "$ADB" ]; then - ADB=$(which adb 2>/dev/null) - if [ -z "$ADB" ]; then - panic "Can't find 'adb' tool in your path. Install it or use \ ---adb=" - fi - log "Auto-config: --adb=$ADB" -fi - -# Check that it works minimally -ADB_VERSION=$($ADB version 2>/dev/null) -echo "$ADB_VERSION" | fgrep -q -e "Android Debug Bridge" -if [ $? != 0 ]; then - panic "Your 'adb' tool seems invalid, use --adb= to specify a \ -different one: $ADB" -fi - -# If there are more than one device connected, and ANDROID_SERIAL is not -# defined, print an error message. -NUM_DEVICES_PLUS2=$($ADB devices 2>/dev/null | wc -l) -if [ "$NUM_DEVICES_PLUS2" -lt 3 -a -z "$ANDROID_SERIAL" ]; then - echo "ERROR: There is more than one Android device connected to ADB." - echo "Please define ANDROID_SERIAL to specify which one to use." - exit 1 -fi - -# A unique ID for this script's session. This needs to be the same in all -# sub-shell commands we're going to launch, so take the PID of the launcher -# process. -TMP_ID=$$ - -# Temporary directory, will get cleaned up on exit. -TMPDIR=/tmp/$USER-adb-gdb-tmp-$TMP_ID -mkdir -p "$TMPDIR" && rm -rf "$TMPDIR"/* - -GDBSERVER_PIDFILE="$TMPDIR"/gdbserver-$TMP_ID.pid - -# Run a command through adb shell, strip the extra \r from the output -# and return the correct status code to detect failures. This assumes -# that the adb shell command prints a final \n to stdout. -# $1+: command to run -# Out: command's stdout -# Return: command's status -# Note: the command's stderr is lost -adb_shell () { - local TMPOUT="$(mktemp)" - local LASTLINE RET - local ADB=${ADB:-adb} - - # The weird sed rule is to strip the final \r on each output line - # Since 'adb shell' never returns the command's proper exit/status code, - # we force it to print it as '%%' in the temporary output file, - # which we will later strip from it. - $ADB shell $@ ";" echo "%%\$?" 2>/dev/null | \ - sed -e 's![[:cntrl:]]!!g' > $TMPOUT - # Get last line in log, which contains the exit code from the command - LASTLINE=$(sed -e '$!d' $TMPOUT) - # Extract the status code from the end of the line, which must - # be '%%'. - RET=$(echo "$LASTLINE" | \ - awk '{ if (match($0, "%%[0-9]+$")) { print substr($0,RSTART+2); } }') - # Remove the status code from the last line. Note that this may result - # in an empty line. - LASTLINE=$(echo "$LASTLINE" | \ - awk '{ if (match($0, "%%[0-9]+$")) { print substr($0,1,RSTART-1); } }') - # The output itself: all lines except the status code. - sed -e '$d' $TMPOUT && printf "%s" "$LASTLINE" - # Remove temp file. - rm -f $TMPOUT - # Exit with the appropriate status. - return $RET -} - -# If --force is specified, try to kill any gdbserver process started by the -# same user on the device. Normally, these are killed automatically by the -# script on exit, but there are a few corner cases where this would still -# be needed. -if [ "$FORCE" ]; then - GDBSERVER_PIDS=$(adb_shell ps | awk '$9 ~ /gdbserver/ { print $2; }') - for GDB_PID in $GDBSERVER_PIDS; do - log "Killing previous gdbserver (PID=$GDB_PID)" - adb_shell kill -9 $GDB_PID - done -fi - -if [ "$START" ]; then - log "Starting $PROGRAM_NAME on device." - adb_shell am start -n $PACKAGE_NAME/$ACTIVITY 2>/dev/null - adb_shell ps | grep -q $PACKAGE_NAME - fail_panic "Could not start $PROGRAM_NAME on device. Are you sure the \ -package is installed?" -fi - -# Return the timestamp of a given time, as number of seconds since epoch. -# $1: file path -# Out: file timestamp -get_file_timestamp () { - stat -c %Y "$1" 2>/dev/null -} - -# Detect the build type and symbol directory. This is done by finding -# the most recent sub-directory containing debug shared libraries under -# $CHROMIUM_SRC/out/ -# -# $1: $BUILDTYPE value, can be empty -# Out: nothing, but this sets SYMBOL_DIR -# -detect_symbol_dir () { - local SUBDIRS SUBDIR LIST DIR DIR_LIBS TSTAMP - # Note: Ninja places debug libraries under out/$BUILDTYPE/lib/, while - # Make places then under out/$BUILDTYPE/lib.target. - if [ "$1" ]; then - SUBDIRS="$1/lib $1/lib.target" - else - SUBDIRS="Release/lib Debug/lib Release/lib.target Debug/lib.target" - fi - LIST=$TMPDIR/scan-subdirs-$$.txt - printf "" > "$LIST" - for SUBDIR in $SUBDIRS; do - DIR=$CHROMIUM_SRC/out/$SUBDIR - if [ -d "$DIR" ]; then - # Ignore build directories that don't contain symbol versions - # of the shared libraries. - DIR_LIBS=$(ls "$DIR"/lib*.so 2>/dev/null) - if [ -z "$DIR_LIBS" ]; then - echo "No shared libs: $DIR" - continue - fi - TSTAMP=$(get_file_timestamp "$DIR") - printf "%s %s\n" "$TSTAMP" "$SUBDIR" >> "$LIST" - fi - done - SUBDIR=$(cat $LIST | sort -r | head -1 | cut -d" " -f2) - rm -f "$LIST" - - if [ -z "$SUBDIR" ]; then - if [ -z "$1" ]; then - panic "Could not find any build directory under \ -$CHROMIUM_SRC/out. Please build the program first!" - else - panic "Could not find any $1 directory under \ -$CHROMIUM_SRC/out. Check your build type!" - fi - fi - - SYMBOL_DIR=$CHROMIUM_SRC/out/$SUBDIR - log "Auto-config: --symbol-dir=$SYMBOL_DIR" -} - -if [ -z "$SYMBOL_DIR" ]; then - detect_symbol_dir "$BUILDTYPE" -fi - -# Allow several concurrent debugging sessions -TARGET_GDBSERVER=/data/local/tmp/gdbserver-adb-gdb-$TMP_ID - -# Return the build fingerprint contained in a build.prop file. -# $1: path to build.prop file -get_build_fingerprint_from () { - cat "$1" | grep -e '^ro.build.fingerprint=' | cut -d= -f2 -} - - -ORG_PULL_LIBS_DIR=$PULL_LIBS_DIR -PULL_LIBS_DIR=${PULL_LIBS_DIR:-$DEFAULT_PULL_LIBS_DIR} - -HOST_FINGERPRINT= -DEVICE_FINGERPRINT=$(adb_shell getprop ro.build.fingerprint) -log "Device build fingerprint: $DEVICE_FINGERPRINT" - -# If --pull-libs-dir is not specified, and this is a platform build, look -# if we can use the symbolic libraries under $ANDROID_PRODUCT_OUT/symbols/ -# directly, if the build fingerprint matches the device. -if [ -z "$ORG_PULL_LIBS_DIR" -a \ - "$ANDROID_PRODUCT_OUT" -a \ - -f "$ANDROID_PRODUCT_OUT/system/build.prop" ]; then - ANDROID_FINGERPRINT=$(get_build_fingerprint_from \ - "$ANDROID_PRODUCT_OUT"/system/build.prop) - log "Android build fingerprint: $ANDROID_FINGERPRINT" - if [ "$ANDROID_FINGERPRINT" = "$DEVICE_FINGERPRINT" ]; then - log "Perfect match!" - PULL_LIBS_DIR=$ANDROID_PRODUCT_OUT/symbols - HOST_FINGERPRINT=$ANDROID_FINGERPRINT - if [ "$PULL_LIBS" ]; then - log "Ignoring --pull-libs since the device and platform build \ -fingerprints match." - NO_PULL_LIBS=true - fi - fi -fi - -# If neither --pull-libs an --no-pull-libs were specified, check the build -# fingerprints of the device, and the cached system libraries on the host. -# -if [ -z "$NO_PULL_LIBS" -a -z "$PULL_LIBS" ]; then - if [ ! -f "$PULL_LIBS_DIR/build.prop" ]; then - log "Auto-config: --pull-libs (no cached libraries)" - PULL_LIBS=true - else - HOST_FINGERPRINT=$(get_build_fingerprint_from "$PULL_LIBS_DIR/build.prop") - log "Host build fingerprint: $HOST_FINGERPRINT" - if [ "$HOST_FINGERPRINT" == "$DEVICE_FINGERPRINT" ]; then - log "Auto-config: --no-pull-libs (fingerprint match)" - NO_PULL_LIBS=true - else - log "Auto-config: --pull-libs (fingerprint mismatch)" - PULL_LIBS=true - fi - fi -fi - -# Extract the system libraries from the device if necessary. -if [ "$PULL_LIBS" -a -z "$NO_PULL_LIBS" ]; then - echo "Extracting system libraries into: $PULL_LIBS_DIR" -fi - -mkdir -p "$PULL_LIBS_DIR" -fail_panic "Can't create --libs-dir directory: $PULL_LIBS_DIR" - -# If requested, work for M-x gdb. The gdb indirections make it -# difficult to pass --annotate=3 to the gdb binary itself. -GDB_ARGS= -if [ "$ANNOTATE" ]; then - GDB_ARGS=$GDB_ARGS" --annotate=$ANNOTATE" -fi - -# Get the PID from the first argument or else find the PID of the -# browser process. -if [ -z "$PID" ]; then - PROCESSNAME=$PACKAGE_NAME - if [ "$SANDBOXED_INDEX" ]; then - PROCESSNAME=$PROCESSNAME:sandboxed_process$SANDBOXED_INDEX - elif [ "$SANDBOXED" ]; then - PROCESSNAME=$PROCESSNAME:sandboxed_process - PID=$(adb_shell ps | \ - awk '$9 ~ /^'$PROCESSNAME'/ { print $2; }' | head -1) - fi - if [ -z "$PID" ]; then - PID=$(adb_shell ps | \ - awk '$9 == "'$PROCESSNAME'" { print $2; }' | head -1) - fi - if [ -z "$PID" ]; then - if [ "$START" ]; then - panic "Can't find application process PID, did it crash?" - else - panic "Can't find application process PID, are you sure it is \ -running? Try using --start." - fi - fi - log "Found process PID: $PID" -elif [ "$SANDBOXED" ]; then - echo "WARNING: --sandboxed option ignored due to use of --pid." -fi - -# Determine if 'adb shell' runs as root or not. -# If so, we can launch gdbserver directly, otherwise, we have to -# use run-as $PACKAGE_NAME ..., which requires the package to be debuggable. -# -if [ "$SU_PREFIX" ]; then - # Need to check that this works properly. - SU_PREFIX_TEST_LOG=$TMPDIR/su-prefix.log - adb_shell $SU_PREFIX echo "foo" > $SU_PREFIX_TEST_LOG 2>&1 - if [ $? != 0 -o "$(cat $SU_PREFIX_TEST_LOG)" != "foo" ]; then - echo "ERROR: Cannot use '$SU_PREFIX' as a valid su prefix:" - echo "$ adb shell $SU_PREFIX echo foo" - cat $SU_PREFIX_TEST_LOG - exit 1 - fi - COMMAND_PREFIX=$SU_PREFIX -else - SHELL_UID=$(adb shell cat /proc/self/status | \ - awk '$1 == "Uid:" { print $2; }') - log "Shell UID: $SHELL_UID" - if [ "$SHELL_UID" != 0 -o -n "$NO_ROOT" ]; then - COMMAND_PREFIX="run-as $PACKAGE_NAME" - else - COMMAND_PREFIX= - fi -fi -log "Command prefix: '$COMMAND_PREFIX'" - -# Pull device's system libraries that are mapped by our process. -# Pulling all system libraries is too long, so determine which ones -# we need by looking at /proc/$PID/maps instead -if [ "$PULL_LIBS" -a -z "$NO_PULL_LIBS" ]; then - echo "Extracting system libraries into: $PULL_LIBS_DIR" - rm -f $PULL_LIBS_DIR/build.prop - MAPPINGS=$(adb_shell $COMMAND_PREFIX cat /proc/$PID/maps) - if [ $? != 0 ]; then - echo "ERROR: Could not list process's memory mappings." - if [ "$SU_PREFIX" ]; then - panic "Are you sure your --su-prefix is correct?" - else - panic "Use --su-prefix if the application is not debuggable." - fi - fi - SYSTEM_LIBS=$(echo "$MAPPINGS" | \ - awk '$6 ~ /\/system\/.*\.so$/ { print $6; }' | sort -u) - for SYSLIB in /system/bin/linker $SYSTEM_LIBS; do - echo "Pulling from device: $SYSLIB" - DST_FILE=$PULL_LIBS_DIR$SYSLIB - DST_DIR=$(dirname "$DST_FILE") - mkdir -p "$DST_DIR" && adb pull $SYSLIB "$DST_FILE" 2>/dev/null - fail_panic "Could not pull $SYSLIB from device !?" - done - echo "Pulling device build.prop" - adb pull /system/build.prop $PULL_LIBS_DIR/build.prop - fail_panic "Could not pull device build.prop !?" -fi - -# Find all the sub-directories of $PULL_LIBS_DIR, up to depth 4 -# so we can add them to solib-search-path later. -SOLIB_DIRS=$(find $PULL_LIBS_DIR -mindepth 1 -maxdepth 4 -type d | \ - grep -v "^$" | tr '\n' ':') - -# This is a re-implementation of gdbclient, where we use compatible -# versions of gdbserver and $GDBNAME to ensure that everything works -# properly. -# - -# Push gdbserver to the device -log "Pushing gdbserver to $TARGET_GDBSERVER" -adb push $GDBSERVER $TARGET_GDBSERVER &>/dev/null -fail_panic "Could not copy gdbserver to the device!" - -PORT=5039 -HOST_PORT=$PORT -TARGET_PORT=$PORT - -# Pull the app_process binary from the device -GDBEXEC=app_process -log "Pulling $GDBEXEC from device" -adb pull /system/bin/$GDBEXEC "$TMPDIR"/$GDBEXEC &>/dev/null -fail_panic "Could not retrieve $GDBEXEC from the device!" - -# Setup network redirection -log "Setting network redirection (host:$HOST_PORT -> device:$TARGET_PORT)" -adb forward tcp:$HOST_PORT tcp:$TARGET_PORT -fail_panic "Could not setup network redirection from \ -host:localhost:$HOST_PORT to device:localhost:$TARGET_PORT!" - -# Start gdbserver in the background -# Note that using run-as requires the package to be debuggable. -# -# If not, this will fail horribly. The alternative is to run the -# program as root, which requires of course root privileges. -# Maybe we should add a --root option to enable this? -# -log "Starting gdbserver in the background:" -GDBSERVER_LOG=$TMPDIR/gdbserver-$TMP_ID.log -log "adb shell $COMMAND_PREFIX $TARGET_GDBSERVER :$TARGET_PORT \ ---attach $PID" -("$ADB" shell $COMMAND_PREFIX $TARGET_GDBSERVER :$TARGET_PORT \ - --attach $PID > $GDBSERVER_LOG 2>&1) & -GDBSERVER_PID=$! -echo "$GDBSERVER_PID" > $GDBSERVER_PIDFILE -log "background job pid: $GDBSERVER_PID" - -# Check that it is still running after a few seconds. If not, this means we -# could not properly attach to it -sleep 2 -log "Job control: $(jobs -l)" -STATE=$(jobs -l | awk '$2 == "'$GDBSERVER_PID'" { print $3; }') -if [ "$STATE" != "Running" ]; then - echo "ERROR: GDBServer could not attach to PID $PID!" - echo "Failure log (use --verbose for more information):" - cat $GDBSERVER_LOG - exit 1 -fi - -# Generate a file containing useful GDB initialization commands -readonly COMMANDS=$TMPDIR/gdb.init -log "Generating GDB initialization commands file: $COMMANDS" -echo -n "" > $COMMANDS -echo "file $TMPDIR/$GDBEXEC" >> $COMMANDS -echo "directory $CHROMIUM_SRC" >> $COMMANDS -echo "set solib-absolute-prefix $PULL_LIBS_DIR" >> $COMMANDS -echo "set solib-search-path $SOLIB_DIRS:$PULL_LIBS_DIR:$SYMBOL_DIR" \ - >> $COMMANDS -echo "echo Attaching and reading symbols, this may take a while.." \ - >> $COMMANDS -echo "target remote :$HOST_PORT" >> $COMMANDS - -if [ "$GDBINIT" ]; then - cat "$GDBINIT" >> $COMMANDS -fi - -if [ "$VERBOSE" -gt 0 ]; then - echo "### START $COMMANDS" - cat $COMMANDS - echo "### END $COMMANDS" -fi - -log "Launching gdb client: $GDB $GDBARGS -x $COMMANDS" -$GDB $GDBARGS -x $COMMANDS && -rm -f "$GDBSERVER_PIDFILE" diff --git a/build/android/adb_gdb_android_webview_shell b/build/android/adb_gdb_android_webview_shell deleted file mode 100755 index f685fda77c..0000000000 --- a/build/android/adb_gdb_android_webview_shell +++ /dev/null @@ -1,16 +0,0 @@ -#!/bin/bash -# -# Copyright (c) 2013 The Chromium Authors. All rights reserved. -# Use of this source code is governed by a BSD-style license that can be -# found in the LICENSE file. -# -# Attach to or start a ContentShell process and debug it. -# See --help for details. -# -PROGDIR=$(dirname "$0") -export ADB_GDB_PROGNAME=$(basename "$0") -export ADB_GDB_ACTIVITY=.AwShellActivity -"$PROGDIR"/adb_gdb \ - --program-name=AwShellApplication \ - --package-name=org.chromium.android_webview.shell \ - "$@" diff --git a/build/android/adb_gdb_chromium_testshell b/build/android/adb_gdb_chromium_testshell deleted file mode 100755 index 0f1b4a7350..0000000000 --- a/build/android/adb_gdb_chromium_testshell +++ /dev/null @@ -1,16 +0,0 @@ -#!/bin/bash -# -# Copyright (c) 2012 The Chromium Authors. All rights reserved. -# Use of this source code is governed by a BSD-style license that can be -# found in the LICENSE file. -# -# Attach to or start a ChromiumTestShell process and debug it. -# See --help for details. -# -PROGDIR=$(dirname "$0") -export ADB_GDB_PROGNAME=$(basename "$0") -export ADB_GDB_ACTIVITY=.ChromiumTestShellActivity -"$PROGDIR"/adb_gdb \ - --program-name=ChromiumTestShell \ - --package-name=org.chromium.chrome.testshell \ - "$@" diff --git a/build/android/adb_gdb_content_shell b/build/android/adb_gdb_content_shell deleted file mode 100755 index 18e1a61d89..0000000000 --- a/build/android/adb_gdb_content_shell +++ /dev/null @@ -1,16 +0,0 @@ -#!/bin/bash -# -# Copyright (c) 2012 The Chromium Authors. All rights reserved. -# Use of this source code is governed by a BSD-style license that can be -# found in the LICENSE file. -# -# Attach to or start a ContentShell process and debug it. -# See --help for details. -# -PROGDIR=$(dirname "$0") -export ADB_GDB_PROGNAME=$(basename "$0") -export ADB_GDB_ACTIVITY=.ContentShellActivity -"$PROGDIR"/adb_gdb \ - --program-name=ContentShell \ - --package-name=org.chromium.content_shell_apk \ - "$@" diff --git a/build/android/adb_gdb_drt b/build/android/adb_gdb_drt deleted file mode 100755 index 6157361d2d..0000000000 --- a/build/android/adb_gdb_drt +++ /dev/null @@ -1,16 +0,0 @@ -#!/bin/bash -# -# Copyright (c) 2012 The Chromium Authors. All rights reserved. -# Use of this source code is governed by a BSD-style license that can be -# found in the LICENSE file. -# -# Attach to or start a DumpRenderTree process and debug it. -# See --help for details. -# -PROGDIR=$(dirname "$0") -export ADB_GDB_PROGNAME=$(basename "$0") -export ADB_GDB_ACTIVITY=.ChromeNativeTestActivity -"$PROGDIR"/adb_gdb \ - --program-name=DumpRenderTree \ - --package-name=org.chromium.native_test \ - "$@" diff --git a/build/android/adb_install_apk.py b/build/android/adb_install_apk.py deleted file mode 100755 index 36adb79d5a..0000000000 --- a/build/android/adb_install_apk.py +++ /dev/null @@ -1,77 +0,0 @@ -#!/usr/bin/env python -# -# Copyright (c) 2012 The Chromium Authors. All rights reserved. -# Use of this source code is governed by a BSD-style license that can be -# found in the LICENSE file. - -"""Utility script to install APKs from the command line quickly.""" - -import multiprocessing -import optparse -import os -import sys - -from pylib import android_commands -from pylib import constants -from pylib.utils import apk_helper -from pylib.utils import test_options_parser - - -def AddInstallAPKOption(option_parser): - """Adds apk option used to install the APK to the OptionParser.""" - test_options_parser.AddBuildTypeOption(option_parser) - option_parser.add_option('--apk', - help=('The name of the apk containing the ' - ' application (with the .apk extension).')) - option_parser.add_option('--apk_package', - help=('The package name used by the apk containing ' - 'the application.')) - option_parser.add_option('--keep_data', - action='store_true', - default=False, - help=('Keep the package data when installing ' - 'the application.')) - - -def ValidateInstallAPKOption(option_parser, options): - """Validates the apk option and potentially qualifies the path.""" - if not options.apk: - option_parser.error('--apk is mandatory.') - if not os.path.exists(options.apk): - options.apk = os.path.join(constants.DIR_SOURCE_ROOT, - 'out', options.build_type, - 'apks', options.apk) - - -def _InstallApk(args): - apk_path, apk_package, keep_data, device = args - android_commands.AndroidCommands(device=device).ManagedInstall( - apk_path, keep_data, apk_package) - print '----- Installed on %s -----' % device - - -def main(argv): - parser = optparse.OptionParser() - AddInstallAPKOption(parser) - options, args = parser.parse_args(argv) - ValidateInstallAPKOption(parser, options) - if len(args) > 1: - raise Exception('Error: Unknown argument:', args[1:]) - - devices = android_commands.GetAttachedDevices() - if not devices: - raise Exception('Error: no connected devices') - - if not options.apk_package: - options.apk_package = apk_helper.GetPackageName(options.apk) - - pool = multiprocessing.Pool(len(devices)) - # Send a tuple (apk_path, apk_package, device) per device. - pool.map(_InstallApk, zip([options.apk] * len(devices), - [options.apk_package] * len(devices), - [options.keep_data] * len(devices), - devices)) - - -if __name__ == '__main__': - sys.exit(main(sys.argv)) diff --git a/build/android/adb_kill_content_shell b/build/android/adb_kill_content_shell deleted file mode 100755 index 64ab5b11fb..0000000000 --- a/build/android/adb_kill_content_shell +++ /dev/null @@ -1,24 +0,0 @@ -#!/bin/bash -# -# Copyright (c) 2012 The Chromium Authors. All rights reserved. -# Use of this source code is governed by a BSD-style license that can be -# found in the LICENSE file. -# -# Kill a running content shell. -# -# Assumes you have sourced the build/android/envsetup.sh script. - -SHELL_PID_LINES=$(adb shell ps | grep ' org.chromium.content_shell_apk') -VAL=$(echo "$SHELL_PID_LINES" | wc -l) -if [ $VAL -lt 1 ] ; then - echo "Not running Content shell." -else - SHELL_PID=$(echo $SHELL_PID_LINES | awk '{print $2}') - if [ "$SHELL_PID" != "" ] ; then - set -x - adb shell kill $SHELL_PID - set - - else - echo "Content shell does not appear to be running." - fi -fi diff --git a/build/android/adb_logcat_monitor.py b/build/android/adb_logcat_monitor.py deleted file mode 100755 index 35ef7905b2..0000000000 --- a/build/android/adb_logcat_monitor.py +++ /dev/null @@ -1,156 +0,0 @@ -#!/usr/bin/env python -# -# Copyright (c) 2012 The Chromium Authors. All rights reserved. -# Use of this source code is governed by a BSD-style license that can be -# found in the LICENSE file. - -"""Saves logcats from all connected devices. - -Usage: adb_logcat_monitor.py [] - -This script will repeatedly poll adb for new devices and save logcats -inside the directory, which it attempts to create. The -script will run until killed by an external signal. To test, run the -script in a shell and -C it after a while. It should be -resilient across phone disconnects and reconnects and start the logcat -early enough to not miss anything. -""" - -import logging -import os -import re -import shutil -import signal -import subprocess -import sys -import time - -# Map from device_id -> (process, logcat_num) -devices = {} - - -class TimeoutException(Exception): - """Exception used to signal a timeout.""" - pass - - -class SigtermError(Exception): - """Exception used to catch a sigterm.""" - pass - - -def StartLogcatIfNecessary(device_id, adb_cmd, base_dir): - """Spawns a adb logcat process if one is not currently running.""" - process, logcat_num = devices[device_id] - if process: - if process.poll() is None: - # Logcat process is still happily running - return - else: - logging.info('Logcat for device %s has died', device_id) - error_filter = re.compile('- waiting for device -') - for line in process.stderr: - if not error_filter.match(line): - logging.error(device_id + ': ' + line) - - logging.info('Starting logcat %d for device %s', logcat_num, - device_id) - logcat_filename = 'logcat_%s_%03d' % (device_id, logcat_num) - logcat_file = open(os.path.join(base_dir, logcat_filename), 'w') - process = subprocess.Popen([adb_cmd, '-s', device_id, - 'logcat', '-v', 'threadtime'], - stdout=logcat_file, - stderr=subprocess.PIPE) - devices[device_id] = (process, logcat_num + 1) - - -def GetAttachedDevices(adb_cmd): - """Gets the device list from adb. - - We use an alarm in this function to avoid deadlocking from an external - dependency. - - Args: - adb_cmd: binary to run adb - - Returns: - list of devices or an empty list on timeout - """ - signal.alarm(2) - try: - out, err = subprocess.Popen([adb_cmd, 'devices'], - stdout=subprocess.PIPE, - stderr=subprocess.PIPE).communicate() - if err: - logging.warning('adb device error %s', err.strip()) - return re.findall('^(\w+)\tdevice$', out, re.MULTILINE) - except TimeoutException: - logging.warning('"adb devices" command timed out') - return [] - except (IOError, OSError): - logging.exception('Exception from "adb devices"') - return [] - finally: - signal.alarm(0) - - -def main(base_dir, adb_cmd='adb'): - """Monitor adb forever. Expects a SIGINT (Ctrl-C) to kill.""" - # We create the directory to ensure 'run once' semantics - if os.path.exists(base_dir): - print 'adb_logcat_monitor: %s already exists? Cleaning' % base_dir - shutil.rmtree(base_dir, ignore_errors=True) - - os.makedirs(base_dir) - logging.basicConfig(filename=os.path.join(base_dir, 'eventlog'), - level=logging.INFO, - format='%(asctime)-2s %(levelname)-8s %(message)s') - - # Set up the alarm for calling 'adb devices'. This is to ensure - # our script doesn't get stuck waiting for a process response - def TimeoutHandler(_, unused_frame): - raise TimeoutException() - signal.signal(signal.SIGALRM, TimeoutHandler) - - # Handle SIGTERMs to ensure clean shutdown - def SigtermHandler(_, unused_frame): - raise SigtermError() - signal.signal(signal.SIGTERM, SigtermHandler) - - logging.info('Started with pid %d', os.getpid()) - pid_file_path = os.path.join(base_dir, 'LOGCAT_MONITOR_PID') - - try: - with open(pid_file_path, 'w') as f: - f.write(str(os.getpid())) - while True: - for device_id in GetAttachedDevices(adb_cmd): - if not device_id in devices: - subprocess.call([adb_cmd, '-s', device_id, 'logcat', '-c']) - devices[device_id] = (None, 0) - - for device in devices: - # This will spawn logcat watchers for any device ever detected - StartLogcatIfNecessary(device, adb_cmd, base_dir) - - time.sleep(5) - except SigtermError: - logging.info('Received SIGTERM, shutting down') - except: - logging.exception('Unexpected exception in main.') - finally: - for process, _ in devices.itervalues(): - if process: - try: - process.terminate() - except OSError: - pass - os.remove(pid_file_path) - - -if __name__ == '__main__': - if 2 <= len(sys.argv) <= 3: - print 'adb_logcat_monitor: Initializing' - sys.exit(main(*sys.argv[1:3])) - - print 'Usage: %s []' % sys.argv[0] diff --git a/build/android/adb_logcat_printer.py b/build/android/adb_logcat_printer.py deleted file mode 100755 index 5194668ec6..0000000000 --- a/build/android/adb_logcat_printer.py +++ /dev/null @@ -1,202 +0,0 @@ -#!/usr/bin/env python -# -# Copyright (c) 2012 The Chromium Authors. All rights reserved. -# Use of this source code is governed by a BSD-style license that can be -# found in the LICENSE file. - -"""Shutdown adb_logcat_monitor and print accumulated logs. - -To test, call './adb_logcat_printer.py ' where - contains 'adb logcat -v threadtime' files named as -logcat__ - -The script will print the files to out, and will combine multiple -logcats from a single device if there is overlap. - -Additionally, if a /LOGCAT_MONITOR_PID exists, the script -will attempt to terminate the contained PID by sending a SIGINT and -monitoring for the deletion of the aforementioned file. -""" - -import cStringIO -import logging -import os -import re -import signal -import sys -import time - - -# Set this to debug for more verbose output -LOG_LEVEL = logging.INFO - - -def CombineLogFiles(list_of_lists, logger): - """Splices together multiple logcats from the same device. - - Args: - list_of_lists: list of pairs (filename, list of timestamped lines) - logger: handler to log events - - Returns: - list of lines with duplicates removed - """ - cur_device_log = [''] - for cur_file, cur_file_lines in list_of_lists: - # Ignore files with just the logcat header - if len(cur_file_lines) < 2: - continue - common_index = 0 - # Skip this step if list just has empty string - if len(cur_device_log) > 1: - try: - line = cur_device_log[-1] - # Used to make sure we only splice on a timestamped line - if re.match('^\d{2}-\d{2} \d{2}:\d{2}:\d{2}.\d{3} ', line): - common_index = cur_file_lines.index(line) - else: - logger.warning('splice error - no timestamp in "%s"?', line.strip()) - except ValueError: - # The last line was valid but wasn't found in the next file - cur_device_log += ['***** POSSIBLE INCOMPLETE LOGCAT *****'] - logger.info('Unable to splice %s. Incomplete logcat?', cur_file) - - cur_device_log += ['*'*30 + ' %s' % cur_file] - cur_device_log.extend(cur_file_lines[common_index:]) - - return cur_device_log - - -def FindLogFiles(base_dir): - """Search a directory for logcat files. - - Args: - base_dir: directory to search - - Returns: - Mapping of device_id to a sorted list of file paths for a given device - """ - logcat_filter = re.compile('^logcat_(\w+)_(\d+)$') - # list of tuples (, , ) - filtered_list = [] - for cur_file in os.listdir(base_dir): - matcher = logcat_filter.match(cur_file) - if matcher: - filtered_list += [(matcher.group(1), int(matcher.group(2)), - os.path.join(base_dir, cur_file))] - filtered_list.sort() - file_map = {} - for device_id, _, cur_file in filtered_list: - if not device_id in file_map: - file_map[device_id] = [] - - file_map[device_id] += [cur_file] - return file_map - - -def GetDeviceLogs(log_filenames, logger): - """Read log files, combine and format. - - Args: - log_filenames: mapping of device_id to sorted list of file paths - logger: logger handle for logging events - - Returns: - list of formatted device logs, one for each device. - """ - device_logs = [] - - for device, device_files in log_filenames.iteritems(): - logger.debug('%s: %s', device, str(device_files)) - device_file_lines = [] - for cur_file in device_files: - with open(cur_file) as f: - device_file_lines += [(cur_file, f.read().splitlines())] - combined_lines = CombineLogFiles(device_file_lines, logger) - # Prepend each line with a short unique ID so it's easy to see - # when the device changes. We don't use the start of the device - # ID because it can be the same among devices. Example lines: - # AB324: foo - # AB324: blah - device_logs += [('\n' + device[-5:] + ': ').join(combined_lines)] - return device_logs - - -def ShutdownLogcatMonitor(base_dir, logger): - """Attempts to shutdown adb_logcat_monitor and blocks while waiting.""" - try: - monitor_pid_path = os.path.join(base_dir, 'LOGCAT_MONITOR_PID') - with open(monitor_pid_path) as f: - monitor_pid = int(f.readline()) - - logger.info('Sending SIGTERM to %d', monitor_pid) - os.kill(monitor_pid, signal.SIGTERM) - i = 0 - while True: - time.sleep(.2) - if not os.path.exists(monitor_pid_path): - return - if not os.path.exists('/proc/%d' % monitor_pid): - logger.warning('Monitor (pid %d) terminated uncleanly?', monitor_pid) - return - logger.info('Waiting for logcat process to terminate.') - i += 1 - if i >= 10: - logger.warning('Monitor pid did not terminate. Continuing anyway.') - return - - except (ValueError, IOError, OSError): - logger.exception('Error signaling logcat monitor - continuing') - - -def main(base_dir, output_file): - log_stringio = cStringIO.StringIO() - logger = logging.getLogger('LogcatPrinter') - logger.setLevel(LOG_LEVEL) - sh = logging.StreamHandler(log_stringio) - sh.setFormatter(logging.Formatter('%(asctime)-2s %(levelname)-8s' - ' %(message)s')) - logger.addHandler(sh) - - try: - # Wait at least 5 seconds after base_dir is created before printing. - # - # The idea is that 'adb logcat > file' output consists of 2 phases: - # 1 Dump all the saved logs to the file - # 2 Stream log messages as they are generated - # - # We want to give enough time for phase 1 to complete. There's no - # good method to tell how long to wait, but it usually only takes a - # second. On most bots, this code path won't occur at all, since - # adb_logcat_monitor.py command will have spawned more than 5 seconds - # prior to called this shell script. - try: - sleep_time = 5 - (time.time() - os.path.getctime(base_dir)) - except OSError: - sleep_time = 5 - if sleep_time > 0: - logger.warning('Monitor just started? Sleeping %.1fs', sleep_time) - time.sleep(sleep_time) - - assert os.path.exists(base_dir), '%s does not exist' % base_dir - ShutdownLogcatMonitor(base_dir, logger) - separator = '\n' + '*' * 80 + '\n\n' - for log in GetDeviceLogs(FindLogFiles(base_dir), logger): - output_file.write(log) - output_file.write(separator) - with open(os.path.join(base_dir, 'eventlog')) as f: - output_file.write('\nLogcat Monitor Event Log\n') - output_file.write(f.read()) - except: - logger.exception('Unexpected exception') - - logger.info('Done.') - sh.flush() - output_file.write('\nLogcat Printer Event Log\n') - output_file.write(log_stringio.getvalue()) - -if __name__ == '__main__': - if len(sys.argv) == 1: - print 'Usage: %s ' % sys.argv[0] - sys.exit(1) - sys.exit(main(sys.argv[1], sys.stdout)) diff --git a/build/android/adb_profile_chrome b/build/android/adb_profile_chrome deleted file mode 100755 index c4445d1772..0000000000 --- a/build/android/adb_profile_chrome +++ /dev/null @@ -1,139 +0,0 @@ -#!/bin/bash -# -# Copyright 2013 The Chromium Authors. All rights reserved. -# Use of this source code is governed by a BSD-style license that can be -# found in the LICENSE file. -# -# Start / stop profiling in chrome. - -# The profiling data is saved to directory /sdcard/Download. The files -# are named beginning chrome-profile-results- -# -# Assumes you have sourced the android build environment script -# (e.g. 'adb' is on your path). -set -e - -usage() { - echo "adb_profile_chrome [--start [-o file] [-c C]|--stop|-d|-t N] [-v N]" - echo "See http://dev.chromium.org/developers/how-tos/trace-event-profiling-tool for detailed instructions on profiling." - echo "" - echo " --start Start profiling." - echo " --output|-o file Save profile output to file. " - echo " (Default is /sdcard/Download/chrome-profile-results-*)" - echo " --categories|-c C Select categories to trace with comma-delimited wildcards." - echo " e.g. '*', 'cat1*,-cat1a'. Default is '*'." - echo " --stop Stop profiling." - echo " --download|-d Download latest trace." - echo " --time|-t N Profile for N seconds and download the resulting trace." - echo " --version|v N Select among installed browsers." - echo " One of stable (default), beta, dev, build" - echo "" - echo "Profiling data is saved to the device." - exit 0 -} - -send_intent() { - local PACKAGE=$1 - local INTENT=$2 - shift - shift - adb shell am broadcast -a $PACKAGE.$INTENT $* -} - -download_latest_trace() { - TRACE_FILE=$(adb logcat -d | \ - grep "Logging performance trace to file: " | \ - tail -1 | \ - perl -pi -e "s/.*\/storage\/emulated\/.+\/([^\r]+).*/\/sdcard\/Download\/\\1/g") - if [ -z "$TRACE_FILE" ]; then - echo "Unable to determine trace file name" - exit 1 - fi - - adb pull $TRACE_FILE 2> /dev/null - LOCAL_TRACE_FILE=$(basename $TRACE_FILE) - if [ ! -f "$LOCAL_TRACE_FILE" ]; then - echo "Unable to download trace file" - exit 1 - fi -} - -do_timed_capture() { - local PACKAGE=$1 - local INTERVAL=$2 - shift - shift - echo -n "Capturing trace..." - send_intent ${PACKAGE} "GPU_PROFILER_START" $* > /dev/null - sleep ${INTERVAL} - send_intent ${PACKAGE} "GPU_PROFILER_STOP" > /dev/null - echo "done" - - echo -n "Downloading trace..." - sleep $[${INTERVAL} / 4 + 1] - download_latest_trace - echo "done" - - echo "Trace written to ${PWD}/${LOCAL_TRACE_FILE}" -} - -PACKAGE=${DEFAULT_PACKAGE:-com.android.chrome} - -while test -n "$1"; do - case "$1" in - -v|--version) - if [[ -z "$2" ]] ; then - usage - fi - shift - case "$1" in - stable) PACKAGE="com.android.chrome" ;; - beta) PACKAGE="com.chrome.beta" ;; - dev) PACKAGE="com.google.android.apps.chrome_dev" ;; - build) PACKAGE="com.google.android.apps.chrome" ;; - *) usage ;; - esac - ;; - --start) FUNCTION="GPU_PROFILER_START" ;; - --stop) FUNCTION="GPU_PROFILER_STOP" ;; - -o|--output) - if [ -z "$2" ] ; then - usage - fi - OUTPUT="-e file '$2'" - shift - ;; - -c|--categories) - if [ -z "$2" ]; then - usage - fi - CATEGORIES="-e categories '$2'" - shift - ;; - -t|--time) - shift - if [ -z "$1" ] ; then - usage - fi - INTERVAL="$1" - ;; - -d|--download) - shift - download_latest_trace - echo "Trace written to ${PWD}/${LOCAL_TRACE_FILE}" - ;; - *) usage ;; - esac - shift -done - -if [ -z "${INTERVAL}" ] ; then - if [ -z "${FUNCTION}" ] ; then - usage - else - send_intent ${PACKAGE} ${FUNCTION} ${OUTPUT} ${CATEGORIES} - fi -else - do_timed_capture ${PACKAGE} ${INTERVAL} ${CATEGORIES} -fi -exit 0 diff --git a/build/android/adb_reverse_forwarder.py b/build/android/adb_reverse_forwarder.py deleted file mode 100755 index ee38332b3c..0000000000 --- a/build/android/adb_reverse_forwarder.py +++ /dev/null @@ -1,63 +0,0 @@ -#!/usr/bin/env python -# -# Copyright (c) 2013 The Chromium Authors. All rights reserved. -# Use of this source code is governed by a BSD-style license that can be -# found in the LICENSE file. - -"""Command line tool for forwarding ports from a device to the host. - -Allows an Android device to connect to services running on the host machine, -i.e., "adb forward" in reverse. Requires |host_forwarder| and |device_forwarder| -to be built. -""" - -import optparse -import sys -import time - -from pylib import android_commands, forwarder -from pylib.utils import run_tests_helper - - -def main(argv): - parser = optparse.OptionParser(usage='Usage: %prog [options] device_port ' - 'host_port [device_port_2 host_port_2] ...', - description=__doc__) - parser.add_option('-v', - '--verbose', - dest='verbose_count', - default=0, - action='count', - help='Verbose level (multiple times for more)') - parser.add_option('--device', - help='Serial number of device we should use.') - parser.add_option('--debug', action='store_const', const='Debug', - dest='build_type', default='Release', - help='Use Debug build of host tools instead of Release.') - - options, args = parser.parse_args(argv) - run_tests_helper.SetLogLevel(options.verbose_count) - - if len(args) < 2 or not len(args) % 2: - parser.error('Need even number of port pairs') - sys.exit(1) - - try: - port_pairs = map(int, args[1:]) - port_pairs = zip(port_pairs[::2], port_pairs[1::2]) - except ValueError: - parser.error('Bad port number') - sys.exit(1) - - adb = android_commands.AndroidCommands(options.device) - try: - forwarder.Forwarder.Map(port_pairs, adb, options.build_type) - while True: - time.sleep(60) - except KeyboardInterrupt: - sys.exit(0) - finally: - forwarder.Forwarder.UnmapAllDevicePorts(adb) - -if __name__ == '__main__': - main(sys.argv) diff --git a/build/android/adb_run_android_webview_shell b/build/android/adb_run_android_webview_shell deleted file mode 100755 index cc9f6d27e8..0000000000 --- a/build/android/adb_run_android_webview_shell +++ /dev/null @@ -1,15 +0,0 @@ -#!/bin/bash -# -# Copyright (c) 2013 The Chromium Authors. All rights reserved. -# Use of this source code is governed by a BSD-style license that can be -# found in the LICENSE file. - -if [ $# -gt 0 ] ; then - INTENT_ARGS="-d \"$1\"" # e.g. a URL -fi - -adb shell am start \ - -a android.intent.action.VIEW \ - -n org.chromium.android_webview.shell/.AwShellActivity \ - $INTENT_ARGS - diff --git a/build/android/adb_run_chromium_testshell b/build/android/adb_run_chromium_testshell deleted file mode 100755 index b17482c761..0000000000 --- a/build/android/adb_run_chromium_testshell +++ /dev/null @@ -1,14 +0,0 @@ -#!/bin/bash -# -# Copyright (c) 2012 The Chromium Authors. All rights reserved. -# Use of this source code is governed by a BSD-style license that can be -# found in the LICENSE file. - -if [ $# -gt 0 ] ; then - INTENT_ARGS="-d \"$1\"" # e.g. a URL -fi - -adb shell am start \ - -a android.intent.action.VIEW \ - -n org.chromium.chrome.testshell/.ChromiumTestShellActivity \ - $INTENT_ARGS diff --git a/build/android/adb_run_content_shell b/build/android/adb_run_content_shell deleted file mode 100755 index 17a734c982..0000000000 --- a/build/android/adb_run_content_shell +++ /dev/null @@ -1,14 +0,0 @@ -#!/bin/bash -# -# Copyright (c) 2012 The Chromium Authors. All rights reserved. -# Use of this source code is governed by a BSD-style license that can be -# found in the LICENSE file. - -if [ $# -gt 0 ] ; then - INTENT_ARGS="-d \"$1\"" # e.g. a URL -fi - -adb shell am start \ - -a android.intent.action.VIEW \ - -n org.chromium.content_shell_apk/.ContentShellActivity \ - $INTENT_ARGS diff --git a/build/android/ant/apk-codegen.xml b/build/android/ant/apk-codegen.xml deleted file mode 100644 index 37abb077f1..0000000000 --- a/build/android/ant/apk-codegen.xml +++ /dev/null @@ -1,114 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/build/android/ant/apk-compile.xml b/build/android/ant/apk-compile.xml deleted file mode 100644 index 4f3d664aec..0000000000 --- a/build/android/ant/apk-compile.xml +++ /dev/null @@ -1,247 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/build/android/ant/apk-package.xml b/build/android/ant/apk-package.xml deleted file mode 100644 index eeb156c94f..0000000000 --- a/build/android/ant/apk-package.xml +++ /dev/null @@ -1,74 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/build/android/ant/chromium-debug.keystore b/build/android/ant/chromium-debug.keystore deleted file mode 100644 index 67eb0aa34c5af88603ee1e2dedf4bfee3e33be2c..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2223 zcmchYc{J1u8^`B2W)NoVyHFI_X32;dTgWo@EhRH!$U2s65fXEe^}Q_0rg12rYiw;?Gs z{=LDH7{WJuK^9r$<#WrWU`ewUg2U>BD9xv`AwniOw(5~UwTvs;VjI1_tSa^$CuH}Q z1eecLmKwrMW_6c;7UVWA)e=Q?zZ-?Tth>`;lwp)#s5Pfy`Pb`)0k=f-jm7$87#9OI z%~Zup+O#c>o`{*k9W&5mdK!v1Ud4@^unLL>p23U?w=|%e*0Pon;j;9)V_kXVG>L?y zvX1yNf8BDt9p_)VL36U_=L|;GAC8-Ro0hvPMajjm44Dxqy z<8WEMsx$r#-|-CnqapW*5S(1^>}s>IbpmvMxLkg@r~OhO-ZfG z6bfdSFY|G(SrzF}<4_hSOZVcI@lPvO4holvcRgQZybC3t@zdoa-LEmXz(%iX;^HWx@ zI(dyNG_x0lABcVX9;NFXLGh@@xj%6=DLZe0?d;R)`BHugs9xjczH6~_jlw=OMP}31 zLjdv1jr13HJE3tj>($%Y6z-0oKl?@7%T7d7Bm}}Sx$|swBl5jtov%K0-alo{nQvvGM!Gu`;`E;4ZoP-9=2*eJC#AIWS zs;NzUIHB-i6&-drp$oIE;+olP+CKS->zo@XT}*#BKJ`*G4I4-SFICY#`s%$AhoHsR zZ_kKYGI6l5r=pn`-BBr-4HkK*GDzyCOw1=v& z^EvYcvoP6w;rU*PQ_U9%{4r^IV=B`%ZoqEfu}5}8app#M^Pj_IfrbioQ6d!>TMr+! zMz!V6^yz3J7hLEgblT1Zy{^xkTLIGB?=*Fu(9Q^JhdRu<7aeo3A$-BwU%C-H(D9=ofQ%#N^RdZ)QPj5|1{?m$kwE7v(V zvq1$$4iarb1l~NoQd9n{e70xniX@cV7r=ywu!#R6K1YCT&? z(C{4L=hx}R+a`*^DPsENE7iMM*cxGbQItY+ENLSmiBuXw7cv-opfSuodf1*}JKM%@ zE-I3x(c~ZhqrFAzh-tf$OQ>SLZ)p~sjG(lgC3x*>isd<1<^}L4bq@M(p$6N2S`vCj z2ZJ;Kfp|QTRG!mFD%hC80|vlgh?9es84|{OKqK8ceFL`d$9-XjphWhi$>R>;73Xsg zqlAUWhW(fD|3dhFAp*Y;!Cwf^{|Hi98iqn64NypwK2i^(?Z=9ZWQRR09smUVv!VTy*>4B{m87SlXgLMto3G}hrME=Bj-=EtU+vEh?Q#rm z4JA%#XY(Q<=jQw(M}T*gCkY~EhxFm=hWufU<}p6wYKnC;sMXf?gg=hsv#b!-{uA*| z)lHTzz0G!kk7VoER#sJGZCCE2KEv4T6vAQnDtgh8XEW*cgHT>l-xQkqt` zmqDPNGdtKf`|4Mu#o^k}(jlgfd3`!&^U#Q>{6Ql}>E50*7auJZoi@6wrQI@q%XooM tRxx5&F~gtfV%`+}Bzpa0aL`OR>U@K&{F-oP)^j+W$;?<{kNOz|{|%@*$JGD; diff --git a/build/android/ant/create-test-jar.js b/build/android/ant/create-test-jar.js deleted file mode 100644 index 855b47e205..0000000000 --- a/build/android/ant/create-test-jar.js +++ /dev/null @@ -1,65 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -/** - * Combines classes from javac.custom.classpath property and ${out.dir}/classes - * into a single jar file ${ant.project.name}.jar and places the file in - * ${lib.java.dir}. - */ - -importClass(java.io.File); -importClass(org.apache.tools.ant.types.Reference); -importClass(org.apache.tools.ant.types.FileSet); -importClass(org.apache.tools.ant.types.ZipFileSet); -importClass(org.apache.tools.ant.taskdefs.Zip); - -var jarTask = project.createTask("jar"); - -// Do not allow duplicates in the jar, the default behavior of Jar task -// is "add" which means duplicates are allowed. -// This can cause a class file to be included multiple times, setting the -// duplicate to "preserve" ensures that only the first definition is included. - -var duplicate = Zip.Duplicate(); -duplicate.setValue("preserve"); -jarTask.setDuplicate(duplicate); - -var destPath = File(project.getProperty("TEST_JAR_PATH")); -jarTask.setDestFile(destPath); - -// Include all the jars in the classpath. -var javacCustomClasspath = - project.getReference("javac.custom.classpath").list(); - -for (var i in javacCustomClasspath) { - var fileName = javacCustomClasspath[i] - var fileExtension = fileName.split("\\.").pop(); - if(fileExtension == "jar") - { - var zipFileSet = ZipFileSet(); - zipFileSet.setIncludes("**/*.class"); - zipFileSet.setSrc(File(fileName)); - jarTask.addFileset(zipFileSet); - } -} - -// Add the compiled classes in ${out.dir}/classes. -var projectClasses = FileSet(); -projectClasses.setIncludes("**/*.class"); -projectClasses.setDir(File(project.getProperty("out.dir") + "/classes")); -jarTask.addFileset(projectClasses); - -// Exclude manifest and resource classes. -var appPackagePath = - (project.getProperty("project.app.package")).replace('.','/'); -var excludedClasses = ["R.class", "R$*.class", "Manifest.class", - "Manifest$*.class", "BuildConfig.class"] - -var exclusionString = ""; -for (var i in excludedClasses) { - exclusionString += appPackagePath+ "/" + excludedClasses[i] + " "; -} - -jarTask.setExcludes(exclusionString); -jarTask.perform(); diff --git a/build/android/ant/empty/res/.keep b/build/android/ant/empty/res/.keep deleted file mode 100644 index 1fd038b8cf..0000000000 --- a/build/android/ant/empty/res/.keep +++ /dev/null @@ -1,2 +0,0 @@ -# This empty res folder can be passed to aapt while building Java libraries or -# APKs that don't have any resources. diff --git a/build/android/arm-linux-androideabi-gold/arm-linux-androideabi-ld b/build/android/arm-linux-androideabi-gold/arm-linux-androideabi-ld deleted file mode 120000 index 5b178e9f42..0000000000 --- a/build/android/arm-linux-androideabi-gold/arm-linux-androideabi-ld +++ /dev/null @@ -1 +0,0 @@ -../../../third_party/android_tools/ndk/toolchains/arm-linux-androideabi-4.6/prebuilt/linux-x86_64/bin/arm-linux-androideabi-ld.gold \ No newline at end of file diff --git a/build/android/arm-linux-androideabi-gold/ld b/build/android/arm-linux-androideabi-gold/ld deleted file mode 120000 index 2366ddac06..0000000000 --- a/build/android/arm-linux-androideabi-gold/ld +++ /dev/null @@ -1 +0,0 @@ -../../../third_party/android_tools/ndk/toolchains/arm-linux-androideabi-4.6/prebuilt/linux-x86_64/arm-linux-androideabi/bin/ld.gold \ No newline at end of file diff --git a/build/android/asan_symbolize.py b/build/android/asan_symbolize.py deleted file mode 100755 index 928798f5e5..0000000000 --- a/build/android/asan_symbolize.py +++ /dev/null @@ -1,103 +0,0 @@ -#!/usr/bin/env python -# -# Copyright 2013 The Chromium Authors. All rights reserved. -# Use of this source code is governed by a BSD-style license that can be -# found in the LICENSE file. - - -import collections -import optparse -import os -import re -import sys - -from pylib import constants - -# Uses symbol.py from third_party/android_platform, not python's. -sys.path.insert(0, - os.path.join(constants.DIR_SOURCE_ROOT, - 'third_party/android_platform/development/scripts')) -import symbol - - -_RE_ASAN = re.compile(r'I/asanwrapper\.sh.*?(#\S*?) (\S*?) \((.*?)\+(.*?)\)') - -def _ParseAsanLogLine(line): - m = re.match(_RE_ASAN, line) - if not m: - return None - return { - 'library': m.group(3), - 'pos': m.group(1), - 'rel_address': '%08x' % int(m.group(4), 16), - } - - -def _FindASanLibraries(): - asan_lib_dir = os.path.join(constants.DIR_SOURCE_ROOT, - 'third_party', 'llvm-build', - 'Release+Asserts', 'lib') - asan_libs = [] - for src_dir, _, files in os.walk(asan_lib_dir): - asan_libs += [os.path.relpath(os.path.join(src_dir, f)) - for f in files - if f.endswith('.so')] - return asan_libs - - -def _TranslateLibPath(library, asan_libs): - for asan_lib in asan_libs: - if os.path.basename(library) == os.path.basename(asan_lib): - return '/' + asan_lib - return symbol.TranslateLibPath(library) - - -def _Symbolize(input): - asan_libs = _FindASanLibraries() - libraries = collections.defaultdict(list) - asan_lines = [] - for asan_log_line in [a.strip() for a in input]: - m = _ParseAsanLogLine(asan_log_line) - if m: - libraries[m['library']].append(m) - asan_lines.append({'raw_log': asan_log_line, 'parsed': m}) - - all_symbols = collections.defaultdict(dict) - original_symbols_dir = symbol.SYMBOLS_DIR - for library, items in libraries.iteritems(): - libname = _TranslateLibPath(library, asan_libs) - lib_relative_addrs = set([i['rel_address'] for i in items]) - info_dict = symbol.SymbolInformationForSet(libname, - lib_relative_addrs, - True) - if info_dict: - all_symbols[library]['symbols'] = info_dict - - for asan_log_line in asan_lines: - m = asan_log_line['parsed'] - if not m: - print asan_log_line['raw_log'] - continue - if (m['library'] in all_symbols and - m['rel_address'] in all_symbols[m['library']]['symbols']): - s = all_symbols[m['library']]['symbols'][m['rel_address']][0] - print s[0], s[1], s[2] - else: - print asan_log_line['raw_log'] - - -def main(): - parser = optparse.OptionParser() - parser.add_option('-l', '--logcat', - help='File containing adb logcat output with ASan stacks. ' - 'Use stdin if not specified.') - options, args = parser.parse_args() - if options.logcat: - input = file(options.logcat, 'r') - else: - input = sys.stdin - _Symbolize(input.readlines()) - - -if __name__ == "__main__": - sys.exit(main()) diff --git a/build/android/avd.py b/build/android/avd.py deleted file mode 100755 index 2685c592be..0000000000 --- a/build/android/avd.py +++ /dev/null @@ -1,63 +0,0 @@ -#!/usr/bin/env python -# Copyright (c) 2013 The Chromium Authors. All rights reserved. -# Use of this source code is governed by a BSD-style license that can be -# found in the LICENSE file. - -"""Launches Android Virtual Devices with a set configuration for testing Chrome. - -The script will launch a specified number of Android Virtual Devices (AVD's). -""" - - -import install_emulator_deps -import logging -import optparse -import os -import subprocess -import sys - -from pylib import constants -from pylib.utils import emulator - - -def main(argv): - # ANDROID_SDK_ROOT needs to be set to the location of the SDK used to launch - # the emulator to find the system images upon launch. - emulator_sdk = os.path.join(constants.EMULATOR_SDK_ROOT, - 'android_tools', 'sdk') - os.environ['ANDROID_SDK_ROOT'] = emulator_sdk - - opt_parser = optparse.OptionParser(description='AVD script.') - opt_parser.add_option('-n', '--num', dest='emulator_count', - help='Number of emulators to launch (default is 1).', - type='int', default='1') - opt_parser.add_option('--abi', default='x86', - help='Platform of emulators to launch (x86 default).') - - options, _ = opt_parser.parse_args(argv[1:]) - - logging.basicConfig(level=logging.INFO, - format='# %(asctime)-15s: %(message)s') - logging.root.setLevel(logging.INFO) - - # Check if KVM is enabled for x86 AVD's and check for x86 system images. - if options.abi =='x86': - if not install_emulator_deps.CheckKVM(): - logging.critical('ERROR: KVM must be enabled in BIOS, and installed. ' - 'Enable KVM in BIOS and run install_emulator_deps.py') - return 1 - elif not install_emulator_deps.CheckX86Image(): - logging.critical('ERROR: System image for x86 AVD not installed. Run ' - 'install_emulator_deps.py') - return 1 - - if not install_emulator_deps.CheckSDK(): - logging.critical('ERROR: Emulator SDK not installed. Run ' - 'install_emulator_deps.py.') - return 1 - - emulator.LaunchEmulators(options.emulator_count, options.abi, True) - - -if __name__ == '__main__': - sys.exit(main(sys.argv)) diff --git a/build/android/avd_configs/AVD_for_Galaxy_Nexus_by_Google_arm.avd/config.ini b/build/android/avd_configs/AVD_for_Galaxy_Nexus_by_Google_arm.avd/config.ini deleted file mode 100644 index 0b2f972337..0000000000 --- a/build/android/avd_configs/AVD_for_Galaxy_Nexus_by_Google_arm.avd/config.ini +++ /dev/null @@ -1,30 +0,0 @@ -avd.ini.encoding=ISO-8859-1 -hw.dPad=no -hw.lcd.density=320 -sdcard.size=512M -hw.cpu.arch=arm -hw.device.hash=-708107041 -hw.camera.back=none -disk.dataPartition.size=800M -hw.gpu.enabled=yes -skin.dynamic=yes -skin.path=720x1280 -hw.keyboard=yes -hw.cpu.model=cortex-a8 -hw.ramSize=1024 -hw.device.manufacturer=Google -hw.sdCard=yes -hw.mainKeys=no -hw.accelerometer=yes -skin.name=720x1280 -abi.type=armeabi-v7a -hw.trackBall=no -hw.device.name=Galaxy Nexus -hw.battery=yes -hw.sensors.proximity=yes -image.sysdir.1=system-images/android-17/armeabi-v7a/ -hw.sensors.orientation=yes -hw.audioInput=yes -hw.camera.front=none -hw.gps=yes -vm.heapSize=128 diff --git a/build/android/avd_configs/AVD_for_Galaxy_Nexus_by_Google_x86.avd/config.ini b/build/android/avd_configs/AVD_for_Galaxy_Nexus_by_Google_x86.avd/config.ini deleted file mode 100644 index 567ba78e21..0000000000 --- a/build/android/avd_configs/AVD_for_Galaxy_Nexus_by_Google_x86.avd/config.ini +++ /dev/null @@ -1,29 +0,0 @@ -avd.ini.encoding=ISO-8859-1 -hw.dPad=no -hw.lcd.density=320 -sdcard.size=512M -hw.cpu.arch=x86 -hw.device.hash=-708107041 -hw.camera.back=none -disk.dataPartition.size=800M -hw.gpu.enabled=yes -skin.path=720x1280 -skin.dynamic=yes -hw.keyboard=yes -hw.ramSize=1024 -hw.device.manufacturer=Google -hw.sdCard=yes -hw.mainKeys=no -hw.accelerometer=yes -skin.name=720x1280 -abi.type=x86 -hw.trackBall=no -hw.device.name=Galaxy Nexus -hw.battery=yes -hw.sensors.proximity=yes -image.sysdir.1=system-images/android-17/x86/ -hw.sensors.orientation=yes -hw.audioInput=yes -hw.camera.front=none -hw.gps=yes -vm.heapSize=128 diff --git a/build/android/bb_run_sharded_steps.py b/build/android/bb_run_sharded_steps.py deleted file mode 100755 index 99841db61e..0000000000 --- a/build/android/bb_run_sharded_steps.py +++ /dev/null @@ -1,42 +0,0 @@ -#!/usr/bin/env python -# -# Copyright (c) 2012 The Chromium Authors. All rights reserved. -# Use of this source code is governed by a BSD-style license that can be -# found in the LICENSE file. - -"""DEPRECATED! -TODO(bulach): remove me once all other repositories reference -'test_runner.py perf' directly. -""" - -import optparse -import os -import sys - -from pylib import cmd_helper - - -def main(argv): - parser = optparse.OptionParser() - parser.add_option('-s', '--steps', - help='A JSON file containing all the steps to be ' - 'sharded.') - parser.add_option('--flaky_steps', - help='A JSON file containing steps that are flaky and ' - 'will have its exit code ignored.') - parser.add_option('-p', '--print_results', - help='Only prints the results for the previously ' - 'executed step, do not run it again.') - options, urls = parser.parse_args(argv) - if options.print_results: - return cmd_helper.RunCmd(['build/android/test_runner.py', 'perf', - '--print-step', options.print_results]) - flaky_options = [] - if options.flaky_steps: - flaky_options = ['--flaky-steps', options.flaky_steps] - return cmd_helper.RunCmd(['build/android/test_runner.py', 'perf', - '--steps', options.steps] + flaky_options) - - -if __name__ == '__main__': - sys.exit(main(sys.argv)) diff --git a/build/android/buildbot/OWNERS b/build/android/buildbot/OWNERS deleted file mode 100644 index e35895556b..0000000000 --- a/build/android/buildbot/OWNERS +++ /dev/null @@ -1,6 +0,0 @@ -set noparent - -bulach@chromium.org -cmp@chromium.org -ilevy@chromium.org -yfriedman@chromium.org diff --git a/build/android/buildbot/bb_annotations.py b/build/android/buildbot/bb_annotations.py deleted file mode 100644 index 059d673188..0000000000 --- a/build/android/buildbot/bb_annotations.py +++ /dev/null @@ -1,46 +0,0 @@ -# Copyright 2013 The Chromium Authors. All rights reserved. -# Use of this source code is governed by a BSD-style license that can be -# found in the LICENSE file. - -"""Helper functions to print buildbot messages.""" - -def PrintLink(label, url): - """Adds a link with name |label| linking to |url| to current buildbot step. - - Args: - label: A string with the name of the label. - url: A string of the URL. - """ - print '@@@STEP_LINK@%s@%s@@@' % (label, url) - - -def PrintMsg(msg): - """Appends |msg| to the current buildbot step text. - - Args: - msg: String to be appended. - """ - print '@@@STEP_TEXT@%s@@@' % msg - - -def PrintSummaryText(msg): - """Appends |msg| to main build summary. Visible from waterfall. - - Args: - msg: String to be appended. - """ - print '@@@STEP_SUMMARY_TEXT@%s@@@' % msg - - -def PrintError(): - """Marks the current step as failed.""" - print '@@@STEP_FAILURE@@@' - - -def PrintWarning(): - """Marks the current step with a warning.""" - print '@@@STEP_WARNINGS@@@' - - -def PrintNamedStep(step): - print '@@@BUILD_STEP %s@@@' % step diff --git a/build/android/buildbot/bb_device_status_check.py b/build/android/buildbot/bb_device_status_check.py deleted file mode 100755 index ae0bb4a7b1..0000000000 --- a/build/android/buildbot/bb_device_status_check.py +++ /dev/null @@ -1,260 +0,0 @@ -#!/usr/bin/env python -# -# Copyright 2013 The Chromium Authors. All rights reserved. -# Use of this source code is governed by a BSD-style license that can be -# found in the LICENSE file. - -"""A class to keep track of devices across builds and report state.""" -import logging -import optparse -import os -import smtplib -import sys -import re -import urllib - -import bb_annotations - -sys.path.append(os.path.join(os.path.dirname(__file__), '..')) -from pylib import android_commands -from pylib import constants -from pylib import perf_tests_helper -from pylib.cmd_helper import GetCmdOutput - - -def DeviceInfo(serial, options): - """Gathers info on a device via various adb calls. - - Args: - serial: The serial of the attached device to construct info about. - - Returns: - Tuple of device type, build id, report as a string, error messages, and - boolean indicating whether or not device can be used for testing. - """ - - device_adb = android_commands.AndroidCommands(serial) - - # TODO(navabi): Replace AdbShellCmd with device_adb. - device_type = device_adb.GetBuildProduct() - device_build = device_adb.GetBuildId() - device_build_type = device_adb.GetBuildType() - device_product_name = device_adb.GetProductName() - - setup_wizard_disabled = device_adb.GetSetupWizardStatus() == 'DISABLED' - battery = device_adb.GetBatteryInfo() - install_output = GetCmdOutput( - ['%s/build/android/adb_install_apk.py' % constants.DIR_SOURCE_ROOT, '--apk', - '%s/build/android/CheckInstallApk-debug.apk' % constants.DIR_SOURCE_ROOT]) - - def _GetData(re_expression, line, lambda_function=lambda x:x): - if not line: - return 'Unknown' - found = re.findall(re_expression, line) - if found and len(found): - return lambda_function(found[0]) - return 'Unknown' - - install_speed = _GetData('(\d+) KB/s', install_output) - ac_power = _GetData('AC powered: (\w+)', battery) - battery_level = _GetData('level: (\d+)', battery) - battery_temp = _GetData('temperature: (\d+)', battery, - lambda x: float(x) / 10.0) - imei_slice = _GetData('Device ID = (\d+)', - device_adb.GetSubscriberInfo(), - lambda x: x[-6:]) - report = ['Device %s (%s)' % (serial, device_type), - ' Build: %s (%s)' % - (device_build, device_adb.GetBuildFingerprint()), - ' Battery: %s%%' % battery_level, - ' Battery temp: %s' % battery_temp, - ' IMEI slice: %s' % imei_slice, - ' Wifi IP: %s' % device_adb.GetWifiIP(), - ' Install Speed: %s KB/s' % install_speed, - ''] - - errors = [] - if battery_level < 15: - errors += ['Device critically low in battery. Turning off device.'] - if (not setup_wizard_disabled and device_build_type != 'user' and - not options.no_provisioning_check): - errors += ['Setup wizard not disabled. Was it provisioned correctly?'] - if device_product_name == 'mantaray' and ac_power != 'true': - errors += ['Mantaray device not connected to AC power.'] - # TODO(navabi): Insert warning once we have a better handle of what install - # speeds to expect. The following lines were causing too many alerts. - # if install_speed < 500: - # errors += ['Device install speed too low. Do not use for testing.'] - - # Causing the device status check step fail for slow install speed or low - # battery currently is too disruptive to the bots (especially try bots). - # Turn off devices with low battery and the step does not fail. - if battery_level < 15: - device_adb.EnableAdbRoot() - device_adb.Shutdown() - full_report = '\n'.join(report) - return device_type, device_build, battery_level, full_report, errors, True - - -def CheckForMissingDevices(options, adb_online_devs): - """Uses file of previous online devices to detect broken phones. - - Args: - options: out_dir parameter of options argument is used as the base - directory to load and update the cache file. - adb_online_devs: A list of serial numbers of the currently visible - and online attached devices. - """ - # TODO(navabi): remove this once the bug that causes different number - # of devices to be detected between calls is fixed. - logger = logging.getLogger() - logger.setLevel(logging.INFO) - - out_dir = os.path.abspath(options.out_dir) - - def ReadDeviceList(file_name): - devices_path = os.path.join(out_dir, file_name) - devices = [] - try: - with open(devices_path) as f: - devices = f.read().splitlines() - except IOError: - # Ignore error, file might not exist - pass - return devices - - def WriteDeviceList(file_name, device_list): - path = os.path.join(out_dir, file_name) - if not os.path.exists(out_dir): - os.makedirs(out_dir) - with open(path, 'w') as f: - # Write devices currently visible plus devices previously seen. - f.write('\n'.join(set(device_list))) - - last_devices_path = os.path.join(out_dir, '.last_devices') - last_devices = ReadDeviceList('.last_devices') - missing_devs = list(set(last_devices) - set(adb_online_devs)) - - all_known_devices = list(set(adb_online_devs) | set(last_devices)) - WriteDeviceList('.last_devices', all_known_devices) - WriteDeviceList('.last_missing', missing_devs) - - if not all_known_devices: - # This can happen if for some reason the .last_devices file is not - # present or if it was empty. - return ['No online devices. Have any devices been plugged in?'] - if missing_devs: - devices_missing_msg = '%d devices not detected.' % len(missing_devs) - bb_annotations.PrintSummaryText(devices_missing_msg) - - # TODO(navabi): Debug by printing both output from GetCmdOutput and - # GetAttachedDevices to compare results. - crbug_link = ('https://code.google.com/p/chromium/issues/entry?summary=' - '%s&comment=%s&labels=Restrict-View-Google,OS-Android,Infra' % - (urllib.quote('Device Offline'), - urllib.quote('Buildbot: %s %s\n' - 'Build: %s\n' - '(please don\'t change any labels)' % - (os.environ.get('BUILDBOT_BUILDERNAME'), - os.environ.get('BUILDBOT_SLAVENAME'), - os.environ.get('BUILDBOT_BUILDNUMBER'))))) - return ['Current online devices: %s' % adb_online_devs, - '%s are no longer visible. Were they removed?\n' % missing_devs, - 'SHERIFF:\n', - '@@@STEP_LINK@Click here to file a bug@%s@@@\n' % crbug_link, - 'Cache file: %s\n\n' % last_devices_path, - 'adb devices: %s' % GetCmdOutput(['adb', 'devices']), - 'adb devices(GetAttachedDevices): %s' % - android_commands.GetAttachedDevices()] - else: - new_devs = set(adb_online_devs) - set(last_devices) - if new_devs and os.path.exists(last_devices_path): - bb_annotations.PrintWarning() - bb_annotations.PrintSummaryText( - '%d new devices detected' % len(new_devs)) - print ('New devices detected %s. And now back to your ' - 'regularly scheduled program.' % list(new_devs)) - - -def SendDeviceStatusAlert(msg): - from_address = 'buildbot@chromium.org' - to_address = 'chromium-android-device-alerts@google.com' - bot_name = os.environ.get('BUILDBOT_BUILDERNAME') - slave_name = os.environ.get('BUILDBOT_SLAVENAME') - subject = 'Device status check errors on %s, %s.' % (slave_name, bot_name) - msg_body = '\r\n'.join(['From: %s' % from_address, 'To: %s' % to_address, - 'Subject: %s' % subject, '', msg]) - try: - server = smtplib.SMTP('localhost') - server.sendmail(from_address, [to_address], msg_body) - server.quit() - except Exception as e: - print 'Failed to send alert email. Error: %s' % e - - -def main(): - parser = optparse.OptionParser() - parser.add_option('', '--out-dir', - help='Directory where the device path is stored', - default=os.path.join(constants.DIR_SOURCE_ROOT, 'out')) - parser.add_option('--no-provisioning-check', - help='Will not check if devices are provisioned properly.') - parser.add_option('--device-status-dashboard', - help='Output device status data for dashboard.') - options, args = parser.parse_args() - if args: - parser.error('Unknown options %s' % args) - devices = android_commands.GetAttachedDevices() - # TODO(navabi): Test to make sure this fails and then fix call - offline_devices = android_commands.GetAttachedDevices(hardware=False, - emulator=False, - offline=True) - - types, builds, batteries, reports, errors = [], [], [], [], [] - fail_step_lst = [] - if devices: - types, builds, batteries, reports, errors, fail_step_lst = ( - zip(*[DeviceInfo(dev, options) for dev in devices])) - - err_msg = CheckForMissingDevices(options, devices) or [] - - unique_types = list(set(types)) - unique_builds = list(set(builds)) - - bb_annotations.PrintMsg('Online devices: %d. Device types %s, builds %s' - % (len(devices), unique_types, unique_builds)) - print '\n'.join(reports) - - for serial, dev_errors in zip(devices, errors): - if dev_errors: - err_msg += ['%s errors:' % serial] - err_msg += [' %s' % error for error in dev_errors] - - if err_msg: - bb_annotations.PrintWarning() - msg = '\n'.join(err_msg) - print msg - SendDeviceStatusAlert(msg) - - if options.device_status_dashboard: - perf_tests_helper.PrintPerfResult('BotDevices', 'OnlineDevices', - [len(devices)], 'devices') - perf_tests_helper.PrintPerfResult('BotDevices', 'OfflineDevices', - [len(offline_devices)], 'devices', - 'unimportant') - for serial, battery in zip(devices, batteries): - perf_tests_helper.PrintPerfResult('DeviceBattery', serial, [battery], '%', - 'unimportant') - - if False in fail_step_lst: - # TODO(navabi): Build fails on device status check step if there exists any - # devices with critically low battery or install speed. Remove those devices - # from testing, allowing build to continue with good devices. - return 1 - - if not devices: - return 1 - - -if __name__ == '__main__': - sys.exit(main()) diff --git a/build/android/buildbot/bb_device_steps.py b/build/android/buildbot/bb_device_steps.py deleted file mode 100755 index 1d83a96e23..0000000000 --- a/build/android/buildbot/bb_device_steps.py +++ /dev/null @@ -1,387 +0,0 @@ -#!/usr/bin/env python -# Copyright (c) 2013 The Chromium Authors. All rights reserved. -# Use of this source code is governed by a BSD-style license that can be -# found in the LICENSE file. - -import collections -import glob -import multiprocessing -import os -import shutil -import sys - -import bb_utils -import bb_annotations - -sys.path.append(os.path.join(os.path.dirname(__file__), '..')) -import provision_devices -from pylib import android_commands -from pylib import constants -from pylib.gtest import gtest_config - -sys.path.append(os.path.join( - constants.DIR_SOURCE_ROOT, 'third_party', 'android_testrunner')) -import errors - - -CHROME_SRC = constants.DIR_SOURCE_ROOT -LOGCAT_DIR = os.path.join(CHROME_SRC, 'out', 'logcat') - -# Describes an instrumation test suite: -# test: Name of test we're running. -# apk: apk to be installed. -# apk_package: package for the apk to be installed. -# test_apk: apk to run tests on. -# test_data: data folder in format destination:source. -# host_driven_root: The host-driven test root directory. -# annotation: Annotation of the tests to include. -# exclude_annotation: The annotation of the tests to exclude. -I_TEST = collections.namedtuple('InstrumentationTest', [ - 'name', 'apk', 'apk_package', 'test_apk', 'test_data', 'host_driven_root', - 'annotation', 'exclude_annotation', 'extra_flags']) - -def I(name, apk, apk_package, test_apk, test_data, host_driven_root=None, - annotation=None, exclude_annotation=None, extra_flags=None): - return I_TEST(name, apk, apk_package, test_apk, test_data, host_driven_root, - annotation, exclude_annotation, extra_flags) - -INSTRUMENTATION_TESTS = dict((suite.name, suite) for suite in [ - I('ContentShell', - 'ContentShell.apk', - 'org.chromium.content_shell_apk', - 'ContentShellTest', - 'content:content/test/data/android/device_files'), - I('ChromiumTestShell', - 'ChromiumTestShell.apk', - 'org.chromium.chrome.testshell', - 'ChromiumTestShellTest', - 'chrome:chrome/test/data/android/device_files', - constants.CHROMIUM_TEST_SHELL_HOST_DRIVEN_DIR), - I('AndroidWebView', - 'AndroidWebView.apk', - 'org.chromium.android_webview.shell', - 'AndroidWebViewTest', - 'webview:android_webview/test/data/device_files'), - ]) - -VALID_TESTS = set(['chromedriver', 'ui', 'unit', 'webkit', 'webkit_layout', - 'webrtc']) - -RunCmd = bb_utils.RunCmd - - -# multiprocessing map_async requires a top-level function for pickle library. -def RebootDeviceSafe(device): - """Reboot a device, wait for it to start, and squelch timeout exceptions.""" - try: - android_commands.AndroidCommands(device).Reboot(True) - except errors.DeviceUnresponsiveError as e: - return e - - -def RebootDevices(): - """Reboot all attached and online devices.""" - # Early return here to avoid presubmit dependence on adb, - # which might not exist in this checkout. - if bb_utils.TESTING: - return - devices = android_commands.GetAttachedDevices(emulator=False) - print 'Rebooting: %s' % devices - if devices: - pool = multiprocessing.Pool(len(devices)) - results = pool.map_async(RebootDeviceSafe, devices).get(99999) - - for device, result in zip(devices, results): - if result: - print '%s failed to startup.' % device - - if any(results): - bb_annotations.PrintWarning() - else: - print 'Reboots complete.' - - -def RunTestSuites(options, suites): - """Manages an invocation of test_runner.py for gtests. - - Args: - options: options object. - suites: List of suite names to run. - """ - args = ['--verbose'] - if options.target == 'Release': - args.append('--release') - if options.asan: - args.append('--tool=asan') - for suite in suites: - bb_annotations.PrintNamedStep(suite) - cmd = ['build/android/test_runner.py', 'gtest', '-s', suite] + args - if suite == 'content_browsertests': - cmd.append('--num_retries=1') - RunCmd(cmd) - -def RunChromeDriverTests(_): - """Run all the steps for running chromedriver tests.""" - bb_annotations.PrintNamedStep('chromedriver_annotation') - RunCmd(['chrome/test/chromedriver/run_buildbot_steps.py', - '--android-package=%s' % constants.CHROMIUM_TEST_SHELL_PACKAGE]) - -def InstallApk(options, test, print_step=False): - """Install an apk to all phones. - - Args: - options: options object - test: An I_TEST namedtuple - print_step: Print a buildbot step - """ - if print_step: - bb_annotations.PrintNamedStep('install_%s' % test.name.lower()) - args = ['--apk', test.apk, '--apk_package', test.apk_package] - if options.target == 'Release': - args.append('--release') - - RunCmd(['build/android/adb_install_apk.py'] + args, halt_on_failure=True) - - -def RunInstrumentationSuite(options, test, flunk_on_failure=True, - python_only=False): - """Manages an invocation of test_runner.py for instrumentation tests. - - Args: - options: options object - test: An I_TEST namedtuple - flunk_on_failure: Flunk the step if tests fail. - Python: Run only host driven Python tests. - """ - bb_annotations.PrintNamedStep('%s_instrumentation_tests' % test.name.lower()) - - InstallApk(options, test) - args = ['--test-apk', test.test_apk, '--test_data', test.test_data, - '--verbose'] - if options.target == 'Release': - args.append('--release') - if options.asan: - args.append('--tool=asan') - if options.flakiness_server: - args.append('--flakiness-dashboard-server=%s' % - options.flakiness_server) - if test.host_driven_root: - args.append('--host-driven-root=%s' % test.host_driven_root) - if test.annotation: - args.extend(['-A', test.annotation]) - if test.exclude_annotation: - args.extend(['-E', test.exclude_annotation]) - if test.extra_flags: - args.extend(test.extra_flags) - if python_only: - args.append('-p') - - RunCmd(['build/android/test_runner.py', 'instrumentation'] + args, - flunk_on_failure=flunk_on_failure) - - -def RunWebkitLint(target): - """Lint WebKit's TestExpectation files.""" - bb_annotations.PrintNamedStep('webkit_lint') - RunCmd(['webkit/tools/layout_tests/run_webkit_tests.py', - '--lint-test-files', - '--chromium', - '--target', target]) - - -def RunWebkitLayoutTests(options): - """Run layout tests on an actual device.""" - bb_annotations.PrintNamedStep('webkit_tests') - cmd_args = [ - '--no-show-results', - '--no-new-test-results', - '--full-results-html', - '--clobber-old-results', - '--exit-after-n-failures', '5000', - '--exit-after-n-crashes-or-timeouts', '100', - '--debug-rwt-logging', - '--results-directory', '..layout-test-results', - '--target', options.target, - '--builder-name', options.build_properties.get('buildername', ''), - '--build-number', str(options.build_properties.get('buildnumber', '')), - '--master-name', options.build_properties.get('mastername', ''), - '--build-name', options.build_properties.get('buildername', ''), - '--platform=android'] - - for flag in 'test_results_server', 'driver_name', 'additional_drt_flag': - if flag in options.factory_properties: - cmd_args.extend(['--%s' % flag.replace('_', '-'), - options.factory_properties.get(flag)]) - - for f in options.factory_properties.get('additional_expectations', []): - cmd_args.extend( - ['--additional-expectations=%s' % os.path.join(CHROME_SRC, *f)]) - - # TODO(dpranke): Remove this block after - # https://codereview.chromium.org/12927002/ lands. - for f in options.factory_properties.get('additional_expectations_files', []): - cmd_args.extend( - ['--additional-expectations=%s' % os.path.join(CHROME_SRC, *f)]) - - RunCmd(['webkit/tools/layout_tests/run_webkit_tests.py'] + cmd_args, - flunk_on_failure=False) - - -def SpawnLogcatMonitor(): - shutil.rmtree(LOGCAT_DIR, ignore_errors=True) - bb_utils.SpawnCmd([ - os.path.join(CHROME_SRC, 'build', 'android', 'adb_logcat_monitor.py'), - LOGCAT_DIR]) - - # Wait for logcat_monitor to pull existing logcat - RunCmd(['sleep', '5']) - -def ProvisionDevices(options): - # Restart adb to work around bugs, sleep to wait for usb discovery. - RunCmd(['adb', 'kill-server']) - RunCmd(['adb', 'start-server']) - RunCmd(['sleep', '1']) - - bb_annotations.PrintNamedStep('provision_devices') - if options.reboot: - RebootDevices() - provision_cmd = ['build/android/provision_devices.py', '-t', options.target] - if options.auto_reconnect: - provision_cmd.append('--auto-reconnect') - RunCmd(provision_cmd) - - -def DeviceStatusCheck(_): - bb_annotations.PrintNamedStep('device_status_check') - RunCmd(['build/android/buildbot/bb_device_status_check.py'], - halt_on_failure=True) - - -def GetDeviceSetupStepCmds(): - return [ - ('provision_devices', ProvisionDevices), - ('device_status_check', DeviceStatusCheck) - ] - - -def RunUnitTests(options): - RunTestSuites(options, gtest_config.STABLE_TEST_SUITES) - - -def RunInstrumentationTests(options): - for test in INSTRUMENTATION_TESTS.itervalues(): - RunInstrumentationSuite(options, test) - - -def RunWebkitTests(options): - RunTestSuites(options, ['webkit_unit_tests']) - RunWebkitLint(options.target) - - -def RunWebRTCTests(options): - RunTestSuites(options, gtest_config.WEBRTC_TEST_SUITES) - - -def GetTestStepCmds(): - return [ - ('chromedriver', RunChromeDriverTests), - ('unit', RunUnitTests), - ('ui', RunInstrumentationTests), - ('webkit', RunWebkitTests), - ('webkit_layout', RunWebkitLayoutTests), - ('webrtc', RunWebRTCTests), - ] - - -def LogcatDump(options): - # Print logcat, kill logcat monitor - bb_annotations.PrintNamedStep('logcat_dump') - logcat_file = os.path.join(CHROME_SRC, 'out', options.target, 'full_log') - with open(logcat_file, 'w') as f: - RunCmd([ - os.path.join(CHROME_SRC, 'build', 'android', 'adb_logcat_printer.py'), - LOGCAT_DIR], stdout=f) - RunCmd(['cat', logcat_file]) - - -def GenerateTestReport(options): - bb_annotations.PrintNamedStep('test_report') - for report in glob.glob( - os.path.join(CHROME_SRC, 'out', options.target, 'test_logs', '*.log')): - RunCmd(['cat', report]) - os.remove(report) - - -def MainTestWrapper(options): - try: - # Spawn logcat monitor - SpawnLogcatMonitor() - - # Run all device setup steps - for _, cmd in GetDeviceSetupStepCmds(): - cmd(options) - - if options.install: - test_obj = INSTRUMENTATION_TESTS[options.install] - InstallApk(options, test_obj, print_step=True) - - if options.test_filter: - bb_utils.RunSteps(options.test_filter, GetTestStepCmds(), options) - - if options.experimental: - RunTestSuites(options, gtest_config.EXPERIMENTAL_TEST_SUITES) - - finally: - # Run all post test steps - LogcatDump(options) - GenerateTestReport(options) - # KillHostHeartbeat() has logic to check if heartbeat process is running, - # and kills only if it finds the process is running on the host. - provision_devices.KillHostHeartbeat() - - -def GetDeviceStepsOptParser(): - parser = bb_utils.GetParser() - parser.add_option('--experimental', action='store_true', - help='Run experiemental tests') - parser.add_option('-f', '--test-filter', metavar='', default=[], - action='append', - help=('Run a test suite. Test suites: "%s"' % - '", "'.join(VALID_TESTS))) - parser.add_option('--asan', action='store_true', help='Run tests with asan.') - parser.add_option('--install', metavar='', - help='Install an apk by name') - parser.add_option('--reboot', action='store_true', - help='Reboot devices before running tests') - parser.add_option( - '--flakiness-server', - help='The flakiness dashboard server to which the results should be ' - 'uploaded.') - parser.add_option( - '--auto-reconnect', action='store_true', - help='Push script to device which restarts adbd on disconnections.') - parser.add_option( - '--logcat-dump-output', - help='The logcat dump output will be "tee"-ed into this file') - - return parser - - -def main(argv): - parser = GetDeviceStepsOptParser() - options, args = parser.parse_args(argv[1:]) - - if args: - return sys.exit('Unused args %s' % args) - - unknown_tests = set(options.test_filter) - VALID_TESTS - if unknown_tests: - return sys.exit('Unknown tests %s' % list(unknown_tests)) - - setattr(options, 'target', options.factory_properties.get('target', 'Debug')) - - MainTestWrapper(options) - - -if __name__ == '__main__': - sys.exit(main(sys.argv)) diff --git a/build/android/buildbot/bb_host_steps.py b/build/android/buildbot/bb_host_steps.py deleted file mode 100755 index a28f5765e4..0000000000 --- a/build/android/buildbot/bb_host_steps.py +++ /dev/null @@ -1,141 +0,0 @@ -#!/usr/bin/env python -# Copyright 2013 The Chromium Authors. All rights reserved. -# Use of this source code is governed by a BSD-style license that can be -# found in the LICENSE file. - -import os -import sys - -import bb_utils -import bb_annotations - -sys.path.append(os.path.join(os.path.dirname(__file__), '..')) -from pylib import constants - - -SLAVE_SCRIPTS_DIR = os.path.join(bb_utils.BB_BUILD_DIR, 'scripts', 'slave') -VALID_HOST_TESTS = set(['check_webview_licenses', 'findbugs']) -EXPERIMENTAL_TARGETS = ['android_experimental'] - -# Short hand for RunCmd which is used extensively in this file. -RunCmd = bb_utils.RunCmd - - -def SrcPath(*path): - return os.path.join(constants.DIR_SOURCE_ROOT, *path) - - -def CheckWebViewLicenses(_): - bb_annotations.PrintNamedStep('check_licenses') - RunCmd([SrcPath('android_webview', 'tools', 'webview_licenses.py'), 'scan'], - warning_code=1) - - -def RunHooks(build_type): - RunCmd([SrcPath('build', 'landmines.py')]) - build_path = SrcPath('out', build_type) - landmine_path = os.path.join(build_path, '.landmines_triggered') - clobber_env = os.environ.get('BUILDBOT_CLOBBER') - if clobber_env or os.path.isfile(landmine_path): - bb_annotations.PrintNamedStep('Clobber') - if not clobber_env: - print 'Clobbering due to triggered landmines:' - with open(landmine_path) as f: - print f.read() - RunCmd(['rm', '-rf', build_path]) - - bb_annotations.PrintNamedStep('runhooks') - RunCmd(['gclient', 'runhooks'], halt_on_failure=True) - - -def Compile(options): - RunHooks(options.target) - cmd = [os.path.join(SLAVE_SCRIPTS_DIR, 'compile.py'), - '--build-tool=ninja', - '--compiler=goma', - '--target=%s' % options.target, - '--goma-dir=%s' % bb_utils.GOMA_DIR] - build_targets = options.build_targets.split(',') - bb_annotations.PrintNamedStep('compile') - for build_target in build_targets: - RunCmd(cmd + ['--build-args=%s' % build_target], halt_on_failure=True) - if options.experimental: - for compile_target in EXPERIMENTAL_TARGETS: - bb_annotations.PrintNamedStep('Experimental Compile %s' % compile_target) - RunCmd(cmd + ['--build-args=%s' % compile_target], flunk_on_failure=False) - - -def ZipBuild(options): - bb_annotations.PrintNamedStep('zip_build') - RunCmd([ - os.path.join(SLAVE_SCRIPTS_DIR, 'zip_build.py'), - '--src-dir', constants.DIR_SOURCE_ROOT, - '--build-dir', SrcPath('out'), - '--exclude-files', 'lib.target,gen,android_webview,jingle_unittests'] - + bb_utils.EncodeProperties(options)) - - -def ExtractBuild(options): - bb_annotations.PrintNamedStep('extract_build') - RunCmd( - [os.path.join(SLAVE_SCRIPTS_DIR, 'extract_build.py'), - '--build-dir', SrcPath('build'), '--build-output-dir', - SrcPath('out')] + bb_utils.EncodeProperties(options), - warning_code=1) - - -def FindBugs(options): - bb_annotations.PrintNamedStep('findbugs') - build_type = [] - if options.target == 'Release': - build_type = ['--release-build'] - RunCmd([SrcPath('build', 'android', 'findbugs_diff.py')] + build_type) - RunCmd([SrcPath( - 'tools', 'android', 'findbugs_plugin', 'test', - 'run_findbugs_plugin_tests.py')] + build_type) - - -def BisectPerfRegression(_): - bb_annotations.PrintNamedStep('Bisect Perf Regression') - RunCmd([SrcPath('tools', 'prepare-bisect-perf-regression.py'), - '-w', os.path.join(constants.DIR_SOURCE_ROOT, os.pardir)]) - RunCmd([SrcPath('tools', 'run-bisect-perf-regression.py'), - '-w', os.path.join(constants.DIR_SOURCE_ROOT, os.pardir)]) - - -def GetHostStepCmds(): - return [ - ('compile', Compile), - ('extract_build', ExtractBuild), - ('check_webview_licenses', CheckWebViewLicenses), - ('bisect_perf_regression', BisectPerfRegression), - ('findbugs', FindBugs), - ('zip_build', ZipBuild) - ] - - -def GetHostStepsOptParser(): - parser = bb_utils.GetParser() - parser.add_option('--steps', help='Comma separated list of host tests.') - parser.add_option('--build-targets', default='All', - help='Comma separated list of build targets.') - parser.add_option('--experimental', action='store_true', - help='Indicate whether to compile experimental targets.') - - return parser - - -def main(argv): - parser = GetHostStepsOptParser() - options, args = parser.parse_args(argv[1:]) - if args: - return sys.exit('Unused args %s' % args) - - setattr(options, 'target', options.factory_properties.get('target', 'Debug')) - - if options.steps: - bb_utils.RunSteps(options.steps.split(','), GetHostStepCmds(), options) - - -if __name__ == '__main__': - sys.exit(main(sys.argv)) diff --git a/build/android/buildbot/bb_run_bot.py b/build/android/buildbot/bb_run_bot.py deleted file mode 100755 index 7637024693..0000000000 --- a/build/android/buildbot/bb_run_bot.py +++ /dev/null @@ -1,273 +0,0 @@ -#!/usr/bin/env python -# -# Copyright (c) 2013 The Chromium Authors. All rights reserved. -# Use of this source code is governed by a BSD-style license that can be -# found in the LICENSE file. - -import collections -import copy -import json -import os -import pipes -import re -import subprocess -import sys - -import bb_utils - -sys.path.append(os.path.join(os.path.dirname(__file__), '..')) -from pylib import constants - - -_BotConfig = collections.namedtuple( - 'BotConfig', ['bot_id', 'host_obj', 'test_obj']) - -HostConfig = collections.namedtuple( - 'HostConfig', - ['script', 'host_steps', 'extra_args', 'extra_gyp_defines', 'target_arch']) - -TestConfig = collections.namedtuple('Tests', ['script', 'tests', 'extra_args']) - - -def BotConfig(bot_id, host_object, test_object=None): - return _BotConfig(bot_id, host_object, test_object) - - -def DictDiff(d1, d2): - diff = [] - for key in sorted(set(d1.keys() + d2.keys())): - if key in d1 and d1[key] != d2.get(key): - diff.append('- %s=%s' % (key, pipes.quote(d1[key]))) - if key in d2 and d2[key] != d1.get(key): - diff.append('+ %s=%s' % (key, pipes.quote(d2[key]))) - return '\n'.join(diff) - - -def GetEnvironment(host_obj, testing): - init_env = dict(os.environ) - init_env['GYP_GENERATORS'] = 'ninja' - init_env['GOMA_DIR'] = bb_utils.GOMA_DIR - envsetup_cmd = '. build/android/envsetup.sh' - if host_obj.target_arch: - envsetup_cmd += ' --target-arch=%s' % host_obj.target_arch - if testing: - # Skip envsetup to avoid presubmit dependence on android deps. - print 'Testing mode - skipping "%s"' % envsetup_cmd - envsetup_cmd = ':' - else: - print 'Running %s' % envsetup_cmd - proc = subprocess.Popen(['bash', '-exc', - envsetup_cmd + ' >&2; python build/android/buildbot/env_to_json.py'], - stdout=subprocess.PIPE, stderr=subprocess.PIPE, - cwd=bb_utils.CHROME_SRC, env=init_env) - json_env, envsetup_output = proc.communicate() - if proc.returncode != 0: - print >> sys.stderr, 'FATAL Failure in envsetup.' - print >> sys.stderr, envsetup_output - sys.exit(1) - env = json.loads(json_env) - env['GYP_DEFINES'] = env.get('GYP_DEFINES', '') + ' fastbuild=1' - extra_gyp = host_obj.extra_gyp_defines - if extra_gyp: - env['GYP_DEFINES'] += ' %s' % extra_gyp - if re.search('(asan|clang)=1', extra_gyp): - env.pop('CXX_target', None) - - # Bots checkout chrome in /b/build/slave//build/src - build_internal_android = os.path.abspath(os.path.join( - bb_utils.CHROME_SRC, '..', '..', '..', '..', '..', 'build_internal', - 'scripts', 'slave', 'android')) - if os.path.exists(build_internal_android): - env['PATH'] = os.pathsep.join([build_internal_android, env['PATH']]) - return env - - -def GetCommands(options, bot_config): - """Get a formatted list of commands. - - Args: - options: Options object. - bot_config: A BotConfig named tuple. - host_step_script: Host step script. - device_step_script: Device step script. - Returns: - list of Command objects. - """ - property_args = bb_utils.EncodeProperties(options) - commands = [[bot_config.host_obj.script, - '--steps=%s' % ','.join(bot_config.host_obj.host_steps)] + - property_args + (bot_config.host_obj.extra_args or [])] - - test_obj = bot_config.test_obj - if test_obj: - run_test_cmd = [test_obj.script, '--reboot'] + property_args - for test in test_obj.tests: - run_test_cmd.extend(['-f', test]) - if test_obj.extra_args: - run_test_cmd.extend(test_obj.extra_args) - commands.append(run_test_cmd) - return commands - - -def GetBotStepMap(): - compile_step = ['compile'] - std_host_tests = ['check_webview_licenses', 'findbugs'] - std_build_steps = ['compile', 'zip_build'] - std_test_steps = ['extract_build'] - std_tests = ['ui', 'unit'] - flakiness_server = ( - '--flakiness-server=%s' % constants.UPSTREAM_FLAKINESS_SERVER) - experimental = ['--experimental'] - - B = BotConfig - H = (lambda steps, extra_args=None, extra_gyp=None, target_arch=None : - HostConfig('build/android/buildbot/bb_host_steps.py', steps, extra_args, - extra_gyp, target_arch)) - T = (lambda tests, extra_args=None : - TestConfig('build/android/buildbot/bb_device_steps.py', tests, - extra_args)) - - bot_configs = [ - # Main builders - B('main-builder-dbg', H(std_build_steps + std_host_tests)), - B('main-builder-rel', H(std_build_steps)), - B('main-clang-builder', - H(compile_step, extra_gyp='clang=1 component=shared_library')), - B('main-clobber', H(compile_step)), - B('main-tests', H(std_test_steps), T(std_tests, [flakiness_server])), - - # Other waterfalls - B('asan-builder-tests', H(compile_step, extra_gyp='asan=1'), - T(std_tests, ['--asan'])), - B('chromedriver-fyi-tests-dbg', H(std_test_steps), - T(['chromedriver'], ['--install=ChromiumTestShell'])), - B('fyi-x86-builder-dbg', - H(compile_step + std_host_tests, experimental, target_arch='x86')), - B('fyi-builder-dbg', - H(std_build_steps + std_host_tests, experimental)), - B('x86-builder-dbg', - H(compile_step + std_host_tests, target_arch='x86')), - B('fyi-builder-rel', H(std_build_steps, experimental)), - B('fyi-tests', H(std_test_steps), - T(std_tests, ['--experimental', flakiness_server])), - B('fyi-component-builder-tests-dbg', - H(compile_step, extra_gyp='component=shared_library'), - T(std_tests, ['--experimental', flakiness_server])), - B('perf-bisect-builder-tests-dbg', H(['bisect_perf_regression'])), - B('perf-tests-rel', H(std_test_steps), - T([], ['--install=ChromiumTestShell'])), - B('webkit-latest-webkit-tests', H(std_test_steps), - T(['webkit_layout', 'webkit'], ['--auto-reconnect'])), - B('webkit-latest-contentshell', H(compile_step), - T(['webkit_layout'], ['--auto-reconnect'])), - B('builder-unit-tests', H(compile_step), T(['unit'])), - B('webrtc-tests', H(std_test_steps), T(['webrtc'], [flakiness_server])), - - # Generic builder config (for substring match). - B('builder', H(std_build_steps)), - ] - - bot_map = dict((config.bot_id, config) for config in bot_configs) - - # These bots have identical configuration to ones defined earlier. - copy_map = [ - ('lkgr-clobber', 'main-clobber'), - ('try-builder-dbg', 'main-builder-dbg'), - ('try-builder-rel', 'main-builder-rel'), - ('try-clang-builder', 'main-clang-builder'), - ('try-fyi-builder-dbg', 'fyi-builder-dbg'), - ('try-x86-builder-dbg', 'x86-builder-dbg'), - ('try-tests', 'main-tests'), - ('try-fyi-tests', 'fyi-tests'), - ('webkit-latest-tests', 'main-tests'), - ('webrtc-builder', 'main-builder-rel'), - ] - for to_id, from_id in copy_map: - assert to_id not in bot_map - # pylint: disable=W0212 - bot_map[to_id] = copy.deepcopy(bot_map[from_id])._replace(bot_id=to_id) - - # Trybots do not upload to flakiness dashboard. They should be otherwise - # identical in configuration to their trunk building counterparts. - test_obj = bot_map[to_id].test_obj - if to_id.startswith('try') and test_obj: - extra_args = test_obj.extra_args - if extra_args and flakiness_server in extra_args: - extra_args.remove(flakiness_server) - return bot_map - - -# Return an object from the map, looking first for an exact id match. -# If this fails, look for an id which is a substring of the specified id. -# Choose the longest of all substring matches. -# pylint: disable=W0622 -def GetBestMatch(id_map, id): - config = id_map.get(id) - if not config: - substring_matches = filter(lambda x: x in id, id_map.iterkeys()) - if substring_matches: - max_id = max(substring_matches, key=len) - print 'Using config from id="%s" (substring match).' % max_id - config = id_map[max_id] - return config - - -def GetRunBotOptParser(): - parser = bb_utils.GetParser() - parser.add_option('--bot-id', help='Specify bot id directly.') - parser.add_option('--testing', action='store_true', - help='For testing: print, but do not run commands') - - return parser - - -def GetBotConfig(options, bot_step_map): - bot_id = options.bot_id or options.factory_properties.get('android_bot_id') - if not bot_id: - print (sys.stderr, - 'A bot id must be specified through option or factory_props.') - return - - bot_config = GetBestMatch(bot_step_map, bot_id) - if not bot_config: - print 'Error: config for id="%s" cannot be inferred.' % bot_id - return bot_config - - -def RunBotCommands(options, commands, env): - print 'Environment changes:' - print DictDiff(dict(os.environ), env) - - for command in commands: - print bb_utils.CommandToString(command) - sys.stdout.flush() - if options.testing: - env['BUILDBOT_TESTING'] = '1' - return_code = subprocess.call(command, cwd=bb_utils.CHROME_SRC, env=env) - if return_code != 0: - return return_code - - -def main(argv): - parser = GetRunBotOptParser() - options, args = parser.parse_args(argv[1:]) - if args: - parser.error('Unused args: %s' % args) - - bot_config = GetBotConfig(options, GetBotStepMap()) - if not bot_config: - sys.exit(1) - - print 'Using config:', bot_config - - commands = GetCommands(options, bot_config) - for command in commands: - print 'Will run: ', bb_utils.CommandToString(command) - print - - env = GetEnvironment(bot_config.host_obj, options.testing) - return RunBotCommands(options, commands, env) - - -if __name__ == '__main__': - sys.exit(main(sys.argv)) diff --git a/build/android/buildbot/bb_utils.py b/build/android/buildbot/bb_utils.py deleted file mode 100644 index f16540bc69..0000000000 --- a/build/android/buildbot/bb_utils.py +++ /dev/null @@ -1,92 +0,0 @@ -# Copyright 2013 The Chromium Authors. All rights reserved. -# Use of this source code is governed by a BSD-style license that can be -# found in the LICENSE file. - -import json -import optparse -import os -import pipes -import subprocess -import sys - -import bb_annotations - -sys.path.append(os.path.join(os.path.dirname(__file__), '..')) -from pylib import constants - - -TESTING = 'BUILDBOT_TESTING' in os.environ - -BB_BUILD_DIR = os.path.abspath( - os.path.join(os.path.dirname(__file__), os.pardir, os.pardir, os.pardir, - os.pardir, os.pardir, os.pardir, os.pardir)) - -CHROME_SRC = os.path.abspath( - os.path.join(os.path.dirname(__file__), '..', '..', '..')) - -GOMA_DIR = os.environ.get('GOMA_DIR', os.path.join(BB_BUILD_DIR, 'goma')) - -def CommandToString(command): - """Returns quoted command that can be run in bash shell.""" - return ' '.join(map(pipes.quote, command)) - - -def SpawnCmd(command, stdout=None, cwd=CHROME_SRC): - """Spawn a process without waiting for termination.""" - print '>', CommandToString(command) - sys.stdout.flush() - if TESTING: - class MockPopen(object): - @staticmethod - def wait(): - return 0 - return MockPopen() - return subprocess.Popen(command, cwd=cwd, stdout=stdout) - - -def RunCmd(command, flunk_on_failure=True, halt_on_failure=False, - warning_code=constants.WARNING_EXIT_CODE, stdout=None, - cwd=CHROME_SRC): - """Run a command relative to the chrome source root.""" - code = SpawnCmd(command, stdout, cwd).wait() - print '<', CommandToString(command) - if code != 0: - print 'ERROR: process exited with code %d' % code - if code != warning_code and flunk_on_failure: - bb_annotations.PrintError() - else: - bb_annotations.PrintWarning() - # Allow steps to have both halting (i.e. 1) and non-halting exit codes. - if code != warning_code and halt_on_failure: - print 'FATAL %d != %d' % (code, warning_code) - sys.exit(1) - return code - - -def GetParser(): - def ConvertJson(option, _, value, parser): - setattr(parser.values, option.dest, json.loads(value)) - parser = optparse.OptionParser() - parser.add_option('--build-properties', action='callback', - callback=ConvertJson, type='string', default={}, - help='build properties in JSON format') - parser.add_option('--factory-properties', action='callback', - callback=ConvertJson, type='string', default={}, - help='factory properties in JSON format') - return parser - - -def EncodeProperties(options): - return ['--factory-properties=%s' % json.dumps(options.factory_properties), - '--build-properties=%s' % json.dumps(options.build_properties)] - - -def RunSteps(steps, step_cmds, options): - unknown_steps = set(steps) - set(step for step, _ in step_cmds) - if unknown_steps: - print >> sys.stderr, 'FATAL: Unknown steps %s' % list(unknown_steps) - sys.exit(1) - - for step, cmd in step_cmds: - if step in steps: - cmd(options) diff --git a/build/android/buildbot/env_to_json.py b/build/android/buildbot/env_to_json.py deleted file mode 100755 index f9a7a443d3..0000000000 --- a/build/android/buildbot/env_to_json.py +++ /dev/null @@ -1,11 +0,0 @@ -#!/usr/bin/python -# Copyright 2013 The Chromium Authors. All rights reserved. -# Use of this source code is governed by a BSD-style license that can be -# found in the LICENSE file. - -# Encode current environment into json. - -import json -import os - -print json.dumps(dict(os.environ)) diff --git a/build/android/buildbot/tests/bb_run_bot_test.py b/build/android/buildbot/tests/bb_run_bot_test.py deleted file mode 100755 index 810c60dac2..0000000000 --- a/build/android/buildbot/tests/bb_run_bot_test.py +++ /dev/null @@ -1,35 +0,0 @@ -#!/usr/bin/env python -# Copyright (c) 2013 The Chromium Authors. All rights reserved. -# Use of this source code is governed by a BSD-style license that can be -# found in the LICENSE file. - -import os -import subprocess -import sys - -BUILDBOT_DIR = os.path.join(os.path.dirname(__file__), '..') -sys.path.append(BUILDBOT_DIR) -import bb_run_bot - -def RunBotProcesses(bot_process_map): - code = 0 - for bot, proc in bot_process_map: - _, err = proc.communicate() - code |= proc.returncode - if proc.returncode != 0: - print 'Error running the bot script with id="%s"' % bot, err - - return code - - -def main(): - procs = [ - (bot, subprocess.Popen( - [os.path.join(BUILDBOT_DIR, 'bb_run_bot.py'), '--bot-id', bot, - '--testing'], stdout=subprocess.PIPE, stderr=subprocess.PIPE)) - for bot in bb_run_bot.GetBotStepMap()] - return RunBotProcesses(procs) - - -if __name__ == '__main__': - sys.exit(main()) diff --git a/build/android/chrome_with_libs.gyp b/build/android/chrome_with_libs.gyp deleted file mode 100644 index 690be885f0..0000000000 --- a/build/android/chrome_with_libs.gyp +++ /dev/null @@ -1,82 +0,0 @@ -# Copyright 2013 The Chromium Authors. All rights reserved. -# Use of this source code is governed by a BSD-style license that can be -# found in the LICENSE file. - -# This file is meant to add more loadable libs into Chrome_apk. -# -# This is useful when building Chrome_apk with some loadable modules which are -# not included in Chrome_apk. -# As an example, when building Chrome_apk with -# libpeer_target_type=loadable_module, -# the libpeerconnection.so is not included in Chrome_apk. To add the missing -# lib, follow the steps below: -# - Run gyp: -# GYP_DEFINES="$GYP_DEFINES libpeer_target_type=loadable_module" CHROMIUM_GYP_FILE="build/android/chrome_with_libs.gyp" build/gyp_chromium -# - Build chrome_with_libs: -# ninja (or make) chrome_with_libs -# -# This tool also allows replacing the loadable module with a new one via the -# following steps: -# - Build Chrome_apk with the gyp define: -# GYP_DEFINES="$GYP_DEFINES libpeer_target_type=loadable_module" build/gyp_chromium -# ninja (or make) Chrome_apk -# - Replace libpeerconnection.so with a new one: -# cp the_new_one path/to/libpeerconnection.so -# - Run gyp: -# GYP_DEFINES="$GYP_DEFINES libpeer_target_type=loadable_module" CHROMIUM_GYP_FILE="build/android/chrome_with_libs.gyp" build/gyp_chromium -# - Build chrome_with_libs: -# ninja (or make) chrome_with_libs -{ - 'targets': [ - { - # An "All" target is required for a top-level gyp-file. - 'target_name': 'All', - 'type': 'none', - 'dependencies': [ - 'chrome_with_libs', - ], - }, - { - 'target_name': 'chrome_with_libs', - 'type': 'none', - 'variables': { - 'intermediate_dir': '<(PRODUCT_DIR)/prebuilt_libs/', - 'chrome_unsigned_path': '<(PRODUCT_DIR)/chrome_apk/Chrome-unsigned.apk', - 'chrome_with_libs_unsigned': '<(intermediate_dir)/Chrome-with-libs-unsigned.apk', - 'chrome_with_libs_final': '<(PRODUCT_DIR)/apks/Chrome-with-libs.apk', - }, - 'dependencies': [ - '<(DEPTH)/clank/native/framework/clank.gyp:chrome_apk' - ], - 'copies': [ - { - 'destination': '<(intermediate_dir)/lib/<(android_app_abi)', - 'files': [ - '<(PRODUCT_DIR)/libpeerconnection.so', - ], - }, - ], - 'actions': [ - { - 'action_name': 'put_libs_in_chrome', - 'variables': { - 'inputs': [ - '<(intermediate_dir)/lib/<(android_app_abi)/libpeerconnection.so', - ], - 'input_apk_path': '<(chrome_unsigned_path)', - 'output_apk_path': '<(chrome_with_libs_unsigned)', - 'libraries_top_dir%': '<(intermediate_dir)', - }, - 'includes': [ 'create_standalone_apk_action.gypi' ], - }, - { - 'action_name': 'finalize_chrome_with_libs', - 'variables': { - 'input_apk_path': '<(chrome_with_libs_unsigned)', - 'output_apk_path': '<(chrome_with_libs_final)', - }, - 'includes': [ 'finalize_apk_action.gypi'], - }, - ], - }], -} diff --git a/build/android/cpufeatures.gypi b/build/android/cpufeatures.gypi deleted file mode 100644 index c08e95641a..0000000000 --- a/build/android/cpufeatures.gypi +++ /dev/null @@ -1,31 +0,0 @@ -# Copyright (c) 2012 The Chromium Authors. All rights reserved. -# Use of this source code is governed by a BSD-style license that can be -# found in the LICENSE file. - -# Depend on the Android NDK's cpu feature detection. The WebView build is part -# of the system and the library already exists; for the normal build there is a -# gyp file in the checked-in NDK to build it. -{ - 'conditions': [ - ['android_webview_build == 1', { - # This is specified twice intentionally: Android provides include paths - # to targets automatically if they depend on libraries, so we add this - # library to every target that includes this .gypi to make the headers - # available, then also add it to targets that link those targets via - # link_settings to ensure it ends up being linked even if the main target - # doesn't include this .gypi. - 'libraries': [ - 'cpufeatures.a', - ], - 'link_settings': { - 'libraries': [ - 'cpufeatures.a', - ], - }, - }, { - 'dependencies': [ - '<(android_ndk_root)/android_tools_ndk.gyp:cpu_features', - ], - }], - ], -} diff --git a/build/android/create_standalone_apk_action.gypi b/build/android/create_standalone_apk_action.gypi deleted file mode 100644 index d17af7c8e5..0000000000 --- a/build/android/create_standalone_apk_action.gypi +++ /dev/null @@ -1,41 +0,0 @@ -# Copyright 2013 The Chromium Authors. All rights reserved. -# Use of this source code is governed by a BSD-style license that can be -# found in the LICENSE file. - -# This file is meant to be included into an action to provide an action that -# combines a directory of shared libraries and an incomplete APK into a -# standalone APK. -# -# To use this, create a gyp action with the following form: -# { -# 'action_name': 'some descriptive action name', -# 'variables': { -# 'inputs': [ 'input_path1', 'input_path2' ], -# 'input_apk_path': '<(unsigned_apk_path)', -# 'output_apk_path': '<(unsigned_standalone_apk_path)', -# 'libraries_top_dir': '<(libraries_top_dir)', -# }, -# 'includes': [ 'relative/path/to/create_standalone_apk_action.gypi' ], -# }, - -{ - 'message': 'Creating standalone APK: <(output_apk_path)', - 'variables': { - 'inputs': [], - }, - 'inputs': [ - '<(DEPTH)/build/android/gyp/util/build_utils.py', - '<(DEPTH)/build/android/gyp/create_standalone_apk.py', - '<(input_apk_path)', - '>@(inputs)', - ], - 'outputs': [ - '<(output_apk_path)', - ], - 'action': [ - 'python', '<(DEPTH)/build/android/gyp/create_standalone_apk.py', - '--libraries-top-dir=<(libraries_top_dir)', - '--input-apk-path=<(input_apk_path)', - '--output-apk-path=<(output_apk_path)', - ], -} diff --git a/build/android/developer_recommended_flags.gypi b/build/android/developer_recommended_flags.gypi deleted file mode 100644 index 28470963c2..0000000000 --- a/build/android/developer_recommended_flags.gypi +++ /dev/null @@ -1,61 +0,0 @@ -# Copyright 2013 The Chromium Authors. All rights reserved. -# Use of this source code is governed by a BSD-style license that can be -# found in the LICENSE file. - -# This is the set of recommended gyp variable settings for Chrome for Android development. -# -# These can be used by copying this file to $CHROME_SRC/chrome/supplement.gypi. -# -# Even better, create chrome/supplement.gypi containing the following: -# { -# 'includes': [ '../build/android/developer_recommended_flags.gypi' ] -# } -# and you'll get new settings automatically. -# When using this method, you can override individual settings by setting them unconditionally (with -# no %) in chrome/supplement.gypi. -# I.e. to disable optimize_jni_generation but use everything else: -# { -# 'variables': { -# 'optimize_jni_generation': 0, -# }, -# 'includes': [ '../build/android/developer_recommended_flags.gypi' ] -# } - -{ - 'variables': { - # When set to 1, only write jni generated files if they've changed. This can prevent unnecessary - # compiling/linking of native libraries when editing java files. - 'optimize_jni_generation%': 1, - - # Set component to 'shared_library' to enable the component build. This builds native code as - # many small shared libraries instead of one monolithic library. This slightly reduces the time - # required for incremental builds. - 'component%': 'shared_library', - - # When gyp_managed_install is set to 1, building an APK will install that APK on the connected - # device(/emulator). To install on multiple devices (or onto a new device), build the APK once - # with each device attached. This greatly reduces the time required for incremental builds. - # - # This comes with some caveats: - # Only works with a single device connected (it will print a warning if - # zero or multiple devices are attached). - # Some actions are always run (i.e. ninja will never say "no work to do"). - 'gyp_managed_install%': 1, - - # With gyp_managed_install, we do not necessarily need a standalone APK. - # When create_standalone_apk is set to 1, we will build a standalone APK - # anyway. For even faster builds, you can set create_standalone_apk to 0. - 'create_standalone_apk%': 1, - - # Set clang to 1 to use the clang compiler. Clang has much (much, much) better warning/error - # messages than gcc. - # TODO(cjhopman): Enable this when http://crbug.com/156420 is addressed. Until then, users can - # set clang to 1, but Android stack traces will sometimes be incomplete. - #'clang%': 1, - - # Set fastbuild to 1 to build with less debugging information. This can greatly decrease linking - # time. The downside is that stack traces will be missing useful information (like line - # numbers). - #'fastbuild%': 1, - }, -} diff --git a/build/android/device_stats_monitor.py b/build/android/device_stats_monitor.py deleted file mode 100755 index 23506a8899..0000000000 --- a/build/android/device_stats_monitor.py +++ /dev/null @@ -1,43 +0,0 @@ -#!/usr/bin/env python -# -# Copyright (c) 2012 The Chromium Authors. All rights reserved. -# Use of this source code is governed by a BSD-style license that can be -# found in the LICENSE file. - -"""Provides iotop/top style profiling for android. - -Usage: - ./device_stats_monitor.py --hz=20 --duration=5 --outfile=/tmp/foo -""" - -import optparse -import os -import sys -import time - -from pylib import android_commands -from pylib import device_stats_monitor -from pylib.utils import test_options_parser - - -def main(argv): - option_parser = optparse.OptionParser() - option_parser.add_option('--hz', type='int', default=20, - help='Number of samples/sec.') - option_parser.add_option('--duration', type='int', default=5, - help='Seconds to monitor.') - option_parser.add_option('--outfile', default='/tmp/devicestatsmonitor', - help='Location to start output file.') - test_options_parser.AddBuildTypeOption(option_parser) - options, args = option_parser.parse_args(argv) - - monitor = device_stats_monitor.DeviceStatsMonitor( - android_commands.AndroidCommands(), options.hz, options.build_type) - monitor.Start() - print 'Waiting for %d seconds while profiling.' % options.duration - time.sleep(options.duration) - url = monitor.StopAndCollect(options.outfile) - print 'View results in browser at %s' % url - -if __name__ == '__main__': - sys.exit(main(sys.argv)) diff --git a/build/android/dex_action.gypi b/build/android/dex_action.gypi deleted file mode 100644 index ac956b6e34..0000000000 --- a/build/android/dex_action.gypi +++ /dev/null @@ -1,61 +0,0 @@ -# Copyright 2013 The Chromium Authors. All rights reserved. -# Use of this source code is governed by a BSD-style license that can be -# found in the LICENSE file. - -# This file is meant to be included into an action to provide a rule that dexes -# compiled java files. If proguard_enabled == "true" and CONFIGURATION_NAME == -# "Release", then it will dex the proguard_enabled_input_path instead of the -# normal dex_input_paths/dex_generated_input_paths. -# -# To use this, create a gyp target with the following form: -# { -# 'action_name': 'some name for the action' -# 'actions': [ -# 'variables': { -# 'dex_input_paths': [ 'files to dex (when proguard is not used) and add to input paths' ], -# 'dex_generated_input_dirs': [ 'dirs that contain generated files to dex' ], -# 'input_paths': [ 'additional files to be added to the list of inputs' ], -# -# # For targets that use proguard: -# 'proguard_enabled': 'true', -# 'proguard_enabled_input_path': 'path to dex when using proguard', -# }, -# 'includes': [ 'relative/path/to/dex_action.gypi' ], -# ], -# }, -# - -{ - 'message': 'Creating dex file: <(output_path)', - 'variables': { - 'dex_input_paths': [], - 'dex_generated_input_dirs': [], - 'input_paths': [], - 'proguard_enabled%': 'false', - 'proguard_enabled_input_path%': '', - }, - 'inputs': [ - '<(DEPTH)/build/android/gyp/util/build_utils.py', - '<(DEPTH)/build/android/gyp/util/md5_check.py', - '<(DEPTH)/build/android/gyp/dex.py', - '>@(input_paths)', - '>@(dex_input_paths)', - ], - 'outputs': [ - '<(output_path)', - ], - 'action': [ - 'python', '<(DEPTH)/build/android/gyp/dex.py', - '--dex-path=<(output_path)', - '--android-sdk-tools=<(android_sdk_tools)', - '--configuration-name=<(CONFIGURATION_NAME)', - '--proguard-enabled=<(proguard_enabled)', - '--proguard-enabled-input-path=<(proguard_enabled_input_path)', - - # TODO(newt): remove this once http://crbug.com/177552 is fixed in ninja. - '--ignore=>!(echo \'>(_inputs)\' | md5sum)', - - '>@(dex_input_paths)', - '>@(dex_generated_input_dirs)', - ] -} diff --git a/build/android/empty/src/.keep b/build/android/empty/src/.keep deleted file mode 100644 index 0f710b673d..0000000000 --- a/build/android/empty/src/.keep +++ /dev/null @@ -1,6 +0,0 @@ -This is a file that needs to live here until http://crbug.com/158155 has -been fixed. - -The ant build system requires that a src folder is always present, and for -some of our targets that is not the case. Giving it an empty src-folder works -nicely though. diff --git a/build/android/empty_proguard.flags b/build/android/empty_proguard.flags deleted file mode 100644 index 53484fe815..0000000000 --- a/build/android/empty_proguard.flags +++ /dev/null @@ -1 +0,0 @@ -# Used for apk targets that do not need proguard. See build/java_apk.gypi. diff --git a/build/android/enable_asserts.py b/build/android/enable_asserts.py deleted file mode 100755 index 5659e9e2a8..0000000000 --- a/build/android/enable_asserts.py +++ /dev/null @@ -1,31 +0,0 @@ -#!/usr/bin/env python -# -# Copyright (c) 2012 The Chromium Authors. All rights reserved. -# Use of this source code is governed by a BSD-style license that can be -# found in the LICENSE file. - -"""Enables dalvik vm asserts in the android device.""" - -from pylib import android_commands -import optparse -import sys - - -def main(argv): - option_parser = optparse.OptionParser() - option_parser.add_option('--enable_asserts', dest='set_asserts', - action='store_true', default=None, - help='Sets the dalvik.vm.enableassertions property to "all"') - option_parser.add_option('--disable_asserts', dest='set_asserts', - action='store_false', default=None, - help='Removes the dalvik.vm.enableassertions property') - options, _ = option_parser.parse_args(argv) - - commands = android_commands.AndroidCommands() - if options.set_asserts != None: - if commands.SetJavaAssertsEnabled(options.set_asserts): - commands.Reboot(full_reboot=False) - - -if __name__ == '__main__': - main(sys.argv) diff --git a/build/android/envsetup.sh b/build/android/envsetup.sh deleted file mode 100755 index f9e3e5ede1..0000000000 --- a/build/android/envsetup.sh +++ /dev/null @@ -1,163 +0,0 @@ -#!/bin/bash -# Copyright (c) 2012 The Chromium Authors. All rights reserved. -# Use of this source code is governed by a BSD-style license that can be -# found in the LICENSE file. - -# Sets up environment for building Chromium on Android. It can either be -# compiled with the Android tree or using the Android SDK/NDK. To build with -# NDK/SDK: ". build/android/envsetup.sh". Environment variable -# ANDROID_SDK_BUILD=1 will then be defined and used in the rest of the setup to -# specifiy build type. - -# TODO(ilevy): Figure out the right check here. This breaks the webkit build as -# is since it's sourced from another script: -# http://build.webkit.org/builders/Chromium%20Android%20Release/builds/34681 -#if [ "$_" == "$0" ]; then -# echo "ERROR: envsetup must be sourced." -# exit 1 -#fi - -# Source functions script. The file is in the same directory as this script. -SCRIPT_DIR="$(dirname "${BASH_SOURCE:-$0}")" -. "${SCRIPT_DIR}"/envsetup_functions.sh - -export ANDROID_SDK_BUILD=1 # Default to SDK build. - -process_options "$@" - -# When building WebView as part of Android we can't use the SDK. Other builds -# default to using the SDK. -if [[ "${CHROME_ANDROID_BUILD_WEBVIEW}" -eq 1 ]]; then - export ANDROID_SDK_BUILD=0 -fi - -if [[ "${ANDROID_SDK_BUILD}" -ne 1 ]]; then - echo "Initializing for non-SDK build." -fi - -# Get host architecture, and abort if it is 32-bit, unless --try-32 -# is also used. -host_arch=$(uname -m) -case "${host_arch}" in - x86_64) # pass - ;; - i?86) - if [[ -z "${try_32bit_host_build}" ]]; then - echo "ERROR: Android build requires a 64-bit host build machine." - echo "If you really want to try it on this machine, use the \ ---try-32bit-host flag." - echo "Be warned that this may fail horribly at link time, due \ -very large binaries." - return 1 - else - echo "WARNING: 32-bit host build enabled. Here be dragons!" - host_arch=x86 - fi - ;; - *) - echo "ERROR: Unsupported host architecture (${host_arch})." - echo "Try running this script on a Linux/x86_64 machine instead." - return 1 -esac - -case "${host_os}" in - "linux") - toolchain_dir="linux-${host_arch}" - ;; - "mac") - toolchain_dir="darwin-${host_arch}" - ;; - *) - echo "Host platform ${host_os} is not supported" >& 2 - return 1 -esac - -CURRENT_DIR="$(readlink -f "${SCRIPT_DIR}/../../")" -if [[ -z "${CHROME_SRC}" ]]; then - # If $CHROME_SRC was not set, assume current directory is CHROME_SRC. - export CHROME_SRC="${CURRENT_DIR}" -fi - -if [[ "${CURRENT_DIR/"${CHROME_SRC}"/}" == "${CURRENT_DIR}" ]]; then - # If current directory is not in $CHROME_SRC, it might be set for other - # source tree. If $CHROME_SRC was set correctly and we are in the correct - # directory, "${CURRENT_DIR/"${CHROME_SRC}"/}" will be "". - # Otherwise, it will equal to "${CURRENT_DIR}" - echo "Warning: Current directory is out of CHROME_SRC, it may not be \ -the one you want." - echo "${CHROME_SRC}" -fi - -if [[ "${ANDROID_SDK_BUILD}" -eq 1 ]]; then - if [[ -z "${TARGET_ARCH}" ]]; then - return 1 - fi - sdk_build_init -# Sets up environment for building Chromium for Android with source. Expects -# android environment setup and lunch. -elif [[ -z "$ANDROID_BUILD_TOP" || \ - -z "$ANDROID_TOOLCHAIN" || \ - -z "$ANDROID_PRODUCT_OUT" ]]; then - echo "Android build environment variables must be set." - echo "Please cd to the root of your Android tree and do: " - echo " . build/envsetup.sh" - echo " lunch" - echo "Then try this again." - echo "Or did you mean NDK/SDK build. Run envsetup.sh without any arguments." - return 1 -elif [[ -n "$CHROME_ANDROID_BUILD_WEBVIEW" ]]; then - webview_build_init -fi - -java -version 2>&1 | grep -qs "Java HotSpot" -if [ $? -ne 0 ]; then - echo "Please check and make sure you are using the Oracle Java SDK, and it" - echo "appears before other Java SDKs in your path." - echo "Refer to the \"Install prerequisites\" section here:" - echo "https://code.google.com/p/chromium/wiki/AndroidBuildInstructions" - return 1 -fi - -if [[ -n "$JAVA_HOME" && -x "$JAVA_HOME/bin/java" ]]; then - "$JAVA_HOME/bin/java" -version 2>&1 | grep -qs "Java HotSpot" - if [ $? -ne 0 ]; then - echo "If JAVA_HOME is defined then it must refer to the install location" - echo "of the Oracle Java SDK." - echo "Refer to the \"Install prerequisites\" section here:" - echo "https://code.google.com/p/chromium/wiki/AndroidBuildInstructions" - return 1 - fi -fi - -# Workaround for valgrind build -if [[ -n "$CHROME_ANDROID_VALGRIND_BUILD" ]]; then -# arm_thumb=0 is a workaround for https://bugs.kde.org/show_bug.cgi?id=270709 - DEFINES+=" arm_thumb=0 release_extra_cflags='-fno-inline\ - -fno-omit-frame-pointer -fno-builtin' release_valgrind_build=1\ - release_optimize=1" -fi - -# Source a bunch of helper functions -. ${CHROME_SRC}/build/android/adb_device_functions.sh - -ANDROID_GOMA_WRAPPER="" -if [[ -d $GOMA_DIR ]]; then - ANDROID_GOMA_WRAPPER="$GOMA_DIR/gomacc" -fi -export ANDROID_GOMA_WRAPPER - -# Declare Android are cross compile. -export GYP_CROSSCOMPILE=1 - -# Performs a gyp_chromium run to convert gyp->Makefile for android code. -android_gyp() { - # This is just a simple wrapper of gyp_chromium, please don't add anything - # in this function. - echo "GYP_GENERATORS set to '$GYP_GENERATORS'" - ( - "${CHROME_SRC}/build/gyp_chromium" --depth="${CHROME_SRC}" --check "$@" - ) -} - -# FLOCK needs to be null on system that has no flock -which flock > /dev/null || export FLOCK= diff --git a/build/android/envsetup_functions.sh b/build/android/envsetup_functions.sh deleted file mode 100755 index f7cf4a1b2c..0000000000 --- a/build/android/envsetup_functions.sh +++ /dev/null @@ -1,326 +0,0 @@ -#!/bin/bash - -# Copyright (c) 2012 The Chromium Authors. All rights reserved. -# Use of this source code is governed by a BSD-style license that can be -# found in the LICENSE file. - -# Defines functions for envsetup.sh which sets up environment for building -# Chromium on Android. The build can be either use the Android NDK/SDK or -# android source tree. Each has a unique init function which calls functions -# prefixed with "common_" that is common for both environment setups. - -################################################################################ -# Check to make sure the toolchain exists for the NDK version. -################################################################################ -common_check_toolchain() { - if [[ ! -d "${ANDROID_TOOLCHAIN}" ]]; then - echo "Can not find Android toolchain in ${ANDROID_TOOLCHAIN}." >& 2 - echo "The NDK version might be wrong." >& 2 - return 1 - fi -} - -################################################################################ -# Exports environment variables common to both sdk and non-sdk build (e.g. PATH) -# based on CHROME_SRC and ANDROID_TOOLCHAIN, along with DEFINES for GYP_DEFINES. -################################################################################ -common_vars_defines() { - # Set toolchain path according to product architecture. - case "${TARGET_ARCH}" in - "arm") - toolchain_arch="arm-linux-androideabi" - ;; - "x86") - toolchain_arch="x86" - ;; - "mips") - toolchain_arch="mipsel-linux-android" - ;; - *) - echo "TARGET_ARCH: ${TARGET_ARCH} is not supported." >& 2 - print_usage - return 1 - ;; - esac - - toolchain_version="4.6" - # We directly set the gcc_version since we know what we use, and it should - # be set to xx instead of x.x. Refer the output of compiler_version.py. - gcc_version="46" - toolchain_target=$(basename \ - ${ANDROID_NDK_ROOT}/toolchains/${toolchain_arch}-${toolchain_version}) - toolchain_path="${ANDROID_NDK_ROOT}/toolchains/${toolchain_target}"\ -"/prebuilt/${toolchain_dir}/bin/" - - # Set only if not already set. - # Don't override ANDROID_TOOLCHAIN if set by Android configuration env. - export ANDROID_TOOLCHAIN=${ANDROID_TOOLCHAIN:-${toolchain_path}} - - common_check_toolchain - - # Add Android SDK/NDK tools to system path. - export PATH=$PATH:${ANDROID_NDK_ROOT} - export PATH=$PATH:${ANDROID_SDK_ROOT}/tools - export PATH=$PATH:${ANDROID_SDK_ROOT}/platform-tools - export PATH=$PATH:${ANDROID_SDK_ROOT}/build-tools/\ -${ANDROID_SDK_BUILD_TOOLS_VERSION} - - # This must be set before ANDROID_TOOLCHAIN, so that clang could find the - # gold linker. - # TODO(michaelbai): Remove this path once the gold linker become the default - # linker. - export PATH=$PATH:${CHROME_SRC}/build/android/${toolchain_arch}-gold - - # Must have tools like arm-linux-androideabi-gcc on the path for ninja - export PATH=$PATH:${ANDROID_TOOLCHAIN} - - # Add Chromium Android development scripts to system path. - # Must be after CHROME_SRC is set. - export PATH=$PATH:${CHROME_SRC}/build/android - - # TODO(beverloo): Remove these once all consumers updated to --strip-binary. - export OBJCOPY=$(echo ${ANDROID_TOOLCHAIN}/*-objcopy) - export STRIP=$(echo ${ANDROID_TOOLCHAIN}/*-strip) - - # The set of GYP_DEFINES to pass to gyp. Use 'readlink -e' on directories - # to canonicalize them (remove double '/', remove trailing '/', etc). - DEFINES="OS=android" - DEFINES+=" host_os=${host_os}" - DEFINES+=" gcc_version=${gcc_version}" - - if [[ -n "$CHROME_ANDROID_OFFICIAL_BUILD" ]]; then - DEFINES+=" branding=Chrome" - DEFINES+=" buildtype=Official" - - # These defines are used by various chrome build scripts to tag the binary's - # version string as 'official' in linux builds (e.g. in - # chrome/trunk/src/chrome/tools/build/version.py). - export OFFICIAL_BUILD=1 - export CHROMIUM_BUILD="_google_chrome" - export CHROME_BUILD_TYPE="_official" - fi - - # The order file specifies the order of symbols in the .text section of the - # shared library, libchromeview.so. The file is an order list of section - # names and the library is linked with option - # --section-ordering-file=. The order file is updated by profiling - # startup after compiling with the order_profiling=1 GYP_DEFINES flag. - ORDER_DEFINES="order_text_section=${CHROME_SRC}/orderfiles/orderfile.out" - - # The following defines will affect ARM code generation of both C/C++ compiler - # and V8 mksnapshot. - case "${TARGET_ARCH}" in - "arm") - DEFINES+=" ${ORDER_DEFINES}" - DEFINES+=" target_arch=arm" - ;; - "x86") - # TODO(tedbo): The ia32 build fails on ffmpeg, so we disable it here. - DEFINES+=" use_libffmpeg=0" - - host_arch=$(uname -m | sed -e \ - 's/i.86/ia32/;s/x86_64/x64/;s/amd64/x64/;s/arm.*/arm/;s/i86pc/ia32/') - DEFINES+=" host_arch=${host_arch}" - DEFINES+=" target_arch=ia32" - ;; - "mips") - DEFINES+=" target_arch=mipsel" - ;; - *) - echo "TARGET_ARCH: ${TARGET_ARCH} is not supported." >& 2 - print_usage - return 1 - esac -} - - -################################################################################ -# Exports common GYP variables based on variable DEFINES and CHROME_SRC. -################################################################################ -common_gyp_vars() { - export GYP_DEFINES="${DEFINES}" - - # Set GYP_GENERATORS to ninja if it's currently unset or null. - if [ -z "$GYP_GENERATORS" ]; then - echo "Defaulting GYP_GENERATORS to ninja." - GYP_GENERATORS=ninja - elif [ "$GYP_GENERATORS" != "ninja" ]; then - echo "Warning: GYP_GENERATORS set to '$GYP_GENERATORS'." - echo "Only GYP_GENERATORS=ninja has continuous coverage." - fi - export GYP_GENERATORS - - # Use our All target as the default - export GYP_GENERATOR_FLAGS="${GYP_GENERATOR_FLAGS} default_target=All" - - # We want to use our version of "all" targets. - export CHROMIUM_GYP_FILE="${CHROME_SRC}/build/all_android.gyp" -} - - -################################################################################ -# Prints out help message on usage. -################################################################################ -print_usage() { - echo "usage: ${0##*/} [--target-arch=value] [--help]" >& 2 - echo "--target-arch=value target CPU architecture (arm=default, x86)" >& 2 - echo "--host-os=value override host OS detection (linux, mac)" >&2 - echo "--try-32bit-host try building a 32-bit host architecture" >&2 - echo "--help this help" >& 2 -} - -################################################################################ -# Process command line options. -# --target-arch= Specifices target CPU architecture. Currently supported -# architectures are "arm" (default), and "x86". -# --help Prints out help message. -################################################################################ -process_options() { - host_os=$(uname -s | sed -e 's/Linux/linux/;s/Darwin/mac/') - try_32bit_host_build= - while [[ -n $1 ]]; do - case "$1" in - --target-arch=*) - target_arch="$(echo "$1" | sed 's/^[^=]*=//')" - ;; - --host-os=*) - host_os="$(echo "$1" | sed 's/^[^=]*=//')" - ;; - --try-32bit-host) - try_32bit_host_build=true - ;; - --help) - print_usage - return 1 - ;; - *) - # Ignore other command line options - echo "Unknown option: $1" - ;; - esac - shift - done - - # Sets TARGET_ARCH. Defaults to arm if not specified. - TARGET_ARCH=${target_arch:-arm} -} - -################################################################################ -# Initializes environment variables for NDK/SDK build. Only Android NDK Revision -# 7 on Linux or Mac is offically supported. To run this script, the system -# environment ANDROID_NDK_ROOT must be set to Android NDK's root path. The -# ANDROID_SDK_ROOT only needs to be set to override the default SDK which is in -# the tree under $ROOT/src/third_party/android_tools/sdk. -# To build Chromium for Android with NDK/SDK follow the steps below: -# > export ANDROID_NDK_ROOT= -# > export ANDROID_SDK_ROOT= # to override the default sdk -# > . build/android/envsetup.sh -# > make -################################################################################ -sdk_build_init() { - - # Allow the caller to override a few environment variables. If any of them is - # unset, we default to a sane value that's known to work. This allows for - # experimentation with a custom SDK. - if [[ -z "${ANDROID_NDK_ROOT}" || ! -d "${ANDROID_NDK_ROOT}" ]]; then - export ANDROID_NDK_ROOT="${CHROME_SRC}/third_party/android_tools/ndk/" - fi - if [[ -z "${ANDROID_SDK_VERSION}" ]]; then - export ANDROID_SDK_VERSION=18 - fi - local sdk_suffix=platforms/android-${ANDROID_SDK_VERSION} - if [[ -z "${ANDROID_SDK_ROOT}" || \ - ! -d "${ANDROID_SDK_ROOT}/${sdk_suffix}" ]]; then - export ANDROID_SDK_ROOT="${CHROME_SRC}/third_party/android_tools/sdk/" - fi - if [[ -z "${ANDROID_SDK_BUILD_TOOLS_VERSION}" ]]; then - export ANDROID_SDK_BUILD_TOOLS_VERSION=18.0.1 - fi - - unset ANDROID_BUILD_TOP - - # Set default target. - export TARGET_PRODUCT="${TARGET_PRODUCT:-trygon}" - - # Unset toolchain so that it can be set based on TARGET_PRODUCT. - # This makes it easy to switch between architectures. - unset ANDROID_TOOLCHAIN - - common_vars_defines - common_gyp_vars - - if [[ -n "$CHROME_ANDROID_BUILD_WEBVIEW" ]]; then - # Can not build WebView with NDK/SDK because it needs the Android build - # system and build inside an Android source tree. - echo "Can not build WebView with NDK/SDK. Requires android source tree." \ - >& 2 - echo "Try . build/android/envsetup.sh instead." >& 2 - return 1 - fi - - # Directory containing build-tools: aapt, aidl, dx - export ANDROID_SDK_TOOLS="${ANDROID_SDK_ROOT}/build-tools/\ -${ANDROID_SDK_BUILD_TOOLS_VERSION}" -} - -################################################################################ -# To build WebView, we use the Android build system and build inside an Android -# source tree. This method is called from non_sdk_build_init() and adds to the -# settings specified there. -############################################################################# -webview_build_init() { - # Use the latest API in the AOSP prebuilts directory (change with AOSP roll). - export ANDROID_SDK_VERSION=17 - - # For the WebView build we always use the NDK and SDK in the Android tree, - # and we don't touch ANDROID_TOOLCHAIN which is already set by Android. - export ANDROID_NDK_ROOT=${ANDROID_BUILD_TOP}/prebuilts/ndk/8 - export ANDROID_SDK_ROOT=${ANDROID_BUILD_TOP}/prebuilts/sdk/\ -${ANDROID_SDK_VERSION} - - common_vars_defines - - # We need to supply SDK paths relative to the top of the Android tree to make - # sure the generated Android makefiles are portable, as they will be checked - # into the Android tree. - ANDROID_SDK=$(python -c \ - "import os.path; print os.path.relpath('${ANDROID_SDK_ROOT}', \ - '${ANDROID_BUILD_TOP}')") - case "${host_os}" in - "linux") - ANDROID_SDK_TOOLS=$(python -c \ - "import os.path; \ - print os.path.relpath('${ANDROID_SDK_ROOT}/../tools/linux', \ - '${ANDROID_BUILD_TOP}')") - ;; - "mac") - ANDROID_SDK_TOOLS=$(python -c \ - "import os.path; \ - print os.path.relpath('${ANDROID_SDK_ROOT}/../tools/darwin', \ - '${ANDROID_BUILD_TOP}')") - ;; - esac - DEFINES+=" android_webview_build=1" - # temporary until all uses of android_build_type are gone (crbug.com/184431) - DEFINES+=" android_build_type=1" - DEFINES+=" android_src=\$(PWD)" - DEFINES+=" android_sdk=\$(PWD)/${ANDROID_SDK}" - DEFINES+=" android_sdk_root=\$(PWD)/${ANDROID_SDK}" - DEFINES+=" android_sdk_tools=\$(PWD)/${ANDROID_SDK_TOOLS}" - DEFINES+=" android_sdk_version=${ANDROID_SDK_VERSION}" - DEFINES+=" android_toolchain=${ANDROID_TOOLCHAIN}" - if [[ -n "$CHROME_ANDROID_WEBVIEW_ENABLE_DMPROF" ]]; then - DEFINES+=" disable_debugallocation=1" - DEFINES+=" android_full_debug=1" - DEFINES+=" android_use_tcmalloc=1" - fi - export GYP_DEFINES="${DEFINES}" - - export GYP_GENERATORS="android" - - export GYP_GENERATOR_FLAGS="${GYP_GENERATOR_FLAGS} default_target=All" - export GYP_GENERATOR_FLAGS="${GYP_GENERATOR_FLAGS} limit_to_target_all=1" - export GYP_GENERATOR_FLAGS="${GYP_GENERATOR_FLAGS} auto_regeneration=0" - - export CHROMIUM_GYP_FILE="${CHROME_SRC}/android_webview/all_webview.gyp" -} diff --git a/build/android/finalize_apk_action.gypi b/build/android/finalize_apk_action.gypi deleted file mode 100644 index 5ee6043b4e..0000000000 --- a/build/android/finalize_apk_action.gypi +++ /dev/null @@ -1,46 +0,0 @@ -# Copyright 2013 The Chromium Authors. All rights reserved. -# Use of this source code is governed by a BSD-style license that can be -# found in the LICENSE file. - -# This file is meant to be included into an action to provide an action that -# signs and zipaligns an APK. -# -# To use this, create a gyp action with the following form: -# { -# 'action_name': 'some descriptive action name', -# 'variables': { -# 'inputs': [ 'input_path1', 'input_path2' ], -# 'input_apk_path': 'relative/path/to/input.apk', -# 'output_apk_path': 'relative/path/to/output.apk', -# }, -# 'includes': [ '../../build/android/finalize_apk.gypi' ], -# }, -# - -{ - 'message': 'Signing/aligning <(_target_name) APK: <(input_apk_path).', - 'variables': { - 'inputs': [], - 'keystore_path%': '<(DEPTH)/build/android/ant/chromium-debug.keystore', - }, - 'inputs': [ - '<(DEPTH)/build/android/gyp/util/build_utils.py', - '<(DEPTH)/build/android/gyp/finalize_apk.py', - '<(keystore_path)', - '<(input_apk_path)', - '>@(inputs)', - ], - 'outputs': [ - '<(output_apk_path)', - ], - 'action': [ - 'python', '<(DEPTH)/build/android/gyp/finalize_apk.py', - '--android-sdk-root=<(android_sdk_root)', - '--unsigned-apk-path=<(input_apk_path)', - '--final-apk-path=<(output_apk_path)', - '--keystore-path=<(keystore_path)', - - # TODO(newt): remove this once crbug.com/177552 is fixed in ninja. - '--ignore=>!(echo \'>(_inputs)\' | md5sum)', - ], -} diff --git a/build/android/findbugs_diff.py b/build/android/findbugs_diff.py deleted file mode 100755 index eb117da36c..0000000000 --- a/build/android/findbugs_diff.py +++ /dev/null @@ -1,50 +0,0 @@ -#!/usr/bin/env python -# -# Copyright (c) 2012 The Chromium Authors. All rights reserved. -# Use of this source code is governed by a BSD-style license that can be -# found in the LICENSE file. - -"""Runs findbugs, and returns an error code if there are new warnings. -This runs findbugs with an additional flag to exclude known bugs. -To update the list of known bugs, do this: - - findbugs_diff.py --rebaseline - -Note that this is separate from findbugs_exclude.xml. The "exclude" file has -false positives that we do not plan to fix. The "known bugs" file has real -bugs that we *do* plan to fix (but haven't done so yet). - -Other options - --only-analyze used to only analyze the class you are interested. - --relase-build analyze the classes in out/Release directory. - --findbugs-args used to passin other findbugs's options. - -Run - $CHROM_SRC/third_party/findbugs/bin/findbugs -textui for details. - -""" - -import optparse -import os -import sys - -from pylib import constants -from pylib.utils import findbugs - - -def main(argv): - parser = findbugs.GetCommonParser() - - options, _ = parser.parse_args() - - if not options.base_dir: - options.base_dir = os.path.join(constants.DIR_SOURCE_ROOT, 'build', - 'android', 'findbugs_filter') - if not options.only_analyze: - options.only_analyze = 'org.chromium.-' - - return findbugs.Run(options) - - -if __name__ == '__main__': - sys.exit(main(sys.argv)) diff --git a/build/android/findbugs_filter/findbugs_exclude.xml b/build/android/findbugs_filter/findbugs_exclude.xml deleted file mode 100644 index 7b6860d0bb..0000000000 --- a/build/android/findbugs_filter/findbugs_exclude.xml +++ /dev/null @@ -1,44 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/build/android/findbugs_filter/findbugs_known_bugs.txt b/build/android/findbugs_filter/findbugs_known_bugs.txt deleted file mode 100644 index a2be5f1ad5..0000000000 --- a/build/android/findbugs_filter/findbugs_known_bugs.txt +++ /dev/null @@ -1,47 +0,0 @@ -H C EC: Using pointer equality to compare a JavaBridgeCoercionTest$CustomType with a JavaBridgeCoercionTest$CustomType2 in org.chromium.content.browser.JavaBridgeCoercionTest.testPassJavaObject() At JavaBridgeCoercionTest.java -M B DE: org.chromium.net.X509Util.clearTestRootCertificates() might ignore java.io.IOException At X509Util.java -M B Nm: The method name org.chromium.base.test.util.ScalableTimeout.ScaleTimeout(long) doesn't start with a lower case letter At ScalableTimeout.java -M B RV: exceptional return value of java.io.File.delete() ignored in org.chromium.android_webview.test.ArchiveTest.doArchiveTest(AwContents, String, boolean, String) At ArchiveTest.java -M B RV: exceptional return value of java.io.File.delete() ignored in org.chromium.android_webview.test.ArchiveTest.testAutoBadPath() At ArchiveTest.java -M B RV: exceptional return value of java.io.File.delete() ignored in org.chromium.android_webview.test.ArchiveTest.testExplicitBadPath() At ArchiveTest.java -M B RV: exceptional return value of java.io.File.delete() ignored in org.chromium.android_webview.test.ArchiveTest.testExplicitGoodPath() At ArchiveTest.java -M B RV: exceptional return value of java.io.File.delete() ignored in org.chromium.base.test.util.TestFileUtil.deleteFile(String) At TestFileUtil.java -M C CSM: Shouldn't use synchronized method, please narrow down the synchronization scope. At HttpAuthDatabase.java -M C CSM: Shouldn't use synchronized method, please narrow down the synchronization scope. At JavaBridgeArrayCoercionTest.java -M C CSM: Shouldn't use synchronized method, please narrow down the synchronization scope. At JavaBridgeArrayTest.java -M C CSM: Shouldn't use synchronized method, please narrow down the synchronization scope. At JavaBridgeBasicsTest.java -M C CSM: Shouldn't use synchronized method, please narrow down the synchronization scope. At JavaBridgeChildFrameTest.java -M C CSM: Shouldn't use synchronized method, please narrow down the synchronization scope. At JavaBridgeCoercionTest.java -M C CSM: Shouldn't use synchronized method, please narrow down the synchronization scope. At JavaBridgeFieldsTest.java -M C CSM: Shouldn't use synchronized method, please narrow down the synchronization scope. At JavaBridgeReturnValuesTest.java -M C CSM: Shouldn't use synchronized method, please narrow down the synchronization scope. At JavaBridgeTestBase.java -M C CSM: Shouldn't use synchronized method, please narrow down the synchronization scope. At PerfTraceEvent.java -M C CSM: Shouldn't use synchronized method, please narrow down the synchronization scope. At SimpleSynchronizedMethod.java -M C CSM: Shouldn't use synchronized method, please narrow down the synchronization scope. At SimpleSynchronizedStaticMethod.java -M C CSM: Shouldn't use synchronized method, please narrow down the synchronization scope. At TraceEvent.java -M C CST: Shouldn't use synchronized(this), please narrow down the synchronization scope. At HttpAuthDatabase.java -M C CST: Shouldn't use synchronized(this), please narrow down the synchronization scope. At SimpleSynchronizedThis.java -M C RCN: Nullcheck of GestureDetector.mVelocityTracker at line 630 of value previously dereferenced in org.chromium.content.browser.third_party.GestureDetector.onTouchEvent(MotionEvent) At GestureDetector.java -M C USELESS_STRING: Invocation of toString on certChain in org.chromium.net.X509Util.verifyServerCertificates(byte[][], String) At X509Util.java -M D DMI: Hard coded reference to an absolute pathname in org.chromium.android_webview.test.ArchiveTest.testAutoBadPath() At ArchiveTest.java -M D DMI: Hard coded reference to an absolute pathname in org.chromium.android_webview.test.ArchiveTest.testExplicitBadPath() At ArchiveTest.java -M D SF: Switch statement found in org.chromium.chrome.browser.ChromeBrowserProvider.insert(Uri, ContentValues) where one case falls through to the next case At ChromeBrowserProvider.java -M D SF: Switch statement found in org.chromium.chrome.browser.database.SQLiteCursor.fillWindow(int, CursorWindow) where default case is missing At SQLiteCursor.java -M D SF: Switch statement found in org.chromium.content.browser.third_party.GestureDetector.onTouchEvent(MotionEvent) where default case is missing At GestureDetector.java -M M UG: org.chromium.content.browser.JavaBridgeReturnValuesTest$TestObject.getBooleanValue() is unsynchronized, org.chromium.content.browser.JavaBridgeReturnValuesTest$TestObject.setBooleanValue(boolean) is synchronized At JavaBridgeReturnValuesTest.java -M M UG: org.chromium.content.browser.JavaBridgeReturnValuesTest$TestObject.getStringValue() is unsynchronized, org.chromium.content.browser.JavaBridgeReturnValuesTest$TestObject.setStringValue(String) is synchronized At JavaBridgeReturnValuesTest.java -M V EI2: new org.chromium.chrome.browser.FindMatchRectsDetails(int, RectF[], RectF) may expose internal representation by storing an externally mutable object into FindMatchRectsDetails.rects At FindMatchRectsDetails.java -M V EI2: org.chromium.chrome.browser.ChromeBrowserProvider$BookmarkNode.setFavicon(byte[]) may expose internal representation by storing an externally mutable object into ChromeBrowserProvider$BookmarkNode.mFavicon At ChromeBrowserProvider.java -M V EI2: org.chromium.chrome.browser.ChromeBrowserProvider$BookmarkNode.setThumbnail(byte[]) may expose internal representation by storing an externally mutable object into ChromeBrowserProvider$BookmarkNode.mThumbnail At ChromeBrowserProvider.java -M V EI2: org.chromium.content.browser.LoadUrlParams.setPostData(byte[]) may expose internal representation by storing an externally mutable object into LoadUrlParams.mPostData At LoadUrlParams.java -M V EI: org.chromium.chrome.browser.ChromeBrowserProvider$BookmarkNode.favicon() may expose internal representation by returning ChromeBrowserProvider$BookmarkNode.mFavicon At ChromeBrowserProvider.java -M V EI: org.chromium.chrome.browser.ChromeBrowserProvider$BookmarkNode.thumbnail() may expose internal representation by returning ChromeBrowserProvider$BookmarkNode.mThumbnail At ChromeBrowserProvider.java -M V MS: org.chromium.android_webview.AwResource.RAW_LOAD_ERROR isn't final and can't be protected from malicious code In AwResource.java -M V MS: org.chromium.android_webview.AwResource.RAW_NO_DOMAIN isn't final and can't be protected from malicious code In AwResource.java -M V MS: org.chromium.android_webview.AwResource.STRING_DEFAULT_TEXT_ENCODING isn't final and can't be protected from malicious code In AwResource.java -M V MS: org.chromium.content.browser.LoadUrlParams.LOAD_TYPE_BROWSER_INITIATED_HTTP_POST should be package protected In LoadUrlParams.java -M V MS: org.chromium.content.browser.LoadUrlParams.LOAD_TYPE_DATA isn't final and can't be protected from malicious code In LoadUrlParams.java -M V MS: org.chromium.content.browser.LoadUrlParams.LOAD_TYPE_DEFAULT should be package protected In LoadUrlParams.java -M V MS: org.chromium.content.browser.LoadUrlParams.UA_OVERRIDE_INHERIT should be package protected In LoadUrlParams.java -M V MS: org.chromium.content.browser.LoadUrlParams.UA_OVERRIDE_TRUE isn't final and can't be protected from malicious code In LoadUrlParams.java -M M LI: Incorrect lazy initialization of static field org.chromium.chrome.browser.sync.ProfileSyncService.sSyncSetupManager in org.chromium.chrome.browser.sync.ProfileSyncService.get(Context) At ProfileSyncService.java diff --git a/build/android/gyp/ant.py b/build/android/gyp/ant.py deleted file mode 100755 index acf3dccdce..0000000000 --- a/build/android/gyp/ant.py +++ /dev/null @@ -1,30 +0,0 @@ -#!/usr/bin/env python -# -# Copyright 2013 The Chromium Authors. All rights reserved. -# Use of this source code is governed by a BSD-style license that can be -# found in the LICENSE file. -"""An Ant wrapper that suppresses useless Ant output - -Ant build scripts output "BUILD SUCCESSFUL" and build timing at the end of -every build. In the Android build, this just adds a lot of useless noise to the -build output. This script forwards its arguments to ant, and prints Ant's -output up until the BUILD SUCCESSFUL line. -""" - -import sys - -from util import build_utils - - -def main(argv): - stdout = build_utils.CheckCallDie(['ant'] + argv[1:], suppress_output=True) - stdout = stdout.strip().split('\n') - for line in stdout: - if line.strip() == 'BUILD SUCCESSFUL': - break - print line - - -if __name__ == '__main__': - sys.exit(main(sys.argv)) - diff --git a/build/android/gyp/apk_install.py b/build/android/gyp/apk_install.py deleted file mode 100755 index e308aabdb2..0000000000 --- a/build/android/gyp/apk_install.py +++ /dev/null @@ -1,99 +0,0 @@ -#!/usr/bin/env python -# -# Copyright 2013 The Chromium Authors. All rights reserved. -# Use of this source code is governed by a BSD-style license that can be -# found in the LICENSE file. - -"""Installs an APK. - -""" - -import optparse -import os -import re -import subprocess -import sys - -from util import build_device -from util import build_utils -from util import md5_check - -BUILD_ANDROID_DIR = os.path.join(os.path.dirname(__file__), '..') -sys.path.append(BUILD_ANDROID_DIR) - -from pylib.utils import apk_helper - -def GetNewMetadata(device, apk_package): - """Gets the metadata on the device for the apk_package apk.""" - output = device.RunShellCommand('ls -l /data/app/') - # Matches lines like: - # -rw-r--r-- system system 7376582 2013-04-19 16:34 org.chromium.chrome.testshell.apk - # -rw-r--r-- system system 7376582 2013-04-19 16:34 org.chromium.chrome.testshell-1.apk - apk_matcher = lambda s: re.match('.*%s(-[0-9]*)?.apk$' % apk_package, s) - matches = filter(apk_matcher, output) - return matches[0] if matches else None - -def HasInstallMetadataChanged(device, apk_package, metadata_path): - """Checks if the metadata on the device for apk_package has changed.""" - if not os.path.exists(metadata_path): - return True - - with open(metadata_path, 'r') as expected_file: - return expected_file.read() != device.GetInstallMetadata(apk_package) - - -def RecordInstallMetadata(device, apk_package, metadata_path): - """Records the metadata from the device for apk_package.""" - metadata = GetNewMetadata(device, apk_package) - if not metadata: - raise Exception('APK install failed unexpectedly.') - - with open(metadata_path, 'w') as outfile: - outfile.write(metadata) - - -def main(argv): - parser = optparse.OptionParser() - parser.add_option('--apk-path', - help='Path to .apk to install.') - parser.add_option('--install-record', - help='Path to install record (touched only when APK is installed).') - parser.add_option('--build-device-configuration', - help='Path to build device configuration.') - parser.add_option('--stamp', - help='Path to touch on success.') - options, _ = parser.parse_args() - - device = build_device.GetBuildDeviceFromPath( - options.build_device_configuration) - if not device: - return - - serial_number = device.GetSerialNumber() - apk_package = apk_helper.GetPackageName(options.apk_path) - - metadata_path = '%s.%s.device.time.stamp' % (options.apk_path, serial_number) - - # If the APK on the device does not match the one that was last installed by - # the build, then the APK has to be installed (regardless of the md5 record). - force_install = HasInstallMetadataChanged(device, apk_package, metadata_path) - - def Install(): - device.Install(options.apk_path, reinstall=True) - RecordInstallMetadata(device, apk_package, metadata_path) - build_utils.Touch(options.install_record) - - - record_path = '%s.%s.md5.stamp' % (options.apk_path, serial_number) - md5_check.CallAndRecordIfStale( - Install, - record_path=record_path, - input_paths=[options.apk_path], - force=force_install) - - if options.stamp: - build_utils.Touch(options.stamp) - - -if __name__ == '__main__': - sys.exit(main(sys.argv)) diff --git a/build/android/gyp/create_device_library_links.py b/build/android/gyp/create_device_library_links.py deleted file mode 100755 index 1df177d6dd..0000000000 --- a/build/android/gyp/create_device_library_links.py +++ /dev/null @@ -1,110 +0,0 @@ -#!/usr/bin/env python -# -# Copyright 2013 The Chromium Authors. All rights reserved. -# Use of this source code is governed by a BSD-style license that can be -# found in the LICENSE file. - -"""Creates symlinks to native libraries for an APK. - -The native libraries should have previously been pushed to the device (in -options.target_dir). This script then creates links in an apk's lib/ folder to -those native libraries. -""" - -import json -import optparse -import os -import sys - -from util import build_device -from util import build_utils -from util import md5_check - -BUILD_ANDROID_DIR = os.path.join(os.path.dirname(__file__), '..') -sys.path.append(BUILD_ANDROID_DIR) - -from pylib.utils import apk_helper - -def RunShellCommand(device, cmd): - output = device.RunShellCommand(cmd) - - if output: - raise Exception( - 'Unexpected output running command: ' + cmd + '\n' + - '\n'.join(output)) - - -def CreateSymlinkScript(options): - libraries = build_utils.ReadJson(options.libraries_json) - - link_cmd = ( - 'rm $APK_LIBRARIES_DIR/%(lib_basename)s > /dev/null 2>&1 \n' - 'ln -s $STRIPPED_LIBRARIES_DIR/%(lib_basename)s ' - '$APK_LIBRARIES_DIR/%(lib_basename)s \n' - ) - - script = '#!/bin/sh \n' - - for lib in libraries: - script += link_cmd % { 'lib_basename': lib } - - with open(options.script_host_path, 'w') as scriptfile: - scriptfile.write(script) - - -def TriggerSymlinkScript(options): - device = build_device.GetBuildDeviceFromPath( - options.build_device_configuration) - if not device: - return - - apk_package = apk_helper.GetPackageName(options.apk) - apk_libraries_dir = '/data/data/%s/lib' % apk_package - - device_dir = os.path.dirname(options.script_device_path) - mkdir_cmd = ('if [ ! -e %(dir)s ]; then mkdir -p %(dir)s; fi ' % - { 'dir': device_dir }) - RunShellCommand(device, mkdir_cmd) - device.PushIfNeeded(options.script_host_path, options.script_device_path) - - trigger_cmd = ( - 'APK_LIBRARIES_DIR=%(apk_libraries_dir)s; ' - 'STRIPPED_LIBRARIES_DIR=%(target_dir)s; ' - '. %(script_device_path)s' - ) % { - 'apk_libraries_dir': apk_libraries_dir, - 'target_dir': options.target_dir, - 'script_device_path': options.script_device_path - } - RunShellCommand(device, trigger_cmd) - - -def main(argv): - parser = optparse.OptionParser() - parser.add_option('--apk', help='Path to the apk.') - parser.add_option('--script-host-path', - help='Path on the host for the symlink script.') - parser.add_option('--script-device-path', - help='Path on the device to push the created symlink script.') - parser.add_option('--libraries-json', - help='Path to the json list of native libraries.') - parser.add_option('--target-dir', - help='Device directory that contains the target libraries for symlinks.') - parser.add_option('--stamp', help='Path to touch on success.') - parser.add_option('--build-device-configuration', - help='Path to build device configuration.') - options, _ = parser.parse_args() - - required_options = ['apk', 'libraries_json', 'script_host_path', - 'script_device_path', 'target_dir'] - build_utils.CheckOptions(options, parser, required=required_options) - - CreateSymlinkScript(options) - TriggerSymlinkScript(options) - - if options.stamp: - build_utils.Touch(options.stamp) - - -if __name__ == '__main__': - sys.exit(main(sys.argv)) diff --git a/build/android/gyp/create_native_libraries_header.py b/build/android/gyp/create_native_libraries_header.py deleted file mode 100755 index 5c1bf1b6a3..0000000000 --- a/build/android/gyp/create_native_libraries_header.py +++ /dev/null @@ -1,50 +0,0 @@ -#!/usr/bin/env python -# -# Copyright 2013 The Chromium Authors. All rights reserved. -# Use of this source code is governed by a BSD-style license that can be -# found in the LICENSE file. - -"""Writes .h file for NativeLibraries.template - -This header should contain the list of native libraries to load in the form: - = { "lib1", "lib2" } -""" - -import json -import optparse -import os -import sys - -from util import build_utils - - -def main(argv): - parser = optparse.OptionParser() - - parser.add_option('--output', help='Path to generated .java file') - parser.add_option('--ordered-libraries', - help='Path to json file containing list of ordered libraries') - parser.add_option('--stamp', help='Path to touch on success') - - # args should be the list of libraries in dependency order. - options, _ = parser.parse_args() - - build_utils.MakeDirectory(os.path.dirname(options.output)) - - with open(options.ordered_libraries, 'r') as libfile: - libraries = json.load(libfile) - # Generates string of the form '= { "base", "net", - # "content_shell_content_view" }' from a list of the form ["libbase.so", - # libnet.so", "libcontent_shell_content_view.so"] - libraries = ['"' + lib[3:-3] + '"' for lib in libraries] - array = '= { ' + ', '.join(libraries) + '}'; - - with open(options.output, 'w') as header: - header.write(array) - - if options.stamp: - build_utils.Touch(options.stamp) - - -if __name__ == '__main__': - sys.exit(main(sys.argv)) diff --git a/build/android/gyp/create_standalone_apk.py b/build/android/gyp/create_standalone_apk.py deleted file mode 100755 index de541a6d5e..0000000000 --- a/build/android/gyp/create_standalone_apk.py +++ /dev/null @@ -1,61 +0,0 @@ -#!/usr/bin/env python -# -# Copyright 2013 The Chromium Authors. All rights reserved. -# Use of this source code is governed by a BSD-style license that can be -# found in the LICENSE file. - -"""Combines stripped libraries and incomplete APK into single standalone APK. - -""" - -import optparse -import os -import shutil -import sys -import tempfile - -from util import build_utils -from util import md5_check - -def CreateStandaloneApk(options): - def DoZip(): - with tempfile.NamedTemporaryFile(suffix='.zip') as intermediate_file: - intermediate_path = intermediate_file.name - shutil.copy(options.input_apk_path, intermediate_path) - apk_path_abs = os.path.abspath(intermediate_path) - build_utils.CheckCallDie( - ['zip', '-r', '-1', apk_path_abs, 'lib'], - cwd=options.libraries_top_dir, - suppress_output=True) - shutil.copy(intermediate_path, options.output_apk_path) - - input_paths = [options.input_apk_path, options.libraries_top_dir] - record_path = '%s.standalone.stamp' % options.input_apk_path - md5_check.CallAndRecordIfStale( - DoZip, - record_path=record_path, - input_paths=input_paths) - - -def main(argv): - parser = optparse.OptionParser() - parser.add_option('--libraries-top-dir', - help='Top directory that contains libraries ' - '(i.e. library paths are like ' - 'libraries_top_dir/lib/android_app_abi/foo.so).') - parser.add_option('--input-apk-path', help='Path to incomplete APK.') - parser.add_option('--output-apk-path', help='Path for standalone APK.') - parser.add_option('--stamp', help='Path to touch on success.') - options, _ = parser.parse_args() - - required_options = ['libraries_top_dir', 'input_apk_path', 'output_apk_path'] - build_utils.CheckOptions(options, parser, required=required_options) - - CreateStandaloneApk(options) - - if options.stamp: - build_utils.Touch(options.stamp) - - -if __name__ == '__main__': - sys.exit(main(sys.argv)) diff --git a/build/android/gyp/dex.py b/build/android/gyp/dex.py deleted file mode 100755 index c1e5869d13..0000000000 --- a/build/android/gyp/dex.py +++ /dev/null @@ -1,63 +0,0 @@ -#!/usr/bin/env python -# -# Copyright 2013 The Chromium Authors. All rights reserved. -# Use of this source code is governed by a BSD-style license that can be -# found in the LICENSE file. - -import fnmatch -import optparse -import os -import sys - -from util import build_utils -from util import md5_check - - -def DoDex(options, paths): - dx_binary = os.path.join(options.android_sdk_tools, 'dx') - - # See http://crbug.com/272064 for context on --force-jumbo. - dex_cmd = [dx_binary, '--dex', '--force-jumbo', '--output', - options.dex_path] + paths - - record_path = '%s.md5.stamp' % options.dex_path - md5_check.CallAndRecordIfStale( - lambda: build_utils.CheckCallDie(dex_cmd, suppress_output=True), - record_path=record_path, - input_paths=paths, - input_strings=dex_cmd) - - build_utils.Touch(options.dex_path) - - -def main(argv): - parser = optparse.OptionParser() - parser.add_option('--android-sdk-tools', - help='Android sdk build tools directory.') - parser.add_option('--dex-path', help='Dex output path.') - parser.add_option('--configuration-name', - help='The build CONFIGURATION_NAME.') - parser.add_option('--proguard-enabled', - help='"true" if proguard is enabled.') - parser.add_option('--proguard-enabled-input-path', - help='Path to dex in Release mode when proguard is enabled.') - parser.add_option('--stamp', help='Path to touch on success.') - - # TODO(newt): remove this once http://crbug.com/177552 is fixed in ninja. - parser.add_option('--ignore', help='Ignored.') - - options, paths = parser.parse_args() - - if (options.proguard_enabled == "true" - and options.configuration_name == "Release"): - paths = [options.proguard_enabled_input_path] - - DoDex(options, paths) - - if options.stamp: - build_utils.Touch(options.stamp) - - -if __name__ == '__main__': - sys.exit(main(sys.argv)) - diff --git a/build/android/gyp/finalize_apk.py b/build/android/gyp/finalize_apk.py deleted file mode 100755 index 0b1d2c258a..0000000000 --- a/build/android/gyp/finalize_apk.py +++ /dev/null @@ -1,69 +0,0 @@ -#!/usr/bin/env python -# -# Copyright 2013 The Chromium Authors. All rights reserved. -# Use of this source code is governed by a BSD-style license that can be -# found in the LICENSE file. -"""Signs and zipaligns APK. - -""" - -import optparse -import os -import shutil -import sys -import tempfile - -from util import build_utils - -def SignApk(keystore_path, unsigned_path, signed_path): - shutil.copy(unsigned_path, signed_path) - sign_cmd = [ - 'jarsigner', - '-sigalg', 'MD5withRSA', - '-digestalg', 'SHA1', - '-keystore', keystore_path, - '-storepass', 'chromium', - signed_path, - 'chromiumdebugkey', - ] - build_utils.CheckCallDie(sign_cmd) - - -def AlignApk(android_sdk_root, unaligned_path, final_path): - align_cmd = [ - os.path.join(android_sdk_root, 'tools', 'zipalign'), - '-f', '4', # 4 bytes - unaligned_path, - final_path, - ] - build_utils.CheckCallDie(align_cmd) - - -def main(argv): - parser = optparse.OptionParser() - - parser.add_option('--android-sdk-root', help='Android sdk root directory.') - parser.add_option('--unsigned-apk-path', help='Path to input unsigned APK.') - parser.add_option('--final-apk-path', - help='Path to output signed and aligned APK.') - parser.add_option('--keystore-path', help='Path to keystore for signing.') - parser.add_option('--stamp', help='Path to touch on success.') - - # TODO(newt): remove this once http://crbug.com/177552 is fixed in ninja. - parser.add_option('--ignore', help='Ignored.') - - options, _ = parser.parse_args() - - with tempfile.NamedTemporaryFile() as intermediate_file: - signed_apk_path = intermediate_file.name - SignApk(options.keystore_path, options.unsigned_apk_path, signed_apk_path) - AlignApk(options.android_sdk_root, signed_apk_path, options.final_apk_path) - - if options.stamp: - build_utils.Touch(options.stamp) - - -if __name__ == '__main__': - sys.exit(main(sys.argv)) - - diff --git a/build/android/gyp/gcc_preprocess.py b/build/android/gyp/gcc_preprocess.py deleted file mode 100755 index 93efdb3a74..0000000000 --- a/build/android/gyp/gcc_preprocess.py +++ /dev/null @@ -1,50 +0,0 @@ -#!/usr/bin/env python -# -# Copyright 2013 The Chromium Authors. All rights reserved. -# Use of this source code is governed by a BSD-style license that can be -# found in the LICENSE file. - -import optparse -import os -import subprocess -import sys - -from util import build_utils - -def DoGcc(options): - build_utils.MakeDirectory(os.path.dirname(options.output)) - - gcc_cmd = [ - 'gcc', # invoke host gcc. - '-E', # stop after preprocessing. - '-D', 'ANDROID', # Specify ANDROID define for pre-processor. - '-x', 'c-header', # treat sources as C header files - '-P', # disable line markers, i.e. '#line 309' - '-I', options.include_path, - '-o', options.output, - options.template - ] - - build_utils.CheckCallDie(gcc_cmd) - - -def main(argv): - parser = optparse.OptionParser() - parser.add_option('--include-path', help='Include path for gcc.') - parser.add_option('--template', help='Path to template.') - parser.add_option('--output', help='Path for generated file.') - parser.add_option('--stamp', help='Path to touch on success.') - - # TODO(newt): remove this once http://crbug.com/177552 is fixed in ninja. - parser.add_option('--ignore', help='Ignored.') - - options, _ = parser.parse_args() - - DoGcc(options) - - if options.stamp: - build_utils.Touch(options.stamp) - - -if __name__ == '__main__': - sys.exit(main(sys.argv)) diff --git a/build/android/gyp/generate_v14_compatible_resources.py b/build/android/gyp/generate_v14_compatible_resources.py deleted file mode 100755 index 71557445aa..0000000000 --- a/build/android/gyp/generate_v14_compatible_resources.py +++ /dev/null @@ -1,336 +0,0 @@ -#!/usr/bin/env python -# -# Copyright 2013 The Chromium Authors. All rights reserved. -# Use of this source code is governed by a BSD-style license that can be -# found in the LICENSE file. - -"""Convert Android xml resources to API 14 compatible. - -There are two reasons that we cannot just use API 17 attributes, -so we are generating another set of resources by this script. - -1. paddingStart attribute can cause a crash on Galaxy Tab 2. -2. There is a bug that paddingStart does not override paddingLeft on - JB-MR1. This is fixed on JB-MR2. - -Therefore, this resource generation script can be removed when -we drop the support for JB-MR1. - -Please refer to http://crbug.com/235118 for the details. -""" - -import optparse -import os -import re -import shutil -import sys -import xml.dom.minidom as minidom - -from util import build_utils - -# Note that we are assuming 'android:' is an alias of -# the namespace 'http://schemas.android.com/apk/res/android'. - -GRAVITY_ATTRIBUTES = ('android:gravity', 'android:layout_gravity') - -# Almost all the attributes that has "Start" or "End" in -# its name should be mapped. -ATTRIBUTES_TO_MAP = {'paddingStart' : 'paddingLeft', - 'drawableStart' : 'drawableLeft', - 'layout_alignStart' : 'layout_alignLeft', - 'layout_marginStart' : 'layout_marginLeft', - 'layout_alignParentStart' : 'layout_alignParentLeft', - 'layout_toStartOf' : 'layout_toLeftOf', - 'paddingEnd' : 'paddingRight', - 'drawableEnd' : 'drawableRight', - 'layout_alignEnd' : 'layout_alignRight', - 'layout_marginEnd' : 'layout_marginRight', - 'layout_alignParentEnd' : 'layout_alignParentRight', - 'layout_toEndOf' : 'layout_toRightOf'} - -ATTRIBUTES_TO_MAP = dict(['android:' + k, 'android:' + v] for k, v - in ATTRIBUTES_TO_MAP.iteritems()) - -ATTRIBUTES_TO_MAP_REVERSED = dict([v,k] for k, v - in ATTRIBUTES_TO_MAP.iteritems()) - - -def IterateXmlElements(node): - """minidom helper function that iterates all the element nodes. - Iteration order is pre-order depth-first.""" - if node.nodeType == node.ELEMENT_NODE: - yield node - for child_node in node.childNodes: - for child_node_element in IterateXmlElements(child_node): - yield child_node_element - - -def WarnIfDeprecatedAttribute(name, value, filename): - """print a warning message if the given attribute is deprecated.""" - if name in ATTRIBUTES_TO_MAP_REVERSED: - print >> sys.stderr, ('warning: ' + filename + ' should use ' + - ATTRIBUTES_TO_MAP_REVERSED[name] + - ' instead of ' + name) - elif name in GRAVITY_ATTRIBUTES and ('left' in value or 'right' in value): - print >> sys.stderr, ('warning: ' + filename + - ' should use start/end instead of left/right for ' + - name) - - -def WriteDomToFile(dom, filename): - """Write the given dom to filename.""" - build_utils.MakeDirectory(os.path.dirname(filename)) - with open(filename, 'w') as f: - dom.writexml(f, '', ' ', '\n', encoding='utf-8') - - -def HasStyleResource(dom): - """Return True if the dom is a style resource, False otherwise.""" - root_node = IterateXmlElements(dom).next() - return bool(root_node.nodeName == 'resources' and - list(root_node.getElementsByTagName('style'))) - - -def ErrorIfStyleResourceExistsInDir(input_dir): - """If a style resource is in input_dir, exist with an error message.""" - for input_filename in build_utils.FindInDirectory(input_dir, '*.xml'): - dom = minidom.parse(input_filename) - if HasStyleResource(dom): - raise Exception('error: style file ' + input_filename + - ' should be under ' + input_dir + - '-v17 directory. Please refer to ' - 'http://crbug.com/243952 for the details.') - - -def GenerateV14LayoutResourceDom(dom, filename_for_warning): - """Convert layout resource to API 14 compatible layout resource. - - Args: - dom: parsed minidom object to be modified. - filename_for_warning: file name to display in case we print warnings. - If None, do not print warning. - Returns: - True if dom is modified, False otherwise. - """ - is_modified = False - - # Iterate all the elements' attributes to find attributes to convert. - for element in IterateXmlElements(dom): - for name, value in list(element.attributes.items()): - # Convert any API 17 Start/End attributes to Left/Right attributes. - # For example, from paddingStart="10dp" to paddingLeft="10dp" - # Note: gravity attributes are not necessary to convert because - # start/end values are backward-compatible. Explained at - # https://plus.sandbox.google.com/+RomanNurik/posts/huuJd8iVVXY?e=Showroom - if name in ATTRIBUTES_TO_MAP: - element.setAttribute(ATTRIBUTES_TO_MAP[name], value) - del element.attributes[name] - is_modified = True - elif filename_for_warning: - WarnIfDeprecatedAttribute(name, value, filename_for_warning) - - return is_modified - - -def GenerateV14StyleResourceDom(dom, filename_for_warning): - """Convert style resource to API 14 compatible style resource. - - Args: - dom: parsed minidom object to be modified. - filename_for_warning: file name to display in case we print warnings. - If None, do not print warning. - Returns: - True if dom is modified, False otherwise. - """ - is_modified = False - - for style_element in dom.getElementsByTagName('style'): - for item_element in style_element.getElementsByTagName('item'): - name = item_element.attributes['name'].value - value = item_element.childNodes[0].nodeValue - if name in ATTRIBUTES_TO_MAP: - item_element.attributes['name'].value = ATTRIBUTES_TO_MAP[name] - is_modified = True - elif filename_for_warning: - WarnIfDeprecatedAttribute(name, value, filename_for_warning) - - return is_modified - - -def GenerateV14LayoutResource(input_filename, output_v14_filename, - output_v17_filename): - """Convert API 17 layout resource to API 14 compatible layout resource. - - It's mostly a simple replacement, s/Start/Left s/End/Right, - on the attribute names. - If the generated resource is identical to the original resource, - don't do anything. If not, write the generated resource to - output_v14_filename, and copy the original resource to output_v17_filename. - """ - dom = minidom.parse(input_filename) - is_modified = GenerateV14LayoutResourceDom(dom, input_filename) - - if is_modified: - # Write the generated resource. - WriteDomToFile(dom, output_v14_filename) - - # Copy the original resource. - build_utils.MakeDirectory(os.path.dirname(output_v17_filename)) - shutil.copy2(input_filename, output_v17_filename) - - -def GenerateV14StyleResource(input_filename, output_v14_filename): - """Convert API 17 style resources to API 14 compatible style resource. - - Write the generated style resource to output_v14_filename. - It's mostly a simple replacement, s/Start/Left s/End/Right, - on the attribute names. - """ - dom = minidom.parse(input_filename) - GenerateV14StyleResourceDom(dom, input_filename) - - # Write the generated resource. - WriteDomToFile(dom, output_v14_filename) - - -def GenerateV14LayoutResourcesInDir(input_dir, output_v14_dir, output_v17_dir): - """Convert layout resources to API 14 compatible resources in input_dir.""" - for input_filename in build_utils.FindInDirectory(input_dir, '*.xml'): - rel_filename = os.path.relpath(input_filename, input_dir) - output_v14_filename = os.path.join(output_v14_dir, rel_filename) - output_v17_filename = os.path.join(output_v17_dir, rel_filename) - GenerateV14LayoutResource(input_filename, output_v14_filename, - output_v17_filename) - - -def GenerateV14StyleResourcesInDir(input_dir, output_v14_dir): - """Convert style resources to API 14 compatible resources in input_dir.""" - for input_filename in build_utils.FindInDirectory(input_dir, '*.xml'): - rel_filename = os.path.relpath(input_filename, input_dir) - output_v14_filename = os.path.join(output_v14_dir, rel_filename) - GenerateV14StyleResource(input_filename, output_v14_filename) - - -def VerifyV14ResourcesInDir(input_dir, resource_type): - """Verify that the resources in input_dir is compatible with v14, i.e., they - don't use attributes that cause crashes on certain devices. Print an error if - they have.""" - for input_filename in build_utils.FindInDirectory(input_dir, '*.xml'): - exception_message = ('error : ' + input_filename + ' has an RTL attribute, ' - 'i.e., attribute that has "start" or "end" in its name.' - ' Pre-v17 resources should not include it because it ' - 'can cause crashes on certain devices. Please refer to ' - 'http://crbug.com/243952 for the details.') - dom = minidom.parse(input_filename) - if resource_type in ('layout', 'xml'): - if GenerateV14LayoutResourceDom(dom, None): - raise Exception(exception_message) - elif resource_type == 'values': - if GenerateV14StyleResourceDom(dom, None): - raise Exception(exception_message) - - -def WarnIfDeprecatedAttributeInDir(input_dir, resource_type): - """Print warning if resources in input_dir have deprecated attributes, e.g., - paddingLeft, PaddingRight""" - for input_filename in build_utils.FindInDirectory(input_dir, '*.xml'): - dom = minidom.parse(input_filename) - if resource_type in ('layout', 'xml'): - GenerateV14LayoutResourceDom(dom, input_filename) - elif resource_type == 'values': - GenerateV14StyleResourceDom(dom, input_filename) - - -def ParseArgs(): - """Parses command line options. - - Returns: - An options object as from optparse.OptionsParser.parse_args() - """ - parser = optparse.OptionParser() - parser.add_option('--res-dir', - help='directory containing resources ' - 'used to generate v14 compatible resources') - parser.add_option('--res-v14-compatibility-dir', - help='output directory into which ' - 'v14 compatible resources will be generated') - parser.add_option('--stamp', help='File to touch on success') - parser.add_option('--verify-only', action="store_true", help='Do not generate' - ' v14 resources. Instead, just verify that the resources are already ' - "compatible with v14, i.e. they don't use attributes that cause crashes " - 'on certain devices.') - - options, args = parser.parse_args() - - if args: - parser.error('No positional arguments should be given.') - - # Check that required options have been provided. - required_options = ('res_dir', 'res_v14_compatibility_dir') - build_utils.CheckOptions(options, parser, required=required_options) - return options - - -def main(argv): - options = ParseArgs() - - build_utils.DeleteDirectory(options.res_v14_compatibility_dir) - build_utils.MakeDirectory(options.res_v14_compatibility_dir) - - for name in os.listdir(options.res_dir): - if not os.path.isdir(os.path.join(options.res_dir, name)): - continue - - dir_pieces = name.split('-') - resource_type = dir_pieces[0] - qualifiers = dir_pieces[1:] - - api_level_qualifier_index = -1 - api_level_qualifier = '' - for index, qualifier in enumerate(qualifiers): - if re.match('v[0-9]+$', qualifier): - api_level_qualifier_index = index - api_level_qualifier = qualifier - break - - # Android pre-v17 API doesn't support RTL. Skip. - if 'ldrtl' in qualifiers: - continue - - input_dir = os.path.abspath(os.path.join(options.res_dir, name)) - - if options.verify_only: - if not api_level_qualifier or int(api_level_qualifier[1:]) < 17: - VerifyV14ResourcesInDir(input_dir, resource_type) - else: - WarnIfDeprecatedAttributeInDir(input_dir, resource_type) - else: - # We also need to copy the original v17 resource to *-v17 directory - # because the generated v14 resource will hide the original resource. - output_v14_dir = os.path.join(options.res_v14_compatibility_dir, name) - output_v17_dir = os.path.join(options.res_v14_compatibility_dir, name + - '-v17') - - # We only convert layout resources under layout*/, xml*/, - # and style resources under values*/. - if resource_type in ('layout', 'xml'): - if not api_level_qualifier: - GenerateV14LayoutResourcesInDir(input_dir, output_v14_dir, - output_v17_dir) - elif resource_type == 'values': - if api_level_qualifier == 'v17': - output_qualifiers = qualifiers[:] - del output_qualifiers[api_level_qualifier_index] - output_v14_dir = os.path.join(options.res_v14_compatibility_dir, - '-'.join([resource_type] + - output_qualifiers)) - GenerateV14StyleResourcesInDir(input_dir, output_v14_dir) - elif not api_level_qualifier: - ErrorIfStyleResourceExistsInDir(input_dir) - - if options.stamp: - build_utils.Touch(options.stamp) - -if __name__ == '__main__': - sys.exit(main(sys.argv)) - diff --git a/build/android/gyp/get_device_configuration.py b/build/android/gyp/get_device_configuration.py deleted file mode 100755 index f27c12be4b..0000000000 --- a/build/android/gyp/get_device_configuration.py +++ /dev/null @@ -1,75 +0,0 @@ -#!/usr/bin/env python -# -# Copyright 2013 The Chromium Authors. All rights reserved. -# Use of this source code is governed by a BSD-style license that can be -# found in the LICENSE file. - -"""Gets and writes the configurations of the attached devices. - -This configuration is used by later build steps to determine which devices to -install to and what needs to be installed to those devices. -""" - -import logging -import optparse -import os -import subprocess -import sys - -from util import build_utils -from util import build_device - -BUILD_ANDROID_DIR = os.path.join(os.path.dirname(__file__), '..') -sys.path.append(BUILD_ANDROID_DIR) - -from pylib.utils import apk_helper - - -def main(argv): - parser = optparse.OptionParser() - parser.add_option('--stamp', action='store') - parser.add_option('--output', action='store') - options, _ = parser.parse_args(argv) - - devices = build_device.GetAttachedDevices() - - device_configurations = [] - for d in devices: - configuration, is_online, has_root = ( - build_device.GetConfigurationForDevice(d)) - - if not is_online: - build_utils.PrintBigWarning( - '%s is not online. Skipping managed install for this device. ' - 'Try rebooting the device to fix this warning.' % d) - continue - - if not has_root: - build_utils.PrintBigWarning( - '"adb root" failed on device: %s\n' - 'Skipping managed install for this device.' - % configuration['description']) - continue - - device_configurations.append(configuration) - - if len(device_configurations) == 0: - build_utils.PrintBigWarning( - 'No valid devices attached. Skipping managed install steps.') - elif len(devices) > 1: - # Note that this checks len(devices) and not len(device_configurations). - # This way, any time there are multiple devices attached it is - # explicitly stated which device we will install things to even if all but - # one device were rejected for other reasons (e.g. two devices attached, - # one w/o root). - build_utils.PrintBigWarning( - 'Multiple devices attached. ' - 'Installing to the preferred device: ' - '%(id)s (%(description)s)' % (device_configurations[0])) - - - build_device.WriteConfigurations(device_configurations, options.output) - - -if __name__ == '__main__': - sys.exit(main(sys.argv)) diff --git a/build/android/gyp/jar.py b/build/android/gyp/jar.py deleted file mode 100755 index 6d4fe12bfa..0000000000 --- a/build/android/gyp/jar.py +++ /dev/null @@ -1,62 +0,0 @@ -#!/usr/bin/env python -# -# Copyright 2013 The Chromium Authors. All rights reserved. -# Use of this source code is governed by a BSD-style license that can be -# found in the LICENSE file. - -import fnmatch -import optparse -import os -import sys - -from util import build_utils -from util import md5_check - - -def DoJar(options): - class_files = build_utils.FindInDirectory(options.classes_dir, '*.class') - for exclude in build_utils.ParseGypList(options.excluded_classes): - class_files = filter( - lambda f: not fnmatch.fnmatch(f, exclude), class_files) - - jar_path = os.path.abspath(options.jar_path) - - # The paths of the files in the jar will be the same as they are passed in to - # the command. Because of this, the command should be run in - # options.classes_dir so the .class file paths in the jar are correct. - jar_cwd = options.classes_dir - class_files_rel = [os.path.relpath(f, jar_cwd) for f in class_files] - jar_cmd = ['jar', 'cf0', jar_path] + class_files_rel - - record_path = '%s.md5.stamp' % options.jar_path - md5_check.CallAndRecordIfStale( - lambda: build_utils.CheckCallDie(jar_cmd, cwd=jar_cwd), - record_path=record_path, - input_paths=class_files, - input_strings=jar_cmd) - - build_utils.Touch(options.jar_path) - - -def main(argv): - parser = optparse.OptionParser() - parser.add_option('--classes-dir', help='Directory containing .class files.') - parser.add_option('--jar-path', help='Jar output path.') - parser.add_option('--excluded-classes', - help='List of .class file patterns to exclude from the jar.') - parser.add_option('--stamp', help='Path to touch on success.') - - # TODO(newt): remove this once http://crbug.com/177552 is fixed in ninja. - parser.add_option('--ignore', help='Ignored.') - - options, _ = parser.parse_args() - - DoJar(options) - - if options.stamp: - build_utils.Touch(options.stamp) - - -if __name__ == '__main__': - sys.exit(main(sys.argv)) - diff --git a/build/android/gyp/jar_toc.py b/build/android/gyp/jar_toc.py deleted file mode 100755 index 54e90bcf28..0000000000 --- a/build/android/gyp/jar_toc.py +++ /dev/null @@ -1,110 +0,0 @@ -#!/usr/bin/env python -# -# Copyright 2013 The Chromium Authors. All rights reserved. -# Use of this source code is governed by a BSD-style license that can be -# found in the LICENSE file. - -"""Creates a TOC file from a Java jar. - -The TOC file contains the non-package API of the jar. This includes all -public/protected classes/functions/members and the values of static final -variables. Some other information (major/minor javac version) is also included. - -This TOC file then can be used to determine if a dependent library should be -rebuilt when this jar changes. I.e. any change to the jar that would require a -rebuild, will have a corresponding change in the TOC file. -""" - -import optparse -import os -import re -import sys -import zipfile - -from util import build_utils -from util import md5_check - - -def GetClassesInZipFile(zip_file): - classes = [] - files = zip_file.namelist() - for f in files: - if f.endswith('.class'): - # f is of the form org/chromium/base/Class$Inner.class - classes.append(f.replace('/', '.')[:-6]) - return classes - - -def CallJavap(classpath, classes): - javap_cmd = [ - 'javap', - '-protected', # In reality both public & protected. - # -verbose is required to get constant values (which can be inlined in - # dependents). - '-verbose', - '-classpath', classpath - ] + classes - return build_utils.CheckCallDie(javap_cmd, suppress_output=True) - - -def ExtractToc(disassembled_classes): - # javap output is structured by indent (2-space) levels. - good_patterns = [ - '^[^ ]', # This includes all class/function/member signatures. - '^ SourceFile:', - '^ minor version:', - '^ major version:', - '^ Constant value:', - ] - bad_patterns = [ - '^const #', # Matches the constant pool (i.e. literals used in the class). - ] - - def JavapFilter(line): - return (re.match('|'.join(good_patterns), line) and - not re.match('|'.join(bad_patterns), line)) - toc = filter(JavapFilter, disassembled_classes.split('\n')) - - return '\n'.join(toc) - - -def UpdateToc(jar_path, toc_path): - classes = GetClassesInZipFile(zipfile.ZipFile(jar_path)) - javap_output = CallJavap(classpath=jar_path, classes=classes) - toc = ExtractToc(javap_output) - - with open(toc_path, 'w') as tocfile: - tocfile.write(toc) - - -def DoJarToc(options): - jar_path = options.jar_path - toc_path = options.toc_path - record_path = '%s.md5.stamp' % toc_path - md5_check.CallAndRecordIfStale( - lambda: UpdateToc(jar_path, toc_path), - record_path=record_path, - input_paths=[jar_path], - ) - build_utils.Touch(toc_path) - - -def main(argv): - parser = optparse.OptionParser() - parser.add_option('--jar-path', help='Input .jar path.') - parser.add_option('--toc-path', help='Output .jar.TOC path.') - parser.add_option('--stamp', help='Path to touch on success.') - - # TODO(newt): remove this once http://crbug.com/177552 is fixed in ninja. - parser.add_option('--ignore', help='Ignored.') - - options, _ = parser.parse_args() - - DoJarToc(options) - - if options.stamp: - build_utils.Touch(options.stamp) - - -if __name__ == '__main__': - sys.exit(main(sys.argv)) diff --git a/build/android/gyp/javac.py b/build/android/gyp/javac.py deleted file mode 100755 index c1170048b5..0000000000 --- a/build/android/gyp/javac.py +++ /dev/null @@ -1,100 +0,0 @@ -#!/usr/bin/env python -# -# Copyright 2013 The Chromium Authors. All rights reserved. -# Use of this source code is governed by a BSD-style license that can be -# found in the LICENSE file. - -import fnmatch -import optparse -import os -import sys - -from util import build_utils -from util import md5_check - - -def DoJavac(options): - output_dir = options.output_dir - - src_dirs = build_utils.ParseGypList(options.src_dirs) - java_files = build_utils.FindInDirectories(src_dirs, '*.java') - if options.javac_includes: - javac_includes = build_utils.ParseGypList(options.javac_includes) - filtered_java_files = [] - for f in java_files: - for include in javac_includes: - if fnmatch.fnmatch(f, include): - filtered_java_files.append(f) - break - java_files = filtered_java_files - - # Compiling guava with certain orderings of input files causes a compiler - # crash... Sorted order works, so use that. - # See https://code.google.com/p/guava-libraries/issues/detail?id=950 - java_files.sort() - classpath = build_utils.ParseGypList(options.classpath) - - jar_inputs = [] - for path in classpath: - if os.path.exists(path + '.TOC'): - jar_inputs.append(path + '.TOC') - else: - jar_inputs.append(path) - - javac_cmd = [ - 'javac', - '-g', - '-source', '1.5', - '-target', '1.5', - '-classpath', ':'.join(classpath), - '-d', output_dir, - '-Xlint:unchecked', - '-Xlint:deprecation', - ] + java_files - - def Compile(): - # Delete the classes directory. This ensures that all .class files in the - # output are actually from the input .java files. For example, if a .java - # file is deleted or an inner class is removed, the classes directory should - # not contain the corresponding old .class file after running this action. - build_utils.DeleteDirectory(output_dir) - build_utils.MakeDirectory(output_dir) - suppress_output = not options.chromium_code - build_utils.CheckCallDie(javac_cmd, suppress_output=suppress_output) - - record_path = '%s/javac.md5.stamp' % options.output_dir - md5_check.CallAndRecordIfStale( - Compile, - record_path=record_path, - input_paths=java_files + jar_inputs, - input_strings=javac_cmd) - - -def main(argv): - parser = optparse.OptionParser() - parser.add_option('--src-dirs', help='Directories containing java files.') - parser.add_option('--javac-includes', - help='A list of file patterns. If provided, only java files that match' + - 'one of the patterns will be compiled.') - parser.add_option('--classpath', help='Classpath for javac.') - parser.add_option('--output-dir', help='Directory for javac output.') - parser.add_option('--stamp', help='Path to touch on success.') - parser.add_option('--chromium-code', type='int', help='Whether code being ' - 'compiled should be built with stricter warnings for ' - 'chromium code.') - - # TODO(newt): remove this once http://crbug.com/177552 is fixed in ninja. - parser.add_option('--ignore', help='Ignored.') - - options, _ = parser.parse_args() - - DoJavac(options) - - if options.stamp: - build_utils.Touch(options.stamp) - - -if __name__ == '__main__': - sys.exit(main(sys.argv)) - - diff --git a/build/android/gyp/process_resources.py b/build/android/gyp/process_resources.py deleted file mode 100755 index 393a6667e9..0000000000 --- a/build/android/gyp/process_resources.py +++ /dev/null @@ -1,97 +0,0 @@ -#!/usr/bin/env python -# -# Copyright (c) 2012 The Chromium Authors. All rights reserved. -# Use of this source code is governed by a BSD-style license that can be -# found in the LICENSE file. - -"""Process Android library resources to generate R.java and crunched images.""" - -import optparse -import os -import shlex - -from util import build_utils - -def ParseArgs(): - """Parses command line options. - - Returns: - An options object as from optparse.OptionsParser.parse_args() - """ - parser = optparse.OptionParser() - parser.add_option('--android-sdk', help='path to the Android SDK folder') - parser.add_option('--android-sdk-tools', - help='path to the Android SDK build tools folder') - parser.add_option('--R-dir', help='directory to hold generated R.java') - parser.add_option('--res-dirs', - help='directories containing resources to be packaged') - parser.add_option('--crunch-input-dir', - help='directory containing images to be crunched') - parser.add_option('--crunch-output-dir', - help='directory to hold crunched resources') - parser.add_option('--non-constant-id', action='store_true') - parser.add_option('--custom-package', help='Java package for R.java') - parser.add_option('--android-manifest', help='AndroidManifest.xml path') - parser.add_option('--stamp', help='File to touch on success') - - # This is part of a temporary fix for crbug.com/177552. - # TODO(newt): remove this once crbug.com/177552 is fixed in ninja. - parser.add_option('--ignore', help='this argument is ignored') - (options, args) = parser.parse_args() - - if args: - parser.error('No positional arguments should be given.') - - # Check that required options have been provided. - required_options = ('android_sdk', 'android_sdk_tools', 'R_dir', - 'res_dirs', 'crunch_input_dir', 'crunch_output_dir') - build_utils.CheckOptions(options, parser, required=required_options) - - return options - - -def main(): - options = ParseArgs() - android_jar = os.path.join(options.android_sdk, 'android.jar') - aapt = os.path.join(options.android_sdk_tools, 'aapt') - - build_utils.MakeDirectory(options.R_dir) - - # Generate R.java. This R.java contains non-final constants and is used only - # while compiling the library jar (e.g. chromium_content.jar). When building - # an apk, a new R.java file with the correct resource -> ID mappings will be - # generated by merging the resources from all libraries and the main apk - # project. - package_command = [aapt, - 'package', - '-m', - '-M', options.android_manifest, - '--auto-add-overlay', - '-I', android_jar, - '--output-text-symbols', options.R_dir, - '-J', options.R_dir] - res_dirs = shlex.split(options.res_dirs) - for res_dir in res_dirs: - package_command += ['-S', res_dir] - if options.non_constant_id: - package_command.append('--non-constant-id') - if options.custom_package: - package_command += ['--custom-package', options.custom_package] - build_utils.CheckCallDie(package_command) - - # Crunch image resources. This shrinks png files and is necessary for 9-patch - # images to display correctly. - build_utils.MakeDirectory(options.crunch_output_dir) - - aapt_cmd = [aapt, - 'crunch', - '-S', options.crunch_input_dir, - '-C', options.crunch_output_dir] - build_utils.CheckCallDie(aapt_cmd, suppress_output=True) - - if options.stamp: - build_utils.Touch(options.stamp) - - -if __name__ == '__main__': - main() diff --git a/build/android/gyp/push_libraries.py b/build/android/gyp/push_libraries.py deleted file mode 100755 index 349e0cbafc..0000000000 --- a/build/android/gyp/push_libraries.py +++ /dev/null @@ -1,72 +0,0 @@ -#!/usr/bin/env python -# -# Copyright 2013 The Chromium Authors. All rights reserved. -# Use of this source code is governed by a BSD-style license that can be -# found in the LICENSE file. - -"""Pushes native libraries to a device. - -""" - -import json -import optparse -import os -import sys - -from util import build_device -from util import build_utils -from util import md5_check - -def DoPush(options): - libraries = build_utils.ReadJson(options.libraries_json) - - device = build_device.GetBuildDeviceFromPath( - options.build_device_configuration) - if not device: - return - - serial_number = device.GetSerialNumber() - # A list so that it is modifiable in Push below. - needs_directory = [True] - for lib in libraries: - device_path = os.path.join(options.device_dir, lib) - host_path = os.path.join(options.libraries_dir, lib) - - def Push(): - if needs_directory: - device.RunShellCommand('mkdir -p ' + options.device_dir) - needs_directory[:] = [] # = False - device.PushIfNeeded(host_path, device_path) - - record_path = '%s.%s.push.md5.stamp' % (host_path, serial_number) - md5_check.CallAndRecordIfStale( - Push, - record_path=record_path, - input_paths=[host_path], - input_strings=[device_path]) - - -def main(argv): - parser = optparse.OptionParser() - parser.add_option('--libraries-dir', - help='Directory that contains stripped libraries.') - parser.add_option('--device-dir', - help='Device directory to push the libraries to.') - parser.add_option('--libraries-json', - help='Path to the json list of native libraries.') - parser.add_option('--stamp', help='Path to touch on success.') - parser.add_option('--build-device-configuration', - help='Path to build device configuration.') - options, _ = parser.parse_args() - - required_options = ['libraries_dir', 'device_dir', 'libraries_json'] - build_utils.CheckOptions(options, parser, required=required_options) - - DoPush(options) - - if options.stamp: - build_utils.Touch(options.stamp) - - -if __name__ == '__main__': - sys.exit(main(sys.argv)) diff --git a/build/android/gyp/strip_library_for_device.py b/build/android/gyp/strip_library_for_device.py deleted file mode 100755 index 05eacfe43e..0000000000 --- a/build/android/gyp/strip_library_for_device.py +++ /dev/null @@ -1,59 +0,0 @@ -#!/usr/bin/env python -# -# Copyright 2013 The Chromium Authors. All rights reserved. -# Use of this source code is governed by a BSD-style license that can be -# found in the LICENSE file. - -import json -import optparse -import os -import sys - -from util import build_utils - - -def StripLibrary(android_strip, android_strip_args, library_path, output_path): - if build_utils.IsTimeStale(output_path, [library_path]): - strip_cmd = ([android_strip] + - android_strip_args + - ['-o', output_path, library_path]) - build_utils.CheckCallDie(strip_cmd) - - - -def main(argv): - parser = optparse.OptionParser() - - parser.add_option('--android-strip', - help='Path to the toolchain\'s strip binary') - parser.add_option('--android-strip-arg', action='append', - help='Argument to be passed to strip') - parser.add_option('--libraries-dir', - help='Directory for un-stripped libraries') - parser.add_option('--stripped-libraries-dir', - help='Directory for stripped libraries') - parser.add_option('--libraries-file', - help='Path to json file containing list of libraries') - parser.add_option('--stamp', help='Path to touch on success') - - - options, _ = parser.parse_args() - - with open(options.libraries_file, 'r') as libfile: - libraries = json.load(libfile) - - build_utils.MakeDirectory(options.stripped_libraries_dir) - - for library in libraries: - library_path = os.path.join(options.libraries_dir, library) - stripped_library_path = os.path.join( - options.stripped_libraries_dir, library) - StripLibrary(options.android_strip, options.android_strip_arg, library_path, - stripped_library_path) - - if options.stamp: - build_utils.Touch(options.stamp) - - -if __name__ == '__main__': - sys.exit(main(sys.argv)) diff --git a/build/android/gyp/util/__init__.py b/build/android/gyp/util/__init__.py deleted file mode 100644 index 727e987e6b..0000000000 --- a/build/android/gyp/util/__init__.py +++ /dev/null @@ -1,4 +0,0 @@ -# Copyright (c) 2012 The Chromium Authors. All rights reserved. -# Use of this source code is governed by a BSD-style license that can be -# found in the LICENSE file. - diff --git a/build/android/gyp/util/build_device.py b/build/android/gyp/util/build_device.py deleted file mode 100644 index 11f6277453..0000000000 --- a/build/android/gyp/util/build_device.py +++ /dev/null @@ -1,98 +0,0 @@ -# Copyright 2013 The Chromium Authors. All rights reserved. -# Use of this source code is governed by a BSD-style license that can be -# found in the LICENSE file. - -""" A simple device interface for build steps. - -""" - -import logging -import os -import re -import sys - -import build_utils - -BUILD_ANDROID_DIR = os.path.join(os.path.dirname(__file__), '..', '..') -sys.path.append(BUILD_ANDROID_DIR) - -from pylib import android_commands - -from pylib.android_commands import GetAttachedDevices - - -class BuildDevice(object): - def __init__(self, configuration): - self.id = configuration['id'] - self.description = configuration['description'] - self.install_metadata = configuration['install_metadata'] - self.adb = android_commands.AndroidCommands(self.id) - - def RunShellCommand(self, *args, **kwargs): - return self.adb.RunShellCommand(*args, **kwargs) - - def PushIfNeeded(self, *args, **kwargs): - return self.adb.PushIfNeeded(*args, **kwargs) - - def GetSerialNumber(self): - return self.id - - def Install(self, *args, **kwargs): - return self.adb.Install(*args, **kwargs) - - def GetInstallMetadata(self, apk_package): - """Gets the metadata on the device for the apk_package apk.""" - # Matches lines like: - # -rw-r--r-- system system 7376582 2013-04-19 16:34 \ - # org.chromium.chrome.testshell.apk - # -rw-r--r-- system system 7376582 2013-04-19 16:34 \ - # org.chromium.chrome.testshell-1.apk - apk_matcher = lambda s: re.match('.*%s(-[0-9]*)?.apk$' % apk_package, s) - matches = filter(apk_matcher, self.install_metadata) - return matches[0] if matches else None - - -def GetConfigurationForDevice(id): - adb = android_commands.AndroidCommands(id) - configuration = None - has_root = False - is_online = adb.IsOnline() - if is_online: - cmd = 'ls -l /data/app; getprop ro.build.description' - cmd_output = adb.RunShellCommand(cmd) - has_root = not 'Permission denied' in cmd_output[0] - if not has_root: - # Disable warning log messages from EnableAdbRoot() - logging.getLogger().disabled = True - has_root = adb.EnableAdbRoot() - logging.getLogger().disabled = False - cmd_output = adb.RunShellCommand(cmd) - - configuration = { - 'id': id, - 'description': cmd_output[-1], - 'install_metadata': cmd_output[:-1], - } - return configuration, is_online, has_root - - -def WriteConfigurations(configurations, path): - # Currently we only support installing to the first device. - build_utils.WriteJson(configurations[:1], path, only_if_changed=True) - - -def ReadConfigurations(path): - return build_utils.ReadJson(path) - - -def GetBuildDevice(configurations): - assert len(configurations) == 1 - return BuildDevice(configurations[0]) - - -def GetBuildDeviceFromPath(path): - configurations = ReadConfigurations(path) - if len(configurations) > 0: - return GetBuildDevice(ReadConfigurations(path)) - return None - diff --git a/build/android/gyp/util/build_utils.py b/build/android/gyp/util/build_utils.py deleted file mode 100644 index 897b6fc949..0000000000 --- a/build/android/gyp/util/build_utils.py +++ /dev/null @@ -1,146 +0,0 @@ -# Copyright 2013 The Chromium Authors. All rights reserved. -# Use of this source code is governed by a BSD-style license that can be -# found in the LICENSE file. - -import fnmatch -import json -import os -import pipes -import shlex -import shutil -import subprocess -import sys -import traceback - - -def MakeDirectory(dir_path): - try: - os.makedirs(dir_path) - except OSError: - pass - - -def DeleteDirectory(dir_path): - if os.path.exists(dir_path): - shutil.rmtree(dir_path) - - -def Touch(path): - MakeDirectory(os.path.dirname(path)) - with open(path, 'a'): - os.utime(path, None) - - -def FindInDirectory(directory, filter): - files = [] - for root, dirnames, filenames in os.walk(directory): - matched_files = fnmatch.filter(filenames, filter) - files.extend((os.path.join(root, f) for f in matched_files)) - return files - - -def FindInDirectories(directories, filter): - all_files = [] - for directory in directories: - all_files.extend(FindInDirectory(directory, filter)) - return all_files - - -def ParseGypList(gyp_string): - # The ninja generator doesn't support $ in strings, so use ## to - # represent $. - # TODO(cjhopman): Remove when - # https://code.google.com/p/gyp/issues/detail?id=327 - # is addressed. - gyp_string = gyp_string.replace('##', '$') - return shlex.split(gyp_string) - - -def CheckOptions(options, parser, required=[]): - for option_name in required: - if not getattr(options, option_name): - parser.error('--%s is required' % option_name.replace('_', '-')) - -def WriteJson(obj, path, only_if_changed=False): - old_dump = None - if os.path.exists(path): - with open(path, 'r') as oldfile: - old_dump = oldfile.read() - - new_dump = json.dumps(obj) - - if not only_if_changed or old_dump != new_dump: - with open(path, 'w') as outfile: - outfile.write(new_dump) - -def ReadJson(path): - with open(path, 'r') as jsonfile: - return json.load(jsonfile) - - -# This can be used in most cases like subprocess.check_call. The output, -# particularly when the command fails, better highlights the command's failure. -# This call will directly exit on a failure in the subprocess so that no python -# stacktrace is printed after the output of the failed command (and will -# instead print a python stack trace before the output of the failed command) -def CheckCallDie(args, suppress_output=False, cwd=None): - if not cwd: - cwd = os.getcwd() - - child = subprocess.Popen(args, - stdout=subprocess.PIPE, stderr=subprocess.STDOUT, cwd=cwd) - - stdout, _ = child.communicate() - - if child.returncode: - stacktrace = traceback.extract_stack() - print >> sys.stderr, ''.join(traceback.format_list(stacktrace)) - # A user should be able to simply copy and paste the command that failed - # into their shell. - copyable_command = ' '.join(map(pipes.quote, args)) - copyable_command = ('( cd ' + os.path.abspath(cwd) + '; ' - + copyable_command + ' )') - print >> sys.stderr, 'Command failed:', copyable_command, '\n' - - if stdout: - print stdout, - - # Directly exit to avoid printing stacktrace. - sys.exit(child.returncode) - - else: - if stdout and not suppress_output: - print stdout, - return stdout - - -def GetModifiedTime(path): - # For a symlink, the modified time should be the greater of the link's - # modified time and the modified time of the target. - return max(os.lstat(path).st_mtime, os.stat(path).st_mtime) - - -def IsTimeStale(output, inputs): - if not os.path.exists(output): - return True - - output_time = GetModifiedTime(output) - for input in inputs: - if GetModifiedTime(input) > output_time: - return True - return False - - -def IsDeviceReady(): - device_state = CheckCallDie(['adb', 'get-state'], suppress_output=True) - return device_state.strip() == 'device' - - -def PrintWarning(message): - print 'WARNING: ' + message - - -def PrintBigWarning(message): - print '***** ' * 8 - PrintWarning(message) - print '***** ' * 8 diff --git a/build/android/gyp/util/md5_check.py b/build/android/gyp/util/md5_check.py deleted file mode 100644 index d45bb94d2a..0000000000 --- a/build/android/gyp/util/md5_check.py +++ /dev/null @@ -1,76 +0,0 @@ -# Copyright 2013 The Chromium Authors. All rights reserved. -# Use of this source code is governed by a BSD-style license that can be -# found in the LICENSE file. - -import hashlib -import os - - -def CallAndRecordIfStale( - function, record_path=None, input_paths=[], input_strings=[], force=False): - """Calls function if the md5sum of the input paths/strings has changed. - - The md5sum of the inputs is compared with the one stored in record_path. If - this has changed (or the record doesn't exist), function will be called and - the new md5sum will be recorded. - - If force is True, the function will be called regardless of whether the - md5sum is out of date. - """ - md5_checker = _Md5Checker( - record_path=record_path, - input_paths=input_paths, - input_strings=input_strings) - if force or md5_checker.IsStale(): - function() - md5_checker.Write() - - -def _UpdateMd5ForFile(md5, path, block_size=2**16): - with open(path, 'rb') as infile: - while True: - data = infile.read(block_size) - if not data: - break - md5.update(data) - - -def _UpdateMd5ForDirectory(md5, dir_path): - for root, _, files in os.walk(dir_path): - for f in files: - _UpdateMd5ForFile(md5, os.path.join(root, f)) - - -def _UpdateMd5ForPath(md5, path): - if os.path.isdir(path): - _UpdateMd5ForDirectory(md5, path) - else: - _UpdateMd5ForFile(md5, path) - - -class _Md5Checker(object): - def __init__(self, record_path=None, input_paths=[], input_strings=[]): - assert record_path.endswith('.stamp'), ( - 'record paths must end in \'.stamp\' so that they are easy to find ' - 'and delete') - - self.record_path = record_path - - md5 = hashlib.md5() - for i in sorted(input_paths): - _UpdateMd5ForPath(md5, i) - for s in input_strings: - md5.update(s) - self.new_digest = md5.hexdigest() - - self.old_digest = '' - if os.path.exists(self.record_path): - with open(self.record_path, 'r') as old_record: - self.old_digest = old_record.read() - - def IsStale(self): - return self.old_digest != self.new_digest - - def Write(self): - with open(self.record_path, 'w') as new_record: - new_record.write(self.new_digest) diff --git a/build/android/gyp/util/md5_check_test.py b/build/android/gyp/util/md5_check_test.py deleted file mode 100644 index 4a3ee6346b..0000000000 --- a/build/android/gyp/util/md5_check_test.py +++ /dev/null @@ -1,69 +0,0 @@ -# Copyright 2013 The Chromium Authors. All rights reserved. -# Use of this source code is governed by a BSD-style license that can be -# found in the LICENSE file. - -import tempfile -import unittest - -import md5_check - - -class TestMd5Check(unittest.TestCase): - def testCallAndRecordIfStale(self): - input_strings = ['string1', 'string2'] - input_file1 = tempfile.NamedTemporaryFile() - input_file2 = tempfile.NamedTemporaryFile() - file1_contents = 'input file 1' - file2_contents = 'input file 2' - input_file1.write(file1_contents) - input_file1.flush() - input_file2.write(file2_contents) - input_file2.flush() - input_files = [input_file1.name, input_file2.name] - - record_path = tempfile.NamedTemporaryFile(suffix='.stamp') - - def CheckCallAndRecord(should_call, message, force=False): - self.called = False - def MarkCalled(): - self.called = True - md5_check.CallAndRecordIfStale( - MarkCalled, - record_path=record_path.name, - input_paths=input_files, - input_strings=input_strings, - force=force) - self.failUnlessEqual(should_call, self.called, message) - - CheckCallAndRecord(True, 'should call when record doesn\'t exist') - CheckCallAndRecord(False, 'should not call when nothing changed') - CheckCallAndRecord(True, force=True, message='should call when forced') - - input_file1.write('some more input') - input_file1.flush() - CheckCallAndRecord(True, 'changed input file should trigger call') - - input_files = input_files[::-1] - CheckCallAndRecord(False, 'reordering of inputs shouldn\'t trigger call') - - input_files = input_files[:1] - CheckCallAndRecord(True, 'removing file should trigger call') - - input_files.append(input_file2.name) - CheckCallAndRecord(True, 'added input file should trigger call') - - input_strings[0] = input_strings[0] + ' a bit longer' - CheckCallAndRecord(True, 'changed input string should trigger call') - - input_strings = input_strings[::-1] - CheckCallAndRecord(True, 'reordering of string inputs should trigger call') - - input_strings = input_strings[:1] - CheckCallAndRecord(True, 'removing a string should trigger call') - - input_strings.append('a brand new string') - CheckCallAndRecord(True, 'added input string should trigger call') - - -if __name__ == '__main__': - unittest.main() diff --git a/build/android/gyp/write_ordered_libraries.py b/build/android/gyp/write_ordered_libraries.py deleted file mode 100755 index 11f12e06e1..0000000000 --- a/build/android/gyp/write_ordered_libraries.py +++ /dev/null @@ -1,125 +0,0 @@ -#!/usr/bin/env python -# -# Copyright 2013 The Chromium Authors. All rights reserved. -# Use of this source code is governed by a BSD-style license that can be -# found in the LICENSE file. - -"""Writes dependency ordered list of native libraries. - -The list excludes any Android system libraries, as those are not bundled with -the APK. - -This list of libraries is used for several steps of building an APK. -In the component build, the --input-libraries only needs to be the top-level -library (i.e. libcontent_shell_content_view). This will then use readelf to -inspect the shared libraries and determine the full list of (non-system) -libraries that should be included in the APK. -""" - -# TODO(cjhopman): See if we can expose the list of library dependencies from -# gyp, rather than calculating it ourselves. -# http://crbug.com/225558 - -import json -import optparse -import os -import re -import sys - -from util import build_utils - -_options = None -_library_re = re.compile( - '.*NEEDED.*Shared library: \[(?P[\w/.]+)\]') - - -def FullLibraryPath(library_name): - return '%s/%s' % (_options.libraries_dir, library_name) - - -def IsSystemLibrary(library_name): - # If the library doesn't exist in the libraries directory, assume that it is - # an Android system library. - return not os.path.exists(FullLibraryPath(library_name)) - - -def CallReadElf(library_or_executable): - readelf_cmd = [_options.readelf, - '-d', - library_or_executable] - return build_utils.CheckCallDie(readelf_cmd, suppress_output=True) - - -def GetDependencies(library_or_executable): - elf = CallReadElf(library_or_executable) - return set(_library_re.findall(elf)) - - -def GetNonSystemDependencies(library_name): - all_deps = GetDependencies(FullLibraryPath(library_name)) - return set((lib for lib in all_deps if not IsSystemLibrary(lib))) - - -def GetSortedTransitiveDependencies(libraries): - """Returns all transitive library dependencies in dependency order.""" - def GraphNode(library): - return (library, GetNonSystemDependencies(library)) - - # First: find all library dependencies. - unchecked_deps = libraries - all_deps = set(libraries) - while unchecked_deps: - lib = unchecked_deps.pop() - new_deps = GetNonSystemDependencies(lib).difference(all_deps) - unchecked_deps.extend(new_deps) - all_deps = all_deps.union(new_deps) - - # Then: simple, slow topological sort. - sorted_deps = [] - unsorted_deps = dict(map(GraphNode, all_deps)) - while unsorted_deps: - for library, dependencies in unsorted_deps.items(): - if not dependencies.intersection(unsorted_deps.keys()): - sorted_deps.append(library) - del unsorted_deps[library] - - return sorted_deps - -def GetSortedTransitiveDependenciesForExecutable(executable): - """Returns all transitive library dependencies in dependency order.""" - all_deps = GetDependencies(executable) - libraries = [lib for lib in all_deps if not IsSystemLibrary(lib)] - return GetSortedTransitiveDependencies(libraries) - - -def main(argv): - parser = optparse.OptionParser() - - parser.add_option('--input-libraries', - help='A list of top-level input libraries.') - parser.add_option('--libraries-dir', - help='The directory which contains shared libraries.') - parser.add_option('--readelf', help='Path to the readelf binary.') - parser.add_option('--output', help='Path to the generated .json file.') - parser.add_option('--stamp', help='Path to touch on success.') - - global _options - _options, _ = parser.parse_args() - - libraries = build_utils.ParseGypList(_options.input_libraries) - if libraries[0].endswith('.so'): - libraries = [os.path.basename(lib) for lib in libraries] - libraries = GetSortedTransitiveDependencies(libraries) - else: - libraries = GetSortedTransitiveDependenciesForExecutable(libraries[0]) - - build_utils.WriteJson(libraries, _options.output, only_if_changed=True) - - if _options.stamp: - build_utils.Touch(_options.stamp) - - -if __name__ == '__main__': - sys.exit(main(sys.argv)) - - diff --git a/build/android/host_heartbeat.py b/build/android/host_heartbeat.py deleted file mode 100755 index 8321a77258..0000000000 --- a/build/android/host_heartbeat.py +++ /dev/null @@ -1,33 +0,0 @@ -#!/usr/bin/env python -# -# Copyright (c) 2013 The Chromium Authors. All rights reserved. -# Use of this source code is governed by a BSD-style license that can be -# found in the LICENSE file. - -"""Sends a heart beat pulse to the currently online Android devices. -This heart beat lets the devices know that they are connected to a host. -""" - -import os -import sys -import time - -from pylib import android_commands - -PULSE_PERIOD = 20 - -def main(): - while True: - try: - devices = android_commands.GetAttachedDevices() - for device in devices: - android_cmd = android_commands.AndroidCommands(device) - android_cmd.RunShellCommand('touch /sdcard/host_heartbeat') - except: - # Keep the heatbeat running bypassing all errors. - pass - time.sleep(PULSE_PERIOD) - - -if __name__ == '__main__': - sys.exit(main()) diff --git a/build/android/install_emulator_deps.py b/build/android/install_emulator_deps.py deleted file mode 100755 index 7b12223626..0000000000 --- a/build/android/install_emulator_deps.py +++ /dev/null @@ -1,151 +0,0 @@ -#!/usr/bin/env python -# Copyright (c) 2013 The Chromium Authors. All rights reserved. -# Use of this source code is governed by a BSD-style license that can be -# found in the LICENSE file. - -"""Installs deps for using SDK emulator for testing. - -The script will download the SDK and system images, if they are not present, and -install and enable KVM, if virtualization has been enabled in the BIOS. -""" - - -import logging -import os -import shutil -import sys - -from pylib import cmd_helper -from pylib import constants -from pylib.utils import run_tests_helper - -# From the Android Developer's website. -SDK_BASE_URL = 'http://dl.google.com/android/adt' -SDK_ZIP = 'adt-bundle-linux-x86_64-20130522.zip' - -# Android x86 system image from the Intel website: -# http://software.intel.com/en-us/articles/intel-eula-x86-android-4-2-jelly-bean-bin -X86_IMG_URL = 'http://download-software.intel.com/sites/landingpage/android/sysimg_x86-17_r01.zip' - -# Android API level -API_TARGET = 'android-%s' % constants.ANDROID_SDK_VERSION - - -def CheckSDK(): - """Check if SDK is already installed. - - Returns: - True if android_tools directory exists in current directory. - """ - return os.path.exists(os.path.join(constants.EMULATOR_SDK_ROOT, - 'android_tools')) - - -def CheckX86Image(): - """Check if Android system images have been installed. - - Returns: - True if android_tools/sdk/system-images directory exists. - """ - return os.path.exists(os.path.join(constants.EMULATOR_SDK_ROOT, - 'android_tools', 'sdk', 'system-images', - API_TARGET, 'x86')) - - -def CheckKVM(): - """Check if KVM is enabled. - - Returns: - True if kvm-ok returns 0 (already enabled) - """ - try: - return not cmd_helper.RunCmd(['kvm-ok']) - except OSError: - logging.info('kvm-ok not installed') - return False - - -def GetSDK(): - """Download the SDK and unzip in android_tools directory.""" - logging.info('Download Android SDK.') - sdk_url = '%s/%s' % (SDK_BASE_URL, SDK_ZIP) - try: - cmd_helper.RunCmd(['curl', '-o', '/tmp/sdk.zip', sdk_url]) - print 'curled unzipping...' - rc = cmd_helper.RunCmd(['unzip', '-o', '/tmp/sdk.zip', '-d', '/tmp/']) - if rc: - logging.critical('ERROR: could not download/unzip Android SDK.') - raise - # Get the name of the sub-directory that everything will be extracted to. - dirname, _ = os.path.splitext(SDK_ZIP) - zip_dir = '/tmp/%s' % dirname - # Move the extracted directory to EMULATOR_SDK_ROOT - dst = os.path.join(constants.EMULATOR_SDK_ROOT, 'android_tools') - shutil.move(zip_dir, dst) - finally: - os.unlink('/tmp/sdk.zip') - - -def InstallKVM(): - """Installs KVM packages.""" - rc = cmd_helper.RunCmd(['sudo', 'apt-get', 'install', 'kvm']) - if rc: - logging.critical('ERROR: Did not install KVM. Make sure hardware ' - 'virtualization is enabled in BIOS (i.e. Intel VT-x or ' - 'AMD SVM).') - # TODO(navabi): Use modprobe kvm-amd on AMD processors. - rc = cmd_helper.RunCmd(['sudo', 'modprobe', 'kvm-intel']) - if rc: - logging.critical('ERROR: Did not add KVM module to Linux Kernal. Make sure ' - 'hardware virtualization is enabled in BIOS.') - # Now check to ensure KVM acceleration can be used. - rc = cmd_helper.RunCmd(['kvm-ok']) - if rc: - logging.critical('ERROR: Can not use KVM acceleration. Make sure hardware ' - 'virtualization is enabled in BIOS (i.e. Intel VT-x or ' - 'AMD SVM).') - - -def GetX86Image(): - """Download x86 system image from Intel's website.""" - logging.info('Download x86 system image directory into sdk directory.') - try: - cmd_helper.RunCmd(['curl', '-o', '/tmp/x86_img.zip', X86_IMG_URL]) - rc = cmd_helper.RunCmd(['unzip', '-o', '/tmp/x86_img.zip', '-d', '/tmp/']) - if rc: - logging.critical('ERROR: Could not download/unzip image zip.') - raise - sys_imgs = os.path.join(constants.EMULATOR_SDK_ROOT, 'android_tools', 'sdk', - 'system-images', API_TARGET, 'x86') - shutil.move('/tmp/x86', sys_imgs) - finally: - os.unlink('/tmp/x86_img.zip') - - -def main(argv): - logging.basicConfig(level=logging.INFO, - format='# %(asctime)-15s: %(message)s') - run_tests_helper.SetLogLevel(verbose_count=1) - - # Calls below will download emulator SDK and/or system images only if needed. - if CheckSDK(): - logging.info('android_tools directory already exists (not downloading).') - else: - GetSDK() - - logging.info('Emulator deps for ARM emulator complete.') - - if CheckX86Image(): - logging.info('system-images directory already exists.') - else: - GetX86Image() - - # Make sure KVM packages are installed and enabled. - if CheckKVM(): - logging.info('KVM already installed and enabled.') - else: - InstallKVM() - - -if __name__ == '__main__': - sys.exit(main(sys.argv)) diff --git a/build/android/java_cpp_template.gypi b/build/android/java_cpp_template.gypi deleted file mode 100644 index fe4238af84..0000000000 --- a/build/android/java_cpp_template.gypi +++ /dev/null @@ -1,78 +0,0 @@ -# Copyright (c) 2012 The Chromium Authors. All rights reserved. -# Use of this source code is governed by a BSD-style license that can be -# found in the LICENSE file. - -# This file is meant to be included into a target to provide a rule -# to generate Java source files from templates that are processed -# through the host C pre-processor. -# -# To use this, create a gyp target with the following form: -# { -# 'target_name': 'android_net_java_constants', -# 'type': 'none', -# 'sources': [ -# 'net/android/NetError.template', -# ], -# 'variables': { -# 'package_name': 'org/chromium/net', -# 'template_deps': ['net/base/certificate_mime_type_list.h'], -# }, -# 'includes': [ '../build/android/java_cpp_template.gypi' ], -# }, -# -# The 'sources' entry should only list template file. The template file -# itself should use the 'ClassName.template' format, and will generate -# 'gen/templates//ClassName.java. The files which template -# dependents on and typically included by the template should be listed -# in template_deps variables. Any change to them will force a rebuild of -# the template, and hence of any source that depends on it. -# - -{ - # Location where all generated Java sources will be placed. - 'variables': { - 'include_path%': '<(DEPTH)', - 'output_dir': '<(SHARED_INTERMEDIATE_DIR)/templates/<(package_name)', - }, - 'direct_dependent_settings': { - 'variables': { - # Ensure that the output directory is used in the class path - # when building targets that depend on this one. - 'generated_src_dirs': [ - '<(output_dir)/', - ], - # Ensure dependents are rebuilt when sources for this rule change. - 'additional_input_paths': [ - '<@(_sources)', - '<@(template_deps)', - ], - }, - }, - # Define a single rule that will be apply to each .template file - # listed in 'sources'. - 'rules': [ - { - 'rule_name': 'generate_java_constants', - 'extension': 'template', - # Set template_deps as additional dependencies. - 'variables': { - 'output_path': '<(output_dir)/<(RULE_INPUT_ROOT).java', - }, - 'inputs': [ - '<(DEPTH)/build/android/gyp/util/build_utils.py', - '<(DEPTH)/build/android/gyp/gcc_preprocess.py', - '<@(template_deps)' - ], - 'outputs': [ - '<(output_path)', - ], - 'action': [ - 'python', '<(DEPTH)/build/android/gyp/gcc_preprocess.py', - '--include-path=<(include_path)', - '--output=<(output_path)', - '--template=<(RULE_INPUT_PATH)', - ], - 'message': 'Generating Java from cpp template <(RULE_INPUT_PATH)', - } - ], -} diff --git a/build/android/lighttpd_server.py b/build/android/lighttpd_server.py deleted file mode 100755 index 11ae794d4a..0000000000 --- a/build/android/lighttpd_server.py +++ /dev/null @@ -1,253 +0,0 @@ -#!/usr/bin/env python -# -# Copyright (c) 2012 The Chromium Authors. All rights reserved. -# Use of this source code is governed by a BSD-style license that can be -# found in the LICENSE file. - -"""Provides a convenient wrapper for spawning a test lighttpd instance. - -Usage: - lighttpd_server PATH_TO_DOC_ROOT -""" - -import codecs -import contextlib -import httplib -import os -import random -import shutil -import socket -import subprocess -import sys -import tempfile -import time - -from pylib import constants -from pylib import pexpect - -class LighttpdServer(object): - """Wraps lighttpd server, providing robust startup. - - Args: - document_root: Path to root of this server's hosted files. - port: TCP port on the _host_ machine that the server will listen on. If - ommitted it will attempt to use 9000, or if unavailable it will find - a free port from 8001 - 8999. - lighttpd_path, lighttpd_module_path: Optional paths to lighttpd binaries. - base_config_path: If supplied this file will replace the built-in default - lighttpd config file. - extra_config_contents: If specified, this string will be appended to the - base config (default built-in, or from base_config_path). - config_path, error_log, access_log: Optional paths where the class should - place temprary files for this session. - """ - - def __init__(self, document_root, port=None, - lighttpd_path=None, lighttpd_module_path=None, - base_config_path=None, extra_config_contents=None, - config_path=None, error_log=None, access_log=None): - self.temp_dir = tempfile.mkdtemp(prefix='lighttpd_for_chrome_android') - self.document_root = os.path.abspath(document_root) - self.fixed_port = port - self.port = port or constants.LIGHTTPD_DEFAULT_PORT - self.server_tag = 'LightTPD ' + str(random.randint(111111, 999999)) - self.lighttpd_path = lighttpd_path or '/usr/sbin/lighttpd' - self.lighttpd_module_path = lighttpd_module_path or '/usr/lib/lighttpd' - self.base_config_path = base_config_path - self.extra_config_contents = extra_config_contents - self.config_path = config_path or self._Mktmp('config') - self.error_log = error_log or self._Mktmp('error_log') - self.access_log = access_log or self._Mktmp('access_log') - self.pid_file = self._Mktmp('pid_file') - self.process = None - - def _Mktmp(self, name): - return os.path.join(self.temp_dir, name) - - def _GetRandomPort(self): - # The ports of test server is arranged in constants.py. - return random.randint(constants.LIGHTTPD_RANDOM_PORT_FIRST, - constants.LIGHTTPD_RANDOM_PORT_LAST) - - def StartupHttpServer(self): - """Starts up a http server with specified document root and port.""" - # If we want a specific port, make sure no one else is listening on it. - if self.fixed_port: - self._KillProcessListeningOnPort(self.fixed_port) - while True: - if self.base_config_path: - # Read the config - with codecs.open(self.base_config_path, 'r', 'utf-8') as f: - config_contents = f.read() - else: - config_contents = self._GetDefaultBaseConfig() - if self.extra_config_contents: - config_contents += self.extra_config_contents - # Write out the config, filling in placeholders from the members of |self| - with codecs.open(self.config_path, 'w', 'utf-8') as f: - f.write(config_contents % self.__dict__) - if (not os.path.exists(self.lighttpd_path) or - not os.access(self.lighttpd_path, os.X_OK)): - raise EnvironmentError( - 'Could not find lighttpd at %s.\n' - 'It may need to be installed (e.g. sudo apt-get install lighttpd)' - % self.lighttpd_path) - self.process = pexpect.spawn(self.lighttpd_path, - ['-D', '-f', self.config_path, - '-m', self.lighttpd_module_path], - cwd=self.temp_dir) - client_error, server_error = self._TestServerConnection() - if not client_error: - assert int(open(self.pid_file, 'r').read()) == self.process.pid - break - self.process.close() - - if self.fixed_port or not 'in use' in server_error: - print 'Client error:', client_error - print 'Server error:', server_error - return False - self.port = self._GetRandomPort() - return True - - def ShutdownHttpServer(self): - """Shuts down our lighttpd processes.""" - if self.process: - self.process.terminate() - shutil.rmtree(self.temp_dir, ignore_errors=True) - - def _TestServerConnection(self): - # Wait for server to start - server_msg = '' - for timeout in xrange(1, 5): - client_error = None - try: - with contextlib.closing(httplib.HTTPConnection( - '127.0.0.1', self.port, timeout=timeout)) as http: - http.set_debuglevel(timeout > 3) - http.request('HEAD', '/') - r = http.getresponse() - r.read() - if (r.status == 200 and r.reason == 'OK' and - r.getheader('Server') == self.server_tag): - return (None, server_msg) - client_error = ('Bad response: %s %s version %s\n ' % - (r.status, r.reason, r.version) + - '\n '.join([': '.join(h) for h in r.getheaders()])) - except (httplib.HTTPException, socket.error) as client_error: - pass # Probably too quick connecting: try again - # Check for server startup error messages - ix = self.process.expect([pexpect.TIMEOUT, pexpect.EOF, '.+'], - timeout=timeout) - if ix == 2: # stdout spew from the server - server_msg += self.process.match.group(0) - elif ix == 1: # EOF -- server has quit so giveup. - client_error = client_error or 'Server exited' - break - return (client_error or 'Timeout', server_msg) - - def _KillProcessListeningOnPort(self, port): - """Checks if there is a process listening on port number |port| and - terminates it if found. - - Args: - port: Port number to check. - """ - if subprocess.call(['fuser', '-kv', '%d/tcp' % port]) == 0: - # Give the process some time to terminate and check that it is gone. - time.sleep(2) - assert subprocess.call(['fuser', '-v', '%d/tcp' % port]) != 0, \ - 'Unable to kill process listening on port %d.' % port - - def _GetDefaultBaseConfig(self): - return """server.tag = "%(server_tag)s" -server.modules = ( "mod_access", - "mod_accesslog", - "mod_alias", - "mod_cgi", - "mod_rewrite" ) - -# default document root required -#server.document-root = "." - -# files to check for if .../ is requested -index-file.names = ( "index.php", "index.pl", "index.cgi", - "index.html", "index.htm", "default.htm" ) -# mimetype mapping -mimetype.assign = ( - ".gif" => "image/gif", - ".jpg" => "image/jpeg", - ".jpeg" => "image/jpeg", - ".png" => "image/png", - ".svg" => "image/svg+xml", - ".css" => "text/css", - ".html" => "text/html", - ".htm" => "text/html", - ".xhtml" => "application/xhtml+xml", - ".xhtmlmp" => "application/vnd.wap.xhtml+xml", - ".js" => "application/x-javascript", - ".log" => "text/plain", - ".conf" => "text/plain", - ".text" => "text/plain", - ".txt" => "text/plain", - ".dtd" => "text/xml", - ".xml" => "text/xml", - ".manifest" => "text/cache-manifest", - ) - -# Use the "Content-Type" extended attribute to obtain mime type if possible -mimetype.use-xattr = "enable" - -## -# which extensions should not be handle via static-file transfer -# -# .php, .pl, .fcgi are most often handled by mod_fastcgi or mod_cgi -static-file.exclude-extensions = ( ".php", ".pl", ".cgi" ) - -server.bind = "127.0.0.1" -server.port = %(port)s - -## virtual directory listings -dir-listing.activate = "enable" -#dir-listing.encoding = "iso-8859-2" -#dir-listing.external-css = "style/oldstyle.css" - -## enable debugging -#debug.log-request-header = "enable" -#debug.log-response-header = "enable" -#debug.log-request-handling = "enable" -#debug.log-file-not-found = "enable" - -#### SSL engine -#ssl.engine = "enable" -#ssl.pemfile = "server.pem" - -# Autogenerated test-specific config follows. - -cgi.assign = ( ".cgi" => "/usr/bin/env", - ".pl" => "/usr/bin/env", - ".asis" => "/bin/cat", - ".php" => "/usr/bin/php-cgi" ) - -server.errorlog = "%(error_log)s" -accesslog.filename = "%(access_log)s" -server.upload-dirs = ( "/tmp" ) -server.pid-file = "%(pid_file)s" -server.document-root = "%(document_root)s" - -""" - - -def main(argv): - server = LighttpdServer(*argv[1:]) - try: - if server.StartupHttpServer(): - raw_input('Server running at http://127.0.0.1:%s -' - ' press Enter to exit it.' % server.port) - else: - print 'Server exit code:', server.process.exitstatus - finally: - server.ShutdownHttpServer() - - -if __name__ == '__main__': - sys.exit(main(sys.argv)) diff --git a/build/android/native_app_dependencies.gypi b/build/android/native_app_dependencies.gypi deleted file mode 100644 index d9241cc303..0000000000 --- a/build/android/native_app_dependencies.gypi +++ /dev/null @@ -1,62 +0,0 @@ -# Copyright 2013 The Chromium Authors. All rights reserved. -# Use of this source code is governed by a BSD-style license that can be -# found in the LICENSE file. - -# This file is meant to be included into a target to provide a rule -# to strip and place dependent shared libraries required by a native binary in a -# single folder that can later be pushed to the device. -# -# NOTE: consider packaging your binary as an apk instead of running a native -# library. -# -# To use this, create a gyp target with the following form: -# { -# 'target_name': 'target_that_depends_on_my_binary', -# 'type': 'none', -# 'dependencies': [ -# 'my_binary', -# ], -# 'variables': { -# 'native_binary': '<(PRODUCT_DIR)/my_binary', -# 'output_dir': 'location to place binary and dependent libraries' -# }, -# 'includes': [ '../../build/android/native_app_dependencies.gypi' ], -# }, -# - -{ - 'copies': [ - { - 'destination': '<(output_dir)', - 'files': [ '<(native_binary)' ], - } - ], - 'conditions': [ - ['component == "shared_library"', { - 'dependencies': [ - '<(DEPTH)/build/android/setup.gyp:copy_system_libraries', - ], - 'variables': { - 'intermediate_dir': '<(PRODUCT_DIR)/<(_target_name)', - 'ordered_libraries_file': '<(intermediate_dir)/native_libraries.json', - }, - 'actions': [ - { - 'variables': { - 'input_libraries': ['<(native_binary)'], - }, - 'includes': ['../../build/android/write_ordered_libraries.gypi'], - }, - { - 'action_name': 'stripping native libraries', - 'variables': { - 'stripped_libraries_dir%': '<(output_dir)', - 'input_paths': ['<(native_binary)'], - 'stamp': '<(intermediate_dir)/strip.stamp', - }, - 'includes': ['../../build/android/strip_native_libraries.gypi'], - }, - ], - }], - ], -} diff --git a/build/android/provision_devices.py b/build/android/provision_devices.py deleted file mode 100755 index 19ab384c3b..0000000000 --- a/build/android/provision_devices.py +++ /dev/null @@ -1,98 +0,0 @@ -#!/usr/bin/env python -# -# Copyright (c) 2013 The Chromium Authors. All rights reserved. -# Use of this source code is governed by a BSD-style license that can be -# found in the LICENSE file. - -"""Provisions Android devices with settings required for bots. - -Usage: - ./provision_devices.py [-d ] -""" - -import optparse -import os -import re -import subprocess -import sys -import time - -from pylib import android_commands -from pylib import constants - -def KillHostHeartbeat(): - ps = subprocess.Popen(['ps', 'aux'], stdout = subprocess.PIPE) - stdout, _ = ps.communicate() - matches = re.findall('\\n.*host_heartbeat.*', stdout) - for match in matches: - print 'An instance of host heart beart running... will kill' - pid = re.findall('(\d+)', match)[1] - subprocess.call(['kill', str(pid)]) - - -def LaunchHostHeartbeat(): - # Kill if existing host_heartbeat - KillHostHeartbeat() - # Launch a new host_heartbeat - print 'Spawning host heartbeat...' - subprocess.Popen([os.path.join(constants.DIR_SOURCE_ROOT, - 'build/android/host_heartbeat.py')]) - - -def PushAndLaunchAdbReboot(devices, target): - """Pushes and launches the adb_reboot binary on the device. - - Arguments: - devices: The list of serial numbers of the device to which the - adb_reboot binary should be pushed. - target : The build target (example, Debug or Release) which helps in - locating the adb_reboot binary. - """ - for device in devices: - print 'Will push and launch adb_reboot on %s' % device - android_cmd = android_commands.AndroidCommands(device) - # Kill if adb_reboot is already running. - android_cmd.KillAllBlocking('adb_reboot', 2) - # Push adb_reboot - print ' Pushing adb_reboot ...' - adb_reboot = os.path.join(constants.DIR_SOURCE_ROOT, - 'out/%s/adb_reboot' % target) - android_cmd.PushIfNeeded(adb_reboot, '/data/local/tmp/') - # Launch adb_reboot - print ' Launching adb_reboot ...' - p = subprocess.Popen(['adb', '-s', device, 'shell'], stdin=subprocess.PIPE) - p.communicate('/data/local/tmp/adb_reboot; exit\n') - LaunchHostHeartbeat() - - -def ProvisionDevices(options): - if options.device is not None: - devices = [options.device] - else: - devices = android_commands.GetAttachedDevices() - for device in devices: - android_cmd = android_commands.AndroidCommands(device) - android_cmd.RunShellCommand('su -c date -u %f' % time.time()) - if options.auto_reconnect: - PushAndLaunchAdbReboot(devices, options.target) - - -def main(argv): - parser = optparse.OptionParser() - parser.add_option('-d', '--device', - help='The serial number of the device to be provisioned') - parser.add_option('-t', '--target', default='Debug', help='The build target') - parser.add_option( - '-r', '--auto-reconnect', action='store_true', - help='Push binary which will reboot the device on adb disconnections.') - options, args = parser.parse_args(argv[1:]) - - if args: - print >> sys.stderr, 'Unused args %s' % args - return 1 - - ProvisionDevices(options) - - -if __name__ == '__main__': - sys.exit(main(sys.argv)) diff --git a/build/android/push_libraries.gypi b/build/android/push_libraries.gypi deleted file mode 100644 index 1f17660c44..0000000000 --- a/build/android/push_libraries.gypi +++ /dev/null @@ -1,45 +0,0 @@ -# Copyright 2013 The Chromium Authors. All rights reserved. -# Use of this source code is governed by a BSD-style license that can be -# found in the LICENSE file. - -# This file is meant to be included into an action to provide a rule that -# pushes stripped shared libraries to the attached Android device. This should -# only be used with the gyp_managed_install flag set. -# -# To use this, create a gyp target with the following form: -# { -# 'actions': [ -# 'variables': { -# 'ordered_libraries_file': 'file generated by write_ordered_libraries' -# 'strip_stamp': 'stamp from strip action to block on' -# 'libraries_source_dir': 'location where stripped libraries are stored' -# 'device_library_dir': 'location on the device where to put pushed libraries', -# 'push_stamp': 'file to touch when the action is complete' -# }, -# 'includes': [ '../../build/android/push_libraries.gypi' ], -# ], -# }, -# - -{ - 'action_name': 'push_libraries_<(_target_name)', - 'message': 'Pushing libraries to device for <(_target_name)', - 'inputs': [ - '<(DEPTH)/build/android/gyp/util/build_utils.py', - '<(DEPTH)/build/android/gyp/util/md5_check.py', - '<(DEPTH)/build/android/gyp/push_libraries.py', - '<(strip_stamp)', - '<(build_device_config_path)', - ], - 'outputs': [ - '<(push_stamp)', - ], - 'action': [ - 'python', '<(DEPTH)/build/android/gyp/push_libraries.py', - '--build-device-configuration=<(build_device_config_path)', - '--libraries-dir=<(libraries_source_dir)', - '--device-dir=<(device_library_dir)', - '--libraries-json=<(ordered_libraries_file)', - '--stamp=<(push_stamp)', - ], -} diff --git a/build/android/pylib/OWNERS b/build/android/pylib/OWNERS deleted file mode 100644 index e463404ccf..0000000000 --- a/build/android/pylib/OWNERS +++ /dev/null @@ -1,3 +0,0 @@ -bulach@chromium.org -craigdh@chromium.org -frankf@chromium.org diff --git a/build/android/pylib/__init__.py b/build/android/pylib/__init__.py deleted file mode 100644 index 96196cffb2..0000000000 --- a/build/android/pylib/__init__.py +++ /dev/null @@ -1,3 +0,0 @@ -# Copyright (c) 2012 The Chromium Authors. All rights reserved. -# Use of this source code is governed by a BSD-style license that can be -# found in the LICENSE file. diff --git a/build/android/pylib/android_commands.py b/build/android/pylib/android_commands.py deleted file mode 100644 index f8c074758d..0000000000 --- a/build/android/pylib/android_commands.py +++ /dev/null @@ -1,1528 +0,0 @@ -# Copyright (c) 2012 The Chromium Authors. All rights reserved. -# Use of this source code is governed by a BSD-style license that can be -# found in the LICENSE file. - -"""Provides an interface to communicate with the device via the adb command. - -Assumes adb binary is currently on system path. -""" - -import collections -import datetime -import logging -import os -import re -import shlex -import subprocess -import sys -import tempfile -import time - -import cmd_helper -import constants -import io_stats_parser -try: - import pexpect -except: - pexpect = None - -sys.path.append(os.path.join( - constants.DIR_SOURCE_ROOT, 'third_party', 'android_testrunner')) -import adb_interface -import am_instrument_parser -import errors - - -# Pattern to search for the next whole line of pexpect output and capture it -# into a match group. We can't use ^ and $ for line start end with pexpect, -# see http://www.noah.org/python/pexpect/#doc for explanation why. -PEXPECT_LINE_RE = re.compile('\n([^\r]*)\r') - -# Set the adb shell prompt to be a unique marker that will [hopefully] not -# appear at the start of any line of a command's output. -SHELL_PROMPT = '~+~PQ\x17RS~+~' - -# Java properties file -LOCAL_PROPERTIES_PATH = '/data/local.prop' - -# Property in /data/local.prop that controls Java assertions. -JAVA_ASSERT_PROPERTY = 'dalvik.vm.enableassertions' - -MEMORY_INFO_RE = re.compile('^(?P\w+):\s+(?P\d+) kB$') -NVIDIA_MEMORY_INFO_RE = re.compile('^\s*(?P\S+)\s*(?P\S+)\s*' - '(?P\d+)\s*(?P\d+)$') - -# Keycode "enum" suitable for passing to AndroidCommands.SendKey(). -KEYCODE_HOME = 3 -KEYCODE_BACK = 4 -KEYCODE_DPAD_UP = 19 -KEYCODE_DPAD_DOWN = 20 -KEYCODE_DPAD_RIGHT = 22 -KEYCODE_ENTER = 66 -KEYCODE_MENU = 82 - -MD5SUM_DEVICE_FOLDER = constants.TEST_EXECUTABLE_DIR + '/md5sum/' -MD5SUM_DEVICE_PATH = MD5SUM_DEVICE_FOLDER + 'md5sum_bin' -MD5SUM_LD_LIBRARY_PATH = 'LD_LIBRARY_PATH=%s' % MD5SUM_DEVICE_FOLDER - - -def GetAVDs(): - """Returns a list of AVDs.""" - re_avd = re.compile('^[ ]+Name: ([a-zA-Z0-9_:.-]+)', re.MULTILINE) - avds = re_avd.findall(cmd_helper.GetCmdOutput(['android', 'list', 'avd'])) - return avds - - -def GetAttachedDevices(hardware=True, emulator=True, offline=False): - """Returns a list of attached, android devices and emulators. - - If a preferred device has been set with ANDROID_SERIAL, it will be first in - the returned list. The arguments specify what devices to include in the list. - - Example output: - - * daemon not running. starting it now on port 5037 * - * daemon started successfully * - List of devices attached - 027c10494100b4d7 device - emulator-5554 offline - - Args: - hardware: Include attached actual devices that are online. - emulator: Include emulators (i.e. AVD's) currently on host. - offline: Include devices and emulators that are offline. - - Returns: List of devices. - """ - adb_devices_output = cmd_helper.GetCmdOutput([constants.ADB_PATH, 'devices']) - - re_device = re.compile('^([a-zA-Z0-9_:.-]+)\tdevice$', re.MULTILINE) - online_devices = re_device.findall(adb_devices_output) - - re_device = re.compile('^(emulator-[0-9]+)\tdevice', re.MULTILINE) - emulator_devices = re_device.findall(adb_devices_output) - - re_device = re.compile('^([a-zA-Z0-9_:.-]+)\toffline$', re.MULTILINE) - offline_devices = re_device.findall(adb_devices_output) - - devices = [] - # First determine list of online devices (e.g. hardware and/or emulator). - if hardware and emulator: - devices = online_devices - elif hardware: - devices = [device for device in online_devices - if device not in emulator_devices] - elif emulator: - devices = emulator_devices - - # Now add offline devices if offline is true - if offline: - devices = devices + offline_devices - - preferred_device = os.environ.get('ANDROID_SERIAL') - if preferred_device in devices: - devices.remove(preferred_device) - devices.insert(0, preferred_device) - return devices - - -def IsDeviceAttached(device): - """Return true if the device is attached and online.""" - return device in GetAttachedDevices() - - -def _GetFilesFromRecursiveLsOutput(path, ls_output, re_file, utc_offset=None): - """Gets a list of files from `ls` command output. - - Python's os.walk isn't used because it doesn't work over adb shell. - - Args: - path: The path to list. - ls_output: A list of lines returned by an `ls -lR` command. - re_file: A compiled regular expression which parses a line into named groups - consisting of at minimum "filename", "date", "time", "size" and - optionally "timezone". - utc_offset: A 5-character string of the form +HHMM or -HHMM, where HH is a - 2-digit string giving the number of UTC offset hours, and MM is a - 2-digit string giving the number of UTC offset minutes. If the input - utc_offset is None, will try to look for the value of "timezone" if it - is specified in re_file. - - Returns: - A dict of {"name": (size, lastmod), ...} where: - name: The file name relative to |path|'s directory. - size: The file size in bytes (0 for directories). - lastmod: The file last modification date in UTC. - """ - re_directory = re.compile('^%s/(?P[^:]+):$' % re.escape(path)) - path_dir = os.path.dirname(path) - - current_dir = '' - files = {} - for line in ls_output: - directory_match = re_directory.match(line) - if directory_match: - current_dir = directory_match.group('dir') - continue - file_match = re_file.match(line) - if file_match: - filename = os.path.join(current_dir, file_match.group('filename')) - if filename.startswith(path_dir): - filename = filename[len(path_dir) + 1:] - lastmod = datetime.datetime.strptime( - file_match.group('date') + ' ' + file_match.group('time')[:5], - '%Y-%m-%d %H:%M') - if not utc_offset and 'timezone' in re_file.groupindex: - utc_offset = file_match.group('timezone') - if isinstance(utc_offset, str) and len(utc_offset) == 5: - utc_delta = datetime.timedelta(hours=int(utc_offset[1:3]), - minutes=int(utc_offset[3:5])) - if utc_offset[0:1] == '-': - utc_delta = -utc_delta - lastmod -= utc_delta - files[filename] = (int(file_match.group('size')), lastmod) - return files - - -def _ParseMd5SumOutput(md5sum_output): - """Returns a list of tuples from the provided md5sum output. - - Args: - md5sum_output: output directly from md5sum binary. - - Returns: - List of namedtuples with attributes |hash| and |path|, where |path| is the - absolute path to the file with an Md5Sum of |hash|. - """ - HashAndPath = collections.namedtuple('HashAndPath', ['hash', 'path']) - split_lines = [line.split(' ') for line in md5sum_output] - return [HashAndPath._make(s) for s in split_lines if len(s) == 2] - - -def _HasAdbPushSucceeded(command_output): - """Returns whether adb push has succeeded from the provided output.""" - # TODO(frankf): We should look at the return code instead of the command - # output for many of the commands in this file. - if not command_output: - return True - # Success looks like this: "3035 KB/s (12512056 bytes in 4.025s)" - # Errors look like this: "failed to copy ... " - if not re.search('^[0-9]', command_output.splitlines()[-1]): - logging.critical('PUSH FAILED: ' + command_output) - return False - return True - - -def GetLogTimestamp(log_line, year): - """Returns the timestamp of the given |log_line| in the given year.""" - try: - return datetime.datetime.strptime('%s-%s' % (year, log_line[:18]), - '%Y-%m-%d %H:%M:%S.%f') - except (ValueError, IndexError): - logging.critical('Error reading timestamp from ' + log_line) - return None - - -class AndroidCommands(object): - """Helper class for communicating with Android device via adb. - - Args: - device: If given, adb commands are only send to the device of this ID. - Otherwise commands are sent to all attached devices. - """ - - def __init__(self, device=None): - adb_dir = os.path.dirname(constants.ADB_PATH) - if adb_dir and adb_dir not in os.environ['PATH'].split(os.pathsep): - # Required by third_party/android_testrunner to call directly 'adb'. - os.environ['PATH'] += os.pathsep + adb_dir - self._adb = adb_interface.AdbInterface() - if device: - self._adb.SetTargetSerial(device) - self._device = device - self._logcat = None - self.logcat_process = None - self._logcat_tmpoutfile = None - self._pushed_files = [] - self._device_utc_offset = None - self._potential_push_size = 0 - self._actual_push_size = 0 - self._md5sum_build_dir = '' - self._external_storage = '' - self._util_wrapper = '' - - def _LogShell(self, cmd): - """Logs the adb shell command.""" - if self._device: - device_repr = self._device[-4:] - else: - device_repr = '????' - logging.info('[%s]> %s', device_repr, cmd) - - def Adb(self): - """Returns our AdbInterface to avoid us wrapping all its methods.""" - return self._adb - - def GetDevice(self): - """Returns the device serial.""" - return self._device - - def IsOnline(self): - """Checks whether the device is online. - - Returns: - True if device is in 'device' mode, False otherwise. - """ - out = self._adb.SendCommand('get-state') - return out.strip() == 'device' - - def IsRootEnabled(self): - """Checks if root is enabled on the device.""" - root_test_output = self.RunShellCommand('ls /root') or [''] - return not 'Permission denied' in root_test_output[0] - - def EnableAdbRoot(self): - """Enables adb root on the device. - - Returns: - True: if output from executing adb root was as expected. - False: otherwise. - """ - if self.GetBuildType() == 'user': - logging.warning("Can't enable root in production builds with type user") - return False - else: - return_value = self._adb.EnableAdbRoot() - # EnableAdbRoot inserts a call for wait-for-device only when adb logcat - # output matches what is expected. Just to be safe add a call to - # wait-for-device. - self._adb.SendCommand('wait-for-device') - return return_value - - def GetDeviceYear(self): - """Returns the year information of the date on device.""" - return self.RunShellCommand('date +%Y')[0] - - def GetExternalStorage(self): - if not self._external_storage: - self._external_storage = self.RunShellCommand('echo $EXTERNAL_STORAGE')[0] - assert self._external_storage, 'Unable to find $EXTERNAL_STORAGE' - return self._external_storage - - def WaitForDevicePm(self): - """Blocks until the device's package manager is available. - - To workaround http://b/5201039, we restart the shell and retry if the - package manager isn't back after 120 seconds. - - Raises: - errors.WaitForResponseTimedOutError after max retries reached. - """ - last_err = None - retries = 3 - while retries: - try: - self._adb.WaitForDevicePm() - return # Success - except errors.WaitForResponseTimedOutError as e: - last_err = e - logging.warning('Restarting and retrying after timeout: %s', e) - retries -= 1 - self.RestartShell() - raise last_err # Only reached after max retries, re-raise the last error. - - def RestartShell(self): - """Restarts the shell on the device. Does not block for it to return.""" - self.RunShellCommand('stop') - self.RunShellCommand('start') - - def Reboot(self, full_reboot=True): - """Reboots the device and waits for the package manager to return. - - Args: - full_reboot: Whether to fully reboot the device or just restart the shell. - """ - # TODO(torne): hive can't reboot the device either way without breaking the - # connection; work out if we can handle this better - if os.environ.get('USING_HIVE'): - logging.warning('Ignoring reboot request as we are on hive') - return - if full_reboot or not self.IsRootEnabled(): - self._adb.SendCommand('reboot') - timeout = 300 - retries = 1 - # Wait for the device to disappear. - while retries < 10 and self.IsOnline(): - time.sleep(1) - retries += 1 - else: - self.RestartShell() - timeout = 120 - # To run tests we need at least the package manager and the sd card (or - # other external storage) to be ready. - self.WaitForDevicePm() - self.WaitForSdCardReady(timeout) - - def Shutdown(self): - """Shuts down the device.""" - self._adb.SendCommand('reboot -p') - - def Uninstall(self, package): - """Uninstalls the specified package from the device. - - Args: - package: Name of the package to remove. - - Returns: - A status string returned by adb uninstall - """ - uninstall_command = 'uninstall %s' % package - - self._LogShell(uninstall_command) - return self._adb.SendCommand(uninstall_command, timeout_time=60) - - def Install(self, package_file_path, reinstall=False): - """Installs the specified package to the device. - - Args: - package_file_path: Path to .apk file to install. - reinstall: Reinstall an existing apk, keeping the data. - - Returns: - A status string returned by adb install - """ - assert os.path.isfile(package_file_path), ('<%s> is not file' % - package_file_path) - - install_cmd = ['install'] - - if reinstall: - install_cmd.append('-r') - - install_cmd.append(package_file_path) - install_cmd = ' '.join(install_cmd) - - self._LogShell(install_cmd) - return self._adb.SendCommand(install_cmd, - timeout_time=2 * 60, - retry_count=0) - - def ManagedInstall(self, apk_path, keep_data=False, package_name=None, - reboots_on_failure=2): - """Installs specified package and reboots device on timeouts. - - If package_name is supplied, checks if the package is already installed and - doesn't reinstall if the apk md5sums match. - - Args: - apk_path: Path to .apk file to install. - keep_data: Reinstalls instead of uninstalling first, preserving the - application data. - package_name: Package name (only needed if keep_data=False). - reboots_on_failure: number of time to reboot if package manager is frozen. - """ - # Check if package is already installed and up to date. - if package_name: - installed_apk_path = self.GetApplicationPath(package_name) - if (installed_apk_path and - not self.GetFilesChanged(apk_path, installed_apk_path)): - logging.info('Skipped install: identical %s APK already installed' % - package_name) - return - # Install. - reboots_left = reboots_on_failure - while True: - try: - if not keep_data: - assert package_name - self.Uninstall(package_name) - install_status = self.Install(apk_path, reinstall=keep_data) - if 'Success' in install_status: - return - except errors.WaitForResponseTimedOutError: - print '@@@STEP_WARNINGS@@@' - logging.info('Timeout on installing %s on device %s', apk_path, - self._device) - - if reboots_left <= 0: - raise Exception('Install failure') - - # Force a hard reboot on last attempt - self.Reboot(full_reboot=(reboots_left == 1)) - reboots_left -= 1 - - def MakeSystemFolderWritable(self): - """Remounts the /system folder rw.""" - out = self._adb.SendCommand('remount') - if out.strip() != 'remount succeeded': - raise errors.MsgException('Remount failed: %s' % out) - - def RestartAdbServer(self): - """Restart the adb server.""" - self.KillAdbServer() - self.StartAdbServer() - - def KillAdbServer(self): - """Kill adb server.""" - adb_cmd = [constants.ADB_PATH, 'kill-server'] - return cmd_helper.RunCmd(adb_cmd) - - def StartAdbServer(self): - """Start adb server.""" - adb_cmd = [constants.ADB_PATH, 'start-server'] - return cmd_helper.RunCmd(adb_cmd) - - def WaitForSystemBootCompleted(self, wait_time): - """Waits for targeted system's boot_completed flag to be set. - - Args: - wait_time: time in seconds to wait - - Raises: - WaitForResponseTimedOutError if wait_time elapses and flag still not - set. - """ - logging.info('Waiting for system boot completed...') - self._adb.SendCommand('wait-for-device') - # Now the device is there, but system not boot completed. - # Query the sys.boot_completed flag with a basic command - boot_completed = False - attempts = 0 - wait_period = 5 - while not boot_completed and (attempts * wait_period) < wait_time: - output = self._adb.SendShellCommand('getprop sys.boot_completed', - retry_count=1) - output = output.strip() - if output == '1': - boot_completed = True - else: - # If 'error: xxx' returned when querying the flag, it means - # adb server lost the connection to the emulator, so restart the adb - # server. - if 'error:' in output: - self.RestartAdbServer() - time.sleep(wait_period) - attempts += 1 - if not boot_completed: - raise errors.WaitForResponseTimedOutError( - 'sys.boot_completed flag was not set after %s seconds' % wait_time) - - def WaitForSdCardReady(self, timeout_time): - """Wait for the SD card ready before pushing data into it.""" - logging.info('Waiting for SD card ready...') - sdcard_ready = False - attempts = 0 - wait_period = 5 - external_storage = self.GetExternalStorage() - while not sdcard_ready and attempts * wait_period < timeout_time: - output = self.RunShellCommand('ls ' + external_storage) - if output: - sdcard_ready = True - else: - time.sleep(wait_period) - attempts += 1 - if not sdcard_ready: - raise errors.WaitForResponseTimedOutError( - 'SD card not ready after %s seconds' % timeout_time) - - # It is tempting to turn this function into a generator, however this is not - # possible without using a private (local) adb_shell instance (to ensure no - # other command interleaves usage of it), which would defeat the main aim of - # being able to reuse the adb shell instance across commands. - def RunShellCommand(self, command, timeout_time=20, log_result=False): - """Send a command to the adb shell and return the result. - - Args: - command: String containing the shell command to send. Must not include - the single quotes as we use them to escape the whole command. - timeout_time: Number of seconds to wait for command to respond before - retrying, used by AdbInterface.SendShellCommand. - log_result: Boolean to indicate whether we should log the result of the - shell command. - - Returns: - list containing the lines of output received from running the command - """ - self._LogShell(command) - if "'" in command: logging.warning(command + " contains ' quotes") - result = self._adb.SendShellCommand( - "'%s'" % command, timeout_time).splitlines() - if ['error: device not found'] == result: - raise errors.DeviceUnresponsiveError('device not found') - if log_result: - self._LogShell('\n'.join(result)) - return result - - def GetShellCommandStatusAndOutput(self, command, timeout_time=20, - log_result=False): - """See RunShellCommand() above. - - Returns: - The tuple (exit code, list of output lines). - """ - lines = self.RunShellCommand( - command + '; echo %$?', timeout_time, log_result) - last_line = lines[-1] - status_pos = last_line.rfind('%') - assert status_pos >= 0 - status = int(last_line[status_pos + 1:]) - if status_pos == 0: - lines = lines[:-1] - else: - lines = lines[:-1] + [last_line[:status_pos]] - return (status, lines) - - def KillAll(self, process): - """Android version of killall, connected via adb. - - Args: - process: name of the process to kill off - - Returns: - the number of processes killed - """ - pids = self.ExtractPid(process) - if pids: - self.RunShellCommand('kill -9 ' + ' '.join(pids)) - return len(pids) - - def KillAllBlocking(self, process, timeout_sec): - """Blocking version of killall, connected via adb. - - This waits until no process matching the corresponding name appears in ps' - output anymore. - - Args: - process: name of the process to kill off - timeout_sec: the timeout in seconds - - Returns: - the number of processes killed - """ - processes_killed = self.KillAll(process) - if processes_killed: - elapsed = 0 - wait_period = 0.1 - # Note that this doesn't take into account the time spent in ExtractPid(). - while self.ExtractPid(process) and elapsed < timeout_sec: - time.sleep(wait_period) - elapsed += wait_period - if elapsed >= timeout_sec: - return 0 - return processes_killed - - def _GetActivityCommand(self, package, activity, wait_for_completion, action, - category, data, extras, trace_file_name, force_stop): - """Creates command to start |package|'s activity on the device. - - Args - as for StartActivity - - Returns: - the command to run on the target to start the activity - """ - cmd = 'am start -a %s' % action - if force_stop: - cmd += ' -S' - if wait_for_completion: - cmd += ' -W' - if category: - cmd += ' -c %s' % category - if package and activity: - cmd += ' -n %s/%s' % (package, activity) - if data: - cmd += ' -d "%s"' % data - if extras: - for key in extras: - value = extras[key] - if isinstance(value, str): - cmd += ' --es' - elif isinstance(value, bool): - cmd += ' --ez' - elif isinstance(value, int): - cmd += ' --ei' - else: - raise NotImplementedError( - 'Need to teach StartActivity how to pass %s extras' % type(value)) - cmd += ' %s %s' % (key, value) - if trace_file_name: - cmd += ' --start-profiler ' + trace_file_name - return cmd - - def StartActivity(self, package, activity, wait_for_completion=False, - action='android.intent.action.VIEW', - category=None, data=None, - extras=None, trace_file_name=None, - force_stop=False): - """Starts |package|'s activity on the device. - - Args: - package: Name of package to start (e.g. 'com.google.android.apps.chrome'). - activity: Name of activity (e.g. '.Main' or - 'com.google.android.apps.chrome.Main'). - wait_for_completion: wait for the activity to finish launching (-W flag). - action: string (e.g. "android.intent.action.MAIN"). Default is VIEW. - category: string (e.g. "android.intent.category.HOME") - data: Data string to pass to activity (e.g. 'http://www.example.com/'). - extras: Dict of extras to pass to activity. Values are significant. - trace_file_name: If used, turns on and saves the trace to this file name. - force_stop: force stop the target app before starting the activity (-S - flag). - """ - cmd = self._GetActivityCommand(package, activity, wait_for_completion, - action, category, data, extras, - trace_file_name, force_stop) - self.RunShellCommand(cmd) - - def StartActivityTimed(self, package, activity, wait_for_completion=False, - action='android.intent.action.VIEW', - category=None, data=None, - extras=None, trace_file_name=None, - force_stop=False): - """Starts |package|'s activity on the device, returning the start time - - Args - as for StartActivity - - Returns: - a timestamp string for the time at which the activity started - """ - cmd = self._GetActivityCommand(package, activity, wait_for_completion, - action, category, data, extras, - trace_file_name, force_stop) - self.StartMonitoringLogcat() - self.RunShellCommand('log starting activity; ' + cmd) - activity_started_re = re.compile('.*starting activity.*') - m = self.WaitForLogMatch(activity_started_re, None) - assert m - start_line = m.group(0) - return GetLogTimestamp(start_line, self.GetDeviceYear()) - - def GoHome(self): - """Tell the device to return to the home screen. Blocks until completion.""" - self.RunShellCommand('am start -W ' - '-a android.intent.action.MAIN -c android.intent.category.HOME') - - def CloseApplication(self, package): - """Attempt to close down the application, using increasing violence. - - Args: - package: Name of the process to kill off, e.g. - com.google.android.apps.chrome - """ - self.RunShellCommand('am force-stop ' + package) - - def GetApplicationPath(self, package): - """Get the installed apk path on the device for the given package. - - Args: - package: Name of the package. - - Returns: - Path to the apk on the device if it exists, None otherwise. - """ - pm_path_output = self.RunShellCommand('pm path ' + package) - # The path output contains anything if and only if the package - # exists. - if pm_path_output: - # pm_path_output is of the form: "package:/path/to/foo.apk" - return pm_path_output[0].split(':')[1] - else: - return None - - def ClearApplicationState(self, package): - """Closes and clears all state for the given |package|.""" - # Check that the package exists before clearing it. Necessary because - # calling pm clear on a package that doesn't exist may never return. - pm_path_output = self.RunShellCommand('pm path ' + package) - # The path output only contains anything if and only if the package exists. - if pm_path_output: - self.RunShellCommand('pm clear ' + package) - - def SendKeyEvent(self, keycode): - """Sends keycode to the device. - - Args: - keycode: Numeric keycode to send (see "enum" at top of file). - """ - self.RunShellCommand('input keyevent %d' % keycode) - - def _RunMd5Sum(self, host_path, device_path): - """Gets the md5sum of a host path and device path. - - Args: - host_path: Path (file or directory) on the host. - device_path: Path on the device. - - Returns: - A tuple containing lists of the host and device md5sum results as - created by _ParseMd5SumOutput(). - """ - if not self._md5sum_build_dir: - default_build_type = os.environ.get('BUILD_TYPE', 'Debug') - build_dir = '%s/%s/' % ( - cmd_helper.OutDirectory().get(), default_build_type) - md5sum_dist_path = '%s/md5sum_dist' % build_dir - if not os.path.exists(md5sum_dist_path): - build_dir = '%s/Release/' % cmd_helper.OutDirectory().get() - md5sum_dist_path = '%s/md5sum_dist' % build_dir - assert os.path.exists(md5sum_dist_path), 'Please build md5sum.' - command = 'push %s %s' % (md5sum_dist_path, MD5SUM_DEVICE_FOLDER) - assert _HasAdbPushSucceeded(self._adb.SendCommand(command)) - self._md5sum_build_dir = build_dir - - cmd = (MD5SUM_LD_LIBRARY_PATH + ' ' + self._util_wrapper + ' ' + - MD5SUM_DEVICE_PATH + ' ' + device_path) - device_hash_tuples = _ParseMd5SumOutput( - self.RunShellCommand(cmd, timeout_time=2 * 60)) - assert os.path.exists(host_path), 'Local path not found %s' % host_path - md5sum_output = cmd_helper.GetCmdOutput( - ['%s/md5sum_bin_host' % self._md5sum_build_dir, host_path]) - host_hash_tuples = _ParseMd5SumOutput(md5sum_output.splitlines()) - return (host_hash_tuples, device_hash_tuples) - - def GetFilesChanged(self, host_path, device_path): - """Compares the md5sum of a host path against a device path. - - Note: Ignores extra files on the device. - - Args: - host_path: Path (file or directory) on the host. - device_path: Path on the device. - - Returns: - A list of tuples of the form (host_path, device_path) for files whose - md5sums do not match. - """ - host_hash_tuples, device_hash_tuples = self._RunMd5Sum( - host_path, device_path) - - # Ignore extra files on the device. - if len(device_hash_tuples) > len(host_hash_tuples): - host_files = [os.path.relpath(os.path.normpath(p.path), - os.path.normpath(host_path)) for p in host_hash_tuples] - - def HostHas(fname): - return any(path in fname for path in host_files) - - device_hash_tuples = [h for h in device_hash_tuples if HostHas(h.path)] - - # Constructs the target device path from a given host path. Don't use when - # only a single file is given as the base name given in device_path may - # differ from that in host_path. - def HostToDevicePath(host_file_path): - return os.path.join(os.path.dirname(device_path), os.path.relpath( - host_file_path, os.path.dirname(os.path.normpath(host_path)))) - - device_hashes = [h.hash for h in device_hash_tuples] - return [(t.path, HostToDevicePath(t.path) if os.path.isdir(host_path) else - device_path) - for t in host_hash_tuples if t.hash not in device_hashes] - - def PushIfNeeded(self, host_path, device_path): - """Pushes |host_path| to |device_path|. - - Works for files and directories. This method skips copying any paths in - |test_data_paths| that already exist on the device with the same hash. - - All pushed files can be removed by calling RemovePushedFiles(). - """ - MAX_INDIVIDUAL_PUSHES = 50 - assert os.path.exists(host_path), 'Local path not found %s' % host_path - - def GetHostSize(path): - return int(cmd_helper.GetCmdOutput(['du', '-sb', path]).split()[0]) - - size = GetHostSize(host_path) - self._pushed_files.append(device_path) - self._potential_push_size += size - - changed_files = self.GetFilesChanged(host_path, device_path) - if not changed_files: - return - - def Push(host, device): - # NOTE: We can't use adb_interface.Push() because it hardcodes a timeout - # of 60 seconds which isn't sufficient for a lot of users of this method. - push_command = 'push %s %s' % (host, device) - self._LogShell(push_command) - - # Retry push with increasing backoff if the device is busy. - retry = 0 - while True: - output = self._adb.SendCommand(push_command, timeout_time=30 * 60) - if _HasAdbPushSucceeded(output): - return - if retry < 3: - retry += 1 - wait_time = 5 * retry - logging.error('Push failed, retrying in %d seconds: %s' % - (wait_time, output)) - time.sleep(wait_time) - else: - raise Exception('Push failed: %s' % output) - - diff_size = 0 - if len(changed_files) <= MAX_INDIVIDUAL_PUSHES: - diff_size = sum(GetHostSize(f[0]) for f in changed_files) - - # TODO(craigdh): Replace this educated guess with a heuristic that - # approximates the push time for each method. - if len(changed_files) > MAX_INDIVIDUAL_PUSHES or diff_size > 0.5 * size: - # We're pushing everything, remove everything first and then create it. - self._actual_push_size += size - if os.path.isdir(host_path): - self.RunShellCommand('rm -r %s' % device_path, timeout_time=2 * 60) - self.RunShellCommand('mkdir -p %s' % device_path) - Push(host_path, device_path) - else: - for f in changed_files: - Push(f[0], f[1]) - self._actual_push_size += diff_size - - def GetPushSizeInfo(self): - """Get total size of pushes to the device done via PushIfNeeded() - - Returns: - A tuple: - 1. Total size of push requests to PushIfNeeded (MB) - 2. Total size that was actually pushed (MB) - """ - return (self._potential_push_size, self._actual_push_size) - - def GetFileContents(self, filename, log_result=False): - """Gets contents from the file specified by |filename|.""" - return self.RunShellCommand('cat "%s" 2>/dev/null' % filename, - log_result=log_result) - - def SetFileContents(self, filename, contents): - """Writes |contents| to the file specified by |filename|.""" - with tempfile.NamedTemporaryFile() as f: - f.write(contents) - f.flush() - self._adb.Push(f.name, filename) - - _TEMP_FILE_BASE_FMT = 'temp_file_%d' - _TEMP_SCRIPT_FILE_BASE_FMT = 'temp_script_file_%d.sh' - - def _GetDeviceTempFileName(self, base_name): - i = 0 - while self.FileExistsOnDevice( - self.GetExternalStorage() + '/' + base_name % i): - i += 1 - return self.GetExternalStorage() + '/' + base_name % i - - def CanAccessProtectedFileContents(self): - """Returns True if Get/SetProtectedFileContents would work via "su". - - Devices running user builds don't have adb root, but may provide "su" which - can be used for accessing protected files. - """ - r = self.RunShellCommand('su -c cat /dev/null') - return r == [] or r[0].strip() == '' - - def GetProtectedFileContents(self, filename, log_result=False): - """Gets contents from the protected file specified by |filename|. - - This is less efficient than GetFileContents, but will work for protected - files and device files. - """ - # Run the script as root - return self.RunShellCommand('su -c cat "%s" 2> /dev/null' % filename) - - def SetProtectedFileContents(self, filename, contents): - """Writes |contents| to the protected file specified by |filename|. - - This is less efficient than SetFileContents, but will work for protected - files and device files. - """ - temp_file = self._GetDeviceTempFileName(AndroidCommands._TEMP_FILE_BASE_FMT) - temp_script = self._GetDeviceTempFileName( - AndroidCommands._TEMP_SCRIPT_FILE_BASE_FMT) - - # Put the contents in a temporary file - self.SetFileContents(temp_file, contents) - # Create a script to copy the file contents to its final destination - self.SetFileContents(temp_script, 'cat %s > %s' % (temp_file, filename)) - # Run the script as root - self.RunShellCommand('su -c sh %s' % temp_script) - # And remove the temporary files - self.RunShellCommand('rm ' + temp_file) - self.RunShellCommand('rm ' + temp_script) - - def RemovePushedFiles(self): - """Removes all files pushed with PushIfNeeded() from the device.""" - for p in self._pushed_files: - self.RunShellCommand('rm -r %s' % p, timeout_time=2 * 60) - - def ListPathContents(self, path): - """Lists files in all subdirectories of |path|. - - Args: - path: The path to list. - - Returns: - A dict of {"name": (size, lastmod), ...}. - """ - # Example output: - # /foo/bar: - # -rw-r----- 1 user group 102 2011-05-12 12:29:54.131623387 +0100 baz.txt - re_file = re.compile('^-(?P[^\s]+)\s+' - '(?P[^\s]+)\s+' - '(?P[^\s]+)\s+' - '(?P[^\s]+)\s+' - '(?P[^\s]+)\s+' - '(?P::flags(). - -This script sets the MH_NO_HEAP_EXECUTION bit on Mach-O executables. It is -intended for use with executables produced by a linker that predates Apple's -modifications to set this bit itself. It is also useful for setting this bit -for non-i386 executables, including x86_64 executables. Apple's linker only -sets it for 32-bit i386 executables, presumably under the assumption that -the value of vm.allow_data_exec is set in stone. However, if someone were to -change vm.allow_data_exec to 2 or 3, 64-bit x86_64 executables would run -without hardware protection against code execution on data pages. This -script can set the bit for x86_64 executables, guaranteeing that they run -with appropriate protection even when vm.allow_data_exec has been tampered -with. - -POSITION-INDEPENDENT EXECUTABLES/ADDRESS SPACE LAYOUT RANDOMIZATION - -This script sets or clears the MH_PIE bit in an executable's Mach-O header, -enabling or disabling position independence on Mac OS X 10.5 and later. -Processes running position-independent executables have varying levels of -ASLR protection depending on the OS release. The main executable's load -address, shared library load addresess, and the heap and stack base -addresses may be randomized. Position-independent executables are produced -by supplying the -pie flag to the linker (or defeated by supplying -no_pie). -Executables linked with a deployment target of 10.7 or higher have PIE on -by default. - -This script is never strictly needed during the build to enable PIE, as all -linkers used are recent enough to support -pie. However, it's used to -disable the PIE bit as needed on already-linked executables. -""" - -import optparse -import os -import struct -import sys - - -# -FAT_MAGIC = 0xcafebabe -FAT_CIGAM = 0xbebafeca - -# -MH_MAGIC = 0xfeedface -MH_CIGAM = 0xcefaedfe -MH_MAGIC_64 = 0xfeedfacf -MH_CIGAM_64 = 0xcffaedfe -MH_EXECUTE = 0x2 -MH_PIE = 0x00200000 -MH_NO_HEAP_EXECUTION = 0x01000000 - - -class MachOError(Exception): - """A class for exceptions thrown by this module.""" - - pass - - -def CheckedSeek(file, offset): - """Seeks the file-like object at |file| to offset |offset| and raises a - MachOError if anything funny happens.""" - - file.seek(offset, os.SEEK_SET) - new_offset = file.tell() - if new_offset != offset: - raise MachOError, \ - 'seek: expected offset %d, observed %d' % (offset, new_offset) - - -def CheckedRead(file, count): - """Reads |count| bytes from the file-like |file| object, raising a - MachOError if any other number of bytes is read.""" - - bytes = file.read(count) - if len(bytes) != count: - raise MachOError, \ - 'read: expected length %d, observed %d' % (count, len(bytes)) - - return bytes - - -def ReadUInt32(file, endian): - """Reads an unsinged 32-bit integer from the file-like |file| object, - treating it as having endianness specified by |endian| (per the |struct| - module), and returns it as a number. Raises a MachOError if the proper - length of data can't be read from |file|.""" - - bytes = CheckedRead(file, 4) - - (uint32,) = struct.unpack(endian + 'I', bytes) - return uint32 - - -def ReadMachHeader(file, endian): - """Reads an entire |mach_header| structure () from the - file-like |file| object, treating it as having endianness specified by - |endian| (per the |struct| module), and returns a 7-tuple of its members - as numbers. Raises a MachOError if the proper length of data can't be read - from |file|.""" - - bytes = CheckedRead(file, 28) - - magic, cputype, cpusubtype, filetype, ncmds, sizeofcmds, flags = \ - struct.unpack(endian + '7I', bytes) - return magic, cputype, cpusubtype, filetype, ncmds, sizeofcmds, flags - - -def ReadFatArch(file): - """Reads an entire |fat_arch| structure () from the file-like - |file| object, treating it as having endianness specified by |endian| - (per the |struct| module), and returns a 5-tuple of its members as numbers. - Raises a MachOError if the proper length of data can't be read from - |file|.""" - - bytes = CheckedRead(file, 20) - - cputype, cpusubtype, offset, size, align = struct.unpack('>5I', bytes) - return cputype, cpusubtype, offset, size, align - - -def WriteUInt32(file, uint32, endian): - """Writes |uint32| as an unsinged 32-bit integer to the file-like |file| - object, treating it as having endianness specified by |endian| (per the - |struct| module).""" - - bytes = struct.pack(endian + 'I', uint32) - assert len(bytes) == 4 - - file.write(bytes) - - -def HandleMachOFile(file, options, offset=0): - """Seeks the file-like |file| object to |offset|, reads its |mach_header|, - and rewrites the header's |flags| field if appropriate. The header's - endianness is detected. Both 32-bit and 64-bit Mach-O headers are supported - (mach_header and mach_header_64). Raises MachOError if used on a header that - does not have a known magic number or is not of type MH_EXECUTE. The - MH_PIE and MH_NO_HEAP_EXECUTION bits are set or cleared in the |flags| field - according to |options| and written to |file| if any changes need to be made. - If already set or clear as specified by |options|, nothing is written.""" - - CheckedSeek(file, offset) - magic = ReadUInt32(file, '<') - if magic == MH_MAGIC or magic == MH_MAGIC_64: - endian = '<' - elif magic == MH_CIGAM or magic == MH_CIGAM_64: - endian = '>' - else: - raise MachOError, \ - 'Mach-O file at offset %d has illusion of magic' % offset - - CheckedSeek(file, offset) - magic, cputype, cpusubtype, filetype, ncmds, sizeofcmds, flags = \ - ReadMachHeader(file, endian) - assert magic == MH_MAGIC or magic == MH_MAGIC_64 - if filetype != MH_EXECUTE: - raise MachOError, \ - 'Mach-O file at offset %d is type 0x%x, expected MH_EXECUTE' % \ - (offset, filetype) - - original_flags = flags - - if options.no_heap_execution: - flags |= MH_NO_HEAP_EXECUTION - else: - flags &= ~MH_NO_HEAP_EXECUTION - - if options.pie: - flags |= MH_PIE - else: - flags &= ~MH_PIE - - if flags != original_flags: - CheckedSeek(file, offset + 24) - WriteUInt32(file, flags, endian) - - -def HandleFatFile(file, options, fat_offset=0): - """Seeks the file-like |file| object to |offset| and loops over its - |fat_header| entries, calling HandleMachOFile for each.""" - - CheckedSeek(file, fat_offset) - magic = ReadUInt32(file, '>') - assert magic == FAT_MAGIC - - nfat_arch = ReadUInt32(file, '>') - - for index in xrange(0, nfat_arch): - cputype, cpusubtype, offset, size, align = ReadFatArch(file) - assert size >= 28 - - # HandleMachOFile will seek around. Come back here after calling it, in - # case it sought. - fat_arch_offset = file.tell() - HandleMachOFile(file, options, offset) - CheckedSeek(file, fat_arch_offset) - - -def main(me, args): - parser = optparse.OptionParser('%prog [options] ') - parser.add_option('--executable-heap', action='store_false', - dest='no_heap_execution', default=True, - help='Clear the MH_NO_HEAP_EXECUTION bit') - parser.add_option('--no-pie', action='store_false', - dest='pie', default=True, - help='Clear the MH_PIE bit') - (options, loose_args) = parser.parse_args(args) - if len(loose_args) != 1: - parser.print_usage() - return 1 - - executable_path = loose_args[0] - executable_file = open(executable_path, 'rb+') - - magic = ReadUInt32(executable_file, '<') - if magic == FAT_CIGAM: - # Check FAT_CIGAM and not FAT_MAGIC because the read was little-endian. - HandleFatFile(executable_file, options) - elif magic == MH_MAGIC or magic == MH_CIGAM or \ - magic == MH_MAGIC_64 or magic == MH_CIGAM_64: - HandleMachOFile(executable_file, options) - else: - raise MachOError, '%s is not a Mach-O or fat file' % executable_file - - executable_file.close() - return 0 - - -if __name__ == '__main__': - sys.exit(main(sys.argv[0], sys.argv[1:])) diff --git a/build/mac/change_mach_o_flags_from_xcode.sh b/build/mac/change_mach_o_flags_from_xcode.sh deleted file mode 100755 index 1824f8db52..0000000000 --- a/build/mac/change_mach_o_flags_from_xcode.sh +++ /dev/null @@ -1,15 +0,0 @@ -#!/bin/sh - -# Copyright (c) 2011 The Chromium Authors. All rights reserved. -# Use of this source code is governed by a BSD-style license that can be -# found in the LICENSE file. - -# This is a small wrapper script around change_mach_o_flags.py allowing it to -# be invoked easily from Xcode. change_mach_o_flags.py expects its arguments -# on the command line, but Xcode puts its parameters in the environment. - -set -e - -exec "$(dirname "${0}")/change_mach_o_flags.py" \ - "${@}" \ - "${BUILT_PRODUCTS_DIR}/${EXECUTABLE_PATH}" diff --git a/build/mac/chrome_mac.croc b/build/mac/chrome_mac.croc deleted file mode 100644 index 8cde00ce20..0000000000 --- a/build/mac/chrome_mac.croc +++ /dev/null @@ -1,36 +0,0 @@ -# -*- python -*- -# Crocodile config file for Chromium mac - -{ - # List of rules, applied in order - 'rules' : [ - # Specify inclusions before exclusions, since rules are in order. - - # Don't include chromeos, linux, or windows specific files - { - 'regexp' : '.*(_|/)(chromeos|linux|win|views)(\\.|_)', - 'include' : 0, - }, - # Don't include ChromeOS dirs - { - 'regexp' : '.*/chromeos/', - 'include' : 0, - }, - - # Groups - { - 'regexp' : '.*_test_mac\\.', - 'group' : 'test', - }, - - # Languages - { - 'regexp' : '.*\\.m$', - 'language' : 'ObjC', - }, - { - 'regexp' : '.*\\.mm$', - 'language' : 'ObjC++', - }, - ], -} diff --git a/build/mac/copy_asan_runtime_dylib.sh b/build/mac/copy_asan_runtime_dylib.sh deleted file mode 100755 index b67b4346cd..0000000000 --- a/build/mac/copy_asan_runtime_dylib.sh +++ /dev/null @@ -1,63 +0,0 @@ -#!/bin/bash - -# Copyright (c) 2013 The Chromium Authors. All rights reserved. -# Use of this source code is governed by a BSD-style license that can be -# found in the LICENSE file. - -# For app bundles built with ASan, copies the runtime lib -# (libclang_rt.asan_osx_dynamic.dylib), on which their executables depend, from -# the compiler installation path into the bundle and fixes the dylib's install -# name in the binary to be relative to @executable_path. - -set -e - -BINARY="${BUILT_PRODUCTS_DIR}/${EXECUTABLE_PATH}" -BINARY_DIR="$(dirname "${BINARY}")" -ASAN_DYLIB_NAME=libclang_rt.asan_osx_dynamic.dylib -ASAN_DYLIB=$(find \ - "${BUILT_PRODUCTS_DIR}/../../third_party/llvm-build/Release+Asserts/lib/clang/" \ - -type f -path "*${ASAN_DYLIB_NAME}") - -# Find the link to the ASan runtime encoded in the binary. -BUILTIN_DYLIB_PATH=$(otool -L "${BINARY}" | \ - sed -Ene 's/^[[:blank:]]+(.*libclang_rt\.asan_osx_dynamic\.dylib).*$/\1/p') - -if [[ -z "${BUILTIN_DYLIB_PATH}" ]]; then - echo "${BINARY} does not depend on the ASan runtime library!" >&2 - # TODO(glider): make this return 1 when we fully switch to the dynamic - # runtime in ASan. - exit 0 -fi - -DYLIB_BASENAME=$(basename "${ASAN_DYLIB}") -if [[ "${DYLIB_BASENAME}" != "${ASAN_DYLIB_NAME}" ]]; then - echo "basename(${ASAN_DYLIB}) != ${ASAN_DYLIB_NAME}" >&2 - exit 1 -fi - -# Check whether the directory containing the executable binary is named -# "MacOS". In this case we're building a full-fledged OSX app and will put -# the runtime into appname.app/Contents/Libraries/. Otherwise this is probably -# an iOS gtest app, and the ASan runtime is put next to the executable. -UPPER_DIR=$(dirname "${BINARY_DIR}") -if [ "${UPPER_DIR}" == "MacOS" ]; then - LIBRARIES_DIR="${UPPER_DIR}/Libraries" - mkdir -p "${LIBRARIES_DIR}" - NEW_LC_ID_DYLIB="@executable_path/../Libraries/${ASAN_DYLIB_NAME}" -else - LIBRARIES_DIR="${BINARY_DIR}" - NEW_LC_ID_DYLIB="@executable_path/${ASAN_DYLIB_NAME}" -fi - -cp "${ASAN_DYLIB}" "${LIBRARIES_DIR}" - -# Make LC_ID_DYLIB of the runtime copy point to its location. -install_name_tool \ - -id "${NEW_LC_ID_DYLIB}" \ - "${LIBRARIES_DIR}/${ASAN_DYLIB_NAME}" - -# Fix the rpath to the runtime library recorded in the binary. -install_name_tool \ - -change "${BUILTIN_DYLIB_PATH}" \ - "${NEW_LC_ID_DYLIB}" \ - "${BINARY}" diff --git a/build/mac/copy_framework_unversioned.sh b/build/mac/copy_framework_unversioned.sh deleted file mode 100755 index 380cc90840..0000000000 --- a/build/mac/copy_framework_unversioned.sh +++ /dev/null @@ -1,118 +0,0 @@ -#!/bin/bash - -# Copyright (c) 2012 The Chromium Authors. All rights reserved. -# Use of this source code is governed by a BSD-style license that can be -# found in the LICENSE file. - -# Copies a framework to its new home, "unversioning" it. -# -# Normally, frameworks are versioned bundles. The contents of a framework are -# stored in a versioned directory within the bundle, and symbolic links -# provide access to the actual code and resources. See -# http://developer.apple.com/mac/library/documentation/MacOSX/Conceptual/BPFrameworks/Concepts/FrameworkAnatomy.html -# -# The symbolic links usually found in frameworks create problems. Symbolic -# links are excluded from code signatures. That means that it's possible to -# remove or retarget a symbolic link within a framework without affecting the -# seal. In Chrome's case, the outer .app bundle contains a framework where -# all application code and resources live. In order for the signature on the -# .app to be meaningful, it encompasses the framework. Because framework -# resources are accessed through the framework's symbolic links, this -# arrangement results in a case where the resources can be altered without -# affecting the .app signature's validity. -# -# Indirection through symbolic links also carries a runtime performance -# penalty on open() operations, although open() typically completes so quickly -# that this is not considered a major performance problem. -# -# To resolve these problems, the frameworks that ship within Chrome's .app -# bundle are unversioned. Unversioning is simple: instead of using the -# original outer .framework directory as the framework that ships within the -# .app, the inner versioned directory is used. Instead of accessing bundled -# resources through symbolic links, they are accessed directly. In normal -# situations, the only hard-coded use of the versioned directory is by dyld, -# when loading the framework's code, but this is handled through a normal -# Mach-O load command, and it is easy to adjust the load command to point to -# the unversioned framework code rather than the versioned counterpart. -# -# The resulting framework bundles aren't strictly conforming, but they work -# as well as normal versioned framework bundles. -# -# An option to skip running install_name_tool is available. By passing -I as -# the first argument to this script, install_name_tool will be skipped. This -# is only suitable for copied frameworks that will not be linked against, or -# when install_name_tool will be run on any linker output when something is -# linked against the copied framework. This option exists to allow signed -# frameworks to pass through without subjecting them to any modifications that -# would break their signatures. - -set -e - -RUN_INSTALL_NAME_TOOL=1 -if [ $# -eq 3 ] && [ "${1}" = "-I" ] ; then - shift - RUN_INSTALL_NAME_TOOL= -fi - -if [ $# -ne 2 ] ; then - echo "usage: ${0} [-I] FRAMEWORK DESTINATION_DIR" >& 2 - exit 1 -fi - -# FRAMEWORK should be a path to a versioned framework bundle, ending in -# .framework. DESTINATION_DIR is the directory that the unversioned framework -# bundle will be copied to. - -FRAMEWORK="${1}" -DESTINATION_DIR="${2}" - -FRAMEWORK_NAME="$(basename "${FRAMEWORK}")" -if [ "${FRAMEWORK_NAME: -10}" != ".framework" ] ; then - echo "${0}: ${FRAMEWORK_NAME} does not end in .framework" >& 2 - exit 1 -fi -FRAMEWORK_NAME_NOEXT="${FRAMEWORK_NAME:0:$((${#FRAMEWORK_NAME} - 10))}" - -# Find the current version. -VERSIONS="${FRAMEWORK}/Versions" -CURRENT_VERSION_LINK="${VERSIONS}/Current" -CURRENT_VERSION_ID="$(readlink "${VERSIONS}/Current")" -CURRENT_VERSION="${VERSIONS}/${CURRENT_VERSION_ID}" - -# Make sure that the framework's structure makes sense as a versioned bundle. -if [ ! -e "${CURRENT_VERSION}/${FRAMEWORK_NAME_NOEXT}" ] ; then - echo "${0}: ${FRAMEWORK_NAME} does not contain a dylib" >& 2 - exit 1 -fi - -DESTINATION="${DESTINATION_DIR}/${FRAMEWORK_NAME}" - -# Copy the versioned directory within the versioned framework to its -# destination location. -mkdir -p "${DESTINATION_DIR}" -rsync -acC --delete --exclude Headers --exclude PrivateHeaders \ - --include '*.so' "${CURRENT_VERSION}/" "${DESTINATION}" - -if [[ -n "${RUN_INSTALL_NAME_TOOL}" ]]; then - # Adjust the Mach-O LC_ID_DYLIB load command in the framework. This does not - # change the LC_LOAD_DYLIB load commands in anything that may have already - # linked against the framework. Not all frameworks will actually need this - # to be changed. Some frameworks may already be built with the proper - # LC_ID_DYLIB for use as an unversioned framework. Xcode users can do this - # by setting LD_DYLIB_INSTALL_NAME to - # $(DYLIB_INSTALL_NAME_BASE:standardizepath)/$(WRAPPER_NAME)/$(PRODUCT_NAME) - # If invoking ld via gcc or g++, pass the desired path to -Wl,-install_name - # at link time. - FRAMEWORK_DYLIB="${DESTINATION}/${FRAMEWORK_NAME_NOEXT}" - LC_ID_DYLIB_OLD="$(otool -l "${FRAMEWORK_DYLIB}" | - grep -A10 "^ *cmd LC_ID_DYLIB$" | - grep -m1 "^ *name" | - sed -Ee 's/^ *name (.*) \(offset [0-9]+\)$/\1/')" - VERSION_PATH="/Versions/${CURRENT_VERSION_ID}/${FRAMEWORK_NAME_NOEXT}" - LC_ID_DYLIB_NEW="$(echo "${LC_ID_DYLIB_OLD}" | - sed -Ee "s%${VERSION_PATH}$%/${FRAMEWORK_NAME_NOEXT}%")" - - if [ "${LC_ID_DYLIB_NEW}" != "${LC_ID_DYLIB_OLD}" ] ; then - install_name_tool -id "${LC_ID_DYLIB_NEW}" "${FRAMEWORK_DYLIB}" - fi -fi diff --git a/build/mac/edit_xibs.sh b/build/mac/edit_xibs.sh deleted file mode 100755 index a3054557b3..0000000000 --- a/build/mac/edit_xibs.sh +++ /dev/null @@ -1,17 +0,0 @@ -#!/bin/sh - -# Copyright (c) 2012 The Chromium Authors. All rights reserved. -# Use of this source code is governed by a BSD-style license that can be -# found in the LICENSE file. - -# This script is a convenience to run GYP for /src/chrome/chrome_nibs.gyp -# with the Xcode generator (as you likely use ninja). Documentation: -# http://dev.chromium.org/developers/design-documents/mac-xib-files - -set -e - -RELSRC=$(dirname "$0")/../.. -SRC=$(cd "$RELSRC" && pwd) -GYP_GENERATORS=xcode python "$SRC/tools/gyp/gyp" "$SRC/chrome/chrome_nibs.gyp" -echo "You can now edit XIB files in Xcode using:" -echo " $SRC/chrome/chrome_nibs.xcodeproj" diff --git a/build/mac/find_sdk.py b/build/mac/find_sdk.py deleted file mode 100755 index 067be638d2..0000000000 --- a/build/mac/find_sdk.py +++ /dev/null @@ -1,82 +0,0 @@ -#!/usr/bin/env python -# Copyright (c) 2012 The Chromium Authors. All rights reserved. -# Use of this source code is governed by a BSD-style license that can be -# found in the LICENSE file. - -import os -import re -import subprocess -import sys - -"""Prints the lowest locally available SDK version greater than or equal to a -given minimum sdk version to standard output. - -Usage: - python find_sdk.py 10.6 # Ignores SDKs < 10.6 -""" - -from optparse import OptionParser - - -def parse_version(version_str): - """'10.6' => [10, 6]""" - return map(int, re.findall(r'(\d+)', version_str)) - - -def main(): - parser = OptionParser() - parser.add_option("--verify", - action="store_true", dest="verify", default=False, - help="return the sdk argument and warn if it doesn't exist") - parser.add_option("--sdk_path", - action="store", type="string", dest="sdk_path", default="", - help="user-specified SDK path; bypasses verification") - (options, args) = parser.parse_args() - min_sdk_version = args[0] - - job = subprocess.Popen(['xcode-select', '-print-path'], - stdout=subprocess.PIPE, - stderr=subprocess.STDOUT) - out, err = job.communicate() - if job.returncode != 0: - print >>sys.stderr, out - print >>sys.stderr, err - raise Exception(('Error %d running xcode-select, you might have to run ' - '|sudo xcode-select --switch /Applications/Xcode.app/Contents/Developer| ' - 'if you are using Xcode 4.') % job.returncode) - # The Developer folder moved in Xcode 4.3. - xcode43_sdk_path = os.path.join( - out.rstrip(), 'Platforms/MacOSX.platform/Developer/SDKs') - if os.path.isdir(xcode43_sdk_path): - sdk_dir = xcode43_sdk_path - else: - sdk_dir = os.path.join(out.rstrip(), 'SDKs') - sdks = [re.findall('^MacOSX(10\.\d+)\.sdk$', s) for s in os.listdir(sdk_dir)] - sdks = [s[0] for s in sdks if s] # [['10.5'], ['10.6']] => ['10.5', '10.6'] - sdks = [s for s in sdks # ['10.5', '10.6'] => ['10.6'] - if parse_version(s) >= parse_version(min_sdk_version)] - if not sdks: - raise Exception('No %s+ SDK found' % min_sdk_version) - best_sdk = sorted(sdks, key=parse_version)[0] - - if options.verify and best_sdk != min_sdk_version and not options.sdk_path: - print >>sys.stderr, '' - print >>sys.stderr, ' vvvvvvv' - print >>sys.stderr, '' - print >>sys.stderr, \ - 'This build requires the %s SDK, but it was not found on your system.' \ - % min_sdk_version - print >>sys.stderr, \ - 'Either install it, or explicitly set mac_sdk in your GYP_DEFINES.' - print >>sys.stderr, '' - print >>sys.stderr, ' ^^^^^^^' - print >>sys.stderr, '' - return min_sdk_version - - return best_sdk - - -if __name__ == '__main__': - if sys.platform != 'darwin': - raise Exception("This script only runs on Mac") - print main() diff --git a/build/mac/make_more_helpers.sh b/build/mac/make_more_helpers.sh deleted file mode 100755 index 6f5c4749eb..0000000000 --- a/build/mac/make_more_helpers.sh +++ /dev/null @@ -1,91 +0,0 @@ -#!/bin/bash - -# Copyright (c) 2012 The Chromium Authors. All rights reserved. -# Use of this source code is governed by a BSD-style license that can be -# found in the LICENSE file. - -# Usage: make_more_helpers.sh -# -# This script creates additional helper .app bundles for Chromium, based on -# the existing helper .app bundle, changing their Mach-O header's flags to -# enable and disable various features. Based on Chromium Helper.app, it will -# create Chromium Helper EH.app, which has the MH_NO_HEAP_EXECUTION bit -# cleared to support Chromium child processes that require an executable heap, -# and Chromium Helper NP.app, which has the MH_PIE bit cleared to support -# Chromium child processes that cannot tolerate ASLR. -# -# This script expects to be called from the chrome_exe target as a postbuild, -# and operates directly within the built-up browser app's versioned directory. -# -# Each helper is adjusted by giving it the proper bundle name, renaming the -# executable, adjusting several Info.plist keys, and changing the executable's -# Mach-O flags. - -set -eu - -make_helper() { - local containing_dir="${1}" - local app_name="${2}" - local feature="${3}" - local flags="${4}" - - local helper_name="${app_name} Helper" - local helper_stem="${containing_dir}/${helper_name}" - local original_helper="${helper_stem}.app" - if [[ ! -d "${original_helper}" ]]; then - echo "${0}: error: ${original_helper} is a required directory" >& 2 - exit 1 - fi - local original_helper_exe="${original_helper}/Contents/MacOS/${helper_name}" - if [[ ! -f "${original_helper_exe}" ]]; then - echo "${0}: error: ${original_helper_exe} is a required file" >& 2 - exit 1 - fi - - local feature_helper="${helper_stem} ${feature}.app" - - rsync -acC --delete --include '*.so' "${original_helper}/" "${feature_helper}" - - local helper_feature="${helper_name} ${feature}" - local helper_feature_exe="${feature_helper}/Contents/MacOS/${helper_feature}" - mv "${feature_helper}/Contents/MacOS/${helper_name}" "${helper_feature_exe}" - - local change_flags="$(dirname "${0}")/change_mach_o_flags.py" - "${change_flags}" ${flags} "${helper_feature_exe}" - - local feature_info="${feature_helper}/Contents/Info" - local feature_info_plist="${feature_info}.plist" - - defaults write "${feature_info}" "CFBundleDisplayName" "${helper_feature}" - defaults write "${feature_info}" "CFBundleExecutable" "${helper_feature}" - - cfbundleid="$(defaults read "${feature_info}" "CFBundleIdentifier")" - feature_cfbundleid="${cfbundleid}.${feature}" - defaults write "${feature_info}" "CFBundleIdentifier" "${feature_cfbundleid}" - - cfbundlename="$(defaults read "${feature_info}" "CFBundleName")" - feature_cfbundlename="${cfbundlename} ${feature}" - defaults write "${feature_info}" "CFBundleName" "${feature_cfbundlename}" - - # As usual, defaults might have put the plist into whatever format excites - # it, but Info.plists get converted back to the expected XML format. - plutil -convert xml1 "${feature_info_plist}" - - # `defaults` also changes the file permissions, so make the file - # world-readable again. - chmod a+r "${feature_info_plist}" -} - -if [[ ${#} -ne 2 ]]; then - echo "usage: ${0} " >& 2 - exit 1 -fi - -DIRECTORY_WITHIN_CONTENTS="${1}" -APP_NAME="${2}" - -CONTENTS_DIR="${BUILT_PRODUCTS_DIR}/${CONTENTS_FOLDER_PATH}" -CONTAINING_DIR="${CONTENTS_DIR}/${DIRECTORY_WITHIN_CONTENTS}" - -make_helper "${CONTAINING_DIR}" "${APP_NAME}" "EH" "--executable-heap" -make_helper "${CONTAINING_DIR}" "${APP_NAME}" "NP" "--no-pie" diff --git a/build/mac/strip_from_xcode b/build/mac/strip_from_xcode deleted file mode 100755 index c26b9fb492..0000000000 --- a/build/mac/strip_from_xcode +++ /dev/null @@ -1,62 +0,0 @@ -#!/bin/bash - -# Copyright (c) 2008 The Chromium Authors. All rights reserved. -# Use of this source code is governed by a BSD-style license that can be -# found in the LICENSE file. - -# This is a handy wrapper script that figures out how to call the strip -# utility (strip_save_dsym in this case), if it even needs to be called at all, -# and then does it. This script should be called by a post-link phase in -# targets that might generate Mach-O executables, dynamic libraries, or -# loadable bundles. -# -# An example "Strip If Needed" build phase placed after "Link Binary With -# Libraries" would do: -# exec "${XCODEPROJ_DEPTH}/build/mac/strip_from_xcode" - -if [ "${CONFIGURATION}" != "Release" ] ; then - # Only strip in release mode. - exit 0 -fi - -declare -a FLAGS - -# MACH_O_TYPE is not set for a command-line tool, so check PRODUCT_TYPE too. -# Weird. -if [ "${MACH_O_TYPE}" = "mh_execute" ] || \ - [ "${PRODUCT_TYPE}" = "com.apple.product-type.tool" ] ; then - # Strip everything (no special flags). No-op. - true -elif [ "${MACH_O_TYPE}" = "mh_dylib" ] || \ - [ "${MACH_O_TYPE}" = "mh_bundle" ]; then - # Strip debugging symbols and local symbols - FLAGS[${#FLAGS[@]}]=-S - FLAGS[${#FLAGS[@]}]=-x -elif [ "${MACH_O_TYPE}" = "staticlib" ] ; then - # Don't strip static libraries. - exit 0 -else - # Warn, but don't treat this as an error. - echo $0: warning: unrecognized MACH_O_TYPE ${MACH_O_TYPE} - exit 0 -fi - -if [ -n "${STRIPFLAGS}" ] ; then - # Pick up the standard STRIPFLAGS Xcode setting, used for "Additional Strip - # Flags". - for stripflag in "${STRIPFLAGS}" ; do - FLAGS[${#FLAGS[@]}]="${stripflag}" - done -fi - -if [ -n "${CHROMIUM_STRIP_SAVE_FILE}" ] ; then - # An Xcode project can communicate a file listing symbols to saved in this - # environment variable by setting it as a build setting. This isn't a - # standard Xcode setting. It's used in preference to STRIPFLAGS to - # eliminate quoting ambiguity concerns. - FLAGS[${#FLAGS[@]}]=-s - FLAGS[${#FLAGS[@]}]="${CHROMIUM_STRIP_SAVE_FILE}" -fi - -exec "$(dirname ${0})/strip_save_dsym" "${FLAGS[@]}" \ - "${BUILT_PRODUCTS_DIR}/${EXECUTABLE_PATH}" diff --git a/build/mac/strip_save_dsym b/build/mac/strip_save_dsym deleted file mode 100755 index ef08d831f1..0000000000 --- a/build/mac/strip_save_dsym +++ /dev/null @@ -1,341 +0,0 @@ -#!/usr/bin/python - -# Copyright (c) 2011 The Chromium Authors. All rights reserved. -# Use of this source code is governed by a BSD-style license that can be -# found in the LICENSE file. - -# Usage: strip_save_dsym -# -# strip_save_dsym is a wrapper around the standard strip utility. Given an -# input Mach-O file, strip_save_dsym will save a copy of the file in a "fake" -# .dSYM bundle for debugging, and then call strip to strip the Mach-O file. -# Note that the .dSYM file is a "fake" in that it's not a self-contained -# .dSYM bundle, it just contains a copy of the original (unstripped) Mach-O -# file, and therefore contains references to object files on the filesystem. -# The generated .dSYM bundle is therefore unsuitable for debugging in the -# absence of these .o files. -# -# If a .dSYM already exists and has a newer timestamp than the Mach-O file, -# this utility does nothing. That allows strip_save_dsym to be run on a file -# that has already been stripped without trashing the .dSYM. -# -# Rationale: the "right" way to generate dSYM bundles, dsymutil, is incredibly -# slow. On the other hand, doing a file copy (which is really all that -# dsymutil does) is comparatively fast. Since we usually just want to strip -# a release-mode executable but still be able to debug it, and we don't care -# so much about generating a hermetic dSYM bundle, we'll prefer the file copy. -# If a real dSYM is ever needed, it's still possible to create one by running -# dsymutil and pointing it at the original Mach-O file inside the "fake" -# bundle, provided that the object files are available. - -import errno -import os -import re -import shutil -import subprocess -import sys -import time - -# Returns a list of architectures contained in a Mach-O file. The file can be -# a universal (fat) file, in which case there will be one list element for -# each contained architecture, or it can be a thin single-architecture Mach-O -# file, in which case the list will contain a single element identifying the -# architecture. On error, returns an empty list. Determines the architecture -# list by calling file. -def macho_archs(macho): - macho_types = ["executable", - "dynamically linked shared library", - "bundle"] - macho_types_re = "Mach-O (?:64-bit )?(?:" + "|".join(macho_types) + ")" - - file_cmd = subprocess.Popen(["/usr/bin/file", "-b", "--", macho], - stdout=subprocess.PIPE) - - archs = [] - - type_line = file_cmd.stdout.readline() - type_match = re.match("^%s (.*)$" % macho_types_re, type_line) - if type_match: - archs.append(type_match.group(1)) - return [type_match.group(1)] - else: - type_match = re.match("^Mach-O universal binary with (.*) architectures$", - type_line) - if type_match: - for i in range(0, int(type_match.group(1))): - arch_line = file_cmd.stdout.readline() - arch_match = re.match( - "^.* \(for architecture (.*)\):\t%s .*$" % macho_types_re, - arch_line) - if arch_match: - archs.append(arch_match.group(1)) - - if file_cmd.wait() != 0: - archs = [] - - if len(archs) == 0: - print >> sys.stderr, "No architectures in %s" % macho - - return archs - -# Returns a dictionary mapping architectures contained in the file as returned -# by macho_archs to the LC_UUID load command for that architecture. -# Architectures with no LC_UUID load command are omitted from the dictionary. -# Determines the UUID value by calling otool. -def macho_uuids(macho): - uuids = {} - - archs = macho_archs(macho) - if len(archs) == 0: - return uuids - - for arch in archs: - if arch == "": - continue - - otool_cmd = subprocess.Popen(["/usr/bin/otool", "-arch", arch, "-l", "-", - macho], - stdout=subprocess.PIPE) - # state 0 is when nothing UUID-related has been seen yet. State 1 is - # entered after a load command begins, but it may not be an LC_UUID load - # command. States 2, 3, and 4 are intermediate states while reading an - # LC_UUID command. State 5 is the terminal state for a successful LC_UUID - # read. State 6 is the error state. - state = 0 - uuid = "" - for otool_line in otool_cmd.stdout: - if state == 0: - if re.match("^Load command .*$", otool_line): - state = 1 - elif state == 1: - if re.match("^ cmd LC_UUID$", otool_line): - state = 2 - else: - state = 0 - elif state == 2: - if re.match("^ cmdsize 24$", otool_line): - state = 3 - else: - state = 6 - elif state == 3: - # The UUID display format changed in the version of otool shipping - # with the Xcode 3.2.2 prerelease. The new format is traditional: - # uuid 4D7135B2-9C56-C5F5-5F49-A994258E0955 - # and with Xcode 3.2.6, then line is indented one more space: - # uuid 4D7135B2-9C56-C5F5-5F49-A994258E0955 - # The old format, from cctools-750 and older's otool, breaks the UUID - # up into a sequence of bytes: - # uuid 0x4d 0x71 0x35 0xb2 0x9c 0x56 0xc5 0xf5 - # 0x5f 0x49 0xa9 0x94 0x25 0x8e 0x09 0x55 - new_uuid_match = re.match("^ {3,4}uuid (.{8}-.{4}-.{4}-.{4}-.{12})$", - otool_line) - if new_uuid_match: - uuid = new_uuid_match.group(1) - - # Skip state 4, there is no second line to read. - state = 5 - else: - old_uuid_match = re.match("^ uuid 0x(..) 0x(..) 0x(..) 0x(..) " - "0x(..) 0x(..) 0x(..) 0x(..)$", - otool_line) - if old_uuid_match: - state = 4 - uuid = old_uuid_match.group(1) + old_uuid_match.group(2) + \ - old_uuid_match.group(3) + old_uuid_match.group(4) + "-" + \ - old_uuid_match.group(5) + old_uuid_match.group(6) + "-" + \ - old_uuid_match.group(7) + old_uuid_match.group(8) + "-" - else: - state = 6 - elif state == 4: - old_uuid_match = re.match("^ 0x(..) 0x(..) 0x(..) 0x(..) " - "0x(..) 0x(..) 0x(..) 0x(..)$", - otool_line) - if old_uuid_match: - state = 5 - uuid += old_uuid_match.group(1) + old_uuid_match.group(2) + "-" + \ - old_uuid_match.group(3) + old_uuid_match.group(4) + \ - old_uuid_match.group(5) + old_uuid_match.group(6) + \ - old_uuid_match.group(7) + old_uuid_match.group(8) - else: - state = 6 - - if otool_cmd.wait() != 0: - state = 6 - - if state == 5: - uuids[arch] = uuid.upper() - - if len(uuids) == 0: - print >> sys.stderr, "No UUIDs in %s" % macho - - return uuids - -# Given a path to a Mach-O file and possible information from the environment, -# determines the desired path to the .dSYM. -def dsym_path(macho): - # If building a bundle, the .dSYM should be placed next to the bundle. Use - # WRAPPER_NAME to make this determination. If called from xcodebuild, - # WRAPPER_NAME will be set to the name of the bundle. - dsym = "" - if "WRAPPER_NAME" in os.environ: - if "BUILT_PRODUCTS_DIR" in os.environ: - dsym = os.path.join(os.environ["BUILT_PRODUCTS_DIR"], - os.environ["WRAPPER_NAME"]) - else: - dsym = os.environ["WRAPPER_NAME"] - else: - dsym = macho - - dsym += ".dSYM" - - return dsym - -# Creates a fake .dSYM bundle at dsym for macho, a Mach-O image with the -# architectures and UUIDs specified by the uuids map. -def make_fake_dsym(macho, dsym): - uuids = macho_uuids(macho) - if len(uuids) == 0: - return False - - dwarf_dir = os.path.join(dsym, "Contents", "Resources", "DWARF") - dwarf_file = os.path.join(dwarf_dir, os.path.basename(macho)) - try: - os.makedirs(dwarf_dir) - except OSError, (err, error_string): - if err != errno.EEXIST: - raise - shutil.copyfile(macho, dwarf_file) - - # info_template is the same as what dsymutil would have written, with the - # addition of the fake_dsym key. - info_template = \ -''' - - - - CFBundleDevelopmentRegion - English - CFBundleIdentifier - com.apple.xcode.dsym.%(root_name)s - CFBundleInfoDictionaryVersion - 6.0 - CFBundlePackageType - dSYM - CFBundleSignature - ???? - CFBundleShortVersionString - 1.0 - CFBundleVersion - 1 - dSYM_UUID - -%(uuid_dict)s - fake_dsym - - - -''' - - root_name = os.path.basename(dsym)[:-5] # whatever.dSYM without .dSYM - uuid_dict = "" - for arch in sorted(uuids): - uuid_dict += "\t\t\t" + arch + "\n"\ - "\t\t\t" + uuids[arch] + "\n" - info_dict = { - "root_name": root_name, - "uuid_dict": uuid_dict, - } - info_contents = info_template % info_dict - info_file = os.path.join(dsym, "Contents", "Info.plist") - info_fd = open(info_file, "w") - info_fd.write(info_contents) - info_fd.close() - - return True - -# For a Mach-O file, determines where the .dSYM bundle should be located. If -# the bundle does not exist or has a modification time older than the Mach-O -# file, calls make_fake_dsym to create a fake .dSYM bundle there, then strips -# the Mach-O file and sets the modification time on the .dSYM bundle and Mach-O -# file to be identical. -def strip_and_make_fake_dsym(macho): - dsym = dsym_path(macho) - macho_stat = os.stat(macho) - dsym_stat = None - try: - dsym_stat = os.stat(dsym) - except OSError, (err, error_string): - if err != errno.ENOENT: - raise - - if dsym_stat is None or dsym_stat.st_mtime < macho_stat.st_mtime: - # Make a .dSYM bundle - if not make_fake_dsym(macho, dsym): - return False - - # Strip the Mach-O file - remove_dsym = True - try: - strip_path = "" - if "SYSTEM_DEVELOPER_BIN_DIR" in os.environ: - strip_path = os.environ["SYSTEM_DEVELOPER_BIN_DIR"] - else: - strip_path = "/usr/bin" - strip_path = os.path.join(strip_path, "strip") - strip_cmdline = [strip_path] + sys.argv[1:] - strip_cmd = subprocess.Popen(strip_cmdline) - if strip_cmd.wait() == 0: - remove_dsym = False - finally: - if remove_dsym: - shutil.rmtree(dsym) - - # Update modification time on the Mach-O file and .dSYM bundle - now = time.time() - os.utime(macho, (now, now)) - os.utime(dsym, (now, now)) - - return True - -def main(argv=None): - if argv is None: - argv = sys.argv - - # This only supports operating on one file at a time. Look at the arguments - # to strip to figure out what the source to be stripped is. Arguments are - # processed in the same way that strip does, although to reduce complexity, - # this doesn't do all of the same checking as strip. For example, strip - # has no -Z switch and would treat -Z on the command line as an error. For - # the purposes this is needed for, that's fine. - macho = None - process_switches = True - ignore_argument = False - for arg in argv[1:]: - if ignore_argument: - ignore_argument = False - continue - if process_switches: - if arg == "-": - process_switches = False - # strip has these switches accept an argument: - if arg in ["-s", "-R", "-d", "-o", "-arch"]: - ignore_argument = True - if arg[0] == "-": - continue - if macho is None: - macho = arg - else: - print >> sys.stderr, "Too many things to strip" - return 1 - - if macho is None: - print >> sys.stderr, "Nothing to strip" - return 1 - - if not strip_and_make_fake_dsym(macho): - return 1 - - return 0 - -if __name__ == "__main__": - sys.exit(main(sys.argv)) diff --git a/build/mac/tweak_info_plist.py b/build/mac/tweak_info_plist.py deleted file mode 100755 index eb38acea4e..0000000000 --- a/build/mac/tweak_info_plist.py +++ /dev/null @@ -1,305 +0,0 @@ -#!/usr/bin/env python - -# Copyright (c) 2012 The Chromium Authors. All rights reserved. -# Use of this source code is governed by a BSD-style license that can be -# found in the LICENSE file. - -# -# Xcode supports build variable substitutions and CPP; sadly, that doesn't work -# because: -# -# 1. Xcode wants to do the Info.plist work before it runs any build phases, -# this means if we were to generate a .h file for INFOPLIST_PREFIX_HEADER -# we'd have to put it in another target so it runs in time. -# 2. Xcode also doesn't check to see if the header being used as a prefix for -# the Info.plist has changed. So even if we updated it, it's only looking -# at the modtime of the info.plist to see if that's changed. -# -# So, we work around all of this by making a script build phase that will run -# during the app build, and simply update the info.plist in place. This way -# by the time the app target is done, the info.plist is correct. -# - -import optparse -import os -from os import environ as env -import plistlib -import re -import subprocess -import sys -import tempfile - -TOP = os.path.join(env['SRCROOT'], '..') - - -def _GetOutput(args): - """Runs a subprocess and waits for termination. Returns (stdout, returncode) - of the process. stderr is attached to the parent.""" - proc = subprocess.Popen(args, stdout=subprocess.PIPE) - (stdout, stderr) = proc.communicate() - return (stdout, proc.returncode) - - -def _GetOutputNoError(args): - """Similar to _GetOutput() but ignores stderr. If there's an error launching - the child (like file not found), the exception will be caught and (None, 1) - will be returned to mimic quiet failure.""" - try: - proc = subprocess.Popen(args, stdout=subprocess.PIPE, - stderr=subprocess.PIPE) - except OSError: - return (None, 1) - (stdout, stderr) = proc.communicate() - return (stdout, proc.returncode) - - -def _RemoveKeys(plist, *keys): - """Removes a varargs of keys from the plist.""" - for key in keys: - try: - del plist[key] - except KeyError: - pass - - -def _AddVersionKeys(plist, version=None): - """Adds the product version number into the plist. Returns True on success and - False on error. The error will be printed to stderr.""" - if version: - match = re.match('\d+\.\d+\.(\d+\.\d+)$', version) - if not match: - print >>sys.stderr, 'Invalid version string specified: "%s"' % version - return False - - full_version = match.group(0) - bundle_version = match.group(1) - - else: - # Pull in the Chrome version number. - VERSION_TOOL = os.path.join(TOP, 'chrome/tools/build/version.py') - VERSION_FILE = os.path.join(TOP, 'chrome/VERSION') - - (stdout, retval1) = _GetOutput([VERSION_TOOL, '-f', VERSION_FILE, '-t', - '@MAJOR@.@MINOR@.@BUILD@.@PATCH@']) - full_version = stdout.rstrip() - - (stdout, retval2) = _GetOutput([VERSION_TOOL, '-f', VERSION_FILE, '-t', - '@BUILD@.@PATCH@']) - bundle_version = stdout.rstrip() - - # If either of the two version commands finished with non-zero returncode, - # report the error up. - if retval1 or retval2: - return False - - # Add public version info so "Get Info" works. - plist['CFBundleShortVersionString'] = full_version - - # Honor the 429496.72.95 limit. The maximum comes from splitting 2^32 - 1 - # into 6, 2, 2 digits. The limitation was present in Tiger, but it could - # have been fixed in later OS release, but hasn't been tested (it's easy - # enough to find out with "lsregister -dump). - # http://lists.apple.com/archives/carbon-dev/2006/Jun/msg00139.html - # BUILD will always be an increasing value, so BUILD_PATH gives us something - # unique that meetings what LS wants. - plist['CFBundleVersion'] = bundle_version - - # Return with no error. - return True - - -def _DoSCMKeys(plist, add_keys): - """Adds the SCM information, visible in about:version, to property list. If - |add_keys| is True, it will insert the keys, otherwise it will remove them.""" - scm_revision = None - if add_keys: - # Pull in the Chrome revision number. - VERSION_TOOL = os.path.join(TOP, 'chrome/tools/build/version.py') - LASTCHANGE_FILE = os.path.join(TOP, 'build/util/LASTCHANGE') - (stdout, retval) = _GetOutput([VERSION_TOOL, '-f', LASTCHANGE_FILE, '-t', - '@LASTCHANGE@']) - if retval: - return False - scm_revision = stdout.rstrip() - - # See if the operation failed. - _RemoveKeys(plist, 'SCMRevision') - if scm_revision != None: - plist['SCMRevision'] = scm_revision - elif add_keys: - print >>sys.stderr, 'Could not determine SCM revision. This may be OK.' - - return True - - -def _DoPDFKeys(plist, add_keys): - """Adds PDF support to the document types list. If add_keys is True, it will - add the type information dictionary. If it is False, it will remove it if - present.""" - - PDF_FILE_EXTENSION = 'pdf' - - def __AddPDFKeys(sub_plist): - """Writes the keys into a sub-dictionary of the plist.""" - sub_plist['CFBundleTypeExtensions'] = [PDF_FILE_EXTENSION] - sub_plist['CFBundleTypeIconFile'] = 'document.icns' - sub_plist['CFBundleTypeMIMETypes'] = 'application/pdf' - sub_plist['CFBundleTypeName'] = 'PDF Document' - sub_plist['CFBundleTypeRole'] = 'Viewer' - - DOCUMENT_TYPES_KEY = 'CFBundleDocumentTypes' - - # First get the list of document types, creating it if necessary. - try: - extensions = plist[DOCUMENT_TYPES_KEY] - except KeyError: - # If this plist doesn't have a type dictionary, create one if set to add the - # keys. If not, bail. - if not add_keys: - return - extensions = plist[DOCUMENT_TYPES_KEY] = [] - - # Loop over each entry in the list, looking for one that handles PDF types. - for i, ext in enumerate(extensions): - # If an entry for .pdf files is found... - if 'CFBundleTypeExtensions' not in ext: - continue - if PDF_FILE_EXTENSION in ext['CFBundleTypeExtensions']: - if add_keys: - # Overwrite the existing keys with new ones. - __AddPDFKeys(ext) - else: - # Otherwise, delete the entry entirely. - del extensions[i] - return - - # No PDF entry exists. If one needs to be added, do so now. - if add_keys: - pdf_entry = {} - __AddPDFKeys(pdf_entry) - extensions.append(pdf_entry) - - -def _AddBreakpadKeys(plist, branding): - """Adds the Breakpad keys. This must be called AFTER _AddVersionKeys() and - also requires the |branding| argument.""" - plist['BreakpadReportInterval'] = '3600' # Deliberately a string. - plist['BreakpadProduct'] = '%s_Mac' % branding - plist['BreakpadProductDisplay'] = branding - plist['BreakpadVersion'] = plist['CFBundleShortVersionString'] - # These are both deliberately strings and not boolean. - plist['BreakpadSendAndExit'] = 'YES' - plist['BreakpadSkipConfirm'] = 'YES' - - -def _RemoveBreakpadKeys(plist): - """Removes any set Breakpad keys.""" - _RemoveKeys(plist, - 'BreakpadURL', - 'BreakpadReportInterval', - 'BreakpadProduct', - 'BreakpadProductDisplay', - 'BreakpadVersion', - 'BreakpadSendAndExit', - 'BreakpadSkipConfirm') - - -def _AddKeystoneKeys(plist, bundle_identifier): - """Adds the Keystone keys. This must be called AFTER _AddVersionKeys() and - also requires the |bundle_identifier| argument (com.example.product).""" - plist['KSVersion'] = plist['CFBundleShortVersionString'] - plist['KSProductID'] = bundle_identifier - plist['KSUpdateURL'] = 'https://tools.google.com/service/update2' - - -def _RemoveKeystoneKeys(plist): - """Removes any set Keystone keys.""" - _RemoveKeys(plist, - 'KSVersion', - 'KSProductID', - 'KSUpdateURL') - - -def Main(argv): - parser = optparse.OptionParser('%prog [options]') - parser.add_option('--breakpad', dest='use_breakpad', action='store', - type='int', default=False, help='Enable Breakpad [1 or 0]') - parser.add_option('--breakpad_uploads', dest='breakpad_uploads', - action='store', type='int', default=False, - help='Enable Breakpad\'s uploading of crash dumps [1 or 0]') - parser.add_option('--keystone', dest='use_keystone', action='store', - type='int', default=False, help='Enable Keystone [1 or 0]') - parser.add_option('--scm', dest='add_scm_info', action='store', type='int', - default=True, help='Add SCM metadata [1 or 0]') - parser.add_option('--pdf', dest='add_pdf_support', action='store', type='int', - default=False, help='Add PDF file handler support [1 or 0]') - parser.add_option('--branding', dest='branding', action='store', - type='string', default=None, help='The branding of the binary') - parser.add_option('--bundle_id', dest='bundle_identifier', - action='store', type='string', default=None, - help='The bundle id of the binary') - parser.add_option('--version', dest='version', action='store', type='string', - default=None, help='The version string [major.minor.build.patch]') - (options, args) = parser.parse_args(argv) - - if len(args) > 0: - print >>sys.stderr, parser.get_usage() - return 1 - - # Read the plist into its parsed format. - DEST_INFO_PLIST = os.path.join(env['TARGET_BUILD_DIR'], env['INFOPLIST_PATH']) - plist = plistlib.readPlist(DEST_INFO_PLIST) - - # Insert the product version. - if not _AddVersionKeys(plist, version=options.version): - return 2 - - # Add Breakpad if configured to do so. - if options.use_breakpad: - if options.branding is None: - print >>sys.stderr, 'Use of Breakpad requires branding.' - return 1 - _AddBreakpadKeys(plist, options.branding) - if options.breakpad_uploads: - plist['BreakpadURL'] = 'https://clients2.google.com/cr/report' - else: - # This allows crash dumping to a file without uploading the - # dump, for testing purposes. Breakpad does not recognise - # "none" as a special value, but this does stop crash dump - # uploading from happening. We need to specify something - # because if "BreakpadURL" is not present, Breakpad will not - # register its crash handler and no crash dumping will occur. - plist['BreakpadURL'] = 'none' - else: - _RemoveBreakpadKeys(plist) - - # Only add Keystone in Release builds. - if options.use_keystone and env['CONFIGURATION'] == 'Release': - if options.bundle_identifier is None: - print >>sys.stderr, 'Use of Keystone requires the bundle id.' - return 1 - _AddKeystoneKeys(plist, options.bundle_identifier) - else: - _RemoveKeystoneKeys(plist) - - # Adds or removes any SCM keys. - if not _DoSCMKeys(plist, options.add_scm_info): - return 3 - - # Adds or removes the PDF file handler entry. - _DoPDFKeys(plist, options.add_pdf_support) - - # Now that all keys have been mutated, rewrite the file. - temp_info_plist = tempfile.NamedTemporaryFile() - plistlib.writePlist(plist, temp_info_plist.name) - - # Info.plist will work perfectly well in any plist format, but traditionally - # applications use xml1 for this, so convert it to ensure that it's valid. - proc = subprocess.Popen(['plutil', '-convert', 'xml1', '-o', DEST_INFO_PLIST, - temp_info_plist.name]) - proc.wait() - return proc.returncode - - -if __name__ == '__main__': - sys.exit(Main(sys.argv[1:])) diff --git a/build/mac/verify_no_objc.sh b/build/mac/verify_no_objc.sh deleted file mode 100755 index 955f9befff..0000000000 --- a/build/mac/verify_no_objc.sh +++ /dev/null @@ -1,43 +0,0 @@ -#!/bin/bash - -# Copyright (c) 2011 The Chromium Authors. All rights reserved. -# Use of this source code is governed by a BSD-style license that can be -# found in the LICENSE file. - -# This script makes sure that no __OBJC,__image_info section appears in the -# executable file built by the Xcode target that runs the script. If such a -# section appears, the script prints an error message and exits nonzero. -# -# Why is this important? -# -# On 10.5, there's a bug in CFBundlePreflightExecutable that causes it to -# crash when operating in an executable that has not loaded at its default -# address (that is, when it's a position-independent executable with the -# MH_PIE bit set in its mach_header) and the executable has an -# __OBJC,__image_info section. See http://crbug.com/88697. -# -# Chrome's main executables don't use any Objective-C at all, and don't need -# to carry this section around. Not linking them as Objective-C when they -# don't need it anyway saves about 4kB in the linked executable, although most -# of that 4kB is just filled with zeroes. -# -# This script makes sure that nobody goofs and accidentally introduces these -# sections into the main executables. - -set -eu - -otool="${DEVELOPER_BIN_DIR:-/usr/bin}/otool" -executable="${BUILT_PRODUCTS_DIR}/${EXECUTABLE_PATH}" - -if "${otool}" -arch i386 -o "${executable}" | grep -q '^Contents.*section$'; \ -then - echo "${0}: ${executable} has an __OBJC,__image_info section" 2>&1 - exit 1 -fi - -if [[ ${PIPESTATUS[0]} -ne 0 ]]; then - echo "${0}: otool failed" 2>&1 - exit 1 -fi - -exit 0 diff --git a/build/nocompile.gypi b/build/nocompile.gypi deleted file mode 100644 index f9021ae379..0000000000 --- a/build/nocompile.gypi +++ /dev/null @@ -1,96 +0,0 @@ -# Copyright (c) 2011 The Chromium Authors. All rights reserved. -# Use of this source code is governed by a BSD-style license that can be -# found in the LICENSE file. - -# This file is meant to be included into an target to create a unittest that -# invokes a set of no-compile tests. A no-compile test is a test that asserts -# a particular construct will not compile. -# -# Also see: -# http://dev.chromium.org/developers/testing/no-compile-tests -# -# To use this, create a gyp target with the following form: -# { -# 'target_name': 'my_module_nc_unittests', -# 'type': 'executable', -# 'sources': [ -# 'nc_testset_1.nc', -# 'nc_testset_2.nc', -# ], -# 'includes': ['path/to/this/gypi/file'], -# } -# -# The .nc files are C++ files that contain code we wish to assert will not -# compile. Each individual test case in the file should be put in its own -# #ifdef section. The expected output should be appended with a C++-style -# comment that has a python list of regular expressions. This will likely -# be greater than 80-characters. Giving a solid expected output test is -# important so that random compile failures do not cause the test to pass. -# -# Example .nc file: -# -# #if defined(TEST_NEEDS_SEMICOLON) // [r"expected ',' or ';' at end of input"] -# -# int a = 1 -# -# #elif defined(TEST_NEEDS_CAST) // [r"invalid conversion from 'void*' to 'char*'"] -# -# void* a = NULL; -# char* b = a; -# -# #endif -# -# If we needed disable TEST_NEEDS_SEMICOLON, then change the define to: -# -# DISABLE_TEST_NEEDS_SEMICOLON -# TEST_NEEDS_CAST -# -# The lines above are parsed by a regexp so avoid getting creative with the -# formatting or ifdef logic; it will likely just not work. -# -# Implementation notes: -# The .nc files are actually processed by a python script which executes the -# compiler and generates a .cc file that is empty on success, or will have a -# series of #error lines on failure, and a set of trivially passing gunit -# TEST() functions on success. This allows us to fail at the compile step when -# something goes wrong, and know during the unittest run that the test was at -# least processed when things go right. - -{ - # TODO(awong): Disabled until http://crbug.com/105388 is resolved. - 'sources/': [['exclude', '\\.nc$']], - 'conditions': [ - [ 'OS=="linux" and clang==0', { - 'rules': [ - { - 'variables': { - 'nocompile_driver': '<(DEPTH)/tools/nocompile_driver.py', - 'nc_result_path': ('<(INTERMEDIATE_DIR)/<(module_dir)/' - '<(RULE_INPUT_ROOT)_nc.cc'), - }, - 'rule_name': 'run_nocompile', - 'extension': 'nc', - 'inputs': [ - '<(nocompile_driver)', - ], - 'outputs': [ - '<(nc_result_path)' - ], - 'action': [ - 'python', - '<(nocompile_driver)', - '4', # number of compilers to invoke in parallel. - '<(RULE_INPUT_PATH)', - '-Wall -Werror -Wfatal-errors -I<(DEPTH)', - '<(nc_result_path)', - ], - 'message': 'Generating no compile results for <(RULE_INPUT_PATH)', - 'process_outputs_as_sources': 1, - }, - ], - }, { - 'sources/': [['exclude', '\\.nc$']] - }], # 'OS=="linux" and clang=="0"' - ], -} - diff --git a/build/output_dll_copy.rules b/build/output_dll_copy.rules deleted file mode 100644 index c6e905131d..0000000000 --- a/build/output_dll_copy.rules +++ /dev/null @@ -1,17 +0,0 @@ - - - - - - - - - diff --git a/build/precompile.cc b/build/precompile.cc deleted file mode 100644 index db1ef6dfe5..0000000000 --- a/build/precompile.cc +++ /dev/null @@ -1,7 +0,0 @@ -// Copyright (c) 2011 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -// Precompiled header generator for Windows builds. No include is needed -// in this file as the PCH include is forced via the "Forced Include File" -// flag in the projects generated by GYP. diff --git a/build/precompile.h b/build/precompile.h deleted file mode 100644 index ab678cab27..0000000000 --- a/build/precompile.h +++ /dev/null @@ -1,110 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -// Precompiled header for Chromium project on Windows, not used by -// other build configurations. Using precompiled headers speeds the -// build up significantly, around 1/4th on VS 2010 on an HP Z600 with 12 -// GB of memory. -// -// Numeric comments beside includes are the number of times they were -// included under src/chrome/browser on 2011/8/20, which was used as a -// baseline for deciding what to include in the PCH. Includes without -// a numeric comment are generally included at least 5 times. It may -// be possible to tweak the speed of the build by commenting out or -// removing some of the less frequently used headers. - -#if defined(BUILD_PRECOMPILE_H_) -#error You shouldn't include the precompiled header file more than once. -#endif - -#define BUILD_PRECOMPILE_H_ - -// The Windows header needs to come before almost all the other -// Windows-specific headers. -#include -#include -#include -#include // 4 -#include // 2 - -// Defines in atlbase.h cause conflicts; if we could figure out how -// this family of headers can be included in the PCH, it might speed -// up the build as several of them are used frequently. -/* -#include -#include -#include -#include // 2 -#include // 2 -#include // 2 -#include // 1 -#include // 1 -#include // 2 -*/ - -// Objbase.h and other files that rely on it bring in [ #define -// interface struct ] which can cause problems in a multi-platform -// build like Chrome's. #undef-ing it does not work as there are -// currently 118 targets that break if we do this, so leaving out of -// the precompiled header for now. -//#include // 2 -//#include // 3 -//#include // 2 -//#include // 2 -//#include // 1 -//#include // 1 -//#include // 2 -//#include // 1 -//#include // 1 -//#include // 2 -//#include // 2 -//#include // 2 -//#include // 1 -//#include // 1 -//#include // 4 -//#include // 2 - -// Caused other conflicts in addition to the 'interface' issue above. -// #include - -#include -#include -#include // 4 -#include -#include // 1 -#include -#include // 1 -#include -#include -#include -#include -#include // 4 - -#include -#include // 3 -#include -#include -#include // 3 -#include // 2 -#include -#include -#include // 3 -#include -#include // 2 -#include // 2 -#include -#include -#include -#include -#include // 2 -#include -#include -#include -#include -#include -#include -#include -#include - -#include "intsafe_workaround.h" diff --git a/build/protoc.gypi b/build/protoc.gypi deleted file mode 100644 index 52fb8a2b60..0000000000 --- a/build/protoc.gypi +++ /dev/null @@ -1,124 +0,0 @@ -# Copyright (c) 2012 The Chromium Authors. All rights reserved. -# Use of this source code is governed by a BSD-style license that can be -# found in the LICENSE file. - -# This file is meant to be included into a target to provide a rule -# to invoke protoc in a consistent manner. For Java-targets, see -# protoc_java.gypi. -# -# To use this, create a gyp target with the following form: -# { -# 'target_name': 'my_proto_lib', -# 'type': 'static_library', -# 'sources': [ -# 'foo.proto', -# 'bar.proto', -# ], -# 'variables': { -# # Optional, see below: 'proto_in_dir': '.' -# 'proto_out_dir': 'dir/for/my_proto_lib' -# }, -# 'includes': ['path/to/this/gypi/file'], -# } -# If necessary, you may add normal .cc files to the sources list or other gyp -# dependencies. The proto headers are guaranteed to be generated before any -# source files, even within this target, are compiled. -# -# The 'proto_in_dir' variable must be the relative path to the -# directory containing the .proto files. If left out, it defaults to '.'. -# -# The 'proto_out_dir' variable specifies the path suffix that output -# files are generated under. Targets that gyp-depend on my_proto_lib -# will be able to include the resulting proto headers with an include -# like: -# #include "dir/for/my_proto_lib/foo.pb.h" -# -# If you need to add an EXPORT macro to a protobuf's c++ header, set the -# 'cc_generator_options' variable with the value: 'dllexport_decl=FOO_EXPORT:' -# e.g. 'dllexport_decl=BASE_EXPORT:' -# -# It is likely you also need to #include a file for the above EXPORT macro to -# work. You can do so with the 'cc_include' variable. -# e.g. 'base/base_export.h' -# -# Implementation notes: -# A proto_out_dir of foo/bar produces -# <(SHARED_INTERMEDIATE_DIR)/protoc_out/foo/bar/{file1,file2}.pb.{cc,h} -# <(SHARED_INTERMEDIATE_DIR)/pyproto/foo/bar/{file1,file2}_pb2.py - -{ - 'variables': { - 'protoc_wrapper': '<(DEPTH)/tools/protoc_wrapper/protoc_wrapper.py', - 'cc_dir': '<(SHARED_INTERMEDIATE_DIR)/protoc_out/<(proto_out_dir)', - 'py_dir': '<(PRODUCT_DIR)/pyproto/<(proto_out_dir)', - 'cc_generator_options%': '', - 'cc_include%': '', - 'proto_in_dir%': '.', - 'conditions': [ - ['use_system_protobuf==0', { - 'protoc': '<(PRODUCT_DIR)/<(EXECUTABLE_PREFIX)protoc<(EXECUTABLE_SUFFIX)', - }, { # use_system_protobuf==1 - 'protoc': '(java_out_dir), since that -# is the root directory of all the output. -# -# Implementation notes: -# A target_name of foo and proto-specified 'package' java.package.path produces: -# <(PRODUCT_DIR)/java_proto/foo/{java/package/path/}{Foo,Bar}.java -# where Foo and Bar are taken from 'java_outer_classname' of the protos. -# -# How the .jar-file is created is different than how protoc is used for other -# targets, and as such, this lives in its own file. - -{ - 'variables': { - 'protoc': '<(PRODUCT_DIR)/<(EXECUTABLE_PREFIX)protoc<(EXECUTABLE_SUFFIX)', - 'java_out_dir': '<(PRODUCT_DIR)/java_proto/<(_target_name)/src', - 'proto_in_dir%': '.', - 'stamp_file': '<(java_out_dir).stamp', - 'script': '<(DEPTH)/build/protoc_java.py', - - # The rest of the variables here are for the java.gypi include. - 'java_in_dir': '<(DEPTH)/build/android/empty', - 'generated_src_dirs': ['<(java_out_dir)'], - # Adding the |stamp_file| to |additional_input_paths| makes the actions in - # the include of java.gypi depend on the genproto_java action. - 'additional_input_paths': ['<(stamp_file)'], - }, - 'actions': [ - { - 'action_name': 'genproto_java', - 'inputs': [ - '<(script)', - '<(protoc)', - '<@(_sources)', - ], - # We do not know the names of the generated files, so we use a stamp. - 'outputs': [ - '<(stamp_file)', - ], - 'action': [ - '<(script)', - '<(protoc)', - '<(proto_in_dir)', - '<(java_out_dir)', - '<(stamp_file)', - '<@(_sources)', - ], - 'message': 'Generating Java code from <(proto_in_dir)', - }, - ], - 'dependencies': [ - '<(DEPTH)/third_party/protobuf/protobuf.gyp:protoc#host', - '<(DEPTH)/third_party/protobuf/protobuf.gyp:protobuf_lite_javalib', - ], - 'includes': [ 'java.gypi' ], -} diff --git a/build/protoc_java.py b/build/protoc_java.py deleted file mode 100755 index 42e204464a..0000000000 --- a/build/protoc_java.py +++ /dev/null @@ -1,56 +0,0 @@ -#!/usr/bin/env python -# Copyright (c) 2012 The Chromium Authors. All rights reserved. -# Use of this source code is governed by a BSD-style license that can be -# found in the LICENSE file. - -"""Generate java source files from protobufs - -Usage: - protoc_java.py {protoc} {proto_path} {java_out} {stamp_file} {proto_files} - -This is a helper file for the genproto_java action in protoc_java.gypi. - -It performs the following steps: -1. Deletes all old sources (ensures deleted classes are not part of new jars). -2. Creates source directory. -3. Generates Java files using protoc. -4. Creates a new stamp file. -""" - -import os -import shutil -import subprocess -import sys - -def main(argv): - if len(argv) < 5: - usage() - return 1 - - protoc_path, proto_path, java_out, stamp_file = argv[1:5] - proto_files = argv[5:] - - # Delete all old sources - if os.path.exists(java_out): - shutil.rmtree(java_out) - - # Create source directory - os.makedirs(java_out) - - # Generate Java files using protoc - ret = subprocess.call( - [protoc_path, '--proto_path', proto_path, '--java_out', java_out] - + proto_files) - - if ret == 0: - # Create a new stamp file - with file(stamp_file, 'a'): - os.utime(stamp_file, None) - - return ret - -def usage(): - print(__doc__); - -if __name__ == '__main__': - sys.exit(main(sys.argv)) diff --git a/build/release.gypi b/build/release.gypi deleted file mode 100644 index 7595ef5a29..0000000000 --- a/build/release.gypi +++ /dev/null @@ -1,17 +0,0 @@ -{ - 'conditions': [ - # Handle build types. - ['buildtype=="Dev"', { - 'includes': ['internal/release_impl.gypi'], - }], - ['buildtype=="Official"', { - 'includes': ['internal/release_impl_official.gypi'], - }], - # TODO(bradnelson): may also need: - # checksenabled - # coverage - # dom_stats - # pgo_instrument - # pgo_optimize - ], -} diff --git a/build/sanitize-mac-build-log.sed b/build/sanitize-mac-build-log.sed deleted file mode 100755 index 3312eac5a8..0000000000 --- a/build/sanitize-mac-build-log.sed +++ /dev/null @@ -1,35 +0,0 @@ -#!/bin/echo Use sanitize-mac-build-log.sh or sed -f - -# Copyright (c) 2012 The Chromium Authors. All rights reserved. -# Use of this source code is governed by a BSD-style license that can be -# found in the LICENSE file. - -# Use this sed script to reduce a Mac build log into something readable. - -# Drop uninformative lines. -/^distcc/d -/^Check dependencies/d -/^ setenv /d -/^ cd /d -/^make: Nothing to be done/d -/^$/d - -# Xcode prints a short "compiling foobar.o" line followed by the lengthy -# full command line. These deletions drop the command line. -\|^ /Developer/usr/bin/|d -\|^ /Developer/Library/PrivateFrameworks/DevToolsCore.framework/|d -\|^ /Developer/Library/Xcode/Plug-ins/CoreBuildTasks.xcplugin/|d - -# Drop any goma command lines as well. -\|^ .*/gomacc |d - -# And, if you've overridden something from your own bin directory, remove those -# full command lines, too. -\|^ /Users/[^/]*/bin/|d - -# There's already a nice note for bindings, don't need the command line. -\|^python scripts/rule_binding.py|d - -# Shorten the "compiling foobar.o" line. -s|^Distributed-CompileC \(.*\) normal i386 c++ com.apple.compilers.gcc.4_2| CC \1| -s|^CompileC \(.*\) normal i386 c++ com.apple.compilers.gcc.4_2| CC \1| diff --git a/build/sanitize-mac-build-log.sh b/build/sanitize-mac-build-log.sh deleted file mode 100755 index dc743fabb5..0000000000 --- a/build/sanitize-mac-build-log.sh +++ /dev/null @@ -1,6 +0,0 @@ -#!/bin/sh -# Copyright (c) 2010 The Chromium Authors. All rights reserved. -# Use of this source code is governed by a BSD-style license that can be -# found in the LICENSE file. -sed -f `dirname "${0}"`/`basename "${0}" sh`sed - diff --git a/build/sanitize-png-files.sh b/build/sanitize-png-files.sh deleted file mode 100755 index e47508e470..0000000000 --- a/build/sanitize-png-files.sh +++ /dev/null @@ -1,445 +0,0 @@ -#!/bin/bash -# Copyright (c) 2010 The Chromium Authors. All rights reserved. -# Use of this source code is governed by a BSD-style license that can be -# found in the LICENSE file. - -# The optimization code is based on pngslim (http://goo.gl/a0XHg) -# and executes a similar pipleline to optimize the png file size. -# The steps that require pngoptimizercl/pngrewrite/deflopt are omitted, -# but this runs all other processes, including: -# 1) various color-dependent optimizations using optipng. -# 2) optimize the number of huffman blocks. -# 3) randomize the huffman table. -# 4) Further optimize using optipng and advdef (zlib stream). -# Due to the step 3), each run may produce slightly different results. -# -# Note(oshima): In my experiment, advdef didn't reduce much. I'm keeping it -# for now as it does not take much time to run. - -readonly ALL_DIRS=" -ash/resources -ui/resources -chrome/app/theme -chrome/browser/resources -chrome/renderer/resources -webkit/glue/resources -remoting/resources -remoting/webapp -" - -# Files larger than this file size (in bytes) will -# use the optimization parameters tailored for large files. -LARGE_FILE_THRESHOLD=3000 - -# Constants used for optimization -readonly DEFAULT_MIN_BLOCK_SIZE=128 -readonly DEFAULT_LIMIT_BLOCKS=256 -readonly DEFAULT_RANDOM_TRIALS=100 -# Taken from the recommendation in the pngslim's readme.txt. -readonly LARGE_MIN_BLOCK_SIZE=1 -readonly LARGE_LIMIT_BLOCKS=2 -readonly LARGE_RANDOM_TRIALS=1 - -# Global variables for stats -TOTAL_OLD_BYTES=0 -TOTAL_NEW_BYTES=0 -TOTAL_FILE=0 -PROCESSED_FILE=0 - -declare -a THROBBER_STR=('-' '\\' '|' '/') -THROBBER_COUNT=0 - -# Show throbber character at current cursor position. -function throbber { - echo -ne "${THROBBER_STR[$THROBBER_COUNT]}\b" - let THROBBER_COUNT=($THROBBER_COUNT+1)%4 -} - -# Usage: pngout_loop ... -# Optimize the png file using pngout with the given options -# using various block split thresholds and filter types. -function pngout_loop { - local file=$1 - shift - local opts=$* - if [ $OPTIMIZE_LEVEL == 1 ]; then - for j in $(seq 0 5); do - throbber - pngout -q -k1 -s1 -f$j $opts $file - done - else - for i in 0 128 256 512; do - for j in $(seq 0 5); do - throbber - pngout -q -k1 -s1 -b$i -f$j $opts $file - done - done - fi -} - -# Usage: get_color_depth_list -# Returns the list of color depth options for current optimization level. -function get_color_depth_list { - if [ $OPTIMIZE_LEVEL == 1 ]; then - echo "-d0" - else - echo "-d1 -d2 -d4 -d8" - fi -} - -# Usage: process_grayscale -# Optimize grayscale images for all color bit depths. -# -# TODO(oshima): Experiment with -d0 w/o -c0. -function process_grayscale { - echo -n "|gray" - for opt in $(get_color_depth_list); do - pngout_loop $file -c0 $opt - done -} - -# Usage: process_grayscale_alpha -# Optimize grayscale images with alpha for all color bit depths. -function process_grayscale_alpha { - echo -n "|gray-a" - pngout_loop $file -c4 - for opt in $(get_color_depth_list); do - pngout_loop $file -c3 $opt - done -} - -# Usage: process_rgb -# Optimize rgb images with or without alpha for all color bit depths. -function process_rgb { - echo -n "|rgb" - for opt in $(get_color_depth_list); do - pngout_loop $file -c3 $opt - done - pngout_loop $file -c2 - pngout_loop $file -c6 -} - -# Usage: huffman_blocks -# Optimize the huffman blocks. -function huffman_blocks { - local file=$1 - echo -n "|huffman" - local size=$(stat -c%s $file) - local min_block_size=$DEFAULT_MIN_BLOCK_SIZE - local limit_blocks=$DEFAULT_LIMIT_BLOCKS - - if [ $size -gt $LARGE_FILE_THRESHOLD ]; then - min_block_size=$LARGE_MIN_BLOCK_SIZE - limit_blocks=$LARGE_LIMIT_BLOCKS - fi - let max_blocks=$size/$min_block_size - if [ $max_blocks -gt $limit_blocks ]; then - max_blocks=$limit_blocks - fi - - for i in $(seq 2 $max_blocks); do - throbber - pngout -q -k1 -ks -s1 -n$i $file - done -} - -# Usage: random_huffman_table_trial -# Try compressing by randomizing the initial huffman table. -# -# TODO(oshima): Try adjusting different parameters for large files to -# reduce runtime. -function random_huffman_table_trial { - echo -n "|random" - local file=$1 - local old_size=$(stat -c%s $file) - local trials_count=$DEFAULT_RANDOM_TRIALS - - if [ $old_size -gt $LARGE_FILE_THRESHOLD ]; then - trials_count=$LARGE_RANDOM_TRIALS - fi - for i in $(seq 1 $trials_count); do - throbber - pngout -q -k1 -ks -s0 -r $file - done - local new_size=$(stat -c%s $file) - if [ $new_size -lt $old_size ]; then - random_huffman_table_trial $file - fi -} - -# Usage: final_comprssion -# Further compress using optipng and advdef. -# TODO(oshima): Experiment with 256. -function final_compression { - echo -n "|final" - local file=$1 - if [ $OPTIMIZE_LEVEL == 2 ]; then - for i in 32k 16k 8k 4k 2k 1k 512; do - throbber - optipng -q -nb -nc -zw$i -zc1-9 -zm1-9 -zs0-3 -f0-5 $file - done - fi - for i in $(seq 1 4); do - throbber - advdef -q -z -$i $file - done - echo -ne "\r" -} - -# Usage: get_color_type -# Returns the color type name of the png file. Here is the list of names -# for each color type codes. -# 0 : grayscale -# 2 : RGB -# 3 : colormap -# 4 : gray+alpha -# 6 : RGBA -# See http://en.wikipedia.org/wiki/Portable_Network_Graphics#Color_depth -# for details about the color type code. -function get_color_type { - local file=$1 - echo $(file $file | awk -F, '{print $3}' | awk '{print $2}') -} - -# Usage: optimize_size -# Performs png file optimization. -function optimize_size { - tput el - local file=$1 - echo -n "$file " - - advdef -q -z -4 $file - - pngout -q -s4 -c0 -force $file $file.tmp.png - if [ -f $file.tmp.png ]; then - rm $file.tmp.png - process_grayscale $file - process_grayscale_alpha $file - else - pngout -q -s4 -c4 -force $file $file.tmp.png - if [ -f $file.tmp.png ]; then - rm $file.tmp.png - process_grayscale_alpha $file - else - process_rgb $file - fi - fi - - echo -n "|filter" - local old_color_type=$(get_color_type $file) - optipng -q -zc9 -zm8 -zs0-3 -f0-5 $file -out $file.tmp.png - local new_color_type=$(get_color_type $file.tmp.png) - # optipng may corrupt a png file when reducing the color type - # to grayscale/grayscale+alpha. Just skip such cases until - # the bug is fixed. See crbug.com/174505, crbug.com/174084. - # The issue is reported in - # https://sourceforge.net/tracker/?func=detail&aid=3603630&group_id=151404&atid=780913 - if [[ $old_color_type == "RGBA" && $new_color_type =~ gray.* ]] ; then - rm $file.tmp.png - echo -n "[skip opting]" - else - mv $file.tmp.png $file - fi - pngout -q -k1 -s1 $file - - huffman_blocks $file - - # TODO(oshima): Experiment with strategy 1. - echo -n "|strategy" - if [ $OPTIMIZE_LEVEL == 2 ]; then - for i in 3 2 0; do - pngout -q -k1 -ks -s$i $file - done - else - pngout -q -k1 -ks -s1 $file - fi - - if [ $OPTIMIZE_LEVEL == 2 ]; then - random_huffman_table_trial $file - fi - - final_compression $file -} - -# Usage: process_file -function process_file { - local file=$1 - local name=$(basename $file) - # -rem alla removes all ancillary chunks except for tRNS - pngcrush -d $TMP_DIR -brute -reduce -rem alla $file > /dev/null - - if [ $OPTIMIZE_LEVEL != 0 ]; then - optimize_size $TMP_DIR/$name - fi -} - -# Usage: sanitize_file -function sanitize_file { - local file=$1 - local name=$(basename $file) - local old=$(stat -c%s $file) - local tmp_file=$TMP_DIR/$name - - process_file $file - - local new=$(stat -c%s $tmp_file) - let diff=$old-$new - let percent=($diff*100)/$old - let TOTAL_FILE+=1 - - tput el - if [ $new -lt $old ]; then - echo -ne "$file : $old => $new ($diff bytes : $percent %)\n" - mv "$tmp_file" "$file" - let TOTAL_OLD_BYTES+=$old - let TOTAL_NEW_BYTES+=$new - let PROCESSED_FILE+=1 - else - if [ $OPTIMIZE_LEVEL == 0 ]; then - echo -ne "$file : skipped\r" - fi - rm $tmp_file - fi -} - -function sanitize_dir { - local dir=$1 - for f in $(find $dir -name "*.png"); do - if $using_cygwin ; then - sanitize_file $(cygpath -w $f) - else - sanitize_file $f - fi - done -} - -function install_if_not_installed { - local program=$1 - local package=$2 - which $program > /dev/null 2>&1 - if [ "$?" != "0" ]; then - if $using_cygwin ; then - echo "Couldn't find $program. Please run setup.exe and install the $package package." - exit 1 - else - read -p "Couldn't find $program. Do you want to install? (y/n)" - [ "$REPLY" == "y" ] && sudo apt-get install $package - [ "$REPLY" == "y" ] || exit - fi - fi -} - -function fail_if_not_installed { - local program=$1 - local url=$2 - which $program > /dev/null 2>&1 - if [ $? != 0 ]; then - echo "Couldn't find $program. Please download and install it from $url ." - exit 1 - fi -} - -function show_help { - local program=$(basename $0) - echo \ -"Usage: $program [options] dir ... - -$program is a utility to reduce the size of png files by removing -unnecessary chunks and compressing the image. - -Options: - -o Specify optimization level: (default is 1) - 0 Just run pngcrush. It removes unnecessary chunks and perform basic - optimization on the encoded data. - 1 Optimize png files using pngout/optipng and advdef. This can further - reduce addtional 5~30%. This is the default level. - 2 Aggressively optimize the size of png files. This may produce - addtional 1%~5% reduction. Warning: this is *VERY* - slow and can take hours to process all files. - -h Print this help text." - exit 1 -} - -if [ ! -e ../.gclient ]; then - echo "$0 must be run in src directory" - exit 1 -fi - -if [ "$(expr substr $(uname -s) 1 6)" == "CYGWIN" ]; then - using_cygwin=true -else - using_cygwin=false -fi - -OPTIMIZE_LEVEL=1 -# Parse options -while getopts o:h opts -do - case $opts in - o) - if [[ ! "$OPTARG" =~ [012] ]]; then - show_help - fi - OPTIMIZE_LEVEL=$OPTARG - [ "$1" == "-o" ] && shift - shift;; - [h?]) - show_help;; - esac -done - -# Make sure we have all necessary commands installed. -install_if_not_installed pngcrush pngcrush -if [ $OPTIMIZE_LEVEL == 2 ]; then - install_if_not_installed optipng optipng - - if $using_cygwin ; then - fail_if_not_installed advdef "http://advancemame.sourceforge.net/comp-readme.html" - else - install_if_not_installed advdef advancecomp - fi - - if $using_cygwin ; then - pngout_url="http://www.advsys.net/ken/utils.htm" - else - pngout_url="http://www.jonof.id.au/kenutils" - fi - fail_if_not_installed pngout $pngout_url -fi - -# Create tmp directory for crushed png file. -TMP_DIR=$(mktemp -d) -if $using_cygwin ; then - TMP_DIR=$(cygpath -w $TMP_DIR) -fi - -# Make sure we cleanup temp dir -trap "rm -rf $TMP_DIR" EXIT - -# If no directories are specified, sanitize all directories. -DIRS=$@ -set ${DIRS:=$ALL_DIRS} - -echo "Optimize level=$OPTIMIZE_LEVEL" -for d in $DIRS; do - if $using_cygwin ; then - d=$(cygpath -w $d) - fi - echo "Sanitizing png files in $d" - sanitize_dir $d - echo -done - -# Print the results. -if [ $PROCESSED_FILE == 0 ]; then - echo "Did not find any files (out of $TOTAL_FILE files)" \ - "that could be optimized" \ - "in $(date -u -d @$SECONDS +%T)s" -else - let diff=$TOTAL_OLD_BYTES-$TOTAL_NEW_BYTES - let percent=$diff*100/$TOTAL_OLD_BYTES - echo "Processed $PROCESSED_FILE files (out of $TOTAL_FILE files)" \ - "in $(date -u -d @$SECONDS +%T)s" - echo "Result : $TOTAL_OLD_BYTES => $TOTAL_NEW_BYTES bytes" \ - "($diff bytes : $percent %)" -fi diff --git a/build/sanitize-win-build-log.sed b/build/sanitize-win-build-log.sed deleted file mode 100755 index ce5165422d..0000000000 --- a/build/sanitize-win-build-log.sed +++ /dev/null @@ -1,18 +0,0 @@ -#!/bin/echo Use sanitize-win-build-log.sh or sed -f - -# Copyright (c) 2012 The Chromium Authors. All rights reserved. -# Use of this source code is governed by a BSD-style license that can be -# found in the LICENSE file. - -# Use this sed script to reduce a Windows build log into something -# machine-parsable. - -# Drop uninformative lines. -/The operation completed successfully\./d - -# Drop parallelization indicators on lines. -s/^[0-9]\+>// - -# Shorten bindings generation lines -s/^.*"\(perl\|[^"]\+perl\.exe\)".*deprecated_generate_bindings\.pl".*\("[^"]\+\.idl"\).*$/ deprecated_generate_bindings \2/ -s/^.*"python".*idl_compiler\.py".*\("[^"]\+\.idl"\).*$/ idl_compiler \1/ diff --git a/build/sanitize-win-build-log.sh b/build/sanitize-win-build-log.sh deleted file mode 100755 index dc743fabb5..0000000000 --- a/build/sanitize-win-build-log.sh +++ /dev/null @@ -1,6 +0,0 @@ -#!/bin/sh -# Copyright (c) 2010 The Chromium Authors. All rights reserved. -# Use of this source code is governed by a BSD-style license that can be -# found in the LICENSE file. -sed -f `dirname "${0}"`/`basename "${0}" sh`sed - diff --git a/build/shim_headers.gypi b/build/shim_headers.gypi deleted file mode 100644 index 4291468de1..0000000000 --- a/build/shim_headers.gypi +++ /dev/null @@ -1,53 +0,0 @@ -# Copyright (c) 2012 The Chromium Authors. All rights reserved. -# Use of this source code is governed by a BSD-style license that can be -# found in the LICENSE file. - -# This file is meant to be included into a target to handle shim headers -# in a consistent manner. To use this the following variables need to be -# defined: -# headers_root_path: string: path to directory containing headers -# header_filenames: list: list of header file names - -{ - 'variables': { - 'shim_headers_path': '<(SHARED_INTERMEDIATE_DIR)/shim_headers/<(_target_name)/<(_toolset)', - 'shim_generator_additional_args%': [], - }, - 'include_dirs++': [ - '<(shim_headers_path)', - ], - 'all_dependent_settings': { - 'include_dirs+++': [ - '<(shim_headers_path)', - ], - 'include_dirs++++': [ - '<(shim_headers_path)', - ], - }, - 'actions': [ - { - 'variables': { - 'generator_path': '<(DEPTH)/tools/generate_shim_headers/generate_shim_headers.py', - 'generator_args': [ - '--headers-root', '<(headers_root_path)', - '--output-directory', '<(shim_headers_path)', - '<@(shim_generator_additional_args)', - '<@(header_filenames)', - ], - }, - 'action_name': 'generate_<(_target_name)_shim_headers', - 'inputs': [ - '<(generator_path)', - ], - 'outputs': [ - '@(library_dexed_jars_paths)', - ], - 'outputs': [ - '<(output_dex_path)', - ], - 'action': [ - 'python', '<(DEPTH)/build/android/gyp/dex.py', - '--dex-path=<(output_dex_path)', - '--android-sdk-tools=<(android_sdk_tools)', - - # TODO(newt): remove this once http://crbug.com/177552 is fixed in ninja. - '--ignore=>!(echo \'>(_inputs)\' | md5sum)', - - '>@(library_dexed_jars_paths)', - ], - }, - ], -} diff --git a/build/update-linux-sandbox.sh b/build/update-linux-sandbox.sh deleted file mode 100755 index ebf8c105a5..0000000000 --- a/build/update-linux-sandbox.sh +++ /dev/null @@ -1,75 +0,0 @@ -#!/bin/sh - -# Copyright (c) 2012 The Chromium Authors. All rights reserved. -# Use of this source code is governed by a BSD-style license that can be -# found in the LICENSE file. - -BUILDTYPE="${BUILDTYPE:-Debug}" -CHROME_SRC_DIR="${CHROME_SRC_DIR:-$(dirname -- $(readlink -fn -- "$0"))/..}" -CHROME_OUT_DIR="${CHROME_SRC_DIR}/out/${BUILDTYPE}" -CHROME_SANDBOX_BUILD_PATH="${CHROME_OUT_DIR}/chrome_sandbox" -CHROME_SANDBOX_INST_PATH="/usr/local/sbin/chrome-devel-sandbox" -CHROME_SANDBOX_INST_DIR=$(dirname -- "$CHROME_SANDBOX_INST_PATH") - -TARGET_DIR_TYPE=$(stat -f -c %t -- "${CHROME_SANDBOX_INST_DIR}" 2>/dev/null) -if [ $? -ne 0 ]; then - echo "Could not get status of ${CHROME_SANDBOX_INST_DIR}" - exit 1 -fi - -# Make sure the path is not on NFS. -if [ "${TARGET_DIR_TYPE}" = "6969" ]; then - echo "Please make sure ${CHROME_SANDBOX_INST_PATH} is not on NFS!" - exit 1 -fi - -installsandbox() { - echo "(using sudo so you may be asked for your password)" - sudo -- cp "${CHROME_SANDBOX_BUILD_PATH}" \ - "${CHROME_SANDBOX_INST_PATH}" && - sudo -- chown root:root "${CHROME_SANDBOX_INST_PATH}" && - sudo -- chmod 4755 "${CHROME_SANDBOX_INST_PATH}" - return $? -} - -if [ ! -d "${CHROME_OUT_DIR}" ]; then - echo -n "${CHROME_OUT_DIR} does not exist. Use \"BUILDTYPE=Release ${0}\" " - echo "If you are building in Release mode" - exit 1 -fi - -if [ ! -f "${CHROME_SANDBOX_BUILD_PATH}" ]; then - echo -n "Could not find ${CHROME_SANDBOX_BUILD_PATH}, " - echo "please make sure you build the chrome_sandbox target" - exit 1 -fi - -if [ ! -f "${CHROME_SANDBOX_INST_PATH}" ]; then - echo -n "Could not find ${CHROME_SANDBOX_INST_PATH}, " - echo "installing it now." - installsandbox -fi - -if [ ! -f "${CHROME_SANDBOX_INST_PATH}" ]; then - echo "Failed to install ${CHROME_SANDBOX_INST_PATH}" - exit 1 -fi - -CURRENT_API=$("${CHROME_SANDBOX_BUILD_PATH}" --get-api) -INSTALLED_API=$("${CHROME_SANDBOX_INST_PATH}" --get-api) - -if [ "${CURRENT_API}" != "${INSTALLED_API}" ]; then - echo "Your installed setuid sandbox is too old, installing it now." - if ! installsandbox; then - echo "Failed to install ${CHROME_SANDBOX_INST_PATH}" - exit 1 - fi -else - echo "Your setuid sandbox is up to date" - if [ "${CHROME_DEVEL_SANDBOX}" != "${CHROME_SANDBOX_INST_PATH}" ]; then - echo -n "Make sure you have \"export " - echo -n "CHROME_DEVEL_SANDBOX=${CHROME_SANDBOX_INST_PATH}\" " - echo "somewhere in your .bashrc" - echo "This variable is currently: ${CHROME_DEVEL_SANDBOX:-empty}" - fi -fi diff --git a/build/util/LASTCHANGE b/build/util/LASTCHANGE deleted file mode 100644 index 3442f10ff2..0000000000 --- a/build/util/LASTCHANGE +++ /dev/null @@ -1 +0,0 @@ -LASTCHANGE=217677 diff --git a/build/util/LASTCHANGE.blink b/build/util/LASTCHANGE.blink deleted file mode 100644 index dbf0c3a783..0000000000 --- a/build/util/LASTCHANGE.blink +++ /dev/null @@ -1 +0,0 @@ -LASTCHANGE=156106 diff --git a/build/util/lastchange.py b/build/util/lastchange.py deleted file mode 100755 index 3c1ce28e28..0000000000 --- a/build/util/lastchange.py +++ /dev/null @@ -1,236 +0,0 @@ -#!/usr/bin/env python -# Copyright (c) 2012 The Chromium Authors. All rights reserved. -# Use of this source code is governed by a BSD-style license that can be -# found in the LICENSE file. - -""" -lastchange.py -- Chromium revision fetching utility. -""" - -import re -import optparse -import os -import subprocess -import sys - -_GIT_SVN_ID_REGEX = re.compile(r'.*git-svn-id:\s*([^@]*)@([0-9]+)', re.DOTALL) - -class VersionInfo(object): - def __init__(self, url, revision): - self.url = url - self.revision = revision - - -def FetchSVNRevision(directory, svn_url_regex): - """ - Fetch the Subversion branch and revision for a given directory. - - Errors are swallowed. - - Returns: - A VersionInfo object or None on error. - """ - try: - proc = subprocess.Popen(['svn', 'info'], - stdout=subprocess.PIPE, - stderr=subprocess.PIPE, - cwd=directory, - shell=(sys.platform=='win32')) - except OSError: - # command is apparently either not installed or not executable. - return None - if not proc: - return None - - attrs = {} - for line in proc.stdout: - line = line.strip() - if not line: - continue - key, val = line.split(': ', 1) - attrs[key] = val - - try: - match = svn_url_regex.search(attrs['URL']) - if match: - url = match.group(2) - else: - url = '' - revision = attrs['Revision'] - except KeyError: - return None - - return VersionInfo(url, revision) - - -def RunGitCommand(directory, command): - """ - Launches git subcommand. - - Errors are swallowed. - - Returns: - A process object or None. - """ - command = ['git'] + command - # Force shell usage under cygwin. This is a workaround for - # mysterious loss of cwd while invoking cygwin's git. - # We can't just pass shell=True to Popen, as under win32 this will - # cause CMD to be used, while we explicitly want a cygwin shell. - if sys.platform == 'cygwin': - command = ['sh', '-c', ' '.join(command)] - try: - proc = subprocess.Popen(command, - stdout=subprocess.PIPE, - stderr=subprocess.PIPE, - cwd=directory, - shell=(sys.platform=='win32')) - return proc - except OSError: - return None - - -def FetchGitRevision(directory): - """ - Fetch the Git hash for a given directory. - - Errors are swallowed. - - Returns: - A VersionInfo object or None on error. - """ - proc = RunGitCommand(directory, ['rev-parse', 'HEAD']) - if proc: - output = proc.communicate()[0].strip() - if proc.returncode == 0 and output: - return VersionInfo('git', output[:7]) - return None - - -def FetchGitSVNURLAndRevision(directory, svn_url_regex): - """ - Fetch the Subversion URL and revision through Git. - - Errors are swallowed. - - Returns: - A tuple containing the Subversion URL and revision. - """ - proc = RunGitCommand(directory, ['log', '-1', - '--grep=git-svn-id', '--format=%b']) - if proc: - output = proc.communicate()[0].strip() - if proc.returncode == 0 and output: - # Extract the latest SVN revision and the SVN URL. - # The target line is the last "git-svn-id: ..." line like this: - # git-svn-id: svn://svn.chromium.org/chrome/trunk/src@85528 0039d316.... - match = _GIT_SVN_ID_REGEX.search(output) - if match: - revision = match.group(2) - url_match = svn_url_regex.search(match.group(1)) - if url_match: - url = url_match.group(2) - else: - url = '' - return url, revision - return None, None - - -def FetchGitSVNRevision(directory, svn_url_regex): - """ - Fetch the Git-SVN identifier for the local tree. - - Errors are swallowed. - """ - url, revision = FetchGitSVNURLAndRevision(directory, svn_url_regex) - if url and revision: - return VersionInfo(url, revision) - return None - - -def FetchVersionInfo(default_lastchange, directory=None, - directory_regex_prior_to_src_url='chrome|blink|svn'): - """ - Returns the last change (in the form of a branch, revision tuple), - from some appropriate revision control system. - """ - svn_url_regex = re.compile( - r'.*/(' + directory_regex_prior_to_src_url + r')(/.*)') - - version_info = (FetchSVNRevision(directory, svn_url_regex) or - FetchGitSVNRevision(directory, svn_url_regex) or - FetchGitRevision(directory)) - if not version_info: - if default_lastchange and os.path.exists(default_lastchange): - revision = open(default_lastchange, 'r').read().strip() - version_info = VersionInfo(None, revision) - else: - version_info = VersionInfo(None, None) - return version_info - - -def WriteIfChanged(file_name, contents): - """ - Writes the specified contents to the specified file_name - iff the contents are different than the current contents. - """ - try: - old_contents = open(file_name, 'r').read() - except EnvironmentError: - pass - else: - if contents == old_contents: - return - os.unlink(file_name) - open(file_name, 'w').write(contents) - - -def main(argv=None): - if argv is None: - argv = sys.argv - - parser = optparse.OptionParser(usage="lastchange.py [options]") - parser.add_option("-d", "--default-lastchange", metavar="FILE", - help="default last change input FILE") - parser.add_option("-o", "--output", metavar="FILE", - help="write last change to FILE") - parser.add_option("--revision-only", action='store_true', - help="just print the SVN revision number") - parser.add_option("-s", "--source-dir", metavar="DIR", - help="use repository in the given directory") - opts, args = parser.parse_args(argv[1:]) - - out_file = opts.output - - while len(args) and out_file is None: - if out_file is None: - out_file = args.pop(0) - if args: - sys.stderr.write('Unexpected arguments: %r\n\n' % args) - parser.print_help() - sys.exit(2) - - if opts.source_dir: - src_dir = opts.source_dir - else: - src_dir = os.path.dirname(os.path.abspath(__file__)) - - version_info = FetchVersionInfo(opts.default_lastchange, src_dir) - - if version_info.revision == None: - version_info.revision = '0' - - if opts.revision_only: - print version_info.revision - else: - contents = "LASTCHANGE=%s\n" % version_info.revision - if out_file: - WriteIfChanged(out_file, contents) - else: - sys.stdout.write(contents) - - return 0 - - -if __name__ == '__main__': - sys.exit(main()) diff --git a/build/util/lib/common/__init__.py b/build/util/lib/common/__init__.py deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/build/util/lib/common/unittest_util.py b/build/util/lib/common/unittest_util.py deleted file mode 100644 index e586224aac..0000000000 --- a/build/util/lib/common/unittest_util.py +++ /dev/null @@ -1,151 +0,0 @@ -# Copyright 2013 The Chromium Authors. All rights reserved. -# Use of this source code is governed by a BSD-style license that can be -# found in the LICENSE file. - -"""Utilities for dealing with the python unittest module.""" - -import fnmatch -import sys -import unittest - - -class _TextTestResult(unittest._TextTestResult): - """A test result class that can print formatted text results to a stream. - - Results printed in conformance with gtest output format, like: - [ RUN ] autofill.AutofillTest.testAutofillInvalid: "test desc." - [ OK ] autofill.AutofillTest.testAutofillInvalid - [ RUN ] autofill.AutofillTest.testFillProfile: "test desc." - [ OK ] autofill.AutofillTest.testFillProfile - [ RUN ] autofill.AutofillTest.testFillProfileCrazyCharacters: "Test." - [ OK ] autofill.AutofillTest.testFillProfileCrazyCharacters - """ - def __init__(self, stream, descriptions, verbosity): - unittest._TextTestResult.__init__(self, stream, descriptions, verbosity) - self._fails = set() - - def _GetTestURI(self, test): - return '%s.%s.%s' % (test.__class__.__module__, - test.__class__.__name__, - test._testMethodName) - - def getDescription(self, test): - return '%s: "%s"' % (self._GetTestURI(test), test.shortDescription()) - - def startTest(self, test): - unittest.TestResult.startTest(self, test) - self.stream.writeln('[ RUN ] %s' % self.getDescription(test)) - - def addSuccess(self, test): - unittest.TestResult.addSuccess(self, test) - self.stream.writeln('[ OK ] %s' % self._GetTestURI(test)) - - def addError(self, test, err): - unittest.TestResult.addError(self, test, err) - self.stream.writeln('[ ERROR ] %s' % self._GetTestURI(test)) - self._fails.add(self._GetTestURI(test)) - - def addFailure(self, test, err): - unittest.TestResult.addFailure(self, test, err) - self.stream.writeln('[ FAILED ] %s' % self._GetTestURI(test)) - self._fails.add(self._GetTestURI(test)) - - def getRetestFilter(self): - return ':'.join(self._fails) - - -class TextTestRunner(unittest.TextTestRunner): - """Test Runner for displaying test results in textual format. - - Results are displayed in conformance with google test output. - """ - - def __init__(self, verbosity=1): - unittest.TextTestRunner.__init__(self, stream=sys.stderr, - verbosity=verbosity) - - def _makeResult(self): - return _TextTestResult(self.stream, self.descriptions, self.verbosity) - - -def GetTestsFromSuite(suite): - """Returns all the tests from a given test suite.""" - tests = [] - for x in suite: - if isinstance(x, unittest.TestSuite): - tests += GetTestsFromSuite(x) - else: - tests += [x] - return tests - - -def GetTestNamesFromSuite(suite): - """Returns a list of every test name in the given suite.""" - return map(lambda x: GetTestName(x), GetTestsFromSuite(suite)) - - -def GetTestName(test): - """Gets the test name of the given unittest test.""" - return '.'.join([test.__class__.__module__, - test.__class__.__name__, - test._testMethodName]) - - -def FilterTestSuite(suite, gtest_filter): - """Returns a new filtered tests suite based on the given gtest filter. - - See http://code.google.com/p/googletest/wiki/AdvancedGuide - for gtest_filter specification. - """ - return unittest.TestSuite(FilterTests(GetTestsFromSuite(suite), gtest_filter)) - - -def FilterTests(all_tests, gtest_filter): - """Filter a list of tests based on the given gtest filter. - - Args: - all_tests: List of tests (unittest.TestSuite) - gtest_filter: Filter to apply. - - Returns: - Filtered subset of the given list of tests. - """ - test_names = [GetTestName(test) for test in all_tests] - filtered_names = FilterTestNames(test_names, gtest_filter) - return [test for test in all_tests if GetTestName(test) in filtered_names] - - -def FilterTestNames(all_tests, gtest_filter): - """Filter a list of test names based on the given gtest filter. - - See http://code.google.com/p/googletest/wiki/AdvancedGuide - for gtest_filter specification. - - Args: - all_tests: List of test names. - gtest_filter: Filter to apply. - - Returns: - Filtered subset of the given list of test names. - """ - pattern_groups = gtest_filter.split('-') - positive_patterns = pattern_groups[0].split(':') - negative_patterns = None - if len(pattern_groups) > 1: - negative_patterns = pattern_groups[1].split(':') - - tests = [] - for test in all_tests: - # Test name must by matched by one positive pattern. - for pattern in positive_patterns: - if fnmatch.fnmatch(test, pattern): - break - else: - continue - # Test name must not be matched by any negative patterns. - for pattern in negative_patterns or []: - if fnmatch.fnmatch(test, pattern): - break - else: - tests += [test] - return tests diff --git a/build/util/lib/common/util.py b/build/util/lib/common/util.py deleted file mode 100644 index a415b1f534..0000000000 --- a/build/util/lib/common/util.py +++ /dev/null @@ -1,151 +0,0 @@ -# Copyright 2013 The Chromium Authors. All rights reserved. -# Use of this source code is governed by a BSD-style license that can be -# found in the LICENSE file. - -"""Generic utilities for all python scripts.""" - -import atexit -import httplib -import os -import signal -import stat -import subprocess -import sys -import tempfile -import urlparse - - -def GetPlatformName(): - """Return a string to be used in paths for the platform.""" - if IsWindows(): - return 'win' - if IsMac(): - return 'mac' - if IsLinux(): - return 'linux' - raise NotImplementedError('Unknown platform "%s".' % sys.platform) - - -def IsWindows(): - return sys.platform == 'cygwin' or sys.platform.startswith('win') - - -def IsLinux(): - return sys.platform.startswith('linux') - - -def IsMac(): - return sys.platform.startswith('darwin') - - -def _DeleteDir(path): - """Deletes a directory recursively, which must exist.""" - # Don't use shutil.rmtree because it can't delete read-only files on Win. - for root, dirs, files in os.walk(path, topdown=False): - for name in files: - filename = os.path.join(root, name) - os.chmod(filename, stat.S_IWRITE) - os.remove(filename) - for name in dirs: - os.rmdir(os.path.join(root, name)) - os.rmdir(path) - - -def Delete(path): - """Deletes the given file or directory (recursively), which must exist.""" - if os.path.isdir(path): - _DeleteDir(path) - else: - os.remove(path) - - -def MaybeDelete(path): - """Deletes the given file or directory (recurisvely), if it exists.""" - if os.path.exists(path): - Delete(path) - - -def MakeTempDir(parent_dir=None): - """Creates a temporary directory and returns an absolute path to it. - - The temporary directory is automatically deleted when the python interpreter - exits normally. - - Args: - parent_dir: the directory to create the temp dir in. If None, the system - temp dir is used. - - Returns: - The absolute path to the temporary directory. - """ - path = tempfile.mkdtemp(dir=parent_dir) - atexit.register(MaybeDelete, path) - return path - - -def Unzip(zip_path, output_dir): - """Unzips the given zip file using a system installed unzip tool. - - Args: - zip_path: zip file to unzip. - output_dir: directory to unzip the contents of the zip file. The directory - must exist. - - Raises: - RuntimeError if the unzip operation fails. - """ - if IsWindows(): - unzip_cmd = ['C:\\Program Files\\7-Zip\\7z.exe', 'x', '-y'] - else: - unzip_cmd = ['unzip', '-o'] - unzip_cmd += [zip_path] - if RunCommand(unzip_cmd, output_dir) != 0: - raise RuntimeError('Unable to unzip %s to %s' % (zip_path, output_dir)) - - -def Kill(pid): - """Terminate the given pid.""" - if IsWindows(): - subprocess.call(['taskkill.exe', '/T', '/F', '/PID', str(pid)]) - else: - os.kill(pid, signal.SIGTERM) - - -def RunCommand(cmd, cwd=None): - """Runs the given command and returns the exit code. - - Args: - cmd: list of command arguments. - cwd: working directory to execute the command, or None if the current - working directory should be used. - - Returns: - The exit code of the command. - """ - process = subprocess.Popen(cmd, cwd=cwd) - process.wait() - return process.returncode - - -def DoesUrlExist(url): - """Determines whether a resource exists at the given URL. - - Args: - url: URL to be verified. - - Returns: - True if url exists, otherwise False. - """ - parsed = urlparse.urlparse(url) - try: - conn = httplib.HTTPConnection(parsed.netloc) - conn.request('HEAD', parsed.path) - response = conn.getresponse() - except (socket.gaierror, socket.error): - return False - finally: - conn.close() - # Follow both permanent (301) and temporary (302) redirects. - if response.status == 302 or response.status == 301: - return DoesUrlExist(response.getheader('location')) - return response.status == 200 diff --git a/build/whitespace_file.txt b/build/whitespace_file.txt deleted file mode 100644 index 405a489430..0000000000 --- a/build/whitespace_file.txt +++ /dev/null @@ -1,73 +0,0 @@ -Copyright (c) 2013 The Chromium Authors. All rights reserved. -Use of this useless file is governed by a BSD-style license that can be -found in the LICENSE file. - - -This file is used for making non-code changes to trigger buildbot cycles. Make -any modification below this line. - -====================================================================== - -Let's make a story. Add one sentence for every commit: - -CHAPTER 1: -It was a dark and blinky night; the rain fell in torrents -- except at -occasional intervals, when it was checked by a violent gust of wind which -swept up the streets (for it is in London that our scene lies), rattling along -the housetops, and fiercely agitating the scanty flame of the lamps that -struggled against the elements. A hooded figure emerged. - -It was a Domo-Kun. - -"What took you so long?", inquired his wife. - -Silence. Oblivious to his silence, she continued, "Did Mr. Usagi enjoy the -waffles you brought him?""You know him, he's not one to forego a waffle, -no matter how burnt," he snickered. - -The pause was filled with the sound of thunder. - -CHAPTER 2: -The jelly was as dark as night, and just as runny. -The Domo-Kun shuddered, remembering the way Mr. Usagi had speared his waffles -with his fork, watching the runny jelly spread and pool across his plate, -like the blood of a dying fawn. "It reminds me of that time --" he started, as -his wife cut in quickly: "-- please. I can't bear to hear it.". A flury of -images coming from the past flowed through his mind. - -"You recall what happened on Mulholland drive?" The ceiling fan rotated slowly -overhead, barely disturbing the thick cigarette smoke. No doubt was left about -when the fan was last cleaned. - -There was a poignant pause. - -CHAPTER 3: -Mr. Usagi felt that something wasn't right. Shortly after the Domo-Kun left he -began feeling sick. He thought out loud to himself, "No, he wouldn't have done -that to me." He considered that perhaps he shouldn't have pushed so hard. -Perhaps he shouldn't have been so cold and sarcastic, after the unimaginable -horror that had occurred just the week before. - -Next time, there won't be any sushi. Why sushi with waffles anyway? It's like -adorning breakfast cereal with halibut -- shameful. - -CHAPTER 4: -The taste of stable sushi in his mouth the next morning was unbearable. He -wondered where the sushi came from as he attempted to wash the taste away with -a bottle of 3000¥ sake. He tries to recall the cook's face. Purple? - -CHAPTER 5: -Many years later, Mr. Usagi would laugh at the memory of the earnest, -well-intentioned Domo-Kun. Another day in the life. - -TRUISMS (1978-1983) -JENNY HOLZER -A LITTLE KNOWLEDGE CAN GO A LONG WAY -A LOT OF PROFESSIONALS ARE CRACKPOTS -A MAN CAN'T KNOW WHAT IT IS TO BE A MOTHER -A NAME MEANS A LOT JUST BY ITSELF -A POSITIVE ATTITUDE MEANS ALL THE DIFFERENCE IN THE WORLD -A RELAXED MAN IS NOT NECESSARILY A BETTER MAN -NO ONE SHOULD EVER USE SVN -AN INFLEXIBLE POSITION SOMETIMES IS A SIGN OF PARALYSIS -IT IS MANS FATE TO OUTSMART HIMSELF diff --git a/build/win/chrome_win.croc b/build/win/chrome_win.croc deleted file mode 100644 index e1e3bb76d6..0000000000 --- a/build/win/chrome_win.croc +++ /dev/null @@ -1,26 +0,0 @@ -# -*- python -*- -# Crocodile config file for Chromium windows - -{ - # List of rules, applied in order - 'rules' : [ - # Specify inclusions before exclusions, since rules are in order. - - # Don't include chromeos, posix, or linux specific files - { - 'regexp' : '.*(_|/)(chromeos|linux|posix)(\\.|_)', - 'include' : 0, - }, - # Don't include ChromeOS dirs - { - 'regexp' : '.*/chromeos/', - 'include' : 0, - }, - - # Groups - { - 'regexp' : '.*_test_win\\.', - 'group' : 'test', - }, - ], -} diff --git a/build/win/compatibility.manifest b/build/win/compatibility.manifest deleted file mode 100644 index f7bc13e593..0000000000 --- a/build/win/compatibility.manifest +++ /dev/null @@ -1,15 +0,0 @@ - - - - - - - - - - - - - - - diff --git a/build/win/importlibs/create_import_lib.gypi b/build/win/importlibs/create_import_lib.gypi deleted file mode 100644 index c809eab84f..0000000000 --- a/build/win/importlibs/create_import_lib.gypi +++ /dev/null @@ -1,54 +0,0 @@ -# Copyright (c) 2012 The Chromium Authors. All rights reserved. -# Use of this source code is governed by a BSD-style license that can be -# found in the LICENSE file. - -# This file is meant to be included into a target to provide a rule -# to create import libraries from an import description file in a consistent -# manner. -# -# To use this, create a gyp target with the following form: -# { -# 'target_name': 'my_proto_lib', -# 'type': 'none', -# 'sources': [ -# 'foo.imports', -# 'bar.imports', -# ], -# 'variables': { -# # Optional, see below: 'proto_in_dir': '.' -# 'create_importlib': 'path-to-script', -# 'lib_dir': 'path-to-output-directory', -# }, -# 'includes': ['path/to/this/gypi/file'], -# } -# -# This will generate import libraries named 'foo.lib' and 'bar.lib' in the -# specified lib directory. - -{ - 'variables': { - 'create_importlib': '<(DEPTH)/build/win/importlibs/create_importlib_win.py', - 'lib_dir': '<(PRODUCT_DIR)/lib', - }, - 'rules': [ - { - 'rule_name': 'create_import_lib', - 'extension': 'imports', - 'inputs': [ - '<(create_importlib)', - ], - 'outputs': [ - '<(lib_dir)/<(RULE_INPUT_ROOT).lib', - ], - 'action': [ - 'python', - '<(create_importlib)', - '--output-file', '<@(_outputs)', - '<(RULE_INPUT_PATH)', - ], - 'msvs_cygwin_shell': 0, - 'message': 'Generating import library from <(RULE_INPUT_PATH)', - 'process_outputs_as_sources': 0, - }, - ], -} diff --git a/build/win/importlibs/create_importlib_win.py b/build/win/importlibs/create_importlib_win.py deleted file mode 100755 index bb6a2f0263..0000000000 --- a/build/win/importlibs/create_importlib_win.py +++ /dev/null @@ -1,217 +0,0 @@ -#!/usr/bin/env python -# Copyright (c) 2012 The Chromium Authors. All rights reserved. -# Use of this source code is governed by a BSD-style license that can be -# found in the LICENSE file. -# -"""Creates an import library from an import description file.""" -import ast -import logging -import optparse -import os -import os.path -import shutil -import subprocess -import sys -import tempfile - - -_USAGE = """\ -Usage: %prog [options] [imports-file] - -Creates an import library from imports-file. - -Note: this script uses the microsoft assembler (ml.exe) and the library tool - (lib.exe), both of which must be in path. -""" - - -_ASM_STUB_HEADER = """\ -; This file is autogenerated by create_importlib_win.py, do not edit. -.386 -.MODEL FLAT, C -.CODE - -; Stubs to provide mangled names to lib.exe for the -; correct generation of import libs. -""" - - -_DEF_STUB_HEADER = """\ -; This file is autogenerated by create_importlib_win.py, do not edit. - -; Export declarations for generating import libs. -""" - - -_LOGGER = logging.getLogger() - - - -class _Error(Exception): - pass - - -class _ImportLibraryGenerator(object): - def __init__(self, temp_dir): - self._temp_dir = temp_dir - - def _Shell(self, cmd, **kw): - ret = subprocess.call(cmd, **kw) - _LOGGER.info('Running "%s" returned %d.', cmd, ret) - if ret != 0: - raise _Error('Command "%s" returned %d.' % (cmd, ret)) - - def _ReadImportsFile(self, imports_file): - # Slurp the imports file. - return ast.literal_eval(open(imports_file).read()) - - def _WriteStubsFile(self, import_names, output_file): - output_file.write(_ASM_STUB_HEADER) - - for name in import_names: - output_file.write('%s PROC\n' % name) - output_file.write('%s ENDP\n' % name) - - output_file.write('END\n') - - def _WriteDefFile(self, dll_name, import_names, output_file): - output_file.write(_DEF_STUB_HEADER) - output_file.write('NAME %s\n' % dll_name) - output_file.write('EXPORTS\n') - for name in import_names: - name = name.split('@')[0] - output_file.write(' %s\n' % name) - - def _CreateObj(self, dll_name, imports): - """Writes an assembly file containing empty declarations. - - For each imported function of the form: - - AddClipboardFormatListener@4 PROC - AddClipboardFormatListener@4 ENDP - - The resulting object file is then supplied to lib.exe with a .def file - declaring the corresponding non-adorned exports as they appear on the - exporting DLL, e.g. - - EXPORTS - AddClipboardFormatListener - - In combination, the .def file and the .obj file cause lib.exe to generate - an x86 import lib with public symbols named like - "__imp__AddClipboardFormatListener@4", binding to exports named like - "AddClipboardFormatListener". - - All of this is perpetrated in a temporary directory, as the intermediate - artifacts are quick and easy to produce, and of no interest to anyone - after the fact.""" - - # Create an .asm file to provide stdcall-like stub names to lib.exe. - asm_name = dll_name + '.asm' - _LOGGER.info('Writing asm file "%s".', asm_name) - with open(os.path.join(self._temp_dir, asm_name), 'wb') as stubs_file: - self._WriteStubsFile(imports, stubs_file) - - # Invoke on the assembler to compile it to .obj. - obj_name = dll_name + '.obj' - cmdline = ['ml.exe', '/nologo', '/c', asm_name, '/Fo', obj_name] - self._Shell(cmdline, cwd=self._temp_dir, stdout=open(os.devnull)) - - return obj_name - - def _CreateImportLib(self, dll_name, imports, architecture, output_file): - """Creates an import lib binding imports to dll_name for architecture. - - On success, writes the import library to output file. - """ - obj_file = None - - # For x86 architecture we have to provide an object file for correct - # name mangling between the import stubs and the exported functions. - if architecture == 'x86': - obj_file = self._CreateObj(dll_name, imports) - - # Create the corresponding .def file. This file has the non stdcall-adorned - # names, as exported by the destination DLL. - def_name = dll_name + '.def' - _LOGGER.info('Writing def file "%s".', def_name) - with open(os.path.join(self._temp_dir, def_name), 'wb') as def_file: - self._WriteDefFile(dll_name, imports, def_file) - - # Invoke on lib.exe to create the import library. - # We generate everything into the temporary directory, as the .exp export - # files will be generated at the same path as the import library, and we - # don't want those files potentially gunking the works. - dll_base_name, ext = os.path.splitext(dll_name) - lib_name = dll_base_name + '.lib' - cmdline = ['lib.exe', - '/machine:%s' % architecture, - '/def:%s' % def_name, - '/out:%s' % lib_name] - if obj_file: - cmdline.append(obj_file) - - self._Shell(cmdline, cwd=self._temp_dir, stdout=open(os.devnull)) - - # Copy the .lib file to the output directory. - shutil.copyfile(os.path.join(self._temp_dir, lib_name), output_file) - _LOGGER.info('Created "%s".', output_file) - - def CreateImportLib(self, imports_file, output_file): - # Read the imports file. - imports = self._ReadImportsFile(imports_file) - - # Creates the requested import library in the output directory. - self._CreateImportLib(imports['dll_name'], - imports['imports'], - imports.get('architecture', 'x86'), - output_file) - - -def main(): - parser = optparse.OptionParser(usage=_USAGE) - parser.add_option('-o', '--output-file', - help='Specifies the output file path.') - parser.add_option('-k', '--keep-temp-dir', - action='store_true', - help='Keep the temporary directory.') - parser.add_option('-v', '--verbose', - action='store_true', - help='Verbose logging.') - - options, args = parser.parse_args() - - if len(args) != 1: - parser.error('You must provide an imports file.') - - if not options.output_file: - parser.error('You must provide an output file.') - - options.output_file = os.path.abspath(options.output_file) - - if options.verbose: - logging.basicConfig(level=logging.INFO) - else: - logging.basicConfig(level=logging.WARN) - - - temp_dir = tempfile.mkdtemp() - _LOGGER.info('Created temporary directory "%s."', temp_dir) - try: - # Create a generator and create the import lib. - generator = _ImportLibraryGenerator(temp_dir) - - ret = generator.CreateImportLib(args[0], options.output_file) - except Exception, e: - _LOGGER.exception('Failed to create import lib.') - ret = 1 - finally: - if not options.keep_temp_dir: - shutil.rmtree(temp_dir) - _LOGGER.info('Deleted temporary directory "%s."', temp_dir) - - return ret - - -if __name__ == '__main__': - sys.exit(main()) diff --git a/build/win/importlibs/filter_export_list.py b/build/win/importlibs/filter_export_list.py deleted file mode 100755 index c2489a9da7..0000000000 --- a/build/win/importlibs/filter_export_list.py +++ /dev/null @@ -1,85 +0,0 @@ -#!/usr/bin/env python -# Copyright (c) 2012 The Chromium Authors. All rights reserved. -# Use of this source code is governed by a BSD-style license that can be -# found in the LICENSE file. -# -"""Help maintaining DLL import lists.""" -import ast -import optparse -import re -import sys - - -_EXPORT_RE = re.compile(r""" - ^\s*(?P[0-9]+) # The ordinal field. - \s+(?P[0-9A-F]+) # The hint field. - \s(?P........) # The RVA field. - \s+(?P[^ ]+) # And finally the name we're really after. -""", re.VERBOSE) - - -_USAGE = r"""\ -Usage: %prog [options] [master-file] - -This script filters a list of exports from a DLL, generated from something -like the following command line: - -C:\> dumpbin /exports user32.dll - -against a master list of imports built from e.g. - -C:\> dumpbin /exports user32.lib - -The point of this is to trim non-public exports from the list, and to -normalize the names to their stdcall-mangled form for the generation of -import libraries. -Note that the export names from the latter incanatation are stdcall-mangled, -e.g. they are suffixed with "@" and the number of argument bytes to the -function. -""" - -def _ReadMasterFile(master_file): - # Slurp the master file. - with open(master_file) as f: - master_exports = ast.literal_eval(f.read()) - - master_mapping = {} - for export in master_exports: - name = export.split('@')[0] - master_mapping[name] = export - - return master_mapping - - -def main(): - parser = optparse.OptionParser(usage=_USAGE) - parser.add_option('-r', '--reverse', - action='store_true', - help='Reverse the matching, e.g. return the functions ' - 'in the master list that aren\'t in the input.') - - options, args = parser.parse_args() - if len(args) != 1: - parser.error('Must provide a master file.') - - master_mapping = _ReadMasterFile(args[0]) - - found_exports = [] - for line in sys.stdin: - match = _EXPORT_RE.match(line) - if match: - export_name = master_mapping.get(match.group('name'), None) - if export_name: - found_exports.append(export_name) - - if options.reverse: - # Invert the found_exports list. - found_exports = set(master_mapping.values()) - set(found_exports) - - # Sort the found exports for tidy output. - print '\n'.join(sorted(found_exports)) - return 0 - - -if __name__ == '__main__': - sys.exit(main()) diff --git a/build/win/importlibs/x86/user32.winxp.imports b/build/win/importlibs/x86/user32.winxp.imports deleted file mode 100644 index 24403a8aee..0000000000 --- a/build/win/importlibs/x86/user32.winxp.imports +++ /dev/null @@ -1,670 +0,0 @@ -# Copyright (c) 2012 The Chromium Authors. All rights reserved. -# Use of this source code is governed by a BSD-style license that can be -# found in the LICENSE file. -# -# This file is used to create a custom import library for Chrome's use of -# user32.dll exports. The set of exports defined below -{ - 'architecture': 'x86', - - # The DLL to bind to. - 'dll_name': 'user32.dll', - - # Name of the generated import library. - 'importlib_name': 'user32.winxp.lib', - - # This is the set of exports observed on a user32.dll from Windows XP SP2. - # The version of the DLL where these were observed is 5.1.2600.2180. - # Incidentally this set of exports also coincides with Windows XP SP3, where - # the version of the DLL is 5.1.2600.5512. - # Don't add new imports here unless and until the minimal supported - # Windows version has been bumped past Windows XP SP2+. - 'imports': [ - 'ActivateKeyboardLayout@8', - 'AdjustWindowRect@12', - 'AdjustWindowRectEx@16', - 'AllowSetForegroundWindow@4', - 'AnimateWindow@12', - 'AnyPopup@0', - 'AppendMenuA@16', - 'AppendMenuW@16', - 'ArrangeIconicWindows@4', - 'AttachThreadInput@12', - 'BeginDeferWindowPos@4', - 'BeginPaint@8', - 'BlockInput@4', - 'BringWindowToTop@4', - 'BroadcastSystemMessage@20', - 'BroadcastSystemMessageA@20', - 'BroadcastSystemMessageExA@24', - 'BroadcastSystemMessageExW@24', - 'BroadcastSystemMessageW@20', - 'CallMsgFilter@8', - 'CallMsgFilterA@8', - 'CallMsgFilterW@8', - 'CallNextHookEx@16', - 'CallWindowProcA@20', - 'CallWindowProcW@20', - 'CascadeChildWindows@8', - 'CascadeWindows@20', - 'ChangeClipboardChain@8', - 'ChangeDisplaySettingsA@8', - 'ChangeDisplaySettingsExA@20', - 'ChangeDisplaySettingsExW@20', - 'ChangeDisplaySettingsW@8', - 'ChangeMenuA@20', - 'ChangeMenuW@20', - 'CharLowerA@4', - 'CharLowerBuffA@8', - 'CharLowerBuffW@8', - 'CharLowerW@4', - 'CharNextA@4', - 'CharNextExA@12', - 'CharNextW@4', - 'CharPrevA@8', - 'CharPrevExA@16', - 'CharPrevW@8', - 'CharToOemA@8', - 'CharToOemBuffA@12', - 'CharToOemBuffW@12', - 'CharToOemW@8', - 'CharUpperA@4', - 'CharUpperBuffA@8', - 'CharUpperBuffW@8', - 'CharUpperW@4', - 'CheckDlgButton@12', - 'CheckMenuItem@12', - 'CheckMenuRadioItem@20', - 'CheckRadioButton@16', - 'ChildWindowFromPoint@12', - 'ChildWindowFromPointEx@16', - 'ClientToScreen@8', - 'ClipCursor@4', - 'CloseClipboard@0', - 'CloseDesktop@4', - 'CloseWindow@4', - 'CloseWindowStation@4', - 'CopyAcceleratorTableA@12', - 'CopyAcceleratorTableW@12', - 'CopyIcon@4', - 'CopyImage@20', - 'CopyRect@8', - 'CountClipboardFormats@0', - 'CreateAcceleratorTableA@8', - 'CreateAcceleratorTableW@8', - 'CreateCaret@16', - 'CreateCursor@28', - 'CreateDesktopA@24', - 'CreateDesktopW@24', - 'CreateDialogIndirectParamA@20', - 'CreateDialogIndirectParamW@20', - 'CreateDialogParamA@20', - 'CreateDialogParamW@20', - 'CreateIcon@28', - 'CreateIconFromResource@16', - 'CreateIconFromResourceEx@28', - 'CreateIconIndirect@4', - 'CreateMDIWindowA@40', - 'CreateMDIWindowW@40', - 'CreateMenu@0', - 'CreatePopupMenu@0', - 'CreateWindowExA@48', - 'CreateWindowExW@48', - 'CreateWindowStationA@16', - 'CreateWindowStationW@16', - 'DdeAbandonTransaction@12', - 'DdeAccessData@8', - 'DdeAddData@16', - 'DdeClientTransaction@32', - 'DdeCmpStringHandles@8', - 'DdeConnect@16', - 'DdeConnectList@20', - 'DdeCreateDataHandle@28', - 'DdeCreateStringHandleA@12', - 'DdeCreateStringHandleW@12', - 'DdeDisconnect@4', - 'DdeDisconnectList@4', - 'DdeEnableCallback@12', - 'DdeFreeDataHandle@4', - 'DdeFreeStringHandle@8', - 'DdeGetData@16', - 'DdeGetLastError@4', - 'DdeImpersonateClient@4', - 'DdeInitializeA@16', - 'DdeInitializeW@16', - 'DdeKeepStringHandle@8', - 'DdeNameService@16', - 'DdePostAdvise@12', - 'DdeQueryConvInfo@12', - 'DdeQueryNextServer@8', - 'DdeQueryStringA@20', - 'DdeQueryStringW@20', - 'DdeReconnect@4', - 'DdeSetQualityOfService@12', - 'DdeSetUserHandle@12', - 'DdeUnaccessData@4', - 'DdeUninitialize@4', - 'DefDlgProcA@16', - 'DefDlgProcW@16', - 'DefFrameProcA@20', - 'DefFrameProcW@20', - 'DefMDIChildProcA@16', - 'DefMDIChildProcW@16', - 'DefRawInputProc@12', - 'DefWindowProcA@16', - 'DefWindowProcW@16', - 'DeferWindowPos@32', - 'DeleteMenu@12', - 'DeregisterShellHookWindow@4', - 'DestroyAcceleratorTable@4', - 'DestroyCaret@0', - 'DestroyCursor@4', - 'DestroyIcon@4', - 'DestroyMenu@4', - 'DestroyWindow@4', - 'DialogBoxIndirectParamA@20', - 'DialogBoxIndirectParamW@20', - 'DialogBoxParamA@20', - 'DialogBoxParamW@20', - 'DisableProcessWindowsGhosting@0', - 'DispatchMessageA@4', - 'DispatchMessageW@4', - 'DlgDirListA@20', - 'DlgDirListComboBoxA@20', - 'DlgDirListComboBoxW@20', - 'DlgDirListW@20', - 'DlgDirSelectComboBoxExA@16', - 'DlgDirSelectComboBoxExW@16', - 'DlgDirSelectExA@16', - 'DlgDirSelectExW@16', - 'DragDetect@12', - 'DragObject@20', - 'DrawAnimatedRects@16', - 'DrawCaption@16', - 'DrawEdge@16', - 'DrawFocusRect@8', - 'DrawFrame@16', - 'DrawFrameControl@16', - 'DrawIcon@16', - 'DrawIconEx@36', - 'DrawMenuBar@4', - 'DrawStateA@40', - 'DrawStateW@40', - 'DrawTextA@20', - 'DrawTextExA@24', - 'DrawTextExW@24', - 'DrawTextW@20', - 'EditWndProc@16', - 'EmptyClipboard@0', - 'EnableMenuItem@12', - 'EnableScrollBar@12', - 'EnableWindow@8', - 'EndDeferWindowPos@4', - 'EndDialog@8', - 'EndMenu@0', - 'EndPaint@8', - 'EndTask@12', - 'EnumChildWindows@12', - 'EnumClipboardFormats@4', - 'EnumDesktopWindows@12', - 'EnumDesktopsA@12', - 'EnumDesktopsW@12', - 'EnumDisplayDevicesA@16', - 'EnumDisplayDevicesW@16', - 'EnumDisplayMonitors@16', - 'EnumDisplaySettingsA@12', - 'EnumDisplaySettingsExA@16', - 'EnumDisplaySettingsExW@16', - 'EnumDisplaySettingsW@12', - 'EnumPropsA@8', - 'EnumPropsExA@12', - 'EnumPropsExW@12', - 'EnumPropsW@8', - 'EnumThreadWindows@12', - 'EnumWindowStationsA@8', - 'EnumWindowStationsW@8', - 'EnumWindows@8', - 'EqualRect@8', - 'ExcludeUpdateRgn@8', - 'ExitWindowsEx@8', - 'FillRect@12', - 'FindWindowA@8', - 'FindWindowExA@16', - 'FindWindowExW@16', - 'FindWindowW@8', - 'FlashWindow@8', - 'FlashWindowEx@4', - 'FrameRect@12', - 'FreeDDElParam@8', - 'GetActiveWindow@0', - 'GetAltTabInfo@20', - 'GetAltTabInfoA@20', - 'GetAltTabInfoW@20', - 'GetAncestor@8', - 'GetAsyncKeyState@4', - 'GetCapture@0', - 'GetCaretBlinkTime@0', - 'GetCaretPos@4', - 'GetClassInfoA@12', - 'GetClassInfoExA@12', - 'GetClassInfoExW@12', - 'GetClassInfoW@12', - 'GetClassLongA@8', - 'GetClassLongW@8', - 'GetClassNameA@12', - 'GetClassNameW@12', - 'GetClassWord@8', - 'GetClientRect@8', - 'GetClipCursor@4', - 'GetClipboardData@4', - 'GetClipboardFormatNameA@12', - 'GetClipboardFormatNameW@12', - 'GetClipboardOwner@0', - 'GetClipboardSequenceNumber@0', - 'GetClipboardViewer@0', - 'GetComboBoxInfo@8', - 'GetCursor@0', - 'GetCursorInfo@4', - 'GetCursorPos@4', - 'GetDC@4', - 'GetDCEx@12', - 'GetDesktopWindow@0', - 'GetDialogBaseUnits@0', - 'GetDlgCtrlID@4', - 'GetDlgItem@8', - 'GetDlgItemInt@16', - 'GetDlgItemTextA@16', - 'GetDlgItemTextW@16', - 'GetDoubleClickTime@0', - 'GetFocus@0', - 'GetForegroundWindow@0', - 'GetGUIThreadInfo@8', - 'GetGuiResources@8', - 'GetIconInfo@8', - 'GetInputDesktop@0', - 'GetInputState@0', - 'GetKBCodePage@0', - 'GetKeyNameTextA@12', - 'GetKeyNameTextW@12', - 'GetKeyState@4', - 'GetKeyboardLayout@4', - 'GetKeyboardLayoutList@8', - 'GetKeyboardLayoutNameA@4', - 'GetKeyboardLayoutNameW@4', - 'GetKeyboardState@4', - 'GetKeyboardType@4', - 'GetLastActivePopup@4', - 'GetLastInputInfo@4', - 'GetLayeredWindowAttributes@16', - 'GetListBoxInfo@4', - 'GetMenu@4', - 'GetMenuBarInfo@16', - 'GetMenuCheckMarkDimensions@0', - 'GetMenuContextHelpId@4', - 'GetMenuDefaultItem@12', - 'GetMenuInfo@8', - 'GetMenuItemCount@4', - 'GetMenuItemID@8', - 'GetMenuItemInfoA@16', - 'GetMenuItemInfoW@16', - 'GetMenuItemRect@16', - 'GetMenuState@12', - 'GetMenuStringA@20', - 'GetMenuStringW@20', - 'GetMessageA@16', - 'GetMessageExtraInfo@0', - 'GetMessagePos@0', - 'GetMessageTime@0', - 'GetMessageW@16', - 'GetMonitorInfoA@8', - 'GetMonitorInfoW@8', - 'GetMouseMovePointsEx@20', - 'GetNextDlgGroupItem@12', - 'GetNextDlgTabItem@12', - 'GetOpenClipboardWindow@0', - 'GetParent@4', - 'GetPriorityClipboardFormat@8', - 'GetProcessDefaultLayout@4', - 'GetProcessWindowStation@0', - 'GetPropA@8', - 'GetPropW@8', - 'GetQueueStatus@4', - 'GetRawInputBuffer@12', - 'GetRawInputData@20', - 'GetRawInputDeviceInfoA@16', - 'GetRawInputDeviceInfoW@16', - 'GetRawInputDeviceList@12', - 'GetRegisteredRawInputDevices@12', - 'GetScrollBarInfo@12', - 'GetScrollInfo@12', - 'GetScrollPos@8', - 'GetScrollRange@16', - 'GetShellWindow@0', - 'GetSubMenu@8', - 'GetSysColor@4', - 'GetSysColorBrush@4', - 'GetSystemMenu@8', - 'GetSystemMetrics@4', - 'GetTabbedTextExtentA@20', - 'GetTabbedTextExtentW@20', - 'GetThreadDesktop@4', - 'GetTitleBarInfo@8', - 'GetTopWindow@4', - 'GetUpdateRect@12', - 'GetUpdateRgn@12', - 'GetUserObjectInformationA@20', - 'GetUserObjectInformationW@20', - 'GetUserObjectSecurity@20', - 'GetWindow@8', - 'GetWindowContextHelpId@4', - 'GetWindowDC@4', - 'GetWindowInfo@8', - 'GetWindowLongA@8', - 'GetWindowLongW@8', - 'GetWindowModuleFileName@12', - 'GetWindowModuleFileNameA@12', - 'GetWindowModuleFileNameW@12', - 'GetWindowPlacement@8', - 'GetWindowRect@8', - 'GetWindowRgn@8', - 'GetWindowRgnBox@8', - 'GetWindowTextA@12', - 'GetWindowTextLengthA@4', - 'GetWindowTextLengthW@4', - 'GetWindowTextW@12', - 'GetWindowThreadProcessId@8', - 'GetWindowWord@8', - 'GrayStringA@36', - 'GrayStringW@36', - 'HideCaret@4', - 'HiliteMenuItem@16', - 'IMPGetIMEA@8', - 'IMPGetIMEW@8', - 'IMPQueryIMEA@4', - 'IMPQueryIMEW@4', - 'IMPSetIMEA@8', - 'IMPSetIMEW@8', - 'ImpersonateDdeClientWindow@8', - 'InSendMessage@0', - 'InSendMessageEx@4', - 'InflateRect@12', - 'InsertMenuA@20', - 'InsertMenuItemA@16', - 'InsertMenuItemW@16', - 'InsertMenuW@20', - 'InternalGetWindowText@12', - 'IntersectRect@12', - 'InvalidateRect@12', - 'InvalidateRgn@12', - 'InvertRect@8', - 'IsCharAlphaA@4', - 'IsCharAlphaNumericA@4', - 'IsCharAlphaNumericW@4', - 'IsCharAlphaW@4', - 'IsCharLowerA@4', - 'IsCharLowerW@4', - 'IsCharUpperA@4', - 'IsCharUpperW@4', - 'IsChild@8', - 'IsClipboardFormatAvailable@4', - 'IsDialogMessage@8', - 'IsDialogMessageA@8', - 'IsDialogMessageW@8', - 'IsDlgButtonChecked@8', - 'IsGUIThread@4', - 'IsHungAppWindow@4', - 'IsIconic@4', - 'IsMenu@4', - 'IsRectEmpty@4', - 'IsWinEventHookInstalled@4', - 'IsWindow@4', - 'IsWindowEnabled@4', - 'IsWindowUnicode@4', - 'IsWindowVisible@4', - 'IsZoomed@4', - 'KillTimer@8', - 'LoadAcceleratorsA@8', - 'LoadAcceleratorsW@8', - 'LoadBitmapA@8', - 'LoadBitmapW@8', - 'LoadCursorA@8', - 'LoadCursorFromFileA@4', - 'LoadCursorFromFileW@4', - 'LoadCursorW@8', - 'LoadIconA@8', - 'LoadIconW@8', - 'LoadImageA@24', - 'LoadImageW@24', - 'LoadKeyboardLayoutA@8', - 'LoadKeyboardLayoutW@8', - 'LoadMenuA@8', - 'LoadMenuIndirectA@4', - 'LoadMenuIndirectW@4', - 'LoadMenuW@8', - 'LoadStringA@16', - 'LoadStringW@16', - 'LockSetForegroundWindow@4', - 'LockWindowUpdate@4', - 'LockWorkStation@0', - 'LookupIconIdFromDirectory@8', - 'LookupIconIdFromDirectoryEx@20', - 'MapDialogRect@8', - 'MapVirtualKeyA@8', - 'MapVirtualKeyExA@12', - 'MapVirtualKeyExW@12', - 'MapVirtualKeyW@8', - 'MapWindowPoints@16', - 'MenuItemFromPoint@16', - 'MessageBeep@4', - 'MessageBoxA@16', - 'MessageBoxExA@20', - 'MessageBoxExW@20', - 'MessageBoxIndirectA@4', - 'MessageBoxIndirectW@4', - 'MessageBoxTimeoutA@24', - 'MessageBoxTimeoutW@24', - 'MessageBoxW@16', - 'ModifyMenuA@20', - 'ModifyMenuW@20', - 'MonitorFromPoint@12', - 'MonitorFromRect@8', - 'MonitorFromWindow@8', - 'MoveWindow@24', - 'MsgWaitForMultipleObjects@20', - 'MsgWaitForMultipleObjectsEx@20', - 'NotifyWinEvent@16', - 'OemKeyScan@4', - 'OemToCharA@8', - 'OemToCharBuffA@12', - 'OemToCharBuffW@12', - 'OemToCharW@8', - 'OffsetRect@12', - 'OpenClipboard@4', - 'OpenDesktopA@16', - 'OpenDesktopW@16', - 'OpenIcon@4', - 'OpenInputDesktop@12', - 'OpenWindowStationA@12', - 'OpenWindowStationW@12', - 'PackDDElParam@12', - 'PaintDesktop@4', - 'PeekMessageA@20', - 'PeekMessageW@20', - 'PostMessageA@16', - 'PostMessageW@16', - 'PostQuitMessage@4', - 'PostThreadMessageA@16', - 'PostThreadMessageW@16', - 'PrintWindow@12', - 'PrivateExtractIconsA@32', - 'PrivateExtractIconsW@32', - 'PtInRect@12', - 'RealChildWindowFromPoint@12', - 'RealGetWindowClass@12', - 'RealGetWindowClassA@12', - 'RealGetWindowClassW@12', - 'RedrawWindow@16', - 'RegisterClassA@4', - 'RegisterClassExA@4', - 'RegisterClassExW@4', - 'RegisterClassW@4', - 'RegisterClipboardFormatA@4', - 'RegisterClipboardFormatW@4', - 'RegisterDeviceNotificationA@12', - 'RegisterDeviceNotificationW@12', - 'RegisterHotKey@16', - 'RegisterRawInputDevices@12', - 'RegisterShellHookWindow@4', - 'RegisterWindowMessageA@4', - 'RegisterWindowMessageW@4', - 'ReleaseCapture@0', - 'ReleaseDC@8', - 'RemoveMenu@12', - 'RemovePropA@8', - 'RemovePropW@8', - 'ReplyMessage@4', - 'ReuseDDElParam@20', - 'ScreenToClient@8', - 'ScrollDC@28', - 'ScrollWindow@20', - 'ScrollWindowEx@32', - 'SendDlgItemMessageA@20', - 'SendDlgItemMessageW@20', - 'SendIMEMessageExA@8', - 'SendIMEMessageExW@8', - 'SendInput@12', - 'SendMessageA@16', - 'SendMessageCallbackA@24', - 'SendMessageCallbackW@24', - 'SendMessageTimeoutA@28', - 'SendMessageTimeoutW@28', - 'SendMessageW@16', - 'SendNotifyMessageA@16', - 'SendNotifyMessageW@16', - 'SetActiveWindow@4', - 'SetCapture@4', - 'SetCaretBlinkTime@4', - 'SetCaretPos@8', - 'SetClassLongA@12', - 'SetClassLongW@12', - 'SetClassWord@12', - 'SetClipboardData@8', - 'SetClipboardViewer@4', - 'SetCursor@4', - 'SetCursorPos@8', - 'SetDebugErrorLevel@4', - 'SetDeskWallpaper@4', - 'SetDlgItemInt@16', - 'SetDlgItemTextA@12', - 'SetDlgItemTextW@12', - 'SetDoubleClickTime@4', - 'SetFocus@4', - 'SetForegroundWindow@4', - 'SetKeyboardState@4', - 'SetLastErrorEx@8', - 'SetLayeredWindowAttributes@16', - 'SetMenu@8', - 'SetMenuContextHelpId@8', - 'SetMenuDefaultItem@12', - 'SetMenuInfo@8', - 'SetMenuItemBitmaps@20', - 'SetMenuItemInfoA@16', - 'SetMenuItemInfoW@16', - 'SetMessageExtraInfo@4', - 'SetMessageQueue@4', - 'SetParent@8', - 'SetProcessDefaultLayout@4', - 'SetProcessWindowStation@4', - 'SetPropA@12', - 'SetPropW@12', - 'SetRect@20', - 'SetRectEmpty@4', - 'SetScrollInfo@16', - 'SetScrollPos@16', - 'SetScrollRange@20', - 'SetShellWindow@4', - 'SetSysColors@12', - 'SetSystemCursor@8', - 'SetThreadDesktop@4', - 'SetTimer@16', - 'SetUserObjectInformationA@16', - 'SetUserObjectInformationW@16', - 'SetUserObjectSecurity@12', - 'SetWinEventHook@28', - 'SetWindowContextHelpId@8', - 'SetWindowLongA@12', - 'SetWindowLongW@12', - 'SetWindowPlacement@8', - 'SetWindowPos@28', - 'SetWindowRgn@12', - 'SetWindowTextA@8', - 'SetWindowTextW@8', - 'SetWindowWord@12', - 'SetWindowsHookA@8', - 'SetWindowsHookExA@16', - 'SetWindowsHookExW@16', - 'SetWindowsHookW@8', - 'ShowCaret@4', - 'ShowCursor@4', - 'ShowOwnedPopups@8', - 'ShowScrollBar@12', - 'ShowWindow@8', - 'ShowWindowAsync@8', - 'SubtractRect@12', - 'SwapMouseButton@4', - 'SwitchDesktop@4', - 'SwitchToThisWindow@8', - 'SystemParametersInfoA@16', - 'SystemParametersInfoW@16', - 'TabbedTextOutA@32', - 'TabbedTextOutW@32', - 'TileChildWindows@8', - 'TileWindows@20', - 'ToAscii@20', - 'ToAsciiEx@24', - 'ToUnicode@24', - 'ToUnicodeEx@28', - 'TrackMouseEvent@4', - 'TrackPopupMenu@28', - 'TrackPopupMenuEx@24', - 'TranslateAccelerator@12', - 'TranslateAcceleratorA@12', - 'TranslateAcceleratorW@12', - 'TranslateMDISysAccel@8', - 'TranslateMessage@4', - 'UnhookWinEvent@4', - 'UnhookWindowsHook@8', - 'UnhookWindowsHookEx@4', - 'UnionRect@12', - 'UnloadKeyboardLayout@4', - 'UnpackDDElParam@16', - 'UnregisterClassA@8', - 'UnregisterClassW@8', - 'UnregisterDeviceNotification@4', - 'UnregisterHotKey@8', - 'UpdateLayeredWindow@36', - 'UpdateWindow@4', - 'UserHandleGrantAccess@12', - 'ValidateRect@8', - 'ValidateRgn@8', - 'VkKeyScanA@4', - 'VkKeyScanExA@8', - 'VkKeyScanExW@8', - 'VkKeyScanW@4', - 'WINNLSEnableIME@8', - 'WINNLSGetEnableStatus@4', - 'WINNLSGetIMEHotkey@4', - 'WaitForInputIdle@8', - 'WaitMessage@0', - 'WinHelpA@16', - 'WinHelpW@16', - 'WindowFromDC@4', - 'WindowFromPoint@8', - 'keybd_event@16', - 'mouse_event@20', - 'wsprintfA', - 'wsprintfW', - 'wvsprintfA@12', - 'wvsprintfW@12', - ] -} diff --git a/build/win/importlibs/x86/user32.winxp.lib b/build/win/importlibs/x86/user32.winxp.lib deleted file mode 100644 index deb55778d5be637c40abdff8d699c8d1e65c0974..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 141662 zcmeEvd7K?Z)pm7*h%o{pA_9gG!y+PtY$76Nl1a!wHYO8-h$J^NH_0V;<_`DX$%2ZA zh^UCDxFc?;h^VNjxFIT{A}VgEh=_=Yh>D1)i1GBpmFc%9??2z0-|tD!J*TRl zu6;dK2Oe8%4{khe(vegBe@D%lJ9Ea|IkRTW_2o14&sno)9W`72y>^likK0`&lP?p= zZa0Wz_eVtX4ZNk9EA5v+=M4^Fy1eLG&vYJ1n-wP3s1t`3Wp+|B(BF3c-Bk}eABal!}iv= z5KqD*3eO%AiNufa1P(t=195UV@SJ@$F2)l$Vi%1OJPAKnIC7pyB(A{|n1OVWcpsj? zQTT3&t#}gdQJ6U(5{d8Q3Cuz~NqiAcVD{k}NR!#X9K1&YaW;qWu)^H+B9XWiPvE)u z9*Ixj2^@{|mAD8`;CZRWW;_Y^D;#r*NF=_FC-D5a8i=eSC3NKnA5{YZ^1Wui%aUq_BhZSDDRwNQP;R&3E_e-QrNgeBof!*2{iEC5(sMpIAgL#7f%BC37b}EATBon z&1o7J<4Jf-VR)lRBv5w^10x8p#1(h~t-UnP#gp)W!szKDkwDl+fivf7Ag`VYwD-_B z2T#I%3LV6Y#JBMTx<_lkPZtNbb!ea{C zkd_kn;t8CE_eg;IEa0UxG%m#xc-gKRO*{!dQFwW;NFd`eu1C*cu=SDYad ziQDi5&RL>y4W7U&57u}ap1`>~Yv4Q2CETv?s>LFafS*?Z=S|nR1Wy9OM|d^-NZf@d za6aN!;`?|4uQ^WRDm;M;rf6J*C-7Q?S7I}s1n?7HcY?+Zcml6SI!RoKCvf3j8t36j zK)xWnVXek3cmfyA(*XBHz#I3~xBySWLkbtK7l{P&;Kjh3;76L`lWjW6Q~yc79N z;tD*0cTLwoTD%K*cd9XhCjoItxD@dyaSfipdl3H;;C>I`5rxan5Q)SccmnV3*Z4Y~ z!24!sT#6^~{z)20v-cAoQ1}4eBXK95zy}v=T!$xc`Jo#4=F5Q(;kzY9@g&@<@Zq&0 zk@z{Dz()`ciO=B)Tro}KVmt|tDSWgo5{Y~81g;#=xEW92W5`Dmm*WXswTH%5JPGha z`1lHqFX9P&;$V$8<4Jf_;gjn{B7v}e61aMa2K-zNdHl75;HQ_V( zP6@>IXMk&FXk3OT@Y!88x_A=sjfBsgqHzPBz~|vl0%`Pl;9B^TfS+p#w<&yKKqM02 z`U3F9nHnF!6Zq0z8fW84xL@JR@F#(=eHr-5bd7i630#+IjN(bSL*c847l~`|1g_s- z<3c%p&1impv;{rSh4=CJ#c#uF?ZUDY{xW;980yplVfi%96 zaIeC*;7{UuJb`b+pTs-x1irJI#@Toh?pL^JNF)+S^P7P0F3~`od>6R+Fb%}X&A|7N z4ie!09^pQP?;}1X!2NyT2S;ci?S25<0)B~e@FYB_@I&xRAdY?r{ODMXEARwJb_=rpTy_z1a66@GJyNF;8;6S(U*4ZPzn;I~sW@Xfy^AP*AmZfYQo?goC>uYq^`4!CEL2J+fH z!0%^hAntz;+>7^0T!JU?he;avwm%T?eT4f?&_EpC2mBHKBwmLn;hzfkBR(X)k0H0^C*aTfYalNE4E#lCjN(Z^7zhvGyCuGeC-B!JG(LbQ@ZjDW=i*6tNa1hbm-q>u zz(a^fiBI4O{Cyvd^YJ9WAK~G(8n@sH{A0exm3RXG1fRqOcoGm^!oR>LaVws{Ba1Yy z#S{4VRE;;|2|Su=AgqrP?o;^B3Xw=4Z~q5)Y_7)p@C5$5rv}3MU&4bDsTdLpKf)78 zj?uUpPar*5<03o>4=e0+x=1B%!V}o}XpPJ91Rl4i#yNNr?pN65RFO)+&o02@XKGx9 zC$KB{Bre4hc*10jbMYiRpfCyi61U(9Jn>kKEARv+@2znjo`eS#p0rk^5(w*)fZcjE zK8+`^`@S0RvpeBIg+1U;0^hs`@MMHn;&MEJJ@?c&8&3khlkk-F8n@#K>~(_1wRi$g zJyhcoJPD5~>nGN?t!vfVLrZGgT4UXLN8?qE;n6h_eb3MtW1a5m#>h}>OMiW^ zJMSpsSDx}zq5Fkf=N&b-$cI+;G@Gq0E9>1wt#*AwyEQg4r1<8|wjLucdPW+<2%7f7 zJ})Eh8QHd?H99srZ-#v@lk|*^)<=ex)V1Q)k;b6< zvJMMPfwrgHtqpD**x0VuhWbWEkw7doxw`rF4ULiB`uciXk*sJjngXR1uc$RfSo-_2 z`OVhgCiMX}1$^23c4K6Nq8w-qv_@Un@-*|?t=iCFtNH zY&3Pv(BYq*tJHo>*>jPdqgb$!3hRPqV^mg-_}Lg?1O-~25 ze|h>`pEASQED?25p!A|Kk9^@)ou~4YJSP7`KZ#t~uV^o6ZK=0= zTI%7*?$fEdZwki4!t6E4#IB11WBM2Kl-LtP)h4V-l$y_PbQRjDE@9yY2CF$pUn_ySDj5FC6{p4vYRG^#XKM zyY*~bIFe!q`F?rP&GoCwuv9Imwd=^@giFXWh6rKppn9C}X zT)#vqwA)6l+1k)IGSp~e^t7VZuAwewC13d~a#Z*ZuVF2Ehi+$?I?B(KoL7pA_?S}p zk-0RCZ7Xzcs2=IBcUoiZ!FnbU$$iE_zF$;Bd2HObcH;b-)L^Aa#u3qSo$|4?w@+0U z=n%O6ne-5-0{3W5irg!ec8}(R6*l!^EmJP!pp{ya(3z)DZq=t!uVHqO<$aCs8sAgk zT4}gzT}|>qa-lj$p$5phA(w$wAEsZc)V)LXo^>_MIgAWoAl<29`oe39i}j>I<=pA? z*19#uQ6WSa&F22k9d8WLT_mhOA1v=kev`I`R=J;pg~zH=Fmk zP`O!xNt1=`Ht#a!C?M(^Mn}5S8bN!kvaGAyinJsjX>`%_G|r+949|6;!gI?@aE=0^ z6YF&^`+G5xr-Ywnwc+~8dV6!jYY%c15Mi3D+cUJe(LvK;2O(KGBqxp4+uKmEHusIJ zZ~2b1D&w98Y4j<4!X;m4q$-7Z!=9({WxPqv(?EtUTTYSiq;Q3~hm*#TirsC?*V`E6 z(Ng3<`CWxcWnDpdkqKXc3hq~p)LiY#OGc=WZW}g#dD(H*h_Ao|CdOMU&aM3lK8?)UIe&hc6ulVzbnCK9!t#tS?5$%qAMI4V zy>er{*`!HCMal9)%n3Tv-F7Q8)Z)Gi9caI5h+sQmq15~i2BjIX7RX+#%k%2Q9~q6;W@aP5lS2 zHV>rE)q>XWx)zcu-?gvJ`tnl6au{DaMXWsEHFvcVMR2fd{QGlunON7!p#=FQaD62Asx<} zt0Nx^YNKl8;W|fwlw2(w!fF-^1{aZjQEPClL!_)96pE!gYPf@u-C4 zWPQ`IMnE_9vMxk@Z6R|64>&0w-PN1;TRQ*AYy6!)%?&C@8EZa?feK9nvT8A5k}H}N)da#bXh zje*Oxo(Ml=!)BXTCcvM;3Nx4B?}1u}kHxrT;mFu9n~_FAwSC!Kl@yw_J2QF7f`+%{ zXvr7aW12wL4N<_8qhx-t(C2@acCO{zCF(IR0LG<~OP6X5vA0fxA9{n!ZS<8n+N>{L zj}~c}d?_|2VDg&Rf<;;;cdML1kitb!Qs?+HO@J!@5eK=df*_iYGHpqY-%Jwt-|JEW zg?*H-;nKUD%>I($@Df!zGGgW~WY+EiMmFtj{Yn}AQu{&jGig>wK9pNMp%w-wN162# ze30+Qewq0uR^=FSIpMYNObko?cFz+n+&b7C!KstA$8C? zInGdwtrCjVMvvMb4u^R{%HEW%X>f>Ap10nl~ zc(4^+Ml5>{GWJ&!lvw^Gd`OC;$qB8$qi&?+054XISLXryI2&H6E3bL z&&oXs?>^@!JP~iQa}*>RK|PA<&4not($CJekwNT-lU)}Vjd>c#s3SPmuDkZ#m&spP zj+)qnZ7gCn0db3jKBHwo=Rx-X>{Ak_sEhCr!_42XlM_CnT zTUkGItd4@WY;1U4k;kkX{)Uqqb!-R9r*t~hpCZZEjf5 zZ8!UR{g2~PE^xI14=?&{m9KGNxDJHdGx zUl!Cs>^-*b$!(6gP`#0FVdrHQE(2A@y<8aN$>sYo>Wn{C1s9W9eXdV7=UA*~nrxrM ze5Tbf*8|%|>t4Y&j*S9tX(3Vd;nWUz9+DiL_8~KgsRM1>L+(9|biEC8`KDjp#nSh> zu`ZUqy}}HugF;924oterNpF-W@B4f?T$%}W`$1rd}WdBQ$QX z6H#vH%6th?Sq*cIW`UOo`A#@hV(w0LM0xdW-C9-PKB&&Qdt09yp&FOuz20i{+f^y> znp1j-6I*w*1tS<+D3?y*xedk^&aF~Nx6*on&(efa_j}>iZo4KEh}Wrl-NI8kKh&AX zajnJ9U1pe}Uu)#fWhN112weQDxgh#Xzu&GWiL8R&=-m2!_fR3-!W?O7YcrPXu@RL9 z?cQ*3X)8|+f3*CLe#h~!1RBj2k6f+uMI%ptFK)gL(&e!Cu~UP3(9I*hKo6f7Fk^J! z6)-0veY??WV?Ex!UG>tvVis{D-yqk>bS0t9wRok7i6ptpN!23Gf%B_EL}h~ZPVs^4D zvXOCbHQcqFQC0cZYYVKWz(KCxp!j6{+LGj}WM?8bY-*<0>WNh^mDh*-cktQo?K*=4 zyJR3M9gjS#vhIrfwGeMC)JwJ0y6Pu;8o%vV4xNJB(zbw{au>+S<=8r^iG5}# zBNy8`3tCOSPbv_ypYz*eosC}MHNLGzxkf#brPU^E>T8%gba@8-d~dAXtOl-8J*}$` zQRf-8KkAU6ZOT{Y_zT*p(4TFs)F8zS6?g@b(GW|c+pL>D5>Mt(L2k{$i5HWe6t48# zuD^Vnl{*P$fxTSoCWlE(?yy}+E%s9Gq^;_x-hyb1xG8!=5TUtmu(9g2E9-+}RMY!S zTY(ax5bCEa)!8pFV*9S_M4s|*<(^BwU2rZ< z>!2h{TSH^bI_Bf$em_5{3td}{3|Ec|B7a9us%#pe>VC& zo%NBKK~yY8?A-Cyk5I~gV}O)Hj>QwLux@h(=!)AZJhw~gBOAIK*^F2&vUHIRlTu2$)o{Wv5=oX_4schoXH14KvWM!Q;94OOq+nddZJpo@I z%Tb`lYtqW2-#UfTz7e!Ia>{|XGNIJ{rWEF*!#s^IL$0?OB2VLFyp;;2n3b)!M`}%* z|EWN+Dy~>BH66r4CMNJkPu@4O85@n|a%~uC83l9eHR@S8B#2>CC#vG=%lbNG;n~w1 z-B@EaR48S?u?SH|hb-SQS7!b2qTpz?AE{)1@*Oi*p@p;Z>!j>==3UYidzZ6})o~<0 z&q>w0oF!|TT z^WP#hfoopZ_^wrr)4>#iGMkk%e049tdAh!iox10N^@M$$#bcOI8r6G-xVwy^uS2u; zjY00nN%}f+XyNK+`@2tW6_oqOxK}D3R@g_oXBTcpElS&}Q4@4w-+~~r*A+UDezA)p zaI7Upt9FltZ-gVJFmAC7HHfu?>vB1 z%xbg(Wme28mI9>{2j8nc(0(uF-{5Plh~7azf;U)^)RUDmno*li1EKwihA!(y3CWFF z;ZXBl!58HyvwniF^!?cIQW*{2ZbkG?`e8Qd2PuNC|!aBf6!gaEOxRqD0D!6RS{NWbyp4KX{4;x-jtb_%uy^s-G(V(b#XCpX$%YV8v%xf$TBoJ)9rIV*RPoHAUX%!*k#E>Jo#wOcrNjn{w$%8Z!Thy_X~=4CyUViKjX zejBBi7mtC|x$@%Bx>8cT>ccXGol(hEF=0@e)VdPA$S9awl}BBv&sEV%lXmFZjzEZ$ zv{u&|RL?EN+G}I9Syxku9iF42ZVKPv)hXL^wXD@e8sKYXAC6`F90gAAL4~q%u*OdR z@MZWl(2@fr7e&6z{t8d|$x(PBUf1L(tccYzzHIsW^&MK?@a%U2p|{ZH>WPe)1bQl) zR}~pC6YzqN5tD#g7oXBdq?T{AakGWFDiW&vr`t9)`KShA1~4Fm z`>3p3nqXw+{zK`CdL2g?=|ychxeEy*mBXT(gvQz;`R!AWBc^G=so zISLY~DZzp-$WdnegkR(NQA#Y{+6gR{0)Z5+=+I59^t5q;1?4LYMx0%3p*lx_X+~SK z7OGcZTTW2YJW+qW)?}77d9`-b2`TODlH4)Nrk4toSurmbMcS-f<$YC{inRUpp>}PH zZUbCbA|p17tuhF#+n$ws66$!^4so6)kg<+Ip2m|Exs`I~(%ZJ1`!!h?1-^3`J>MR; zTC$eSQ)5uCxw)KgIEq{q>-}_9_Tt&MC|Bk!i(9k{k+qsR3L`3BPLH`Tx?@y>nHe zkfmC#N(zHBihUXVvcYt|eH%*WM{acW3Xyhi6>zIJ1oLQjBGMOZ;I(mBzLoLo&J0 z>4n{ipm#eBDK_nHNY6vWP0<^I0+jm(<;Hu1-3{qwFX!9S!zc2mUBvc!Q(292jrHeD zy=8Nm%Iz7w^_kP9P+pwEa~qTb=hl`5CGvLu1z+Ro?As~h^3J2)3uVOC9i55bMWrG% zV(U&dvOMD{hgR;n^t$$%np{e`b!mG=L5Qr}y6n&%1aEwyU+NUTTe;-LD`@q#(z(%v zK7t(S`LH>WN%I0J2~;RIA|v_x^;U9`{9*fLItIvrm5~cFgC3Ihbi6;CRgha%5BX>L zWaT7LfnfayPv%_60}S$o+-MUk%*-Oc-ukhXa0r6aG72J<>X#XbL?89oyLUo>kcZiDh zc^c#+J279Zw;CM&iQFo`*p-JOt&@jyWOUeZYcR*9XQIO2s%JJ# zmc-f>4gSL4%GH+6D6P+~$90J8PhYp%>F}r4Z8jcdVc6pT4BV*Zz`Bt?kDTiNJ8IV4 znKS0jnKfgsFQ1`*&YC@I=4|=*+DWfXg}7{TB5v3%5s&Pih!dWii0gqFdnV!oz`jpO z#09_uz-fCW;@iNnPff%pfT?>Y;&s47z|hkYaU0OTPaU zE^s$6uzw2MGH8942rMBD_-J~$DV0h13`@IK>wi#6EO2xco(quVTrg9cmx=Fb|QWR9CtXr z1=#mFiMSZp<%mR#06z!j9hr!0fWu}a;(fs6qY|+dxCa=RnTYQLi)SU`i@@Qt5f)(b z9DEz_FtC1ZB5nodJs0r?OgTCc7Xj(>60sS$A2{WhM0_2X`+R%{u;;OfI0twLIO7Ef zH?ZWmM0^=I;)Mt!u*W=v5x5sPtq0);j-H>0D}j9$B;tJFVPIn~!T~H^h;RUhElR|@ zfL)IVKX4bYY%$&q9M%UNFzE!m8@LxZ`9$Oo;D{xO_%N{lQsfEXA>j07$P>Wq<%zfo zn7$$rmjFATgzpC)0M_;+PXO~)f*+VVfII>0u?lX02Y^#g1_v;AHPQ%}bPB!=xD#0M zqC{K^Ogk0n20RR`eKEod%smb6fypmHngI6z1E=F%z>GCWFJRZTNK4>W;J6yn0GPH8 z-wC9Hi5La$22L5mcLMY3iTE6F_gGGaBFpCZB}wj!;8$AFP-NHgHnv)~_?@zO+G3her_L^Oe)0KG3q_<(6= zBR+vgfHPi!@(V0E2WbQx{7U3wVCQr3PT+Q6@vEQ%rk{tn10DlLUX6GGPB|at066Y7 z$Opib3y{ZwU0;j118xUScpcIOIQsR-qrhGlqKp6!0Bhfnh+BYp7r{TU?;DZFfQNwf z7b6aVd2fOa*!RuQ0gnQsZvj7W$|We{z%g${-2fc?Ht+)v14C~|+5?N;fjkb(d?(TZ znEoz=14!SEZ~(UhCtQj!0#n`t|G*=_8J8vE4xs_ z7I_x92RP+(NE2Yj=Mg4g*K45zZUY9s0Dr*DFCwo4dwmIc5V#*0_%ir_>0d#80i@R< zoWLExlCL5Tf&H&X{sJBa)_)D@3mo%xq#-cn8%RUo0pOGyzyloqO?)4)$BhUxa4&Gm zw~(&D;onA`0qpi2d;@SlFmw~b4lMaDz6Ch!W_$~<>-XRvxDOckKKuhm`~cwtcDn^- z40sS2`XRmvIQB=#55PV@MmYi=2G;%raR8kBQ^XH&#I4{5cKI3N2e<=R{Bwj8nEDHZ z6L<(1x(#^^So}+*F);0R8gSfQ za05*FE#3`03N-J=Hv#>>gBxJcJ%~48#_#d{z?6HD=YUCn!25tZffMe-Hv&`sh_)K| zC$Rp0lvUuEKfxcc|DW+4fcOj25V#Fk^Z?=%IO4BJdtmPeQEvec0qg&UdIUJ`A=IV7 zK7U8N0S^IdA4Z%4^Z$V|4($C;q%-hOVEw-kH^8DtP)`C=|Bbu~q>q9ZxDQzIAH+8> z_c7GHz@GmFFYq8Rq^@Td$0Vt^8aOyj#YMow!09`s;wIqeol|i+u;=4aaSm`laOy75 z0W%+;imQNwcTL5mz~m>S;#}YX;PgqUxCJ=&iK(~(*n4s+&I29<);!UMg#rQ*}T zzPm#QJP54a1MdcoelmE0J@-t-*}wz9`lqDgcHo4)QgJPC=u=a13GgVeesAyr$386; zR|5O&lZp#~M}hX!Q*keF+PRxKNaT#j{s*pBNev+CrnAjjlkRk;0D-x zYAP-S{t2u*5dMLqr{UXx-JY3>mjMp|>!u@2z_ABG2TVRV6@S`nricT?RB@n~CY~v#i-W|$;t+ADc$PR!JX;(to+FMBM~WHZC^1va60^k|F;_fS z94($FjuFon$BGw-mPQW#Z-HZ1DuUr_=)(bxK;d2{9OD(+$Mf0ZWq52 zcZgq$JH>CrUE;UmZt**DkNCZ~SNuWTC;lkz7k?6e7Jm^Bh`)*l#oxq3;_u>N@elD& z@h|a+__uge{6{<{{wqY1Bx$l!vUBpdWS8Xe$*##0l1a%ElgY`GlHHQslRc6rCwnGO zN%l&fn(UoCE!ih|da`e_U$TGljATl3Kr%HsFqxJ-Gnt+olpLHKk{p^mD>*EAc5-;~ zoaBh)$Ye%xR5CM}mCR1&By*GJCPydFOO8pNpB$UKAUQ61VKOi2N#-XDlHO!tvM4z| zS)BAGCnP5(OOmC@vSfL(A~`APPgW)a$*Sb!WOZ^%@}lI_Sh6|Ul59=3C1)isOT`9Si)i$f zQ^}{3&m`9*pG`iOd_K80`9ku=Rwomi#>VMRHs6%jEXtSIHg8uai5I-z0Y> zzfJB=ewW;n{64ui`9pGF^2g-<9w;IQd8N&*WdpBgwy$ zN0a{~k0q#h(C@AF)BV!@(`Tep(gV_|>4E9A^qJ}O^q}^jYa)>9f8x~iIwzf*J~ur&eO`J@`uz0R^abg0=?l|&X-_&oU6A&s3)4mE@#*5UFFheW zFfur=~AXPfK5to}R8r*QT{}T{@T!rS)`u zx*^?|HqtZFO=&Y7PDj#KI+~uDw$o19O~=yB>6UbBx-C5`eQEl#^yTT<=_}H6(pRSE zrmsp75&u^Q{$CyVe|6yh)q(%t)`91xuTIZTUz1*tzBc85?B|Xh17PIqBh4uYPYBpC+miCNnQ|HZMRu-ow$Q{9CcPQUv zf2(Qbo;H>pHq^;XrZK4AA2_;_8`ZWMIk7F@JRj>iFa`_nvyozZ_00SxY?GBA zOsUVu^zR1sVyr!@i^J!)u?97WZF_1B+02vEEONd|*-Yl^Xi0+BR*ST1dvd-OI&jhk zXxI+I&>t({G_CIm$n6 zNwG-;`DGg^aqQ_Jur_SS`#SIkpi!6`BBY!#5GU&`u{qLWL^8)&(H~Jx6 zqL7eF`fV8oTCj?=PUSCWiAk=lNG%{(k$r@r}sx6edeblZ=5DHp0L}L*{Mlkaint7BpKh zU@@DfX{Aa^*iIAqTjfbwA!9$;7D&3+UM{cK+cg{&fV~-XW`<0@9F2}`XpGe-`R}7s zDpYyIFIgi}-f4}ExLx4tcpQ0BuexVBOG`Obh}cnZ+LBAl?R~;3oye&b*%TV*1=H}14VU~LX-MR$d5HMUYICwmA1S0} zVWqtk+Bh{wt>^@iE|p9b8Ms6J;l(N%$=vIj;S?&j%R*LK5RT(!W%Pqky{o2P#;X0T zBZXaQtm*~$koQB8AN{3ymmI^{_^vC4LshoCk8mRU9sK@5nf*jQNI=tf|zQq?IH z4&~G}FIr%#dHqvbOip)C(^Jg((3Zud+xS#6>e}h zt?ZBlGTF8x-M#y2-EVVAj!tmv&d7DLTRHz7-t(%98@r#?yv5wQr+Ae=(+%=vItxUv zZlzl}v$wR8l+4bk%9Pm~zwMo?q?A@Zrk$1ody}gDg+gs_O(mhs3Fd9|1FaL?gGxHe z7W37Wr}UGW06KV!@|F3inj-qCHd)IGK>wof(>TCrWxtmFRx!Q(n?zMr>-Ex<$lpw? zWIFGnVt6!@`I6-xZzU1LAlqbz$nuYCU>KdfWRnB{><@XvU85geJ|=beM=-clfUFEb#SyG za4$Q3L=|Btk>A5E z9;9A9`-u{T%puzuJFSqpa}d1&&mU7ZrJ zv6U9cX&>43Lb7m~D#`(;cNPTc7`xVu^By=(6}`ue9I643P8|6|cE$7;O99!*sNcN{ z>>o7DREgu&L^MReYjwNK?@S|U@eOE7OT%De1?wcL#;3N!mmz|*EPF#4TyF2qF*vb@ zjmj{qv<)v0gEMNbmr9-X5D@C&1(t_>ZUC5x-h3;oe+XyDcMJXMKM6|NFyC6o(P zJ)m4DD_mWSxV5bc47=rpnAnXj>}T;6Ey@wf#nSrrZ(M<6XSTIaUd3Xwdd5PR90xa} zkceM^g5S!@!gh3=L>qCEp!n{RBCY)@=hs@%>P(=sv5IN+Bd-Qh8rx#3pRDdt0^T)o z5|dYz#J`5aG`o2^)$2#t@|3oTQA*EL)_O6cIww%(Bm8&q)fd(kHEHaIiyXNeO?&d- z`&72jWnW!JVV&EqSa7EVENS!|6FK)pZ1?U5+^YZvn1#sbXZJG5*#P!ie!IPeK~^&M zm-0J|V?R2r5sYIoqon54RIF10^{z&s+R78CUOY02cUOYDeL%Gu?zg-Dz?Z2C-^o#mDq3y*rSfevj*< z{ot&7nMnR2_bQQnnM&&1gYSdG?Q_nt=f~B%!|8*==;bNy)?^=P>CT-u2fR~5X#Q3+ z6Y>ywBQo};%vHh3@7q7roldc4%Pt)meiE|d+1*d8RYMFJfuvPGX$ixgubvglS+PtdCw7O8A%|qdD&sh@s!QD&&H8J`b2>9S zJK40YOyn8`>TBy?lxYi3G*bZ8L|4j?VrcX zj?PsH$OI}k(E^oDb@kCqpgx)e!RfdpQk|8IS5K^8Kt_=|p(!*ur^~8?5popj6om1g zG25SifNWN*`i)t+irH}-=xPQsa(0bME7CNO$pYxf0*N;P7QDgJdH%9y-X<`m4>vU* zXU2o-)oRYz=yFadH7b>;HV?2E@HG1CqX&fsr-Hh3JZ0tVe#(*<9_u--b2`-s5u+2@ zA)tQfOiA?z7obX^g+n_25c7A`+q6NHPBU^Um(1ZEW+ zr5CZAqfqrWQ@CoLg6UqZ<#6xIRT(9R-f51iGRTOHYkx*vewv;3HovxWI3w0d?98;v zz+9rrp^@+-f$Zc;{Fp@Ys%Coi_t=SD8UDNz4&jCBZ|@XClKE#9I*Fd8m088OaxsvOn=-iE25Pes<3XvAe=_#r{@lHKQroOId7L44f2{KiHbz5m( zA!os;p;7K~4wi$0dM5T5Is8`TUj|wgK`lX3C%bdjiJD?k^+0&g8#(e0bW;LEoz99X zT$$+~IHTf;d#YvWFPg=PX>DBR%;M;{KxEm0m97PJvz(VTRMbWfF2iRlSKh>mlOpO= zWuu)HpDJeksN$odNxhpFeI?o6ptdJ)?_`y&exxXVgyDCqkg6!rW?b%bFNOi8pb6ylb87g+>(>P9Y!tS(j zoy#P5vE?1Ul&4VbN1g^TfttW-g42>k-v%3SMY*^VGpflj~uQ+>j7d)(eI%qw~)^w?u`=$;jnPy1U;_6*e#G-@VCAAw^}rO~@l?AnD@ct_df9aj@Oe+Cr+EuE=SqG|;irmLB2 z_uHKzgSpP-{R3-y7p`2;-?w65dHZPjy~7J_#+1aoJTxc?Kv0Ar(}jTp-}FIaV;pVmaF{X8`(H- zQmYoz7Bf?uhyz}>@qRRo$VtZR#`<$&`AN38z=!H~o5@GkJVBQ=#IbKA75`A`>suu@ z8d#$oF0}JnE_;F{*FeX5b2d4=%Szq?V;$=w&t%6cX>%Z1-ZTd5tdEV?(LzVh(B?)5 za@&K3Tw38^)?~AqFv_T?1$U-AmWLVd@cO~L&@7mGnFBR$PTFCPBiF>oQo(^6%=sT5 zn)_Hk7`xi&V~Jr+eZ07~Qm+UyqaQDXOwKDm%sq1JpMZd?0v5AiLH%1Ex~!3q4joqn z?+OiujE^QJTI3umOZs|S?_bMV6*2xgMJ7a^18Yd+OYM}kC-xg>G;u^Bzs;4}(7;H) zAYx_|bK#|uc}J#Y^No>wKie@sGUT1n8jgFn>mM#WFu`CN)Ly_}`Xck6tTB`I;F&ZzsWohJ zBG0^uiLH@SAVbw>O`V)d=2ACDL0?BA^h(I=$+@G9tBs$WP%d?#n_znupFeLr7?|iOlpqVRkER(lyWH-2kgMsb$C?MNI{@w4p#T*sj9(ttJ$Q` zxmrVMRKLYFi3{_Ls5Cb>rLrPf-fi^2doW=Fi8Zb=o^njAm@3E6%4u~+T79-!63!^K z(N$KC{A?S=g)lzSqjSB!%NX9Bj=To=Yh8-q+q6F?lqwSnbj~eGA8p@)opEn zx62L%EmztIAR(fL8J4;C7`dNIxesZmX!9@E@Ct&E8*k-|F#hS!f2BfrqNh5cjF^{v}LL)h=pe~M# zbsoIXV9vRwZ9lSG<3*}(JZD{F9|#o*9UHtbGEI;jY0o2>lY8}m*-+w4i8u#4txHY? z@R0aERl(&sDXV8)btI0_7k`s6xwBtHGXknQR!4hrI?{ROcg)xJF1*CoQ1DE7;;;3` zQgEpIsCGk$r6EOuah~rcG|}_4;iel;naNGWNhQb{?fK53>Ff2X2jhX>6ci(_;?1oN zGttONUay3aCzXI+C85O5u+RIf>}-alkVbu(Z_1kbv3E%&wQRhk>JcODo5_=hL38$g ztV=>43l8}mW#MHvxViQKD2Ie}k1g8=tu4GOIvqqAm(SxsPE7;zA! zt9`e8gRH!~9BOu|)`xtTd_05CSG&J3YE$K%SG0U%SXNHClGm2XwKGGsAqk8ToqTK^ zl_LKo%rMb8)Iw{X$TcXmd2f+oYpQ5HxJ^I{rCnmse+|_^FE+D#&Am4;VRQ;^$Y`a3 zIb$f-MvYEfY}y!i6MR2Si>jFv&&<)jLl;S&s!BwY9w_zB=sNHc^r@7mOkJ+T+3vEF z`}L5L=NLo=?7jqcc#8N4_cT3B;Rm?YRqtI)_&y<%|#OE>-%pE(AX$}KhsA!@K` ziM2jf#u6Mdxkw;g+9rTWS?D3fq(tVOO2*$AHO1!mx>#=bq9YmFuyX6XhF zIYy$!vl<23X?t5+23~kJ%rzS|@3R9h&c1jIM@Ecl+d8hGF;`=dOJwus3QUL6&hGCv zB&aOx4rtG`lsUj2PySw2zo;2pX=ds>WyYqyf|;Be#i^~Iv^HVnfk^Eel6zO>If1SAHrJEfo>8oN5o}jgS@vr?&&ZWUpeOey z4+9l%k3AKOMaWeFQ)jNQ#dnz!Xf7yhY9FqPPhIO6BU&8}wSya-4xS*!X=^Ket6THo za^Au?c}@<=Dp?+JN@sy(6F8#;XO5D$fT8KF4rO3~You7WZ?#!m*`|+K-UbP*2EOD+ zC4tL0fnl!ZC^Eq1v0CH?vx_e7b4+y=1h%vEn)uoV`6)05 zw*gSqub0_))NkaHnaw>$pw$fr}IPTuFv2JeB@uI*t zB6rTWbr8|240&l+FeQ&KqDoAemD{(t`ELq98%Bbv)5!yp>n2ED=f=*Xd-03b#!j|) zb*P>U(`$>EF`8mfy?>CExH}f2Yj)a{qB){$8x-5$M*mtSP+m=qdPM zAk^_fxgPCULPqvs{i>ak-Vb(fsMblJmc!>+Bhp$~#+<=o(2eQHL9aN5}Q zjqi2U?lek!MmCd@E(6ryS#c^##_FU+~(#sG3bqrOG4U^$X>!teaS~ z#S zi}@4pw=YrU+5VL8dh}XBZ4DUbXDRHN8CpJwl0(7-}|;oJ#+Wnl*RkjJb1W z&6q2H+W%(gzh*zr{Izz{l4K|Gt}RENGzr(q?<(ZKr*_RjJwL| z-y|2PL&Q_|csxY(I{G&W*zY}iE^T1%ey6p*JN3~1XH8wwx9miz4gMo8@<=bB8`0^n zJ@7xSN5@}|1Ya=N8Xm=`?)RQc#eZ>$wxS~+^pCzR6(+>>#8Tf`Zs!U}fn`guEm93f2HHFTVt)GBF zrEq?%MatG36H$~8sci9otZdCTa&mWz`JtZ^8N1_&(fz?YQMqu=b4~TN7UiDG<&uQz ztAk|NCP!|uWo4UHCgV%RIWzNFr-C&>{grz|E+ce*j+1Y8KHoI(rFnelMxhyVH0;lD zGMd6Y)sNRhz_^oSEIzV^(Uy)`Td4%RR0?;Nyx~DOmDpzG$LrI;_Bh36kJqWhQ;_BinL2~9DTU3cLQu-zl zWBy@CjMDu%zS1|lAYPx2Fh0>T8iPUi_VVpfjA^oD;^#J1VVZMPeqNz|&XXh)?L1fg zc5~f!CBCEc`3?r(Zi){h$=oxh7_Iwrd?`04Qg7~F%qrJ#9as5uoLdmP&q8STDCVVM zAf_{R6!Vi~%yJp03Ue&3_bg_Xt6NogXBXrw>eoDlcxfGr9|*?C+@IsiPqFrJuM8JW zYdD7TxhTf=)C?QV6;xrHV}_YQTR#QyxVK>=+Y5J5J)?7fjxQ!-_0Q7`o2q_j{h@M+ zjPdQ0<*S@4=R{hmrz^g^BjH>$va}p$j7HLLU&g2+RnD$fVJm18sjso0WRpk0Sz8=) zcpalG-5ZUKF7|hv!C`e(OX1vtcs&#$eMTXxtjcGwL}Y)CFFj+tQzE=!)^#yHKHgX? zA5h3!wf31E>61@&thBmXxh{xt9q4m~ky$#=#(H$qG?zOR(WTYIwieIynAFa`YOO`A zZJM58tDHLuY8&c-ALOyo?0BVEEU35l0n@>TiCRIL#%DzC&+(PASROot^T>6~nVhP8 z9*l(PP|g)ZUgL3aJFI!kH%$*=KdUCu8*~jb1a+O zDuzu*v@Gcu{s$$xpx&kV=(!%7cZx5gbbpR7e6bn#=UT?#XkbUeLOV`AvrH3=O{XJ- zM=QSUfxUSQeWCaFqX1$lE{od-Y%(cHTVAA$3K4JM6meG%T1|qZ#KD9G9-9!=;glWIHj# zhKZj_Vkr{iuMt#^m&c(c-6j5K?$7-#sSA@FKfVrpVu6_NFHZijqt6?;lqfx5?`#JaWdm0 z+b55xbk8X^wqEU+_&pXb^2(R_g0*$pxp0bOQyp%a0i5k+%<`d&@VzL@hh(eBS5U)H zZ|c;L&zZG*)0{4P$C)=HoG&im47V$l=8TLjP9sj-+>n3eh+~@A{>@7aE5FEuk-0y| z7pt+h;&j91ZbxyiFJC4i>9^&|O7-R8SGmP$Xm z8f~4=B#%Y(2WpOZeEB4{Z*S1B$>9u{2rGM(pt&tyt3`SjLmsC(a)(`xnb8dyE}3~MjWc3%LK`)oG6FK@{K2$n`J5B! z$22r!<{Bdxjpg%9q@Fp0@$r1>Z-sK?$G7SYyhbUKl{#EX$lXuZ~cQZ?LiR=TmOnZ`^ZRQj5C_E@BD5>`52AxZO-zAQzNDMV)K++G#{p$?Tu?L z#r_BNN~9;TRdeBdg1md&7_IwroOveF_HA>ltE|~@(Abvdi;$5J4I|Y|x zR$z_Q(ywK#=EhA%Rk}39#_6x)T;}XEM&|w;U(FKBFRy1@*#-ZJWV(+YCs)>||;zpggedS5;dMdJ379KNc1Ph)lHTP2^pA~#(8 zFCVtZ9M9W)F7GN|mV6V+`SyIy%K0@Gr|A^y}o=M8kx;{uV%_# zXUzyp=aN_ne4k;YYgTarW^nvTd9H%iiLA2TZ@A3W+bmG-&vB+#K_8oTzkR^)@cX{wSD&&JB}hdB>+ zC*i&+7Yz32I71X!5&DQ>q7J;ed3^^lU16By@yAv7BgJCxqaM?a+=+ChVN$2UR-EyU z)kz=YOw?-m8$3&wsu#u7X}2*}s0Ab5-u^#6tB6Vp=$ai^@la)a;j6 zsLF?`pnpS_ZJ(4}!=v48_6UI;xJ&J7$u>ee#0!kFT#+7MjS=h9e9EzT#{)Z#^6Me7 zbo;d9(?kD?>sXOhkk2TtA)JrSC-=PU@4`90xSSnnPp&b1a=O7^pexN&5U#zEA3v*k za1r9VYRjT zJ$!w@iS_X=4tdLDAICqw`Z=~T@wEcZ?6ko|vVOggHB8jftdaQrMgePBV9IjFMv6BW zPISmdk&@L~_Sg!-H$5hqeqJ?DI#iLd_KgA8j*P)?d0c_1UitD@(CU&M%eM`ax>6*+ zp(xK-&^sdQ|L+(^#igwU!faADCCZOGix;KD96VW8y|d6@@yS!jt$lIJ?`=*0mtz_7#~DR+xHb8#&z;Q{tl)~c32$# zfVdVlnkowYj)V)}_~I~@D{fIdBSR`oLB&{_DKb+1q0f|U*h-h^Sa0k{AzRp>m1iqx z(P+2xkA1csSc-olnQ(L3MwMU{b6_O5|1@AiZm%{vE$GeC+{~?#i{^06^*t`7zd znPRH5%M2@(;n>ckpA#20!1oMx8=LiQJ^tj33*|UVa-@9y!mu^FFyWUQe=E)s#=>@6 zhAmu@EgQBN+b=V0;RIe;wpg8byI~s{taoswakVlQYr%eHm^#}=25~)*oUrzbS^0V@ zQqJzse6-v&)~@@Ru{2X`z2w)H2{%Hz%Ob1I2t{h(J2@X+epjuoij=e87$&;Dl8Ra7 zS%p{*xhrJL4k*f}TV&n(w^_b$P*IvM)=u9Y@>OSxv}wQNZ0c^mO0|D%9C%O2Rkc?T z$&~>W5er0;_@jQnVb1*$gJ;N_8Ru`jFCO?4;seS z@VeIg)>hfG^{RlfF&mq^_?ux?Pg!EpJ=5+7n_0qx8tH)y!}B{d8SBj=uw}k zPu-5`N>uq7g;*~6kI$yBe6P3)7wMrtmgPg+R*^4~EB|Zwg6rwMsNbS~`nFRF(lHsEH`&SXjWx`< zXI1C@BV+KLH5+YN%m%Dt&R(Y_XpDE}TtG(d;m;$7`+= z=Pzgt)mPBzrj@v2xp7y+Ro_NEb6s$9%VB2Wj?~1vMG|pD2pnau&=94uW9hallCghQWK4JOrMN0mj zjIodE?CgN2G+*re)~8s$ZS{8DtZjC??Z&#XZav&QR5os7b7OlM=0>M$2CLOd$LxZA zgS6Z7shX|2O>C?eu{UGE#(kM~euuMc494a*p2pY~Y{X>~OKa^-y^Z1eNCy@&RYyay zy=MDxW>|R89e(xZXx~uPk`dW?@^r?Dy}-4xW>=1m{9$d`_>HxS`!dD}=%qzU{eGMY zL%s#*Vs|UXWvrjJf53;~Y_-;~pyW+O$$Lh~r51v`VOZHzi}f(3VzS4Y=v^yZ+ zQ|t0x@JiR%v9z1Y_*83KtpvpCvjaUYy1#cvu3b;duvK2WF6b}OYRNM#Tc?A;L-qZ@ zk-BTT&$V!Cw_TGpN~IA?ESDVQGtyLMHLl1k(!oC009qiQtbG2Dq}w4rTUfM9bH(!i zp@yr4>BW|8&nxcxim^Q_%T{qEG&V9i%(9_2T-w@PU(srebZM)ezZs@{NX+)?f9998?p*=D2>FPqZyZv)<>+Z*@VoA$JS$x z(5yHu1S_(B=b>yG#(JGc8lHBe)ow6rI<<1?cO=TEWWh=h-BB>ZGPkhZsG~c96EcGk zVLi%cRq03#FIk~it5XYdEzRuCbgZL6l~X!SWA_lvVmv`*Q=TW%M$FbcIB#>TPO&!@ zY&7CWbSj%G6_tI<7%SnTyXO63_Ny}-Evque&&SES|nBDwOpAzyuSW3Wzrim)S7 zw(Q4jZ;mcx4V&T8tdaWkdAY1|4zFU0#?B}@#<12mV1|MwM@(+g7GyzoDjnj;nCbbN z+Zyw#nFMdbxh!97F6LN|FNdsj-i@uLzQALnuBkWpEX@_`Qyu4V_18wQOi*n`CKit` zG;AB|&E~|k_yxTw+6z9mCcE<`Q-Tl)BN^W zXQNM7I)B8*NedhwdWG3&oXD{C23(kA9jx367OXPLoANXty1eV^L$qjxfhYQgmB;WA z&P4^BRY&r%JafF^+=weJa87{SgHkci#OjpAhOg0W*3C4pSNO{2npkbwXV~n%8n5t` zFAb4i+6kIV+lbW%yFnvYo~@t{L+2lz=(E8h&2P@j#$s&Lvcz!VAZ>L#7PWG;)e_zK zut1a!WsG@gj5#b8rI};vkjpa6E9-+}G-eBi_@!B6W0HNcN^u$Mx2*KIa<==I&moaoW+1~>b>tb_>AcEgTiO~L zYt~^dTBr5+pu#B~%Gk-xCr5Zgql3~lUBL?Zp{P|?M|i_cBxQMHWA0Nt-WAQ-U>z%w z-HLttSl{hM9^(YqAQX&2X|>=~pR2O8 z7_-m}@JljmOX?#Vx*IE>z#HK_y@0dwzL-d?uE}s#E_($vDxHtL)@PIbU^-6?v!qy) z_nM8;bzH0j);!*<$x+#y6YB@BlU(f@Oh45^q<;Wo`EW%_`=HOYIymgHJXgWmAe}Zk zL|ls-Lv?lFz1O)f8-KA{rLK6IjV?Qp&ReD~%NE_9S9CaHD3DcSgxjd5Kj%S447PBjBo9SH;rm49$hpn|5$oZSt6^rd4dz)s#%b zqxE*DHB#%=arLXZt~760QaRa_XYcWF|t@(4XPe{`nLMa#qCB1-8T660%U`NHLs(tNRctK;+S&^d>$ z;=+2#NUe#=Ullj%RaPBq#m28=mbHU9tBJ^)v6ghRV%uD6Hiq(xLg|*Ypl?U#)@}*d zGSg(`^Gc*O-KyD8?y>`_@=TEuzD+W97Hq7wdzzygYn4X;1$`_!wd|~b3&y{7Ouh${ zWm7F?G4;}X#-JH5%NQ%=FAEq0stHZImpiT{tu6I-5Rntgb#}nDBg6Fy$F*t{eTN+x zu5$ve%Hb+lPo~}PuQXhZW-uHqn*(Egu5&eue^PGG=31j!!#UVHa7E@-in&*s1Djr# zH|#AN&RF|>UJhH;5l)Qn)j51s`_8eMyz@0*bHn_xZnrfeZ42r_#wlOM3sw#3RJhkD zMr-WpXO+@v7wIuypqLhqVJq{fF;w@4ab?+JyQ^NS*vQPYG3W=XeEb#cK6)zR?{$ht zE?;|rDbEr~rPnJK>K81ebM*ZHm5sO9KBEg26FQFzH)9TYajUhdZ=}<$HJiwWUI5Fo z#!~AImUXDL#iuD9kFoyaMVx1$yd$7usA6nyM*K4aB%D;N{fy!*Qi6SdA2Q!Q3^T*`T> zh9^?C-eY-&r8$#-LC{2|(PbVJrjshQ$gv#%Uc-bFKiP2s6;mt5_`ZC`s_7QVhwnFx zYM!&&s3lU@e}MCtD|D;Y9TC0{=J8dnIU@0RIp?dIUXgjL4;db_4(V?vF5mBnaDCY4 zsys^^>vMlZaSd+5G7wC8{BwS)mGFX*%K@l`uQ04?qF8M_^t-2}V>H%3{ix+@wKq+O z6;Esr(3OgsT6=Gap@wuv(g-HMXI>jXqK48^lB^$(8&+MxKU-h0ttZltMU{kG7wH{flE%=(^ zvzMDxD{Zk=xUWm5&W6>s2KD2Y;+&+$XtS=2UOH9l>R7My8&T%!z0O$fxq-NswYn&U zX4N2Q1WUKKkzEqsB(~-CVY-N9ur}g1?4^4xvAuaWYNmmf+$iB^(9%q?82pyUL>BW^ ztrTKx-_EdA?%77t>pLD>)n09^oZlpw*01l>^R^+C&V!MChToM;{D=`h8%`wG&4x=G zSB4$TiRAiTz!f&$rMU{m1a!*A_YD_~&i&{sU$!D`=?^RqKZduOwPUQ0cZ=au&6=L) zs9c^SeY_v$GFC3rk#We6h;c=2a8qyZ!X^&AsSQ`&VHlZ-`>|rf2}u)UUmTl3`HAGJ z*Ei{%Ea3pFbP0&mB0mkd!Y<`Ra@{JqS{>}@%{_8$BDsDRa8<2EVr|*a4cAFy4HGuM zGASFfSlRxCVN>U#Pf%RO7;npEtQw=San3I#Bg}mC{^6=6J9ZA*?V4*dw({b9gm!JP zORWKx-Dg!B>lCcj(a8+ID&T~nQ6W#3#R%?^TlHG z_ZhybY%xpwdwsUXs9dsF#{yQ4)qpln`=F+Jp%VC=smcT@h|X9_0JN{6W+C(=0^4=bk8CKgka z@odFhAF&1ahvLHLyD0>JDYJCQ3R)?$y~-Yh-R_*IdTRVT`oxPf(2d)~<=@wZ~RzCuug* zi>=saiPY9lv`p=KcYd=mvPoXI;SrYZwG@&Slml<_14#oZCKcDx7thUo9oRTI2ZX; z%h=hp8oh_n8V)?D$QLVddmBF0o!-HBO+U?N%RAPveELOpGw+k-t6ZbR^2^f=UvSs7 zR~Sl%FlKAJuVz$tO;_WI^-lJ)JpWrZDEn(hV`N6#B?1%a@-Z1{>7Jqa=vGl#)G>~& zRzJsX_?%+dcE}B%1$`Adb>sleET_S|0G6$#W4-mMjAem$3baRAIt62S^gzb>zjGJm zG{#u{Ea+I+p2?Xo@1ab!!;Pb*Q?MYPOhrDK9xzh)s_rn0%|INK!&iAMQqW%^tAc|q zpPbQ@n+#+cdX;GD7>$g64)Gb~rAvO(UY0F3*LbLA(>ITK#jY$*Y(?f-hDV)j`@eMm z*I_=Z8cG_=!AdC@i_>R2R!r^AyTItpJfcPOX-pjY3CP9wvDKu zakX^Co26r`XnmF^XJWs6ibdk@1jDp^%Se4_MQe0yG`NJcbo@nXk`oP^z0Nfl(3K8b zEEbm-HofRst!m(ZPiNc6V71~TiIN1T8BDq>Uoxw(<>In(4y7@(nht5N&ILi^)^>(UaGUxqP zWhyA&v}5JJ`(32+oRRsPL7#I%cF@O0twY4OYGk7_jL9jE@0UxqK*;UbS78G1fk8P>i^eI;VqMJ}x7(Qq7w>KAqhP?6Z76zG`J4B}BLdCSumN0(kQ4@>n|8&t)4=f55s=sE|NEK@Yo=Tpn zBsmOKB|vM~3h=kr?(B!1gLb%nqW(K54?4JPm1j-5j=Rwevtmf-P$A`<7mMQ_7 fNLlYPsu8$vzfo@avYd<)Xn1P_L;4{k_qF>E%tUp! diff --git a/build/win/install-build-deps.py b/build/win/install-build-deps.py deleted file mode 100755 index d9e50b6e7e..0000000000 --- a/build/win/install-build-deps.py +++ /dev/null @@ -1,47 +0,0 @@ -#!/usr/bin/env python -# Copyright (c) 2012 The Chromium Authors. All rights reserved. -# Use of this source code is governed by a BSD-style license that can be -# found in the LICENSE file. - -import shutil -import sys -import os - -def patch_msbuild(): - """VS2010 MSBuild has a ULDI bug that we patch here. See http://goo.gl/Pn8tj. - """ - source_path = os.path.join(os.environ['ProgramFiles(x86)'], - "MSBuild", - "Microsoft.Cpp", - "v4.0", - "Microsoft.CppBuild.targets") - backup_path = source_path + ".backup" - if not os.path.exists(backup_path): - try: - print "Backing up %s..." % source_path - shutil.copyfile(source_path, backup_path) - except IOError: - print "Could not back up %s to %s. Run as Administrator?" % ( - source_path, backup_path) - return 1 - - source = open(source_path).read() - base = ('''' - replace = base + ''' Condition="'$(ConfigurationType)'=='StaticLibrary'">''' - result = source.replace(find, replace) - - if result != source: - open(source_path, "w").write(result) - print "Patched %s." % source_path - return 0 - - -def main(): - return patch_msbuild() - - -if __name__ == "__main__": - sys.exit(main()) diff --git a/build/win/setup_cygwin_mount.py b/build/win/setup_cygwin_mount.py deleted file mode 100644 index d68a3af41d..0000000000 --- a/build/win/setup_cygwin_mount.py +++ /dev/null @@ -1,20 +0,0 @@ -# Copyright (c) 2012 The Chromium Authors. All rights reserved. -# Use of this source code is governed by a BSD-style license that can be -# found in the LICENSE file. - -import os -import sys - -def main(): - if len(sys.argv) != 2 or sys.argv[1] != '--win-only': - return 1 - if sys.platform in ('win32', 'cygwin'): - self_dir = os.path.dirname(sys.argv[0]) - mount_path = os.path.join(self_dir, "../../third_party/cygwin") - batch_path = os.path.join(mount_path, "setup_mount.bat") - return os.system(os.path.normpath(batch_path) + ">nul") - return 0 - - -if __name__ == "__main__": - sys.exit(main()) diff --git a/build/win_precompile.gypi b/build/win_precompile.gypi deleted file mode 100644 index fb86076666..0000000000 --- a/build/win_precompile.gypi +++ /dev/null @@ -1,20 +0,0 @@ -# Copyright (c) 2011 The Chromium Authors. All rights reserved. -# Use of this source code is governed by a BSD-style license that can be -# found in the LICENSE file. - -# Include this file to make targets in your .gyp use the default -# precompiled header on Windows, in debug builds only as the official -# builders blow up (out of memory) if precompiled headers are used for -# release builds. - -{ - 'conditions': [ - ['OS=="win" and chromium_win_pch==1', { - 'target_defaults': { - 'msvs_precompiled_header': '<(DEPTH)/build/precompile.h', - 'msvs_precompiled_source': '<(DEPTH)/build/precompile.cc', - 'sources': ['<(DEPTH)/build/precompile.cc'], - } - }], - ], -}

- * It keeps all state in memory, and there is no difference between apply() and commit(). - */ -public class InMemorySharedPreferences implements SharedPreferences { - - // Guarded on its own monitor. - private final Map mData; - - public InMemorySharedPreferences() { - mData = new HashMap(); - } - - public InMemorySharedPreferences(Map data) { - mData = data; - } - - @Override - public Map getAll() { - synchronized (mData) { - return Collections.unmodifiableMap(mData); - } - } - - @Override - public String getString(String key, String defValue) { - synchronized (mData) { - if (mData.containsKey(key)) { - return (String) mData.get(key); - } - } - return defValue; - } - - @SuppressWarnings("unchecked") - @Override - public Set getStringSet(String key, Set defValues) { - synchronized (mData) { - if (mData.containsKey(key)) { - return Collections.unmodifiableSet((Set) mData.get(key)); - } - } - return defValues; - } - - @Override - public int getInt(String key, int defValue) { - synchronized (mData) { - if (mData.containsKey(key)) { - return (Integer) mData.get(key); - } - } - return defValue; - } - - @Override - public long getLong(String key, long defValue) { - synchronized (mData) { - if (mData.containsKey(key)) { - return (Long) mData.get(key); - } - } - return defValue; - } - - @Override - public float getFloat(String key, float defValue) { - synchronized (mData) { - if (mData.containsKey(key)) { - return (Float) mData.get(key); - } - } - return defValue; - } - - @Override - public boolean getBoolean(String key, boolean defValue) { - synchronized (mData) { - if (mData.containsKey(key)) { - return (Boolean) mData.get(key); - } - } - return defValue; - } - - @Override - public boolean contains(String key) { - synchronized (mData) { - return mData.containsKey(key); - } - } - - @Override - public SharedPreferences.Editor edit() { - return new InMemoryEditor(); - } - - @Override - public void registerOnSharedPreferenceChangeListener( - SharedPreferences.OnSharedPreferenceChangeListener - listener) { - throw new UnsupportedOperationException(); - } - - @Override - public void unregisterOnSharedPreferenceChangeListener( - SharedPreferences.OnSharedPreferenceChangeListener listener) { - throw new UnsupportedOperationException(); - } - - private class InMemoryEditor implements SharedPreferences.Editor { - - // All guarded by |mChanges| - private boolean mClearCalled; - private volatile boolean mApplyCalled; - private final Map mChanges = new HashMap(); - - @Override - public SharedPreferences.Editor putString(String key, String value) { - synchronized (mChanges) { - if (mApplyCalled) throw new IllegalStateException(); - mChanges.put(key, value); - return this; - } - } - - @Override - public SharedPreferences.Editor putStringSet(String key, Set values) { - synchronized (mChanges) { - if (mApplyCalled) throw new IllegalStateException(); - mChanges.put(key, values); - return this; - } - } - - @Override - public SharedPreferences.Editor putInt(String key, int value) { - synchronized (mChanges) { - if (mApplyCalled) throw new IllegalStateException(); - mChanges.put(key, value); - return this; - } - } - - @Override - public SharedPreferences.Editor putLong(String key, long value) { - synchronized (mChanges) { - if (mApplyCalled) throw new IllegalStateException(); - mChanges.put(key, value); - return this; - } - } - - @Override - public SharedPreferences.Editor putFloat(String key, float value) { - synchronized (mChanges) { - if (mApplyCalled) throw new IllegalStateException(); - mChanges.put(key, value); - return this; - } - } - - @Override - public SharedPreferences.Editor putBoolean(String key, boolean value) { - synchronized (mChanges) { - if (mApplyCalled) throw new IllegalStateException(); - mChanges.put(key, value); - return this; - } - } - - @Override - public SharedPreferences.Editor remove(String key) { - synchronized (mChanges) { - if (mApplyCalled) throw new IllegalStateException(); - // Magic value for removes - mChanges.put(key, this); - return this; - } - } - - @Override - public SharedPreferences.Editor clear() { - synchronized (mChanges) { - if (mApplyCalled) throw new IllegalStateException(); - mClearCalled = true; - return this; - } - } - - @Override - public boolean commit() { - apply(); - return true; - } - - @Override - public void apply() { - synchronized (mData) { - synchronized (mChanges) { - if (mApplyCalled) throw new IllegalStateException(); - if (mClearCalled) { - mData.clear(); - } - for (Map.Entry entry : mChanges.entrySet()) { - String key = entry.getKey(); - Object value = entry.getValue(); - if (value == this) { - // Special value for removal - mData.remove(key); - } else { - mData.put(key, value); - } - } - // The real shared prefs clears out the temporaries allowing the caller to - // reuse the Editor instance, however this is undocumented behavior and subtle - // to read, so instead we just ban any future use of this instance. - mApplyCalled = true; - } - } - } - } - -} diff --git a/base/test/android/javatests/src/org/chromium/base/test/util/InstrumentationUtils.java b/base/test/android/javatests/src/org/chromium/base/test/util/InstrumentationUtils.java deleted file mode 100644 index 0dc730a739..0000000000 --- a/base/test/android/javatests/src/org/chromium/base/test/util/InstrumentationUtils.java +++ /dev/null @@ -1,32 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -package org.chromium.base.test.util; - -import android.app.Instrumentation; - -import java.util.concurrent.Callable; -import java.util.concurrent.ExecutionException; -import java.util.concurrent.FutureTask; - -/** - * Utility methods built around the android.app.Instrumentation class. - */ -public final class InstrumentationUtils { - - private InstrumentationUtils() { - } - - public static R runOnMainSyncAndGetResult(Instrumentation instrumentation, - Callable callable) throws Throwable { - FutureTask task = new FutureTask(callable); - instrumentation.runOnMainSync(task); - try { - return task.get(); - } catch (ExecutionException e) { - // Unwrap the cause of the exception and re-throw it. - throw e.getCause(); - } - } -} diff --git a/base/test/android/javatests/src/org/chromium/base/test/util/PhoneOnly.java b/base/test/android/javatests/src/org/chromium/base/test/util/PhoneOnly.java deleted file mode 100644 index 1c82e2046a..0000000000 --- a/base/test/android/javatests/src/org/chromium/base/test/util/PhoneOnly.java +++ /dev/null @@ -1,19 +0,0 @@ -// Copyright (c) 2013 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -package org.chromium.base.test.util; - -import java.lang.annotation.ElementType; -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; -import java.lang.annotation.Target; - -/** - * Annotation for specifying that the test should only be run on phones. - */ -@Target(ElementType.METHOD) -@Retention(RetentionPolicy.RUNTIME) -public @interface PhoneOnly { - -} diff --git a/base/test/android/javatests/src/org/chromium/base/test/util/ScalableTimeout.java b/base/test/android/javatests/src/org/chromium/base/test/util/ScalableTimeout.java deleted file mode 100644 index a107b32a91..0000000000 --- a/base/test/android/javatests/src/org/chromium/base/test/util/ScalableTimeout.java +++ /dev/null @@ -1,28 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -package org.chromium.base.test.util; - -/** - * Utility class for scaling various timeouts by a common factor. - * For example, to run tests under Valgrind, you might want the following: - * adb shell "echo 20.0 > /data/local/tmp/chrome_timeout_scale" - */ -public class ScalableTimeout { - private static Double sTimeoutScale = null; - private static final String PROPERTY_FILE = "/data/local/tmp/chrome_timeout_scale"; - - public static long ScaleTimeout(long timeout) { - if (sTimeoutScale == null) { - try { - char[] data = TestFileUtil.readUtf8File(PROPERTY_FILE, 32); - sTimeoutScale = Double.parseDouble(new String(data)); - } catch (Exception e) { - // NumberFormatException, FileNotFoundException, IOException - sTimeoutScale = 1.0; - } - } - return (long)(timeout * sTimeoutScale); - } -} diff --git a/base/test/android/javatests/src/org/chromium/base/test/util/TabletOnly.java b/base/test/android/javatests/src/org/chromium/base/test/util/TabletOnly.java deleted file mode 100644 index 36cdf8130c..0000000000 --- a/base/test/android/javatests/src/org/chromium/base/test/util/TabletOnly.java +++ /dev/null @@ -1,19 +0,0 @@ -// Copyright (c) 2013 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -package org.chromium.base.test.util; - -import java.lang.annotation.ElementType; -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; -import java.lang.annotation.Target; - -/** - * Annotation for specifying that the test should only be run on tablets. - */ -@Target(ElementType.METHOD) -@Retention(RetentionPolicy.RUNTIME) -public @interface TabletOnly { - -} diff --git a/base/test/android/javatests/src/org/chromium/base/test/util/TestFileUtil.java b/base/test/android/javatests/src/org/chromium/base/test/util/TestFileUtil.java deleted file mode 100644 index 1afbc11adb..0000000000 --- a/base/test/android/javatests/src/org/chromium/base/test/util/TestFileUtil.java +++ /dev/null @@ -1,77 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -package org.chromium.base.test.util; - -import java.io.File; -import java.io.FileInputStream; -import java.io.FileNotFoundException; -import java.io.FileOutputStream; -import java.io.IOException; -import java.io.InputStreamReader; -import java.io.OutputStreamWriter; -import java.io.Reader; -import java.io.Writer; -import java.util.Arrays; - -/** - * Utility class for dealing with files for test. - */ -public class TestFileUtil { - public static void createNewHtmlFile(String name, String title, String body) - throws IOException { - File file = new File(name); - if (!file.createNewFile()) { - throw new IOException("File \"" + name + "\" already exists"); - } - - Writer writer = null; - try { - writer = new OutputStreamWriter(new FileOutputStream(file), "UTF-8"); - writer.write("" + - "" + title + "" + - "" + - (body != null ? body : "") + - "" + - ""); - } finally { - if (writer != null) { - writer.close(); - } - } - } - - public static void deleteFile(String name) { - File file = new File(name); - file.delete(); - } - - /** - * @param fileName the file to read in. - * @param sizeLimit cap on the file size: will throw an exception if exceeded - * @return Array of chars read from the file - * @throws FileNotFoundException file does not exceed - * @throws IOException error encountered accessing the file - */ - public static char[] readUtf8File(String fileName, int sizeLimit) throws - FileNotFoundException, IOException { - Reader reader = null; - try { - File f = new File(fileName); - if (f.length() > sizeLimit) { - throw new IOException("File " + fileName + " length " + f.length() + - " exceeds limit " + sizeLimit); - } - char[] buffer = new char[(int) f.length()]; - reader = new InputStreamReader(new FileInputStream(f), "UTF-8"); - int charsRead = reader.read(buffer); - // Debug check that we've exhausted the input stream (will fail e.g. if the - // file grew after we inspected its length). - assert !reader.ready(); - return charsRead < buffer.length ? Arrays.copyOfRange(buffer, 0, charsRead) : buffer; - } finally { - if (reader != null) reader.close(); - } - } -} diff --git a/base/test/android/javatests/src/org/chromium/base/test/util/TestThread.java b/base/test/android/javatests/src/org/chromium/base/test/util/TestThread.java deleted file mode 100644 index 11e6afdecd..0000000000 --- a/base/test/android/javatests/src/org/chromium/base/test/util/TestThread.java +++ /dev/null @@ -1,143 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -package org.chromium.base.test.util; - -import android.os.Handler; -import android.os.Looper; - -import java.util.concurrent.atomic.AtomicBoolean; - -/** - * This class is usefull when writing instrumentation tests that exercise code that posts tasks - * (to the same thread). - * Since the test code is run in a single thread, the posted tasks are never executed. - * The TestThread class lets you run that code on a specific thread synchronously and flush the - * message loop on that thread. - * - * Example of test using this: - * - * public void testMyAwesomeClass() { - * TestThread testThread = new TestThread(); - * testThread.startAndWaitForReadyState(); - * - * testThread.runOnTestThreadSyncAndProcessPendingTasks(new Runnable() { - * @Override - * public void run() { - * MyAwesomeClass.doStuffAsync(); - * } - * }); - * // Once we get there we know doStuffAsync has been executed and all the tasks it posted. - * assertTrue(MyAwesomeClass.stuffWasDone()); - * } - * - * Notes: - * - this is only for tasks posted to the same thread. Anyway if you were posting to a different - * thread, you'd probably need to set that other thread up. - * - this only supports tasks posted using Handler.post(), it won't work with postDelayed and - * postAtTime. - * - if your test instanciates an object and that object is the one doing the posting of tasks, you - * probably want to instanciate it on the test thread as it might create the Handler it posts - * tasks to in the constructor. - */ - -public class TestThread extends Thread { - private Object mThreadReadyLock; - private AtomicBoolean mThreadReady; - private Handler mMainThreadHandler; - private Handler mTestThreadHandler; - - public TestThread() { - mMainThreadHandler = new Handler(); - // We can't use the AtomicBoolean as the lock or findbugs will freak out... - mThreadReadyLock = new Object(); - mThreadReady = new AtomicBoolean(); - } - - @Override - public void run() { - Looper.prepare(); - mTestThreadHandler = new Handler(); - mTestThreadHandler.post(new Runnable() { - @Override - public void run() { - synchronized (mThreadReadyLock) { - mThreadReady.set(true); - mThreadReadyLock.notify(); - } - } - }); - Looper.loop(); - } - - /** - * Starts this TestThread and blocks until it's ready to accept calls. - */ - public void startAndWaitForReadyState() { - checkOnMainThread(); - start(); - synchronized (mThreadReadyLock) { - try { - // Note the mThreadReady and while are not really needed. - // There are there so findbugs don't report warnings. - while (!mThreadReady.get()) { - mThreadReadyLock.wait(); - } - } catch (InterruptedException ie) { - System.err.println("Error starting TestThread."); - ie.printStackTrace(); - } - } - } - - /** - * Runs the passed Runnable synchronously on the TestThread and returns when all pending - * runnables have been excuted. - * Should be called from the main thread. - */ - public void runOnTestThreadSyncAndProcessPendingTasks(Runnable r) { - checkOnMainThread(); - - runOnTestThreadSync(r); - - // Run another task, when it's done it means all pendings tasks have executed. - runOnTestThreadSync(null); - } - - /** - * Runs the passed Runnable on the test thread and blocks until it has finished executing. - * Should be called from the main thread. - * @param r The runnable to be executed. - */ - public void runOnTestThreadSync(final Runnable r) { - checkOnMainThread(); - final Object lock = new Object(); - // Task executed is not really needed since we are only on one thread, it is here to appease - // findbugs. - final AtomicBoolean taskExecuted = new AtomicBoolean(); - mTestThreadHandler.post(new Runnable() { - @Override - public void run() { - if (r != null) r.run(); - synchronized (lock) { - taskExecuted.set(true); - lock.notify(); - } - } - }); - synchronized (lock) { - try { - while (!taskExecuted.get()) { - lock.wait(); - } - } catch (InterruptedException ie) { - ie.printStackTrace(); - } - } - } - - private void checkOnMainThread() { - assert Looper.myLooper() == mMainThreadHandler.getLooper(); - } -} diff --git a/base/test/android/javatests/src/org/chromium/base/test/util/TimeoutScale.java b/base/test/android/javatests/src/org/chromium/base/test/util/TimeoutScale.java deleted file mode 100644 index a3b0641cf2..0000000000 --- a/base/test/android/javatests/src/org/chromium/base/test/util/TimeoutScale.java +++ /dev/null @@ -1,22 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -package org.chromium.base.test.util; - -import java.lang.annotation.ElementType; -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; -import java.lang.annotation.Target; - -/** - * This annotation can be used to scale a specific test timeout. - */ -@Target(ElementType.METHOD) -@Retention(RetentionPolicy.RUNTIME) -public @interface TimeoutScale { - /** - * @return A number to scale the test timeout. - */ - public int value(); -} diff --git a/base/test/android/javatests/src/org/chromium/base/test/util/UrlUtils.java b/base/test/android/javatests/src/org/chromium/base/test/util/UrlUtils.java deleted file mode 100644 index 767c87256b..0000000000 --- a/base/test/android/javatests/src/org/chromium/base/test/util/UrlUtils.java +++ /dev/null @@ -1,45 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -package org.chromium.base.test.util; - -import org.chromium.base.PathUtils; - -import junit.framework.Assert; - -/** - * Collection of URL utilities. - */ -public class UrlUtils { - private final static String DATA_DIR = "/chrome/test/data/"; - - /** - * Construct a suitable URL for loading a test data file. - * @param path Pathname relative to external/chrome/testing/data - */ - public static String getTestFileUrl(String path) { - return "file://" + PathUtils.getExternalStorageDirectory() + DATA_DIR + path; - } - - /** - * Construct a data:text/html URI for loading from an inline HTML. - * @param html An unencoded HTML - * @return String An URI that contains the given HTML - */ - public static String encodeHtmlDataUri(String html) { - try { - // URLEncoder encodes into application/x-www-form-encoded, so - // ' '->'+' needs to be undone and replaced with ' '->'%20' - // to match the Data URI requirements. - String encoded = - "data:text/html;utf-8," + - java.net.URLEncoder.encode(html, "UTF-8"); - encoded = encoded.replace("+", "%20"); - return encoded; - } catch (java.io.UnsupportedEncodingException e) { - Assert.fail("Unsupported encoding: " + e.getMessage()); - return null; - } - } -} diff --git a/base/test/data/file_util/binary_file.bin b/base/test/data/file_util/binary_file.bin deleted file mode 100644 index f53cc8283a595bfcab9f1bb1dcabf95d210133ab..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 538 zcmeZ`n!v!!z`(!)#Q*;@Fzf)*Am9Kd@e?0_(tPr}_!zcuo>knz=yO&vBqOs}p`a)~ zy(lqPAvrNGFTX?~DOI7UG*2NjPr=1MSRpq*B~_1?mrDg|^t-u|hgSV5p9sUfR$LP| z0r|aFk`w2EX{m|&V47#*Vz9chiR@rL>%^I0ntS4EFwGC9gEEsdKxW}|xep^NgZZ_7 zcbI|)3`~sNj2u88Gchpu0WlDKQ)gsg5CAd)Kzs)X8^{C&5(vO(h6_Lz5LsPfVPFEO z18D;3gVRthNC*hd>|tg|0Wkzv7#w;*3^cHSg&{_cf#E_B6N3zz6f)OgJu}!gxERo# sB|!J#0(vE>6(vB)P&=R^ko!P>g?j>`OM!tQL9Zw!u_O^FT@Ca<08g4+ga7~l diff --git a/base/test/data/file_util/binary_file_diff.bin b/base/test/data/file_util/binary_file_diff.bin deleted file mode 100644 index 103b26d09330ea2b61ebf54db4e25138ddedbe2c..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 538 zcmeZ`n!v!!z`(!)#Q*;@Fzf)*Am9Kd@e?0_(tPr}_!zcuo>knz=yO&vBqOs}p`a)~ zy(lqPAvrNGFTX?~DOI7UG*2NjPr=1MSRpq*B~_1?mrDg|^t-u|hgSV5p9sUfR$LP| z0r|aFk`w2EX{m|&V47#*Vz9chiR@rL>%^I0ntS4EFwGC9gEEsdKxW}|xep^NgZZ_7 zcbI|)X=#kyj2u88Gchpu0WlDKQ)gsg5CAd)Kzs)X8^{C&5(vO(h6_Lz5LsPfVPFEO z18D;3gVRthNC*hd>|tg|0Wkzv7#w;*3^cHSg&{_cf#E_B6N3zz6f)OgJu}!gxERo# sB|!J#0(vE>6(vB)P&=R^ko!P>g?j>`OM!tQL9Zw!u_O^FT@Ca<04z0KP5=M^ diff --git a/base/test/data/file_util/binary_file_same.bin b/base/test/data/file_util/binary_file_same.bin deleted file mode 100644 index f53cc8283a595bfcab9f1bb1dcabf95d210133ab..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 538 zcmeZ`n!v!!z`(!)#Q*;@Fzf)*Am9Kd@e?0_(tPr}_!zcuo>knz=yO&vBqOs}p`a)~ zy(lqPAvrNGFTX?~DOI7UG*2NjPr=1MSRpq*B~_1?mrDg|^t-u|hgSV5p9sUfR$LP| z0r|aFk`w2EX{m|&V47#*Vz9chiR@rL>%^I0ntS4EFwGC9gEEsdKxW}|xep^NgZZ_7 zcbI|)3`~sNj2u88Gchpu0WlDKQ)gsg5CAd)Kzs)X8^{C&5(vO(h6_Lz5LsPfVPFEO z18D;3gVRthNC*hd>|tg|0Wkzv7#w;*3^cHSg&{_cf#E_B6N3zz6f)OgJu}!gxERo# sB|!J#0(vE>6(vB)P&=R^ko!P>g?j>`OM!tQL9Zw!u_O^FT@Ca<08g4+ga7~l diff --git a/base/test/data/file_util/blank_line.txt b/base/test/data/file_util/blank_line.txt deleted file mode 100644 index 88920698cf..0000000000 --- a/base/test/data/file_util/blank_line.txt +++ /dev/null @@ -1,3 +0,0 @@ -The next line is blank. - -But this one isn't. diff --git a/base/test/data/file_util/blank_line_crlf.txt b/base/test/data/file_util/blank_line_crlf.txt deleted file mode 100644 index 3aefe52fec..0000000000 --- a/base/test/data/file_util/blank_line_crlf.txt +++ /dev/null @@ -1,3 +0,0 @@ -The next line is blank. - -But this one isn't. diff --git a/base/test/data/file_util/crlf.txt b/base/test/data/file_util/crlf.txt deleted file mode 100644 index 0e62728660..0000000000 --- a/base/test/data/file_util/crlf.txt +++ /dev/null @@ -1 +0,0 @@ -This file is the same. diff --git a/base/test/data/file_util/different.txt b/base/test/data/file_util/different.txt deleted file mode 100644 index 5b9f9c4312..0000000000 --- a/base/test/data/file_util/different.txt +++ /dev/null @@ -1 +0,0 @@ -This file is different. diff --git a/base/test/data/file_util/different_first.txt b/base/test/data/file_util/different_first.txt deleted file mode 100644 index 8661d6646d..0000000000 --- a/base/test/data/file_util/different_first.txt +++ /dev/null @@ -1 +0,0 @@ -this file is the same. diff --git a/base/test/data/file_util/different_last.txt b/base/test/data/file_util/different_last.txt deleted file mode 100644 index e8b3e5af56..0000000000 --- a/base/test/data/file_util/different_last.txt +++ /dev/null @@ -1 +0,0 @@ -This file is the same. \ No newline at end of file diff --git a/base/test/data/file_util/empty1.txt b/base/test/data/file_util/empty1.txt deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/base/test/data/file_util/empty2.txt b/base/test/data/file_util/empty2.txt deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/base/test/data/file_util/first1.txt b/base/test/data/file_util/first1.txt deleted file mode 100644 index 2c6e3001b1..0000000000 --- a/base/test/data/file_util/first1.txt +++ /dev/null @@ -1,2 +0,0 @@ -The first line is the same. -The second line is different. diff --git a/base/test/data/file_util/first2.txt b/base/test/data/file_util/first2.txt deleted file mode 100644 index e39b5ec292..0000000000 --- a/base/test/data/file_util/first2.txt +++ /dev/null @@ -1,2 +0,0 @@ -The first line is the same. -The second line is not. diff --git a/base/test/data/file_util/original.txt b/base/test/data/file_util/original.txt deleted file mode 100644 index 4422f5754a..0000000000 --- a/base/test/data/file_util/original.txt +++ /dev/null @@ -1 +0,0 @@ -This file is the same. diff --git a/base/test/data/file_util/same.txt b/base/test/data/file_util/same.txt deleted file mode 100644 index 4422f5754a..0000000000 --- a/base/test/data/file_util/same.txt +++ /dev/null @@ -1 +0,0 @@ -This file is the same. diff --git a/base/test/data/file_util/same_length.txt b/base/test/data/file_util/same_length.txt deleted file mode 100644 index 157405cd19..0000000000 --- a/base/test/data/file_util/same_length.txt +++ /dev/null @@ -1 +0,0 @@ -This file is not same. diff --git a/base/test/data/file_util/shortened.txt b/base/test/data/file_util/shortened.txt deleted file mode 100644 index 2bee82ca1b..0000000000 --- a/base/test/data/file_util/shortened.txt +++ /dev/null @@ -1 +0,0 @@ -This file is the \ No newline at end of file diff --git a/base/test/data/json/bom_feff.json b/base/test/data/json/bom_feff.json deleted file mode 100644 index b05ae5083e..0000000000 --- a/base/test/data/json/bom_feff.json +++ /dev/null @@ -1,10 +0,0 @@ -{ - "appName": { - "message": "Gmail", - "description": "App name." - }, - "appDesc": { - "message": "بريد إلكتروني يوفر إمكانية البحث مع مقدار أقل من الرسائل غير المرغوب فيها.", - "description":"App description." - } -} \ No newline at end of file diff --git a/base/test/data/prefs/invalid.json b/base/test/data/prefs/invalid.json deleted file mode 100644 index 43392a92fb..0000000000 --- a/base/test/data/prefs/invalid.json +++ /dev/null @@ -1 +0,0 @@ -!@#$%^& \ No newline at end of file diff --git a/base/test/data/prefs/read.json b/base/test/data/prefs/read.json deleted file mode 100644 index ea578a47f4..0000000000 --- a/base/test/data/prefs/read.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "homepage": "http://www.cnn.com", - "some_directory": "/usr/local/", - "tabs": { - "new_windows_in_tabs": true, - "max_tabs": 20 - } -} diff --git a/base/test/data/prefs/read.need_empty_value.json b/base/test/data/prefs/read.need_empty_value.json deleted file mode 100644 index 48e1749448..0000000000 --- a/base/test/data/prefs/read.need_empty_value.json +++ /dev/null @@ -1,10 +0,0 @@ -{ - "list": [ 1 ], - "list_needs_empty_value": [ 2 ], - "dict": { - "dummy": true - }, - "dict_needs_empty_value": { - "dummy": true - } -} diff --git a/base/test/data/prefs/write.golden.json b/base/test/data/prefs/write.golden.json deleted file mode 100644 index 9a5523c730..0000000000 --- a/base/test/data/prefs/write.golden.json +++ /dev/null @@ -1,11 +0,0 @@ -{ - "homepage": "http://www.cnn.com", - "long_int": { - "pref": "214748364842" - }, - "some_directory": "/usr/sbin/", - "tabs": { - "max_tabs": 10, - "new_windows_in_tabs": false - } -} diff --git a/base/test/data/prefs/write.golden.need_empty_value.json b/base/test/data/prefs/write.golden.need_empty_value.json deleted file mode 100644 index fa79590f62..0000000000 --- a/base/test/data/prefs/write.golden.need_empty_value.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "dict_needs_empty_value": { - - }, - "list_needs_empty_value": [ ] -} diff --git a/base/test/data/serializer_nested_test.json b/base/test/data/serializer_nested_test.json deleted file mode 100644 index cfea8e86a9..0000000000 --- a/base/test/data/serializer_nested_test.json +++ /dev/null @@ -1,17 +0,0 @@ -{ - "bool": true, - "dict": { - "bool": true, - "dict": { - "bees": "knees", - "cats": "meow" - }, - "foos": "bar", - "list": [ 3.4, "second", null ] - }, - "int": 42, - "list": [ 1, 2 ], - "null": null, - "real": 3.14, - "string": "hello" -} diff --git a/base/test/data/serializer_test.json b/base/test/data/serializer_test.json deleted file mode 100644 index 446925ea7b..0000000000 --- a/base/test/data/serializer_test.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "bool": true, - "int": 42, - "list": [ 1, 2 ], - "null": null, - "real": 3.14, - "string": "hello" -} diff --git a/base/test/data/serializer_test_nowhitespace.json b/base/test/data/serializer_test_nowhitespace.json deleted file mode 100644 index a1afdc5830..0000000000 --- a/base/test/data/serializer_test_nowhitespace.json +++ /dev/null @@ -1 +0,0 @@ -{"bool":true,"int":42,"list":[1,2],"null":null,"real":3.14,"string":"hello"} \ No newline at end of file diff --git a/base/test/expectations/OWNERS b/base/test/expectations/OWNERS deleted file mode 100644 index 14fce2ae68..0000000000 --- a/base/test/expectations/OWNERS +++ /dev/null @@ -1 +0,0 @@ -rsesek@chromium.org diff --git a/base/test/expectations/expectation.cc b/base/test/expectations/expectation.cc deleted file mode 100644 index 31a387eba3..0000000000 --- a/base/test/expectations/expectation.cc +++ /dev/null @@ -1,157 +0,0 @@ -// Copyright (c) 2013 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "base/test/expectations/expectation.h" - -#include "base/logging.h" - -#if defined(OS_WIN) -#include "base/win/windows_version.h" -#elif defined(OS_MACOSX) && !defined(OS_IOS) -#include "base/mac/mac_util.h" -#elif defined(OS_LINUX) -#include "base/sys_info.h" -#endif - -namespace test_expectations { - -bool ResultFromString(const base::StringPiece& result, Result* out_result) { - if (result == "Failure") - *out_result = RESULT_FAILURE; - else if (result == "Timeout") - *out_result = RESULT_TIMEOUT; - else if (result == "Crash") - *out_result = RESULT_CRASH; - else if (result == "Skip") - *out_result = RESULT_SKIP; - else if (result == "Pass") - *out_result = RESULT_PASS; - else - return false; - - return true; -} - -static bool IsValidPlatform(const Platform* platform) { - const std::string& name = platform->name; - const std::string& variant = platform->variant; - - if (name == "Win") { - if (variant != "" && - variant != "XP" && - variant != "Vista" && - variant != "7" && - variant != "8") { - return false; - } - } else if (name == "Mac") { - if (variant != "" && - variant != "10.6" && - variant != "10.7" && - variant != "10.8") { - return false; - } - } else if (name == "Linux") { - if (variant != "" && - variant != "32" && - variant != "64") { - return false; - } - } else if (name == "ChromeOS") { - // TODO(rsesek): Figure out what ChromeOS needs. - } else if (name == "iOS") { - // TODO(rsesek): Figure out what iOS needs. Probably Device and Simulator. - } else if (name == "Android") { - // TODO(rsesek): Figure out what Android needs. - } else { - return false; - } - - return true; -} - -bool PlatformFromString(const base::StringPiece& modifier, - Platform* out_platform) { - size_t sep = modifier.find('-'); - if (sep == std::string::npos) { - out_platform->name = modifier.as_string(); - out_platform->variant.clear(); - } else { - out_platform->name = modifier.substr(0, sep).as_string(); - out_platform->variant = modifier.substr(sep + 1).as_string(); - } - - return IsValidPlatform(out_platform); -} - -Platform GetCurrentPlatform() { - Platform platform; -#if defined(OS_WIN) - platform.name = "Win"; - base::win::Version version = base::win::GetVersion(); - if (version == base::win::VERSION_XP) - platform.variant = "XP"; - else if (version == base::win::VERSION_VISTA) - platform.variant = "Vista"; - else if (version == base::win::VERSION_WIN7) - platform.variant = "7"; - else if (version == base::win::VERSION_WIN8) - platform.variant = "8"; -#elif defined(OS_IOS) - platform.name = "iOS"; -#elif defined(OS_MACOSX) - platform.name = "Mac"; - if (base::mac::IsOSSnowLeopard()) - platform.variant = "10.6"; - else if (base::mac::IsOSLion()) - platform.variant = "10.7"; - else if (base::mac::IsOSMountainLion()) - platform.variant = "10.8"; -#elif defined(OS_CHROMEOS) - platform.name = "ChromeOS"; -#elif defined(OS_ANDROID) - platform.name = "Android"; -#elif defined(OS_LINUX) - platform.name = "Linux"; - std::string arch = base::SysInfo::OperatingSystemArchitecture(); - if (arch == "x86") - platform.variant = "32"; - else if (arch == "x86_64") - platform.variant = "64"; -#else - NOTREACHED(); -#endif - return platform; -} - -bool ConfigurationFromString(const base::StringPiece& modifier, - Configuration* out_configuration) { - if (modifier == "Debug") - *out_configuration = CONFIGURATION_DEBUG; - else if (modifier == "Release") - *out_configuration = CONFIGURATION_RELEASE; - else - return false; - - return true; -} - -Configuration GetCurrentConfiguration() { -#if NDEBUG - return CONFIGURATION_RELEASE; -#else - return CONFIGURATION_DEBUG; -#endif - NOTREACHED(); - return CONFIGURATION_UNSPECIFIED; -} - -Expectation::Expectation() - : configuration(CONFIGURATION_UNSPECIFIED), - result(RESULT_PASS) { -} - -Expectation::~Expectation() {} - -} // namespace test_expectations diff --git a/base/test/expectations/expectation.h b/base/test/expectations/expectation.h deleted file mode 100644 index be5a9d7ff1..0000000000 --- a/base/test/expectations/expectation.h +++ /dev/null @@ -1,94 +0,0 @@ -// Copyright (c) 2013 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef BASE_TEST_EXPECTATIONS_EXPECTATION_H_ -#define BASE_TEST_EXPECTATIONS_EXPECTATION_H_ - -#include -#include - -#include "base/base_export.h" -#include "base/compiler_specific.h" -#include "base/strings/string_piece.h" - -namespace test_expectations { - -// A Result is the expectation of a test's behavior. -enum Result { - // The test has a failing assertion. - RESULT_FAILURE, - - // The test does not complete within the test runner's alloted duration. - RESULT_TIMEOUT, - - // The test crashes during the course of its execution. - RESULT_CRASH, - - // The test should not be run ever. - RESULT_SKIP, - - // The test passes, used to override a more general expectation. - RESULT_PASS, -}; - -// Converts a text string form of a |result| to its enum value, written to -// |out_result|. Returns true on success and false on error. -bool ResultFromString(const base::StringPiece& result, - Result* out_result) WARN_UNUSED_RESULT; - -// A Platform stores information about the OS environment. -struct Platform { - // The name of the platform. E.g., "Win", or "Mac". - std::string name; - - // The variant of the platform, either an OS version like "XP" or "10.8", or - // "Device" or "Simulator" in the case of mobile. - std::string variant; -}; - -// Converts a text string |modifier| to a Platform struct, written to -// |out_platform|. Returns true on success and false on failure. -bool PlatformFromString(const base::StringPiece& modifier, - Platform* out_platform) WARN_UNUSED_RESULT; - -// Returns the Platform for the currently running binary. -Platform GetCurrentPlatform(); - -// The build configuration. -enum Configuration { - CONFIGURATION_UNSPECIFIED, - CONFIGURATION_DEBUG, - CONFIGURATION_RELEASE, -}; - -// Converts the |modifier| to a Configuration constant, writing the value to -// |out_configuration|. Returns true on success or false on failure. -bool ConfigurationFromString(const base::StringPiece& modifier, - Configuration* out_configuration) WARN_UNUSED_RESULT; - -// Returns the Configuration for the currently running binary. -Configuration GetCurrentConfiguration(); - -// An Expectation is records what the result for a given test name should be on -// the specified platforms and configuration. -struct Expectation { - Expectation(); - ~Expectation(); - - // The name of the test, like FooBarTest.BarIsBaz. - std::string test_name; - - // The set of platforms for which this expectation is applicable. - std::vector platforms; - - // The build configuration. - Configuration configuration; - - // The expected result of this test. - Result result; -}; - -} // namespace test_expectations - -#endif // BASE_TEST_EXPECTATIONS_EXPECTATION_H_ diff --git a/base/test/expectations/expectation_unittest.cc b/base/test/expectations/expectation_unittest.cc deleted file mode 100644 index 8a7af71a97..0000000000 --- a/base/test/expectations/expectation_unittest.cc +++ /dev/null @@ -1,120 +0,0 @@ -// Copyright (c) 2013 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "base/test/expectations/expectation.h" - -#include "base/basictypes.h" -#include "testing/gtest/include/gtest/gtest.h" - -TEST(TestExpectationsFunctionsTest, ResultFromString) { - test_expectations::Result result = test_expectations::RESULT_PASS; - - EXPECT_TRUE(ResultFromString("Failure", &result)); - EXPECT_EQ(test_expectations::RESULT_FAILURE, result); - - EXPECT_TRUE(ResultFromString("Timeout", &result)); - EXPECT_EQ(test_expectations::RESULT_TIMEOUT, result); - - EXPECT_TRUE(ResultFromString("Crash", &result)); - EXPECT_EQ(test_expectations::RESULT_CRASH, result); - - EXPECT_TRUE(ResultFromString("Skip", &result)); - EXPECT_EQ(test_expectations::RESULT_SKIP, result); - - EXPECT_TRUE(ResultFromString("Pass", &result)); - EXPECT_EQ(test_expectations::RESULT_PASS, result); - - // Case sensitive. - EXPECT_FALSE(ResultFromString("failure", &result)); - EXPECT_EQ(test_expectations::RESULT_PASS, result); -} - -TEST(TestExpectationsFunctionsTest, ConfigurationFromString) { - test_expectations::Configuration config = - test_expectations::CONFIGURATION_UNSPECIFIED; - - EXPECT_TRUE(ConfigurationFromString("Debug", &config)); - EXPECT_EQ(test_expectations::CONFIGURATION_DEBUG, config); - - EXPECT_TRUE(ConfigurationFromString("Release", &config)); - EXPECT_EQ(test_expectations::CONFIGURATION_RELEASE, config); - - EXPECT_FALSE(ConfigurationFromString("NotAConfig", &config)); - EXPECT_EQ(test_expectations::CONFIGURATION_RELEASE, config); - - // Case sensitive. - EXPECT_FALSE(ConfigurationFromString("debug", &config)); - EXPECT_EQ(test_expectations::CONFIGURATION_RELEASE, config); -} - -TEST(TestExpectationsFunctionsTest, PlatformFromString) { - test_expectations::Platform platform; - - EXPECT_TRUE(PlatformFromString("Win", &platform)); - EXPECT_EQ("Win", platform.name); - EXPECT_EQ("", platform.variant); - - EXPECT_TRUE(PlatformFromString("Mac-10.6", &platform)); - EXPECT_EQ("Mac", platform.name); - EXPECT_EQ("10.6", platform.variant); - - EXPECT_TRUE(PlatformFromString("ChromeOS", &platform)); - EXPECT_EQ("ChromeOS", platform.name); - EXPECT_EQ("", platform.variant); - - EXPECT_TRUE(PlatformFromString("Linux-", &platform)); - EXPECT_EQ("Linux", platform.name); - EXPECT_EQ("", platform.variant); - - EXPECT_FALSE(PlatformFromString("", &platform)); -} - -TEST(TestExpectationsFunctionsTest, IsValidPlatform) { - const char* kValidPlatforms[] = { - "Win", - "Win-XP", - "Win-Vista", - "Win-7", - "Win-8", - "Mac", - "Mac-10.6", - "Mac-10.7", - "Mac-10.8", - "Linux", - "Linux-32", - "Linux-64", - "ChromeOS", - "iOS", - "Android", - }; - - const char* kInvalidPlatforms[] = { - "Solaris", - "Plan9", - }; - - for (size_t i = 0; i < arraysize(kValidPlatforms); ++i) { - test_expectations::Platform platform; - EXPECT_TRUE(test_expectations::PlatformFromString( - kValidPlatforms[i], &platform)) << kValidPlatforms[i]; - } - - for (size_t i = 0; i < arraysize(kInvalidPlatforms); ++i) { - test_expectations::Platform platform; - EXPECT_FALSE(test_expectations::PlatformFromString( - kInvalidPlatforms[i], &platform)) << kInvalidPlatforms[i]; - } -} - -TEST(TestExpectationsFunctionsTest, CurrentPlatform) { - test_expectations::Platform current = - test_expectations::GetCurrentPlatform(); - EXPECT_FALSE(current.name.empty()); -} - -TEST(TestExpectationsFunctionsTest, CurrentConfiguration) { - test_expectations::Configuration current = - test_expectations::GetCurrentConfiguration(); - EXPECT_NE(test_expectations::CONFIGURATION_UNSPECIFIED, current); -} diff --git a/base/test/expectations/parser.cc b/base/test/expectations/parser.cc deleted file mode 100644 index c7132e5d48..0000000000 --- a/base/test/expectations/parser.cc +++ /dev/null @@ -1,201 +0,0 @@ -// Copyright (c) 2013 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "base/test/expectations/parser.h" - -#include "base/strings/string_util.h" - -namespace test_expectations { - -Parser::Parser(Delegate* delegate, const std::string& input) - : delegate_(delegate), - input_(input), - pos_(NULL), - end_(NULL), - line_number_(0), - data_error_(false) { -} - -Parser::~Parser() { -} - -void Parser::Parse() { - pos_ = &input_[0]; - end_ = pos_ + input_.length(); - - line_number_ = 1; - - StateFuncPtr state = &Parser::Start; - while (state) { - state = (this->*state)(); - } -} - -inline bool Parser::HasNext() { - return pos_ < end_; -} - -Parser::StateFunc Parser::Start() { - // If at the start of a line is whitespace, skip it and arrange to come back - // here. - if (IsAsciiWhitespace(*pos_)) - return SkipWhitespaceAndNewLines(&Parser::Start); - - // Handle comments at the start of lines. - if (*pos_ == '#') - return &Parser::ParseComment; - - // After arranging to come back here from skipping whitespace and comments, - // the parser may be at the end of the input. - if (pos_ >= end_) - return NULL; - - current_ = Expectation(); - data_error_ = false; - - return &Parser::ParseBugURL; -} - -Parser::StateFunc Parser::ParseComment() { - if (*pos_ != '#') - return SyntaxError("Invalid start of comment"); - - do { - ++pos_; - } while (HasNext() && *pos_ != '\n'); - - return &Parser::Start; -} - -Parser::StateFunc Parser::ParseBugURL() { - return SkipWhitespace(ExtractString( - &Parser::BeginModifiers)); -} - -Parser::StateFunc Parser::BeginModifiers() { - if (*pos_ != '[' || !HasNext()) - return SyntaxError("Expected '[' for start of modifiers"); - - ++pos_; - return SkipWhitespace(&Parser::InModifiers); -} - -Parser::StateFunc Parser::InModifiers() { - if (*pos_ == ']') - return &Parser::EndModifiers; - - return ExtractString(SkipWhitespace( - &Parser::SaveModifier)); -} - -Parser::StateFunc Parser::SaveModifier() { - if (extracted_string_.empty()) - return SyntaxError("Invalid modifier list"); - - Configuration config; - if (ConfigurationFromString(extracted_string_, &config)) { - if (current_.configuration != CONFIGURATION_UNSPECIFIED) - DataError("Cannot use more than one configuration modifier"); - else - current_.configuration = config; - } else { - Platform platform; - if (PlatformFromString(extracted_string_, &platform)) - current_.platforms.push_back(platform); - else - DataError("Invalid modifier string"); - } - - return SkipWhitespace(&Parser::InModifiers); -} - -Parser::StateFunc Parser::EndModifiers() { - if (*pos_ != ']' || !HasNext()) - return SyntaxError("Expected ']' for end of modifiers list"); - - ++pos_; - return SkipWhitespace(&Parser::ParseTestName); -} - -Parser::StateFunc Parser::ParseTestName() { - return ExtractString(&Parser::SaveTestName); -} - -Parser::StateFunc Parser::SaveTestName() { - if (extracted_string_.empty()) - return SyntaxError("Invalid test name"); - - current_.test_name = extracted_string_.as_string(); - return SkipWhitespace(&Parser::ParseExpectation); -} - -Parser::StateFunc Parser::ParseExpectation() { - if (*pos_ != '=' || !HasNext()) - return SyntaxError("Expected '=' for expectation result"); - - ++pos_; - return SkipWhitespace(&Parser::ParseExpectationType); -} - -Parser::StateFunc Parser::ParseExpectationType() { - return ExtractString(&Parser::SaveExpectationType); -} - -Parser::StateFunc Parser::SaveExpectationType() { - if (!ResultFromString(extracted_string_, ¤t_.result)) - DataError("Unknown expectation type"); - - return SkipWhitespace(&Parser::End); -} - -Parser::StateFunc Parser::End() { - if (!data_error_) - delegate_->EmitExpectation(current_); - - if (HasNext()) - return SkipWhitespaceAndNewLines(&Parser::Start); - - return NULL; -} - -Parser::StateFunc Parser::ExtractString(StateFunc success) { - const char* start = pos_; - while (!IsAsciiWhitespace(*pos_) && *pos_ != ']' && HasNext()) { - ++pos_; - if (*pos_ == '#') { - return SyntaxError("Unexpected start of comment"); - } - } - extracted_string_ = base::StringPiece(start, pos_ - start); - return success; -} - -Parser::StateFunc Parser::SkipWhitespace(Parser::StateFunc next) { - while ((*pos_ == ' ' || *pos_ == '\t') && HasNext()) { - ++pos_; - } - return next; -} - -Parser::StateFunc Parser::SkipWhitespaceAndNewLines(Parser::StateFunc next) { - while (IsAsciiWhitespace(*pos_) && HasNext()) { - if (*pos_ == '\n') { - ++line_number_; - } - ++pos_; - } - return next; -} - -Parser::StateFunc Parser::SyntaxError(const std::string& message) { - delegate_->OnSyntaxError(message); - return NULL; -} - -void Parser::DataError(const std::string& error) { - data_error_ = true; - delegate_->OnDataError(error); -} - -} // namespace test_expectations diff --git a/base/test/expectations/parser.h b/base/test/expectations/parser.h deleted file mode 100644 index 69a741a852..0000000000 --- a/base/test/expectations/parser.h +++ /dev/null @@ -1,143 +0,0 @@ -// Copyright (c) 2013 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef BASE_TEST_EXPECTATIONS_PARSER_H_ -#define BASE_TEST_EXPECTATIONS_PARSER_H_ - -#include - -#include "base/basictypes.h" -#include "base/strings/string_piece.h" -#include "base/test/expectations/expectation.h" - -namespace test_expectations { - -// This is the internal parser for test expectations. It parses an input -// string and reports information to its Delegate as it's processing the -// input. -// -// The input format is documented here: -// https://docs.google.com/a/chromium.org/document/d/1edhMJ5doY_dzfbKNCzeJJ-8XxPrexTbNL2Y_jVvLB8Q/view -// -// Basic format: -// "http://bug/1234 [ OS-Version ] Test.Name = Result" -// -// The parser is implemented as a state machine, with each state returning a -// function pointer to the next state. -class Parser { - public: - // The parser will call these methods on its delegate during a Parse() - // operation. - class Delegate { - public: - // When a well-formed and valid Expectation has been parsed from the input, - // it is reported to the delegate via this method. - virtual void EmitExpectation(const Expectation& expectation) = 0; - - // Called when the input string is not well-formed. Parsing will stop after - // this method is called. - virtual void OnSyntaxError(const std::string& message) = 0; - - // Called when an Expectation has been parsed because it is well-formed but - // contains invalid data (i.e. the modifiers or result are not valid - // keywords). This Expectation will not be reported via EmitExpectation. - virtual void OnDataError(const std::string& message) = 0; - }; - - // Creates a new parser for |input| that will send data to |delegate|. - Parser(Delegate* delegate, const std::string& input); - ~Parser(); - - // Runs the parser of the input string. - void Parse(); - - private: - // This bit of hackery is used to implement a function pointer type that - // returns a pointer to a function of the same signature. Since a definition - // like that is inherently recursive, it's impossible to do: - // type StateFunc(*StateFunc)(StateData*); - // However, this approach works without the need to use void*. Inspired by - // . - struct StateFunc; - typedef StateFunc(Parser::*StateFuncPtr)(); - struct StateFunc { - StateFunc(StateFuncPtr pf) : pf_(pf) {} - operator StateFuncPtr() { - return pf_; - } - StateFuncPtr pf_; - }; - - // Tests whether there is at least one more character at pos_ before end_. - bool HasNext(); - - // The parser state functions. On entry, the parser state is at the beginning - // of the token. Each returns a function pointer to the next state function, - // or NULL to end parsing. On return, the parser is at the beginning of the - // next token. - StateFunc Start(); - StateFunc ParseComment(); - StateFunc ParseBugURL(); - StateFunc BeginModifiers(); - StateFunc InModifiers(); - StateFunc SaveModifier(); - StateFunc EndModifiers(); - StateFunc ParseTestName(); - StateFunc SaveTestName(); - StateFunc ParseExpectation(); - StateFunc ParseExpectationType(); - StateFunc SaveExpectationType(); - StateFunc End(); - - // A state function that collects character data from the current position - // to the next whitespace character. Returns the |success| function when at - // the end of the string, with the data stored in |extracted_string_|. - StateFunc ExtractString(StateFunc success); - - // Function that skips over horizontal whitespace characters and then returns - // the |next| state. - StateFunc SkipWhitespace(StateFunc next); - - // Does the same as SkipWhitespace but includes newlines. - StateFunc SkipWhitespaceAndNewLines(StateFunc next); - - // State function that reports the given syntax error |message| to the - // delegate and then returns NULL, ending the parse loop. - StateFunc SyntaxError(const std::string& message); - - // Function that reports the data |error| to the delegate without stopping - // parsing. - void DataError(const std::string& error); - - // Parser delegate. - Delegate* delegate_; - - // The input string. - std::string input_; - - // Current location in the |input_|. - const char* pos_; - - // Pointer to the end of the |input_|. - const char* end_; - - // Current line number, as updated by SkipWhitespace(). - int line_number_; - - // The character data extracted from |input_| as a result of the - // ExtractString() state. - base::StringPiece extracted_string_; - - // The Expectation object that is currently being processed by the parser. - // Reset in Start(). - Expectation current_; - - // If DataError() has been called during the course of parsing |current_|. - // If true, then |current_| will not be emitted to the Delegate. - bool data_error_; -}; - -} // namespace test_expectations - -#endif // BASE_TEST_EXPECTATIONS_PARSER_H_ diff --git a/base/test/expectations/parser_unittest.cc b/base/test/expectations/parser_unittest.cc deleted file mode 100644 index 1c55a05f16..0000000000 --- a/base/test/expectations/parser_unittest.cc +++ /dev/null @@ -1,209 +0,0 @@ -// Copyright (c) 2013 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "base/test/expectations/parser.h" - -#include -#include - -#include "base/compiler_specific.h" -#include "testing/gtest/include/gtest/gtest.h" - -using test_expectations::Parser; - -class TestExpectationParserTest : public testing::Test, - public Parser::Delegate { - public: - virtual void EmitExpectation( - const test_expectations::Expectation& expectation) OVERRIDE { - expectations_.push_back(expectation); - } - - virtual void OnSyntaxError(const std::string& message) OVERRIDE { - syntax_error_ = message; - } - - virtual void OnDataError(const std::string& error) OVERRIDE { - data_errors_.push_back(error); - } - - protected: - std::vector expectations_; - std::string syntax_error_; - std::vector data_errors_; -}; - -TEST_F(TestExpectationParserTest, Basic) { - Parser(this, - "http://crbug.com/1234 [ Win-8 ] DouglasTest.PoopsOk = Timeout"). - Parse(); - EXPECT_TRUE(syntax_error_.empty()); - EXPECT_EQ(0u, data_errors_.size()); - - ASSERT_EQ(1u, expectations_.size()); - EXPECT_EQ("DouglasTest.PoopsOk", expectations_[0].test_name); - EXPECT_EQ(test_expectations::RESULT_TIMEOUT, expectations_[0].result); - EXPECT_EQ(test_expectations::CONFIGURATION_UNSPECIFIED, - expectations_[0].configuration); - - ASSERT_EQ(1u, expectations_[0].platforms.size()); - EXPECT_EQ("Win", expectations_[0].platforms[0].name); - EXPECT_EQ("8", expectations_[0].platforms[0].variant); -} - -TEST_F(TestExpectationParserTest, MultiModifier) { - Parser(this, "BUG [ Win-XP Mac ] OhMy.MeOhMy = Failure").Parse(); - EXPECT_TRUE(syntax_error_.empty()); - EXPECT_EQ(0u, data_errors_.size()); - - ASSERT_EQ(1u, expectations_.size()); - EXPECT_EQ("OhMy.MeOhMy", expectations_[0].test_name); - EXPECT_EQ(test_expectations::RESULT_FAILURE, - expectations_[0].result); - EXPECT_EQ(test_expectations::CONFIGURATION_UNSPECIFIED, - expectations_[0].configuration); - - ASSERT_EQ(2u, expectations_[0].platforms.size()); - - EXPECT_EQ("Win", expectations_[0].platforms[0].name); - EXPECT_EQ("XP", expectations_[0].platforms[0].variant); - - EXPECT_EQ("Mac", expectations_[0].platforms[1].name); - EXPECT_EQ("", expectations_[0].platforms[1].variant); -} - -TEST_F(TestExpectationParserTest, EmptyModifier) { - Parser(this, - "BUG [] First.Test = Failure\n" - "BUG2 [ ] Second.Test = Crash").Parse(); - EXPECT_EQ(0u, data_errors_.size()); - - ASSERT_EQ(2u, expectations_.size()); - - EXPECT_EQ("First.Test", expectations_[0].test_name); - EXPECT_EQ(test_expectations::RESULT_FAILURE, - expectations_[0].result); - EXPECT_EQ(test_expectations::CONFIGURATION_UNSPECIFIED, - expectations_[0].configuration); - EXPECT_EQ(0u, expectations_[0].platforms.size()); - - EXPECT_EQ("Second.Test", expectations_[1].test_name); - EXPECT_EQ(test_expectations::RESULT_CRASH, - expectations_[1].result); - EXPECT_EQ(test_expectations::CONFIGURATION_UNSPECIFIED, - expectations_[1].configuration); - EXPECT_EQ(0u, expectations_[1].platforms.size()); -} - -TEST_F(TestExpectationParserTest, MultiLine) { - Parser(this, - "BUG [ Linux ] Line.First = Failure\n" - "\n" - "# A test comment.\n" - "BUG2 [ Release ] Line.Second = Skip").Parse(); - EXPECT_TRUE(syntax_error_.empty()); - EXPECT_EQ(0u, data_errors_.size()); - - ASSERT_EQ(2u, expectations_.size()); - EXPECT_EQ("Line.First", expectations_[0].test_name); - EXPECT_EQ(test_expectations::RESULT_FAILURE, expectations_[0].result); - EXPECT_EQ(test_expectations::CONFIGURATION_UNSPECIFIED, - expectations_[0].configuration); - - ASSERT_EQ(1u, expectations_[0].platforms.size()); - EXPECT_EQ("Linux", expectations_[0].platforms[0].name); - EXPECT_EQ("", expectations_[0].platforms[0].variant); - - EXPECT_EQ("Line.Second", expectations_[1].test_name); - EXPECT_EQ(test_expectations::RESULT_SKIP, expectations_[1].result); - EXPECT_EQ(test_expectations::CONFIGURATION_RELEASE, - expectations_[1].configuration); - EXPECT_EQ(0u, expectations_[1].platforms.size()); -} - -TEST_F(TestExpectationParserTest, MultiLineWithComments) { - Parser(this, - " # Comment for your thoughts\n" - " \t \n" - "BUG [ Mac-10.8 Debug] Foo=Bar =Skip # Why not another comment?\n" - "BUG2 [Win-XP\tWin-Vista ] Cow.GoesMoo =\tTimeout\n\n").Parse(); - EXPECT_TRUE(syntax_error_.empty()) << syntax_error_; - EXPECT_EQ(0u, data_errors_.size()); - - ASSERT_EQ(2u, expectations_.size()); - EXPECT_EQ("Foo=Bar", expectations_[0].test_name); - EXPECT_EQ(test_expectations::RESULT_SKIP, expectations_[0].result); - EXPECT_EQ(test_expectations::CONFIGURATION_DEBUG, - expectations_[0].configuration); - - ASSERT_EQ(1u, expectations_[0].platforms.size()); - EXPECT_EQ("Mac", expectations_[0].platforms[0].name); - EXPECT_EQ("10.8", expectations_[0].platforms[0].variant); - - EXPECT_EQ("Cow.GoesMoo", expectations_[1].test_name); - EXPECT_EQ(test_expectations::RESULT_TIMEOUT, expectations_[1].result); - EXPECT_EQ(test_expectations::CONFIGURATION_UNSPECIFIED, - expectations_[1].configuration); - - ASSERT_EQ(2u, expectations_[1].platforms.size()); - EXPECT_EQ("Win", expectations_[1].platforms[0].name); - EXPECT_EQ("XP", expectations_[1].platforms[0].variant); - EXPECT_EQ("Win", expectations_[1].platforms[0].name); - EXPECT_EQ("Vista", expectations_[1].platforms[1].variant); -} - -TEST_F(TestExpectationParserTest, WeirdSpaces) { - Parser(this, " BUG [Linux] Weird = Skip ").Parse(); - EXPECT_EQ(1u, expectations_.size()); - EXPECT_TRUE(syntax_error_.empty()); - EXPECT_EQ(0u, data_errors_.size()); -} - -TEST_F(TestExpectationParserTest, SyntaxErrors) { - const char* kErrors[] = { - "Foo [ dfasd", - "Foo [Linux] # This is an illegal comment", - "Foo [Linux] Bar # Another illegal comment.", - "Foo [Linux] Bar = # Another illegal comment.", - "Foo[Linux]Bar=Failure", - "Foo\n[Linux] Bar = Failure", - "Foo [\nLinux] Bar = Failure", - "Foo [Linux\n] Bar = Failure", - "Foo [ Linux ] \n Bar = Failure", - "Foo [ Linux ] Bar =\nFailure", - "Foo [ Linux \n ] Bar =\nFailure", - }; - - for (size_t i = 0; i < arraysize(kErrors); ++i) { - Parser(this, kErrors[i]).Parse(); - EXPECT_FALSE(syntax_error_.empty()) - << "Should have error for #" << i << ": " << kErrors[i]; - syntax_error_.clear(); - } -} - -TEST_F(TestExpectationParserTest, DataErrors) { - const char* kOneError[] = { - "http://crbug.com/1234 [MagicBrowzR] BadModifier = Timeout", - "________ [Linux] BadResult = WhatNow", - "http://wkb.ug/1234 [Debug Release Win-7] MultipleConfigs = Skip", - }; - - for (size_t i = 0; i < arraysize(kOneError); ++i) { - Parser(this, kOneError[i]).Parse(); - EXPECT_EQ(1u, data_errors_.size()) << kOneError[i]; - data_errors_.clear(); - } - - const char* kTwoErrors[] = { - ". [Mac-TurningIntoiOS] BadModifierVariant.BadResult = Foobar", - "1234 [ Debug Release OS/2 ] MultipleConfigs.BadModifier = Pass", - }; - - for (size_t i = 0; i < arraysize(kTwoErrors); ++i) { - Parser(this, kTwoErrors[i]).Parse(); - EXPECT_EQ(2u, data_errors_.size()) << kTwoErrors[i]; - data_errors_.clear(); - } -} diff --git a/base/test/mock_chrome_application_mac.h b/base/test/mock_chrome_application_mac.h deleted file mode 100644 index ffa3080aec..0000000000 --- a/base/test/mock_chrome_application_mac.h +++ /dev/null @@ -1,33 +0,0 @@ -// Copyright (c) 2011 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef BASE_TEST_MOCK_CHROME_APPLICATION_MAC_H_ -#define BASE_TEST_MOCK_CHROME_APPLICATION_MAC_H_ - -#if defined(__OBJC__) - -#import - -#include "base/mac/scoped_sending_event.h" -#include "base/message_loop/message_pump_mac.h" - -// A basic implementation of CrAppProtocol and -// CrAppControlProtocol. This can be used in tests that need an -// NSApplication and use a runloop, or which need a ScopedSendingEvent -// when handling a nested event loop. -@interface MockCrApp : NSApplication { - @private - BOOL handlingSendEvent_; -} -@end - -#endif - -// To be used to instantiate MockCrApp from C++ code. -namespace mock_cr_app { -void RegisterMockCrApp(); -} // namespace mock_cr_app - -#endif // BASE_TEST_MOCK_CHROME_APPLICATION_MAC_H_ diff --git a/base/test/mock_chrome_application_mac.mm b/base/test/mock_chrome_application_mac.mm deleted file mode 100644 index 089055361d..0000000000 --- a/base/test/mock_chrome_application_mac.mm +++ /dev/null @@ -1,44 +0,0 @@ -// Copyright (c) 2011 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "base/test/mock_chrome_application_mac.h" - -#include "base/auto_reset.h" -#include "base/logging.h" - -@implementation MockCrApp - -+ (NSApplication*)sharedApplication { - NSApplication* app = [super sharedApplication]; - DCHECK([app conformsToProtocol:@protocol(CrAppControlProtocol)]) - << "Existing NSApp (class " << [[app className] UTF8String] - << ") does not conform to required protocol."; - DCHECK(base::MessagePumpMac::UsingCrApp()) - << "MessagePumpMac::Create() was called before " - << "+[MockCrApp sharedApplication]"; - return app; -} - -- (void)sendEvent:(NSEvent*)event { - base::AutoReset scoper(&handlingSendEvent_, YES); - [super sendEvent:event]; -} - -- (void)setHandlingSendEvent:(BOOL)handlingSendEvent { - handlingSendEvent_ = handlingSendEvent; -} - -- (BOOL)isHandlingSendEvent { - return handlingSendEvent_; -} - -@end - -namespace mock_cr_app { - -void RegisterMockCrApp() { - [MockCrApp sharedApplication]; -} - -} // namespace mock_cr_app diff --git a/base/test/mock_devices_changed_observer.cc b/base/test/mock_devices_changed_observer.cc deleted file mode 100644 index c05f26a613..0000000000 --- a/base/test/mock_devices_changed_observer.cc +++ /dev/null @@ -1,15 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "base/test/mock_devices_changed_observer.h" - -namespace base { - -MockDevicesChangedObserver::MockDevicesChangedObserver() { -} - -MockDevicesChangedObserver::~MockDevicesChangedObserver() { -} - -} // namespace base diff --git a/base/test/mock_devices_changed_observer.h b/base/test/mock_devices_changed_observer.h deleted file mode 100644 index 3ada16b8d4..0000000000 --- a/base/test/mock_devices_changed_observer.h +++ /dev/null @@ -1,29 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef BASE_TEST_MOCK_DEVICES_CHANGED_OBSERVER_H_ -#define BASE_TEST_MOCK_DEVICES_CHANGED_OBSERVER_H_ - -#include - -#include "base/system_monitor/system_monitor.h" -#include "testing/gmock/include/gmock/gmock.h" - -namespace base { - -class MockDevicesChangedObserver - : public base::SystemMonitor::DevicesChangedObserver { - public: - MockDevicesChangedObserver(); - ~MockDevicesChangedObserver(); - - MOCK_METHOD1(OnDevicesChanged, - void(base::SystemMonitor::DeviceType device_type)); - - DISALLOW_COPY_AND_ASSIGN(MockDevicesChangedObserver); -}; - -} // namespace base - -#endif // BASE_TEST_MOCK_DEVICES_CHANGED_OBSERVER_H_ diff --git a/base/test/mock_time_provider.cc b/base/test/mock_time_provider.cc deleted file mode 100644 index 9e5547fcd9..0000000000 --- a/base/test/mock_time_provider.cc +++ /dev/null @@ -1,31 +0,0 @@ -// Copyright (c) 2011 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "base/logging.h" -#include "base/test/mock_time_provider.h" - -using ::testing::DefaultValue; - -namespace base { - -MockTimeProvider* MockTimeProvider::instance_ = NULL; - -MockTimeProvider::MockTimeProvider() { - DCHECK(!instance_) << "Only one instance of MockTimeProvider can exist"; - DCHECK(!DefaultValue is rarely useful. One such use is when A is non-const ref that you -// want filled by the dispatchee, and the tuple is merely a container for that -// output (a "tier"). See MakeRefTuple and its usages. - -struct Tuple0 { - typedef Tuple0 ValueTuple; - typedef Tuple0 RefTuple; - typedef Tuple0 ParamTuple; -}; - -template -struct Tuple1 { - public: - typedef A TypeA; - - Tuple1() {} - explicit Tuple1(typename TupleTraits::ParamType a) : a(a) {} - - A a; -}; - -template -struct Tuple2 { - public: - typedef A TypeA; - typedef B TypeB; - - Tuple2() {} - Tuple2(typename TupleTraits::ParamType a, - typename TupleTraits::ParamType b) - : a(a), b(b) { - } - - A a; - B b; -}; - -template -struct Tuple3 { - public: - typedef A TypeA; - typedef B TypeB; - typedef C TypeC; - - Tuple3() {} - Tuple3(typename TupleTraits::ParamType a, - typename TupleTraits::ParamType b, - typename TupleTraits::ParamType c) - : a(a), b(b), c(c){ - } - - A a; - B b; - C c; -}; - -template -struct Tuple4 { - public: - typedef A TypeA; - typedef B TypeB; - typedef C TypeC; - typedef D TypeD; - - Tuple4() {} - Tuple4(typename TupleTraits::ParamType a, - typename TupleTraits::ParamType b, - typename TupleTraits::ParamType c, - typename TupleTraits::ParamType d) - : a(a), b(b), c(c), d(d) { - } - - A a; - B b; - C c; - D d; -}; - -template -struct Tuple5 { - public: - typedef A TypeA; - typedef B TypeB; - typedef C TypeC; - typedef D TypeD; - typedef E TypeE; - - Tuple5() {} - Tuple5(typename TupleTraits::ParamType a, - typename TupleTraits::ParamType b, - typename TupleTraits::ParamType c, - typename TupleTraits::ParamType d, - typename TupleTraits::ParamType e) - : a(a), b(b), c(c), d(d), e(e) { - } - - A a; - B b; - C c; - D d; - E e; -}; - -template -struct Tuple6 { - public: - typedef A TypeA; - typedef B TypeB; - typedef C TypeC; - typedef D TypeD; - typedef E TypeE; - typedef F TypeF; - - Tuple6() {} - Tuple6(typename TupleTraits::ParamType a, - typename TupleTraits::ParamType b, - typename TupleTraits::ParamType c, - typename TupleTraits::ParamType d, - typename TupleTraits::ParamType e, - typename TupleTraits::ParamType f) - : a(a), b(b), c(c), d(d), e(e), f(f) { - } - - A a; - B b; - C c; - D d; - E e; - F f; -}; - -template -struct Tuple7 { - public: - typedef A TypeA; - typedef B TypeB; - typedef C TypeC; - typedef D TypeD; - typedef E TypeE; - typedef F TypeF; - typedef G TypeG; - - Tuple7() {} - Tuple7(typename TupleTraits::ParamType a, - typename TupleTraits::ParamType b, - typename TupleTraits::ParamType c, - typename TupleTraits::ParamType d, - typename TupleTraits::ParamType e, - typename TupleTraits::ParamType f, - typename TupleTraits::ParamType g) - : a(a), b(b), c(c), d(d), e(e), f(f), g(g) { - } - - A a; - B b; - C c; - D d; - E e; - F f; - G g; -}; - -template -struct Tuple8 { - public: - typedef A TypeA; - typedef B TypeB; - typedef C TypeC; - typedef D TypeD; - typedef E TypeE; - typedef F TypeF; - typedef G TypeG; - typedef H TypeH; - - Tuple8() {} - Tuple8(typename TupleTraits::ParamType a, - typename TupleTraits::ParamType b, - typename TupleTraits::ParamType c, - typename TupleTraits::ParamType d, - typename TupleTraits::ParamType e, - typename TupleTraits::ParamType f, - typename TupleTraits::ParamType g, - typename TupleTraits::ParamType h) - : a(a), b(b), c(c), d(d), e(e), f(f), g(g), h(h) { - } - - A a; - B b; - C c; - D d; - E e; - F f; - G g; - H h; -}; - -// Tuple types ---------------------------------------------------------------- -// -// Allows for selection of ValueTuple/RefTuple/ParamTuple without needing the -// definitions of class types the tuple takes as parameters. - -template <> -struct TupleTypes< Tuple0 > { - typedef Tuple0 ValueTuple; - typedef Tuple0 RefTuple; - typedef Tuple0 ParamTuple; -}; - -template -struct TupleTypes< Tuple1 > { - typedef Tuple1::ValueType> ValueTuple; - typedef Tuple1::RefType> RefTuple; - typedef Tuple1::ParamType> ParamTuple; -}; - -template -struct TupleTypes< Tuple2 > { - typedef Tuple2::ValueType, - typename TupleTraits::ValueType> ValueTuple; -typedef Tuple2::RefType, - typename TupleTraits::RefType> RefTuple; - typedef Tuple2::ParamType, - typename TupleTraits::ParamType> ParamTuple; -}; - -template -struct TupleTypes< Tuple3 > { - typedef Tuple3::ValueType, - typename TupleTraits::ValueType, - typename TupleTraits::ValueType> ValueTuple; -typedef Tuple3::RefType, - typename TupleTraits::RefType, - typename TupleTraits::RefType> RefTuple; - typedef Tuple3::ParamType, - typename TupleTraits::ParamType, - typename TupleTraits::ParamType> ParamTuple; -}; - -template -struct TupleTypes< Tuple4 > { - typedef Tuple4::ValueType, - typename TupleTraits::ValueType, - typename TupleTraits::ValueType, - typename TupleTraits::ValueType> ValueTuple; -typedef Tuple4::RefType, - typename TupleTraits::RefType, - typename TupleTraits::RefType, - typename TupleTraits::RefType> RefTuple; - typedef Tuple4::ParamType, - typename TupleTraits::ParamType, - typename TupleTraits::ParamType, - typename TupleTraits::ParamType> ParamTuple; -}; - -template -struct TupleTypes< Tuple5 > { - typedef Tuple5::ValueType, - typename TupleTraits::ValueType, - typename TupleTraits::ValueType, - typename TupleTraits::ValueType, - typename TupleTraits::ValueType> ValueTuple; -typedef Tuple5::RefType, - typename TupleTraits::RefType, - typename TupleTraits::RefType, - typename TupleTraits::RefType, - typename TupleTraits::RefType> RefTuple; - typedef Tuple5::ParamType, - typename TupleTraits::ParamType, - typename TupleTraits::ParamType, - typename TupleTraits::ParamType, - typename TupleTraits::ParamType> ParamTuple; -}; - -template -struct TupleTypes< Tuple6 > { - typedef Tuple6::ValueType, - typename TupleTraits::ValueType, - typename TupleTraits::ValueType, - typename TupleTraits::ValueType, - typename TupleTraits::ValueType, - typename TupleTraits::ValueType> ValueTuple; -typedef Tuple6::RefType, - typename TupleTraits::RefType, - typename TupleTraits::RefType, - typename TupleTraits::RefType, - typename TupleTraits::RefType, - typename TupleTraits::RefType> RefTuple; - typedef Tuple6::ParamType, - typename TupleTraits::ParamType, - typename TupleTraits::ParamType, - typename TupleTraits::ParamType, - typename TupleTraits::ParamType, - typename TupleTraits::ParamType> ParamTuple; -}; - -template -struct TupleTypes< Tuple7 > { - typedef Tuple7::ValueType, - typename TupleTraits::ValueType, - typename TupleTraits::ValueType, - typename TupleTraits::ValueType, - typename TupleTraits::ValueType, - typename TupleTraits::ValueType, - typename TupleTraits::ValueType> ValueTuple; -typedef Tuple7::RefType, - typename TupleTraits::RefType, - typename TupleTraits::RefType, - typename TupleTraits::RefType, - typename TupleTraits::RefType, - typename TupleTraits::RefType, - typename TupleTraits::RefType> RefTuple; - typedef Tuple7::ParamType, - typename TupleTraits::ParamType, - typename TupleTraits::ParamType, - typename TupleTraits::ParamType, - typename TupleTraits::ParamType, - typename TupleTraits::ParamType, - typename TupleTraits::ParamType> ParamTuple; -}; - -template -struct TupleTypes< Tuple8 > { - typedef Tuple8::ValueType, - typename TupleTraits::ValueType, - typename TupleTraits::ValueType, - typename TupleTraits::ValueType, - typename TupleTraits::ValueType, - typename TupleTraits::ValueType, - typename TupleTraits::ValueType, - typename TupleTraits::ValueType> ValueTuple; -typedef Tuple8::RefType, - typename TupleTraits::RefType, - typename TupleTraits::RefType, - typename TupleTraits::RefType, - typename TupleTraits::RefType, - typename TupleTraits::RefType, - typename TupleTraits::RefType, - typename TupleTraits::RefType> RefTuple; - typedef Tuple8::ParamType, - typename TupleTraits::ParamType, - typename TupleTraits::ParamType, - typename TupleTraits::ParamType, - typename TupleTraits::ParamType, - typename TupleTraits::ParamType, - typename TupleTraits::ParamType, - typename TupleTraits::ParamType> ParamTuple; -}; - -// Tuple creators ------------------------------------------------------------- -// -// Helper functions for constructing tuples while inferring the template -// argument types. - -inline Tuple0 MakeTuple() { - return Tuple0(); -} - -template -inline Tuple1 MakeTuple(const A& a) { - return Tuple1(a); -} - -template -inline Tuple2 MakeTuple(const A& a, const B& b) { - return Tuple2(a, b); -} - -template -inline Tuple3 MakeTuple(const A& a, const B& b, const C& c) { - return Tuple3(a, b, c); -} - -template -inline Tuple4 MakeTuple(const A& a, const B& b, const C& c, - const D& d) { - return Tuple4(a, b, c, d); -} - -template -inline Tuple5 MakeTuple(const A& a, const B& b, const C& c, - const D& d, const E& e) { - return Tuple5(a, b, c, d, e); -} - -template -inline Tuple6 MakeTuple(const A& a, const B& b, const C& c, - const D& d, const E& e, const F& f) { - return Tuple6(a, b, c, d, e, f); -} - -template -inline Tuple7 MakeTuple(const A& a, const B& b, const C& c, - const D& d, const E& e, const F& f, - const G& g) { - return Tuple7(a, b, c, d, e, f, g); -} - -template -inline Tuple8 MakeTuple(const A& a, const B& b, - const C& c, const D& d, - const E& e, const F& f, - const G& g, const H& h) { - return Tuple8(a, b, c, d, e, f, g, h); -} - -// The following set of helpers make what Boost refers to as "Tiers" - a tuple -// of references. - -template -inline Tuple1 MakeRefTuple(A& a) { - return Tuple1(a); -} - -template -inline Tuple2 MakeRefTuple(A& a, B& b) { - return Tuple2(a, b); -} - -template -inline Tuple3 MakeRefTuple(A& a, B& b, C& c) { - return Tuple3(a, b, c); -} - -template -inline Tuple4 MakeRefTuple(A& a, B& b, C& c, D& d) { - return Tuple4(a, b, c, d); -} - -template -inline Tuple5 MakeRefTuple(A& a, B& b, C& c, D& d, E& e) { - return Tuple5(a, b, c, d, e); -} - -template -inline Tuple6 MakeRefTuple(A& a, B& b, C& c, D& d, E& e, - F& f) { - return Tuple6(a, b, c, d, e, f); -} - -template -inline Tuple7 MakeRefTuple(A& a, B& b, C& c, D& d, - E& e, F& f, G& g) { - return Tuple7(a, b, c, d, e, f, g); -} - -template -inline Tuple8 MakeRefTuple(A& a, B& b, C& c, - D& d, E& e, F& f, - G& g, H& h) { - return Tuple8(a, b, c, d, e, f, g, h); -} - -// Dispatchers ---------------------------------------------------------------- -// -// Helper functions that call the given method on an object, with the unpacked -// tuple arguments. Notice that they all have the same number of arguments, -// so you need only write: -// DispatchToMethod(object, &Object::method, args); -// This is very useful for templated dispatchers, since they don't need to know -// what type |args| is. - -// Non-Static Dispatchers with no out params. - -template -inline void DispatchToMethod(ObjT* obj, Method method, const Tuple0& arg) { - (obj->*method)(); -} - -template -inline void DispatchToMethod(ObjT* obj, Method method, const A& arg) { - (obj->*method)(base::internal::UnwrapTraits::Unwrap(arg)); -} - -template -inline void DispatchToMethod(ObjT* obj, Method method, const Tuple1& arg) { - (obj->*method)(base::internal::UnwrapTraits::Unwrap(arg.a)); -} - -template -inline void DispatchToMethod(ObjT* obj, - Method method, - const Tuple2& arg) { - (obj->*method)(base::internal::UnwrapTraits::Unwrap(arg.a), - base::internal::UnwrapTraits::Unwrap(arg.b)); -} - -template -inline void DispatchToMethod(ObjT* obj, Method method, - const Tuple3& arg) { - (obj->*method)(base::internal::UnwrapTraits::Unwrap(arg.a), - base::internal::UnwrapTraits::Unwrap(arg.b), - base::internal::UnwrapTraits::Unwrap(arg.c)); -} - -template -inline void DispatchToMethod(ObjT* obj, Method method, - const Tuple4& arg) { - (obj->*method)(base::internal::UnwrapTraits::Unwrap(arg.a), - base::internal::UnwrapTraits::Unwrap(arg.b), - base::internal::UnwrapTraits::Unwrap(arg.c), - base::internal::UnwrapTraits::Unwrap(arg.d)); -} - -template -inline void DispatchToMethod(ObjT* obj, Method method, - const Tuple5& arg) { - (obj->*method)(base::internal::UnwrapTraits::Unwrap(arg.a), - base::internal::UnwrapTraits::Unwrap(arg.b), - base::internal::UnwrapTraits::Unwrap(arg.c), - base::internal::UnwrapTraits::Unwrap(arg.d), - base::internal::UnwrapTraits::Unwrap(arg.e)); -} - -template -inline void DispatchToMethod(ObjT* obj, Method method, - const Tuple6& arg) { - (obj->*method)(base::internal::UnwrapTraits::Unwrap(arg.a), - base::internal::UnwrapTraits::Unwrap(arg.b), - base::internal::UnwrapTraits::Unwrap(arg.c), - base::internal::UnwrapTraits::Unwrap(arg.d), - base::internal::UnwrapTraits::Unwrap(arg.e), - base::internal::UnwrapTraits::Unwrap(arg.f)); -} - -template -inline void DispatchToMethod(ObjT* obj, Method method, - const Tuple7& arg) { - (obj->*method)(base::internal::UnwrapTraits::Unwrap(arg.a), - base::internal::UnwrapTraits::Unwrap(arg.b), - base::internal::UnwrapTraits::Unwrap(arg.c), - base::internal::UnwrapTraits::Unwrap(arg.d), - base::internal::UnwrapTraits::Unwrap(arg.e), - base::internal::UnwrapTraits::Unwrap(arg.f), - base::internal::UnwrapTraits::Unwrap(arg.g)); -} - -template -inline void DispatchToMethod(ObjT* obj, Method method, - const Tuple8& arg) { - (obj->*method)(base::internal::UnwrapTraits::Unwrap(arg.a), - base::internal::UnwrapTraits::Unwrap(arg.b), - base::internal::UnwrapTraits::Unwrap(arg.c), - base::internal::UnwrapTraits::Unwrap(arg.d), - base::internal::UnwrapTraits::Unwrap(arg.e), - base::internal::UnwrapTraits::Unwrap(arg.f), - base::internal::UnwrapTraits::Unwrap(arg.g), - base::internal::UnwrapTraits::Unwrap(arg.h)); -} - -// Static Dispatchers with no out params. - -template -inline void DispatchToFunction(Function function, const Tuple0& arg) { - (*function)(); -} - -template -inline void DispatchToFunction(Function function, const A& arg) { - (*function)(arg); -} - -template -inline void DispatchToFunction(Function function, const Tuple1& arg) { - (*function)(base::internal::UnwrapTraits::Unwrap(arg.a)); -} - -template -inline void DispatchToFunction(Function function, const Tuple2& arg) { - (*function)(base::internal::UnwrapTraits::Unwrap(arg.a), - base::internal::UnwrapTraits::Unwrap(arg.b)); -} - -template -inline void DispatchToFunction(Function function, const Tuple3& arg) { - (*function)(base::internal::UnwrapTraits::Unwrap(arg.a), - base::internal::UnwrapTraits::Unwrap(arg.b), - base::internal::UnwrapTraits::Unwrap(arg.c)); -} - -template -inline void DispatchToFunction(Function function, - const Tuple4& arg) { - (*function)(base::internal::UnwrapTraits::Unwrap(arg.a), - base::internal::UnwrapTraits::Unwrap(arg.b), - base::internal::UnwrapTraits::Unwrap(arg.c), - base::internal::UnwrapTraits::Unwrap(arg.d)); -} - -template -inline void DispatchToFunction(Function function, - const Tuple5& arg) { - (*function)(base::internal::UnwrapTraits::Unwrap(arg.a), - base::internal::UnwrapTraits::Unwrap(arg.b), - base::internal::UnwrapTraits::Unwrap(arg.c), - base::internal::UnwrapTraits::Unwrap(arg.d), - base::internal::UnwrapTraits::Unwrap(arg.e)); -} - -template -inline void DispatchToFunction(Function function, - const Tuple6& arg) { - (*function)(base::internal::UnwrapTraits::Unwrap(arg.a), - base::internal::UnwrapTraits::Unwrap(arg.b), - base::internal::UnwrapTraits::Unwrap(arg.c), - base::internal::UnwrapTraits::Unwrap(arg.d), - base::internal::UnwrapTraits::Unwrap(arg.e), - base::internal::UnwrapTraits::Unwrap(arg.f)); -} - -template -inline void DispatchToFunction(Function function, - const Tuple7& arg) { - (*function)(base::internal::UnwrapTraits::Unwrap(arg.a), - base::internal::UnwrapTraits::Unwrap(arg.b), - base::internal::UnwrapTraits::Unwrap(arg.c), - base::internal::UnwrapTraits::Unwrap(arg.d), - base::internal::UnwrapTraits::Unwrap(arg.e), - base::internal::UnwrapTraits::Unwrap(arg.f), - base::internal::UnwrapTraits::Unwrap(arg.g)); -} - -template -inline void DispatchToFunction(Function function, - const Tuple8& arg) { - (*function)(base::internal::UnwrapTraits::Unwrap(arg.a), - base::internal::UnwrapTraits::Unwrap(arg.b), - base::internal::UnwrapTraits::Unwrap(arg.c), - base::internal::UnwrapTraits::Unwrap(arg.d), - base::internal::UnwrapTraits::Unwrap(arg.e), - base::internal::UnwrapTraits::Unwrap(arg.f), - base::internal::UnwrapTraits::Unwrap(arg.g), - base::internal::UnwrapTraits::Unwrap(arg.h)); -} - -// Dispatchers with 0 out param (as a Tuple0). - -template -inline void DispatchToMethod(ObjT* obj, - Method method, - const Tuple0& arg, Tuple0*) { - (obj->*method)(); -} - -template -inline void DispatchToMethod(ObjT* obj, Method method, const A& arg, Tuple0*) { - (obj->*method)(base::internal::UnwrapTraits::Unwrap(arg)); -} - -template -inline void DispatchToMethod(ObjT* obj, - Method method, - const Tuple1& arg, Tuple0*) { - (obj->*method)(base::internal::UnwrapTraits::Unwrap(arg.a)); -} - -template -inline void DispatchToMethod(ObjT* obj, - Method method, - const Tuple2& arg, Tuple0*) { - (obj->*method)(base::internal::UnwrapTraits::Unwrap(arg.a), - base::internal::UnwrapTraits::Unwrap(arg.b)); -} - -template -inline void DispatchToMethod(ObjT* obj, Method method, - const Tuple3& arg, Tuple0*) { - (obj->*method)(base::internal::UnwrapTraits::Unwrap(arg.a), - base::internal::UnwrapTraits::Unwrap(arg.b), - base::internal::UnwrapTraits::Unwrap(arg.c)); -} - -template -inline void DispatchToMethod(ObjT* obj, Method method, - const Tuple4& arg, Tuple0*) { - (obj->*method)(base::internal::UnwrapTraits::Unwrap(arg.a), - base::internal::UnwrapTraits::Unwrap(arg.b), - base::internal::UnwrapTraits::Unwrap(arg.c), - base::internal::UnwrapTraits::Unwrap(arg.d)); -} - -template -inline void DispatchToMethod(ObjT* obj, Method method, - const Tuple5& arg, Tuple0*) { - (obj->*method)(base::internal::UnwrapTraits::Unwrap(arg.a), - base::internal::UnwrapTraits::Unwrap(arg.b), - base::internal::UnwrapTraits::Unwrap(arg.c), - base::internal::UnwrapTraits::Unwrap(arg.d), - base::internal::UnwrapTraits::Unwrap(arg.e)); -} - -template -inline void DispatchToMethod(ObjT* obj, Method method, - const Tuple6& arg, Tuple0*) { - (obj->*method)(base::internal::UnwrapTraits::Unwrap(arg.a), - base::internal::UnwrapTraits::Unwrap(arg.b), - base::internal::UnwrapTraits::Unwrap(arg.c), - base::internal::UnwrapTraits::Unwrap(arg.d), - base::internal::UnwrapTraits::Unwrap(arg.e), - base::internal::UnwrapTraits::Unwrap(arg.f)); -} - -// Dispatchers with 1 out param. - -template -inline void DispatchToMethod(ObjT* obj, Method method, - const Tuple0& in, - Tuple1* out) { - (obj->*method)(&out->a); -} - -template -inline void DispatchToMethod(ObjT* obj, Method method, - const InA& in, - Tuple1* out) { - (obj->*method)(in, &out->a); -} - -template -inline void DispatchToMethod(ObjT* obj, Method method, - const Tuple1& in, - Tuple1* out) { - (obj->*method)(base::internal::UnwrapTraits::Unwrap(in.a), &out->a); -} - -template -inline void DispatchToMethod(ObjT* obj, Method method, - const Tuple2& in, - Tuple1* out) { - (obj->*method)(base::internal::UnwrapTraits::Unwrap(in.a), - base::internal::UnwrapTraits::Unwrap(in.b), - &out->a); -} - -template -inline void DispatchToMethod(ObjT* obj, Method method, - const Tuple3& in, - Tuple1* out) { - (obj->*method)(base::internal::UnwrapTraits::Unwrap(in.a), - base::internal::UnwrapTraits::Unwrap(in.b), - base::internal::UnwrapTraits::Unwrap(in.c), - &out->a); -} - -template -inline void DispatchToMethod(ObjT* obj, Method method, - const Tuple4& in, - Tuple1* out) { - (obj->*method)(base::internal::UnwrapTraits::Unwrap(in.a), - base::internal::UnwrapTraits::Unwrap(in.b), - base::internal::UnwrapTraits::Unwrap(in.c), - base::internal::UnwrapTraits::Unwrap(in.d), - &out->a); -} - -template -inline void DispatchToMethod(ObjT* obj, Method method, - const Tuple5& in, - Tuple1* out) { - (obj->*method)(base::internal::UnwrapTraits::Unwrap(in.a), - base::internal::UnwrapTraits::Unwrap(in.b), - base::internal::UnwrapTraits::Unwrap(in.c), - base::internal::UnwrapTraits::Unwrap(in.d), - base::internal::UnwrapTraits::Unwrap(in.e), - &out->a); -} - -template -inline void DispatchToMethod(ObjT* obj, Method method, - const Tuple6& in, - Tuple1* out) { - (obj->*method)(base::internal::UnwrapTraits::Unwrap(in.a), - base::internal::UnwrapTraits::Unwrap(in.b), - base::internal::UnwrapTraits::Unwrap(in.c), - base::internal::UnwrapTraits::Unwrap(in.d), - base::internal::UnwrapTraits::Unwrap(in.e), - base::internal::UnwrapTraits::Unwrap(in.f), - &out->a); -} - -// Dispatchers with 2 out params. - -template -inline void DispatchToMethod(ObjT* obj, Method method, - const Tuple0& in, - Tuple2* out) { - (obj->*method)(&out->a, &out->b); -} - -template -inline void DispatchToMethod(ObjT* obj, Method method, - const InA& in, - Tuple2* out) { - (obj->*method)(in, &out->a, &out->b); -} - -template -inline void DispatchToMethod(ObjT* obj, Method method, - const Tuple1& in, - Tuple2* out) { - (obj->*method)( - base::internal::UnwrapTraits::Unwrap(in.a), &out->a, &out->b); -} - -template -inline void DispatchToMethod(ObjT* obj, Method method, - const Tuple2& in, - Tuple2* out) { - (obj->*method)(base::internal::UnwrapTraits::Unwrap(in.a), - base::internal::UnwrapTraits::Unwrap(in.b), - &out->a, - &out->b); -} - -template -inline void DispatchToMethod(ObjT* obj, Method method, - const Tuple3& in, - Tuple2* out) { - (obj->*method)(base::internal::UnwrapTraits::Unwrap(in.a), - base::internal::UnwrapTraits::Unwrap(in.b), - base::internal::UnwrapTraits::Unwrap(in.c), - &out->a, - &out->b); -} - -template -inline void DispatchToMethod(ObjT* obj, Method method, - const Tuple4& in, - Tuple2* out) { - (obj->*method)(base::internal::UnwrapTraits::Unwrap(in.a), - base::internal::UnwrapTraits::Unwrap(in.b), - base::internal::UnwrapTraits::Unwrap(in.c), - base::internal::UnwrapTraits::Unwrap(in.d), - &out->a, - &out->b); -} - -template -inline void DispatchToMethod(ObjT* obj, Method method, - const Tuple5& in, - Tuple2* out) { - (obj->*method)(base::internal::UnwrapTraits::Unwrap(in.a), - base::internal::UnwrapTraits::Unwrap(in.b), - base::internal::UnwrapTraits::Unwrap(in.c), - base::internal::UnwrapTraits::Unwrap(in.d), - base::internal::UnwrapTraits::Unwrap(in.e), - &out->a, - &out->b); -} - -template -inline void DispatchToMethod(ObjT* obj, Method method, - const Tuple6& in, - Tuple2* out) { - (obj->*method)(base::internal::UnwrapTraits::Unwrap(in.a), - base::internal::UnwrapTraits::Unwrap(in.b), - base::internal::UnwrapTraits::Unwrap(in.c), - base::internal::UnwrapTraits::Unwrap(in.d), - base::internal::UnwrapTraits::Unwrap(in.e), - base::internal::UnwrapTraits::Unwrap(in.f), - &out->a, - &out->b); -} - -// Dispatchers with 3 out params. - -template -inline void DispatchToMethod(ObjT* obj, Method method, - const Tuple0& in, - Tuple3* out) { - (obj->*method)(&out->a, &out->b, &out->c); -} - -template -inline void DispatchToMethod(ObjT* obj, Method method, - const InA& in, - Tuple3* out) { - (obj->*method)(in, &out->a, &out->b, &out->c); -} - -template -inline void DispatchToMethod(ObjT* obj, Method method, - const Tuple1& in, - Tuple3* out) { - (obj->*method)(base::internal::UnwrapTraits::Unwrap(in.a), - &out->a, - &out->b, - &out->c); -} - -template -inline void DispatchToMethod(ObjT* obj, Method method, - const Tuple2& in, - Tuple3* out) { - (obj->*method)(base::internal::UnwrapTraits::Unwrap(in.a), - base::internal::UnwrapTraits::Unwrap(in.b), - &out->a, - &out->b, - &out->c); -} - -template -inline void DispatchToMethod(ObjT* obj, Method method, - const Tuple3& in, - Tuple3* out) { - (obj->*method)(base::internal::UnwrapTraits::Unwrap(in.a), - base::internal::UnwrapTraits::Unwrap(in.b), - base::internal::UnwrapTraits::Unwrap(in.c), - &out->a, - &out->b, - &out->c); -} - -template -inline void DispatchToMethod(ObjT* obj, Method method, - const Tuple4& in, - Tuple3* out) { - (obj->*method)(base::internal::UnwrapTraits::Unwrap(in.a), - base::internal::UnwrapTraits::Unwrap(in.b), - base::internal::UnwrapTraits::Unwrap(in.c), - base::internal::UnwrapTraits::Unwrap(in.d), - &out->a, - &out->b, - &out->c); -} - -template -inline void DispatchToMethod(ObjT* obj, Method method, - const Tuple5& in, - Tuple3* out) { - (obj->*method)(base::internal::UnwrapTraits::Unwrap(in.a), - base::internal::UnwrapTraits::Unwrap(in.b), - base::internal::UnwrapTraits::Unwrap(in.c), - base::internal::UnwrapTraits::Unwrap(in.d), - base::internal::UnwrapTraits::Unwrap(in.e), - &out->a, - &out->b, - &out->c); -} - -template -inline void DispatchToMethod(ObjT* obj, Method method, - const Tuple6& in, - Tuple3* out) { - (obj->*method)(base::internal::UnwrapTraits::Unwrap(in.a), - base::internal::UnwrapTraits::Unwrap(in.b), - base::internal::UnwrapTraits::Unwrap(in.c), - base::internal::UnwrapTraits::Unwrap(in.d), - base::internal::UnwrapTraits::Unwrap(in.e), - base::internal::UnwrapTraits::Unwrap(in.f), - &out->a, - &out->b, - &out->c); -} - -// Dispatchers with 4 out params. - -template -inline void DispatchToMethod(ObjT* obj, Method method, - const Tuple0& in, - Tuple4* out) { - (obj->*method)(&out->a, &out->b, &out->c, &out->d); -} - -template -inline void DispatchToMethod(ObjT* obj, Method method, - const InA& in, - Tuple4* out) { - (obj->*method)(base::internal::UnwrapTraits::Unwrap(in), - &out->a, - &out->b, - &out->c, - &out->d); -} - -template -inline void DispatchToMethod(ObjT* obj, Method method, - const Tuple1& in, - Tuple4* out) { - (obj->*method)(base::internal::UnwrapTraits::Unwrap(in.a), - &out->a, - &out->b, - &out->c, - &out->d); -} - -template -inline void DispatchToMethod(ObjT* obj, Method method, - const Tuple2& in, - Tuple4* out) { - (obj->*method)(base::internal::UnwrapTraits::Unwrap(in.a), - base::internal::UnwrapTraits::Unwrap(in.b), - &out->a, - &out->b, - &out->c, - &out->d); -} - -template -inline void DispatchToMethod(ObjT* obj, Method method, - const Tuple3& in, - Tuple4* out) { - (obj->*method)(base::internal::UnwrapTraits::Unwrap(in.a), - base::internal::UnwrapTraits::Unwrap(in.b), - base::internal::UnwrapTraits::Unwrap(in.c), - &out->a, - &out->b, - &out->c, - &out->d); -} - -template -inline void DispatchToMethod(ObjT* obj, Method method, - const Tuple4& in, - Tuple4* out) { - (obj->*method)(base::internal::UnwrapTraits::Unwrap(in.a), - base::internal::UnwrapTraits::Unwrap(in.b), - base::internal::UnwrapTraits::Unwrap(in.c), - base::internal::UnwrapTraits::Unwrap(in.d), - &out->a, - &out->b, - &out->c, - &out->d); -} - -template -inline void DispatchToMethod(ObjT* obj, Method method, - const Tuple5& in, - Tuple4* out) { - (obj->*method)(base::internal::UnwrapTraits::Unwrap(in.a), - base::internal::UnwrapTraits::Unwrap(in.b), - base::internal::UnwrapTraits::Unwrap(in.c), - base::internal::UnwrapTraits::Unwrap(in.d), - base::internal::UnwrapTraits::Unwrap(in.e), - &out->a, - &out->b, - &out->c, - &out->d); -} - -template -inline void DispatchToMethod(ObjT* obj, Method method, - const Tuple6& in, - Tuple4* out) { - (obj->*method)(base::internal::UnwrapTraits::Unwrap(in.a), - base::internal::UnwrapTraits::Unwrap(in.b), - base::internal::UnwrapTraits::Unwrap(in.c), - base::internal::UnwrapTraits::Unwrap(in.d), - base::internal::UnwrapTraits::Unwrap(in.e), - base::internal::UnwrapTraits::Unwrap(in.f), - &out->a, - &out->b, - &out->c, - &out->d); -} - -// Dispatchers with 5 out params. - -template -inline void DispatchToMethod(ObjT* obj, Method method, - const Tuple0& in, - Tuple5* out) { - (obj->*method)(&out->a, &out->b, &out->c, &out->d, &out->e); -} - -template -inline void DispatchToMethod(ObjT* obj, Method method, - const InA& in, - Tuple5* out) { - (obj->*method)(base::internal::UnwrapTraits::Unwrap(in), - &out->a, - &out->b, - &out->c, - &out->d, - &out->e); -} - -template -inline void DispatchToMethod(ObjT* obj, Method method, - const Tuple1& in, - Tuple5* out) { - (obj->*method)(base::internal::UnwrapTraits::Unwrap(in.a), - &out->a, - &out->b, - &out->c, - &out->d, - &out->e); -} - -template -inline void DispatchToMethod(ObjT* obj, Method method, - const Tuple2& in, - Tuple5* out) { - (obj->*method)(base::internal::UnwrapTraits::Unwrap(in.a), - base::internal::UnwrapTraits::Unwrap(in.b), - &out->a, - &out->b, - &out->c, - &out->d, - &out->e); -} - -template -inline void DispatchToMethod(ObjT* obj, Method method, - const Tuple3& in, - Tuple5* out) { - (obj->*method)(base::internal::UnwrapTraits::Unwrap(in.a), - base::internal::UnwrapTraits::Unwrap(in.b), - base::internal::UnwrapTraits::Unwrap(in.c), - &out->a, - &out->b, - &out->c, - &out->d, - &out->e); -} - -template -inline void DispatchToMethod(ObjT* obj, Method method, - const Tuple4& in, - Tuple5* out) { - (obj->*method)(base::internal::UnwrapTraits::Unwrap(in.a), - base::internal::UnwrapTraits::Unwrap(in.b), - base::internal::UnwrapTraits::Unwrap(in.c), - base::internal::UnwrapTraits::Unwrap(in.d), - &out->a, - &out->b, - &out->c, - &out->d, - &out->e); -} - -template -inline void DispatchToMethod(ObjT* obj, Method method, - const Tuple5& in, - Tuple5* out) { - (obj->*method)(base::internal::UnwrapTraits::Unwrap(in.a), - base::internal::UnwrapTraits::Unwrap(in.b), - base::internal::UnwrapTraits::Unwrap(in.c), - base::internal::UnwrapTraits::Unwrap(in.d), - base::internal::UnwrapTraits::Unwrap(in.e), - &out->a, - &out->b, - &out->c, - &out->d, - &out->e); -} - -template -inline void DispatchToMethod(ObjT* obj, Method method, - const Tuple6& in, - Tuple5* out) { - (obj->*method)(base::internal::UnwrapTraits::Unwrap(in.a), - base::internal::UnwrapTraits::Unwrap(in.b), - base::internal::UnwrapTraits::Unwrap(in.c), - base::internal::UnwrapTraits::Unwrap(in.d), - base::internal::UnwrapTraits::Unwrap(in.e), - base::internal::UnwrapTraits::Unwrap(in.f), - &out->a, - &out->b, - &out->c, - &out->d, - &out->e); -} - -#endif // BASE_TUPLE_H__ diff --git a/base/tuple_unittest.cc b/base/tuple_unittest.cc deleted file mode 100644 index 402394cb66..0000000000 --- a/base/tuple_unittest.cc +++ /dev/null @@ -1,128 +0,0 @@ -// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "base/tuple.h" - -#include "base/compiler_specific.h" -#include "testing/gtest/include/gtest/gtest.h" - -namespace { - -void DoAdd(int a, int b, int c, int* res) { - *res = a + b + c; -} - -struct Addy { - Addy() { } - void DoAdd(int a, int b, int c, int d, int* res) { - *res = a + b + c + d; - } -}; - -struct Addz { - Addz() { } - void DoAdd(int a, int b, int c, int d, int e, int* res) { - *res = a + b + c + d + e; - } -}; - -} // namespace - -TEST(TupleTest, Basic) { - Tuple0 t0 ALLOW_UNUSED = MakeTuple(); - Tuple1 t1(1); - Tuple2 t2 = MakeTuple(1, static_cast("wee")); - Tuple3 t3(1, 2, 3); - Tuple4 t4(1, 2, 3, &t1.a); - Tuple5 t5(1, 2, 3, 4, &t4.a); - Tuple6 t6(1, 2, 3, 4, 5, &t4.a); - - EXPECT_EQ(1, t1.a); - EXPECT_EQ(1, t2.a); - EXPECT_EQ(1, t3.a); - EXPECT_EQ(2, t3.b); - EXPECT_EQ(3, t3.c); - EXPECT_EQ(1, t4.a); - EXPECT_EQ(2, t4.b); - EXPECT_EQ(3, t4.c); - EXPECT_EQ(1, t5.a); - EXPECT_EQ(2, t5.b); - EXPECT_EQ(3, t5.c); - EXPECT_EQ(4, t5.d); - EXPECT_EQ(1, t6.a); - EXPECT_EQ(2, t6.b); - EXPECT_EQ(3, t6.c); - EXPECT_EQ(4, t6.d); - EXPECT_EQ(5, t6.e); - - EXPECT_EQ(1, t1.a); - DispatchToFunction(&DoAdd, t4); - EXPECT_EQ(6, t1.a); - - int res = 0; - DispatchToFunction(&DoAdd, MakeTuple(9, 8, 7, &res)); - EXPECT_EQ(24, res); - - Addy addy; - EXPECT_EQ(1, t4.a); - DispatchToMethod(&addy, &Addy::DoAdd, t5); - EXPECT_EQ(10, t4.a); - - Addz addz; - EXPECT_EQ(10, t4.a); - DispatchToMethod(&addz, &Addz::DoAdd, t6); - EXPECT_EQ(15, t4.a); -} - -namespace { - -struct CopyLogger { - CopyLogger() { ++TimesConstructed; } - CopyLogger(const CopyLogger& tocopy) { ++TimesConstructed; ++TimesCopied; } - ~CopyLogger() { } - - static int TimesCopied; - static int TimesConstructed; -}; - -void SomeLoggerMethRef(const CopyLogger& logy, const CopyLogger* ptr, bool* b) { - *b = &logy == ptr; -} - -void SomeLoggerMethCopy(CopyLogger logy, const CopyLogger* ptr, bool* b) { - *b = &logy == ptr; -} - -int CopyLogger::TimesCopied = 0; -int CopyLogger::TimesConstructed = 0; - -} // namespace - -TEST(TupleTest, Copying) { - CopyLogger logger; - EXPECT_EQ(0, CopyLogger::TimesCopied); - EXPECT_EQ(1, CopyLogger::TimesConstructed); - - bool res = false; - - // Creating the tuple should copy the class to store internally in the tuple. - Tuple3 tuple(logger, &logger, &res); - tuple.b = &tuple.a; - EXPECT_EQ(2, CopyLogger::TimesConstructed); - EXPECT_EQ(1, CopyLogger::TimesCopied); - - // Our internal Logger and the one passed to the function should be the same. - res = false; - DispatchToFunction(&SomeLoggerMethRef, tuple); - EXPECT_TRUE(res); - EXPECT_EQ(2, CopyLogger::TimesConstructed); - EXPECT_EQ(1, CopyLogger::TimesCopied); - - // Now they should be different, since the function call will make a copy. - res = false; - DispatchToFunction(&SomeLoggerMethCopy, tuple); - EXPECT_FALSE(res); - EXPECT_EQ(3, CopyLogger::TimesConstructed); - EXPECT_EQ(2, CopyLogger::TimesCopied); -} diff --git a/base/value_conversions.cc b/base/value_conversions.cc deleted file mode 100644 index 2fd88f800c..0000000000 --- a/base/value_conversions.cc +++ /dev/null @@ -1,46 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "base/value_conversions.h" - -#include "base/files/file_path.h" -#include "base/strings/string_number_conversions.h" -#include "base/time/time.h" -#include "base/values.h" - -namespace base { - -// |Value| internally stores strings in UTF-8, so we have to convert from the -// system native code to UTF-8 and back. -StringValue* CreateFilePathValue(const FilePath& in_value) { - return new StringValue(in_value.AsUTF8Unsafe()); -} - -bool GetValueAsFilePath(const Value& value, FilePath* file_path) { - std::string str; - if (!value.GetAsString(&str)) - return false; - if (file_path) - *file_path = FilePath::FromUTF8Unsafe(str); - return true; -} - -// |Value| does not support 64-bit integers, and doubles do not have enough -// precision, so we store the 64-bit time value as a string instead. -StringValue* CreateTimeDeltaValue(const TimeDelta& time) { - std::string string_value = base::Int64ToString(time.ToInternalValue()); - return new StringValue(string_value); -} - -bool GetValueAsTimeDelta(const Value& value, TimeDelta* time) { - std::string str; - int64 int_value; - if (!value.GetAsString(&str) || !base::StringToInt64(str, &int_value)) - return false; - if (time) - *time = TimeDelta::FromInternalValue(int_value); - return true; -} - -} // namespace base diff --git a/base/value_conversions.h b/base/value_conversions.h deleted file mode 100644 index fde9a26929..0000000000 --- a/base/value_conversions.h +++ /dev/null @@ -1,29 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef BASE_VALUE_CONVERSIONS_H_ -#define BASE_VALUE_CONVERSIONS_H_ - -// This file contains methods to convert things to a |Value| and back. - -#include "base/base_export.h" - - -namespace base { - -class FilePath; -class TimeDelta; -class StringValue; -class Value; - -// The caller takes ownership of the returned value. -BASE_EXPORT StringValue* CreateFilePathValue(const FilePath& in_value); -BASE_EXPORT bool GetValueAsFilePath(const Value& value, FilePath* file_path); - -BASE_EXPORT StringValue* CreateTimeDeltaValue(const TimeDelta& time); -BASE_EXPORT bool GetValueAsTimeDelta(const Value& value, TimeDelta* time); - -} // namespace - -#endif // BASE_VALUE_CONVERSIONS_H_ diff --git a/base/values.cc b/base/values.cc deleted file mode 100644 index adfb980139..0000000000 --- a/base/values.cc +++ /dev/null @@ -1,1119 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "base/values.h" - -#include -#include - -#include "base/float_util.h" -#include "base/json/json_writer.h" -#include "base/logging.h" -#include "base/strings/string_util.h" -#include "base/strings/utf_string_conversions.h" - -namespace base { - -namespace { - -// Make a deep copy of |node|, but don't include empty lists or dictionaries -// in the copy. It's possible for this function to return NULL and it -// expects |node| to always be non-NULL. -Value* CopyWithoutEmptyChildren(const Value* node) { - DCHECK(node); - switch (node->GetType()) { - case Value::TYPE_LIST: { - const ListValue* list = static_cast(node); - ListValue* copy = new ListValue; - for (ListValue::const_iterator it = list->begin(); it != list->end(); - ++it) { - Value* child_copy = CopyWithoutEmptyChildren(*it); - if (child_copy) - copy->Append(child_copy); - } - if (!copy->empty()) - return copy; - - delete copy; - return NULL; - } - - case Value::TYPE_DICTIONARY: { - const DictionaryValue* dict = static_cast(node); - DictionaryValue* copy = new DictionaryValue; - for (DictionaryValue::Iterator it(*dict); !it.IsAtEnd(); it.Advance()) { - Value* child_copy = CopyWithoutEmptyChildren(&it.value()); - if (child_copy) - copy->SetWithoutPathExpansion(it.key(), child_copy); - } - if (!copy->empty()) - return copy; - - delete copy; - return NULL; - } - - default: - // For everything else, just make a copy. - return node->DeepCopy(); - } -} - -// A small functor for comparing Values for std::find_if and similar. -class ValueEquals { - public: - // Pass the value against which all consecutive calls of the () operator will - // compare their argument to. This Value object must not be destroyed while - // the ValueEquals is in use. - explicit ValueEquals(const Value* first) : first_(first) { } - - bool operator ()(const Value* second) const { - return first_->Equals(second); - } - - private: - const Value* first_; -}; - -} // namespace - -Value::~Value() { -} - -// static -Value* Value::CreateNullValue() { - return new Value(TYPE_NULL); -} - -// static -FundamentalValue* Value::CreateBooleanValue(bool in_value) { - return new FundamentalValue(in_value); -} - -// static -FundamentalValue* Value::CreateIntegerValue(int in_value) { - return new FundamentalValue(in_value); -} - -// static -FundamentalValue* Value::CreateDoubleValue(double in_value) { - return new FundamentalValue(in_value); -} - -// static -StringValue* Value::CreateStringValue(const std::string& in_value) { - return new StringValue(in_value); -} - -// static -StringValue* Value::CreateStringValue(const string16& in_value) { - return new StringValue(in_value); -} - -bool Value::GetAsBoolean(bool* out_value) const { - return false; -} - -bool Value::GetAsInteger(int* out_value) const { - return false; -} - -bool Value::GetAsDouble(double* out_value) const { - return false; -} - -bool Value::GetAsString(std::string* out_value) const { - return false; -} - -bool Value::GetAsString(string16* out_value) const { - return false; -} - -bool Value::GetAsList(ListValue** out_value) { - return false; -} - -bool Value::GetAsList(const ListValue** out_value) const { - return false; -} - -bool Value::GetAsDictionary(DictionaryValue** out_value) { - return false; -} - -bool Value::GetAsDictionary(const DictionaryValue** out_value) const { - return false; -} - -Value* Value::DeepCopy() const { - // This method should only be getting called for null Values--all subclasses - // need to provide their own implementation;. - DCHECK(IsType(TYPE_NULL)); - return CreateNullValue(); -} - -bool Value::Equals(const Value* other) const { - // This method should only be getting called for null Values--all subclasses - // need to provide their own implementation;. - DCHECK(IsType(TYPE_NULL)); - return other->IsType(TYPE_NULL); -} - -// static -bool Value::Equals(const Value* a, const Value* b) { - if ((a == NULL) && (b == NULL)) return true; - if ((a == NULL) ^ (b == NULL)) return false; - return a->Equals(b); -} - -Value::Value(Type type) : type_(type) {} - -Value::Value(const Value& that) : type_(that.type_) {} - -Value& Value::operator=(const Value& that) { - type_ = that.type_; - return *this; -} - -///////////////////// FundamentalValue //////////////////// - -FundamentalValue::FundamentalValue(bool in_value) - : Value(TYPE_BOOLEAN), boolean_value_(in_value) { -} - -FundamentalValue::FundamentalValue(int in_value) - : Value(TYPE_INTEGER), integer_value_(in_value) { -} - -FundamentalValue::FundamentalValue(double in_value) - : Value(TYPE_DOUBLE), double_value_(in_value) { - if (!IsFinite(double_value_)) { - NOTREACHED() << "Non-finite (i.e. NaN or positive/negative infinity) " - << "values cannot be represented in JSON"; - double_value_ = 0.0; - } -} - -FundamentalValue::~FundamentalValue() { -} - -bool FundamentalValue::GetAsBoolean(bool* out_value) const { - if (out_value && IsType(TYPE_BOOLEAN)) - *out_value = boolean_value_; - return (IsType(TYPE_BOOLEAN)); -} - -bool FundamentalValue::GetAsInteger(int* out_value) const { - if (out_value && IsType(TYPE_INTEGER)) - *out_value = integer_value_; - return (IsType(TYPE_INTEGER)); -} - -bool FundamentalValue::GetAsDouble(double* out_value) const { - if (out_value && IsType(TYPE_DOUBLE)) - *out_value = double_value_; - else if (out_value && IsType(TYPE_INTEGER)) - *out_value = integer_value_; - return (IsType(TYPE_DOUBLE) || IsType(TYPE_INTEGER)); -} - -FundamentalValue* FundamentalValue::DeepCopy() const { - switch (GetType()) { - case TYPE_BOOLEAN: - return CreateBooleanValue(boolean_value_); - - case TYPE_INTEGER: - return CreateIntegerValue(integer_value_); - - case TYPE_DOUBLE: - return CreateDoubleValue(double_value_); - - default: - NOTREACHED(); - return NULL; - } -} - -bool FundamentalValue::Equals(const Value* other) const { - if (other->GetType() != GetType()) - return false; - - switch (GetType()) { - case TYPE_BOOLEAN: { - bool lhs, rhs; - return GetAsBoolean(&lhs) && other->GetAsBoolean(&rhs) && lhs == rhs; - } - case TYPE_INTEGER: { - int lhs, rhs; - return GetAsInteger(&lhs) && other->GetAsInteger(&rhs) && lhs == rhs; - } - case TYPE_DOUBLE: { - double lhs, rhs; - return GetAsDouble(&lhs) && other->GetAsDouble(&rhs) && lhs == rhs; - } - default: - NOTREACHED(); - return false; - } -} - -///////////////////// StringValue //////////////////// - -StringValue::StringValue(const std::string& in_value) - : Value(TYPE_STRING), - value_(in_value) { - DCHECK(IsStringUTF8(in_value)); -} - -StringValue::StringValue(const string16& in_value) - : Value(TYPE_STRING), - value_(UTF16ToUTF8(in_value)) { -} - -StringValue::~StringValue() { -} - -bool StringValue::GetAsString(std::string* out_value) const { - if (out_value) - *out_value = value_; - return true; -} - -bool StringValue::GetAsString(string16* out_value) const { - if (out_value) - *out_value = UTF8ToUTF16(value_); - return true; -} - -StringValue* StringValue::DeepCopy() const { - return CreateStringValue(value_); -} - -bool StringValue::Equals(const Value* other) const { - if (other->GetType() != GetType()) - return false; - std::string lhs, rhs; - return GetAsString(&lhs) && other->GetAsString(&rhs) && lhs == rhs; -} - -///////////////////// BinaryValue //////////////////// - -BinaryValue::BinaryValue() - : Value(TYPE_BINARY), - size_(0) { -} - -BinaryValue::BinaryValue(scoped_ptr buffer, size_t size) - : Value(TYPE_BINARY), - buffer_(buffer.Pass()), - size_(size) { -} - -BinaryValue::~BinaryValue() { -} - -// static -BinaryValue* BinaryValue::CreateWithCopiedBuffer(const char* buffer, - size_t size) { - char* buffer_copy = new char[size]; - memcpy(buffer_copy, buffer, size); - scoped_ptr scoped_buffer_copy(buffer_copy); - return new BinaryValue(scoped_buffer_copy.Pass(), size); -} - -BinaryValue* BinaryValue::DeepCopy() const { - return CreateWithCopiedBuffer(buffer_.get(), size_); -} - -bool BinaryValue::Equals(const Value* other) const { - if (other->GetType() != GetType()) - return false; - const BinaryValue* other_binary = static_cast(other); - if (other_binary->size_ != size_) - return false; - return !memcmp(GetBuffer(), other_binary->GetBuffer(), size_); -} - -///////////////////// DictionaryValue //////////////////// - -DictionaryValue::DictionaryValue() - : Value(TYPE_DICTIONARY) { -} - -DictionaryValue::~DictionaryValue() { - Clear(); -} - -bool DictionaryValue::GetAsDictionary(DictionaryValue** out_value) { - if (out_value) - *out_value = this; - return true; -} - -bool DictionaryValue::GetAsDictionary(const DictionaryValue** out_value) const { - if (out_value) - *out_value = this; - return true; -} - -bool DictionaryValue::HasKey(const std::string& key) const { - DCHECK(IsStringUTF8(key)); - ValueMap::const_iterator current_entry = dictionary_.find(key); - DCHECK((current_entry == dictionary_.end()) || current_entry->second); - return current_entry != dictionary_.end(); -} - -void DictionaryValue::Clear() { - ValueMap::iterator dict_iterator = dictionary_.begin(); - while (dict_iterator != dictionary_.end()) { - delete dict_iterator->second; - ++dict_iterator; - } - - dictionary_.clear(); -} - -void DictionaryValue::Set(const std::string& path, Value* in_value) { - DCHECK(IsStringUTF8(path)); - DCHECK(in_value); - - std::string current_path(path); - DictionaryValue* current_dictionary = this; - for (size_t delimiter_position = current_path.find('.'); - delimiter_position != std::string::npos; - delimiter_position = current_path.find('.')) { - // Assume that we're indexing into a dictionary. - std::string key(current_path, 0, delimiter_position); - DictionaryValue* child_dictionary = NULL; - if (!current_dictionary->GetDictionary(key, &child_dictionary)) { - child_dictionary = new DictionaryValue; - current_dictionary->SetWithoutPathExpansion(key, child_dictionary); - } - - current_dictionary = child_dictionary; - current_path.erase(0, delimiter_position + 1); - } - - current_dictionary->SetWithoutPathExpansion(current_path, in_value); -} - -void DictionaryValue::SetBoolean(const std::string& path, bool in_value) { - Set(path, CreateBooleanValue(in_value)); -} - -void DictionaryValue::SetInteger(const std::string& path, int in_value) { - Set(path, CreateIntegerValue(in_value)); -} - -void DictionaryValue::SetDouble(const std::string& path, double in_value) { - Set(path, CreateDoubleValue(in_value)); -} - -void DictionaryValue::SetString(const std::string& path, - const std::string& in_value) { - Set(path, CreateStringValue(in_value)); -} - -void DictionaryValue::SetString(const std::string& path, - const string16& in_value) { - Set(path, CreateStringValue(in_value)); -} - -void DictionaryValue::SetWithoutPathExpansion(const std::string& key, - Value* in_value) { - // If there's an existing value here, we need to delete it, because - // we own all our children. - std::pair ins_res = - dictionary_.insert(std::make_pair(key, in_value)); - if (!ins_res.second) { - DCHECK_NE(ins_res.first->second, in_value); // This would be bogus - delete ins_res.first->second; - ins_res.first->second = in_value; - } -} - -void DictionaryValue::SetBooleanWithoutPathExpansion( - const std::string& path, bool in_value) { - SetWithoutPathExpansion(path, CreateBooleanValue(in_value)); -} - -void DictionaryValue::SetIntegerWithoutPathExpansion( - const std::string& path, int in_value) { - SetWithoutPathExpansion(path, CreateIntegerValue(in_value)); -} - -void DictionaryValue::SetDoubleWithoutPathExpansion( - const std::string& path, double in_value) { - SetWithoutPathExpansion(path, CreateDoubleValue(in_value)); -} - -void DictionaryValue::SetStringWithoutPathExpansion( - const std::string& path, const std::string& in_value) { - SetWithoutPathExpansion(path, CreateStringValue(in_value)); -} - -void DictionaryValue::SetStringWithoutPathExpansion( - const std::string& path, const string16& in_value) { - SetWithoutPathExpansion(path, CreateStringValue(in_value)); -} - -bool DictionaryValue::Get( - const std::string& path, const Value** out_value) const { - DCHECK(IsStringUTF8(path)); -// LOG(WARNING) << "\n1\n"; - std::string current_path(path); - const DictionaryValue* current_dictionary = this; -// LOG(WARNING) << "\n2\n"; - for (size_t delimiter_position = current_path.find('.'); - delimiter_position != std::string::npos; - delimiter_position = current_path.find('.')) { - const DictionaryValue* child_dictionary = NULL; - if (!current_dictionary->GetDictionary( - current_path.substr(0, delimiter_position), &child_dictionary)) - return false; - - current_dictionary = child_dictionary; - current_path.erase(0, delimiter_position + 1); - } -// LOG(WARNING) << "\n3\n"; - - return current_dictionary->GetWithoutPathExpansion(current_path, out_value); -} - -bool DictionaryValue::Get(const std::string& path, Value** out_value) { - return static_cast(*this).Get( - path, - const_cast(out_value)); -} - -bool DictionaryValue::GetBoolean(const std::string& path, - bool* bool_value) const { - const Value* value; - if (!Get(path, &value)) - return false; - - return value->GetAsBoolean(bool_value); -} - -bool DictionaryValue::GetInteger(const std::string& path, - int* out_value) const { - const Value* value; - if (!Get(path, &value)) - return false; - - return value->GetAsInteger(out_value); -} - -bool DictionaryValue::GetDouble(const std::string& path, - double* out_value) const { - const Value* value; - if (!Get(path, &value)) - return false; - - return value->GetAsDouble(out_value); -} - -bool DictionaryValue::GetString(const std::string& path, - std::string* out_value) const { - const Value* value; - if (!Get(path, &value)) - return false; - - return value->GetAsString(out_value); -} - -bool DictionaryValue::GetString(const std::string& path, - string16* out_value) const { - const Value* value; - if (!Get(path, &value)) - return false; - - return value->GetAsString(out_value); -} - -bool DictionaryValue::GetStringASCII(const std::string& path, - std::string* out_value) const { - std::string out; - if (!GetString(path, &out)) - return false; - - if (!IsStringASCII(out)) { - NOTREACHED(); - return false; - } - - out_value->assign(out); - return true; -} - -bool DictionaryValue::GetBinary(const std::string& path, - const BinaryValue** out_value) const { - const Value* value; - bool result = Get(path, &value); - if (!result || !value->IsType(TYPE_BINARY)) - return false; - - if (out_value) - *out_value = static_cast(value); - - return true; -} - -bool DictionaryValue::GetBinary(const std::string& path, - BinaryValue** out_value) { - return static_cast(*this).GetBinary( - path, - const_cast(out_value)); -} - -bool DictionaryValue::GetDictionary(const std::string& path, - const DictionaryValue** out_value) const { - const Value* value; - bool result = Get(path, &value); - if (!result || !value->IsType(TYPE_DICTIONARY)) - return false; - - if (out_value) - *out_value = static_cast(value); - - return true; -} - -bool DictionaryValue::GetDictionary(const std::string& path, - DictionaryValue** out_value) { - return static_cast(*this).GetDictionary( - path, - const_cast(out_value)); -} - -bool DictionaryValue::GetList(const std::string& path, - const ListValue** out_value) const { - const Value* value; - bool result = Get(path, &value); - if (!result || !value->IsType(TYPE_LIST)) - return false; - - if (out_value) - *out_value = static_cast(value); - - return true; -} - -bool DictionaryValue::GetList(const std::string& path, ListValue** out_value) { - return static_cast(*this).GetList( - path, - const_cast(out_value)); -} - -bool DictionaryValue::GetWithoutPathExpansion(const std::string& key, - const Value** out_value) const { - DCHECK(IsStringUTF8(key)); - ValueMap::const_iterator entry_iterator = dictionary_.find(key); - if (entry_iterator == dictionary_.end()) - return false; - - const Value* entry = entry_iterator->second; - if (out_value) - *out_value = entry; - return true; -} - -bool DictionaryValue::GetWithoutPathExpansion(const std::string& key, - Value** out_value) { - return static_cast(*this).GetWithoutPathExpansion( - key, - const_cast(out_value)); -} - -bool DictionaryValue::GetBooleanWithoutPathExpansion(const std::string& key, - bool* out_value) const { - const Value* value; - if (!GetWithoutPathExpansion(key, &value)) - return false; - - return value->GetAsBoolean(out_value); -} - -bool DictionaryValue::GetIntegerWithoutPathExpansion(const std::string& key, - int* out_value) const { - const Value* value; - if (!GetWithoutPathExpansion(key, &value)) - return false; - - return value->GetAsInteger(out_value); -} - -bool DictionaryValue::GetDoubleWithoutPathExpansion(const std::string& key, - double* out_value) const { - const Value* value; - if (!GetWithoutPathExpansion(key, &value)) - return false; - - return value->GetAsDouble(out_value); -} - -bool DictionaryValue::GetStringWithoutPathExpansion( - const std::string& key, - std::string* out_value) const { - const Value* value; - if (!GetWithoutPathExpansion(key, &value)) - return false; - - return value->GetAsString(out_value); -} - -bool DictionaryValue::GetStringWithoutPathExpansion(const std::string& key, - string16* out_value) const { - const Value* value; - if (!GetWithoutPathExpansion(key, &value)) - return false; - - return value->GetAsString(out_value); -} - -bool DictionaryValue::GetDictionaryWithoutPathExpansion( - const std::string& key, - const DictionaryValue** out_value) const { - const Value* value; - bool result = GetWithoutPathExpansion(key, &value); - if (!result || !value->IsType(TYPE_DICTIONARY)) - return false; - - if (out_value) - *out_value = static_cast(value); - - return true; -} - -bool DictionaryValue::GetDictionaryWithoutPathExpansion( - const std::string& key, - DictionaryValue** out_value) { - const DictionaryValue& const_this = - static_cast(*this); - return const_this.GetDictionaryWithoutPathExpansion( - key, - const_cast(out_value)); -} - -bool DictionaryValue::GetListWithoutPathExpansion( - const std::string& key, - const ListValue** out_value) const { - const Value* value; - bool result = GetWithoutPathExpansion(key, &value); - if (!result || !value->IsType(TYPE_LIST)) - return false; - - if (out_value) - *out_value = static_cast(value); - - return true; -} - -bool DictionaryValue::GetListWithoutPathExpansion(const std::string& key, - ListValue** out_value) { - return - static_cast(*this).GetListWithoutPathExpansion( - key, - const_cast(out_value)); -} - -bool DictionaryValue::Remove(const std::string& path, - scoped_ptr* out_value) { - DCHECK(IsStringUTF8(path)); - std::string current_path(path); - DictionaryValue* current_dictionary = this; - size_t delimiter_position = current_path.rfind('.'); - if (delimiter_position != std::string::npos) { - if (!GetDictionary(current_path.substr(0, delimiter_position), - ¤t_dictionary)) - return false; - current_path.erase(0, delimiter_position + 1); - } - - return current_dictionary->RemoveWithoutPathExpansion(current_path, - out_value); -} - -bool DictionaryValue::RemoveWithoutPathExpansion(const std::string& key, - scoped_ptr* out_value) { - DCHECK(IsStringUTF8(key)); - ValueMap::iterator entry_iterator = dictionary_.find(key); - if (entry_iterator == dictionary_.end()) - return false; - - Value* entry = entry_iterator->second; - if (out_value) - out_value->reset(entry); - else - delete entry; - dictionary_.erase(entry_iterator); - return true; -} - -DictionaryValue* DictionaryValue::DeepCopyWithoutEmptyChildren() { - Value* copy = CopyWithoutEmptyChildren(this); - return copy ? static_cast(copy) : new DictionaryValue; -} - -void DictionaryValue::MergeDictionary(const DictionaryValue* dictionary) { - for (DictionaryValue::Iterator it(*dictionary); !it.IsAtEnd(); it.Advance()) { - const Value* merge_value = &it.value(); - // Check whether we have to merge dictionaries. - if (merge_value->IsType(Value::TYPE_DICTIONARY)) { - DictionaryValue* sub_dict; - if (GetDictionaryWithoutPathExpansion(it.key(), &sub_dict)) { - sub_dict->MergeDictionary( - static_cast(merge_value)); - continue; - } - } - // All other cases: Make a copy and hook it up. - SetWithoutPathExpansion(it.key(), merge_value->DeepCopy()); - } -} - -void DictionaryValue::Swap(DictionaryValue* other) { - dictionary_.swap(other->dictionary_); -} - -DictionaryValue::Iterator::Iterator(const DictionaryValue& target) - : target_(target), - it_(target.dictionary_.begin()) {} - -DictionaryValue* DictionaryValue::DeepCopy() const { - DictionaryValue* result = new DictionaryValue; - - for (ValueMap::const_iterator current_entry(dictionary_.begin()); - current_entry != dictionary_.end(); ++current_entry) { - result->SetWithoutPathExpansion(current_entry->first, - current_entry->second->DeepCopy()); - } - - return result; -} - -bool DictionaryValue::Equals(const Value* other) const { - if (other->GetType() != GetType()) - return false; - - const DictionaryValue* other_dict = - static_cast(other); - Iterator lhs_it(*this); - Iterator rhs_it(*other_dict); - while (!lhs_it.IsAtEnd() && !rhs_it.IsAtEnd()) { - if (lhs_it.key() != rhs_it.key() || - !lhs_it.value().Equals(&rhs_it.value())) { - return false; - } - lhs_it.Advance(); - rhs_it.Advance(); - } - if (!lhs_it.IsAtEnd() || !rhs_it.IsAtEnd()) - return false; - - return true; -} - -///////////////////// ListValue //////////////////// - -ListValue::ListValue() : Value(TYPE_LIST) { -} - -ListValue::~ListValue() { - Clear(); -} - -void ListValue::Clear() { - for (ValueVector::iterator i(list_.begin()); i != list_.end(); ++i) - delete *i; - list_.clear(); -} - -bool ListValue::Set(size_t index, Value* in_value) { - if (!in_value) - return false; - - if (index >= list_.size()) { - // Pad out any intermediate indexes with null settings - while (index > list_.size()) - Append(CreateNullValue()); - Append(in_value); - } else { - DCHECK(list_[index] != in_value); - delete list_[index]; - list_[index] = in_value; - } - return true; -} - -bool ListValue::Get(size_t index, const Value** out_value) const { - if (index >= list_.size()) - return false; - - if (out_value) - *out_value = list_[index]; - - return true; -} - -bool ListValue::Get(size_t index, Value** out_value) { - return static_cast(*this).Get( - index, - const_cast(out_value)); -} - -bool ListValue::GetBoolean(size_t index, bool* bool_value) const { - const Value* value; - if (!Get(index, &value)) - return false; - - return value->GetAsBoolean(bool_value); -} - -bool ListValue::GetInteger(size_t index, int* out_value) const { - const Value* value; - if (!Get(index, &value)) - return false; - - return value->GetAsInteger(out_value); -} - -bool ListValue::GetDouble(size_t index, double* out_value) const { - const Value* value; - if (!Get(index, &value)) - return false; - - return value->GetAsDouble(out_value); -} - -bool ListValue::GetString(size_t index, std::string* out_value) const { - const Value* value; - if (!Get(index, &value)) - return false; - - return value->GetAsString(out_value); -} - -bool ListValue::GetString(size_t index, string16* out_value) const { - const Value* value; - if (!Get(index, &value)) - return false; - - return value->GetAsString(out_value); -} - -bool ListValue::GetBinary(size_t index, const BinaryValue** out_value) const { - const Value* value; - bool result = Get(index, &value); - if (!result || !value->IsType(TYPE_BINARY)) - return false; - - if (out_value) - *out_value = static_cast(value); - - return true; -} - -bool ListValue::GetBinary(size_t index, BinaryValue** out_value) { - return static_cast(*this).GetBinary( - index, - const_cast(out_value)); -} - -bool ListValue::GetDictionary(size_t index, - const DictionaryValue** out_value) const { - const Value* value; - bool result = Get(index, &value); - if (!result || !value->IsType(TYPE_DICTIONARY)) - return false; - - if (out_value) - *out_value = static_cast(value); - - return true; -} - -bool ListValue::GetDictionary(size_t index, DictionaryValue** out_value) { - return static_cast(*this).GetDictionary( - index, - const_cast(out_value)); -} - -bool ListValue::GetList(size_t index, const ListValue** out_value) const { - const Value* value; - bool result = Get(index, &value); - if (!result || !value->IsType(TYPE_LIST)) - return false; - - if (out_value) - *out_value = static_cast(value); - - return true; -} - -bool ListValue::GetList(size_t index, ListValue** out_value) { - return static_cast(*this).GetList( - index, - const_cast(out_value)); -} - -bool ListValue::Remove(size_t index, scoped_ptr* out_value) { - if (index >= list_.size()) - return false; - - if (out_value) - out_value->reset(list_[index]); - else - delete list_[index]; - - list_.erase(list_.begin() + index); - return true; -} - -bool ListValue::Remove(const Value& value, size_t* index) { - for (ValueVector::iterator i(list_.begin()); i != list_.end(); ++i) { - if ((*i)->Equals(&value)) { - size_t previous_index = i - list_.begin(); - delete *i; - list_.erase(i); - - if (index) - *index = previous_index; - return true; - } - } - return false; -} - -ListValue::iterator ListValue::Erase(iterator iter, - scoped_ptr* out_value) { - if (out_value) - out_value->reset(*iter); - else - delete *iter; - - return list_.erase(iter); -} - -void ListValue::Append(Value* in_value) { - DCHECK(in_value); - list_.push_back(in_value); -} - -void ListValue::AppendBoolean(bool in_value) { - Append(CreateBooleanValue(in_value)); -} - -void ListValue::AppendInteger(int in_value) { - Append(CreateIntegerValue(in_value)); -} - -void ListValue::AppendDouble(double in_value) { - Append(CreateDoubleValue(in_value)); -} - -void ListValue::AppendString(const std::string& in_value) { - Append(CreateStringValue(in_value)); -} - -void ListValue::AppendString(const string16& in_value) { - Append(CreateStringValue(in_value)); -} - -void ListValue::AppendStrings(const std::vector& in_values) { - for (std::vector::const_iterator it = in_values.begin(); - it != in_values.end(); ++it) { - AppendString(*it); - } -} - -void ListValue::AppendStrings(const std::vector& in_values) { - for (std::vector::const_iterator it = in_values.begin(); - it != in_values.end(); ++it) { - AppendString(*it); - } -} - -bool ListValue::AppendIfNotPresent(Value* in_value) { - DCHECK(in_value); - for (ValueVector::const_iterator i(list_.begin()); i != list_.end(); ++i) { - if ((*i)->Equals(in_value)) { - delete in_value; - return false; - } - } - list_.push_back(in_value); - return true; -} - -bool ListValue::Insert(size_t index, Value* in_value) { - DCHECK(in_value); - if (index > list_.size()) - return false; - - list_.insert(list_.begin() + index, in_value); - return true; -} - -ListValue::const_iterator ListValue::Find(const Value& value) const { - return std::find_if(list_.begin(), list_.end(), ValueEquals(&value)); -} - -void ListValue::Swap(ListValue* other) { - list_.swap(other->list_); -} - -bool ListValue::GetAsList(ListValue** out_value) { - if (out_value) - *out_value = this; - return true; -} - -bool ListValue::GetAsList(const ListValue** out_value) const { - if (out_value) - *out_value = this; - return true; -} - -ListValue* ListValue::DeepCopy() const { - ListValue* result = new ListValue; - - for (ValueVector::const_iterator i(list_.begin()); i != list_.end(); ++i) - result->Append((*i)->DeepCopy()); - - return result; -} - -bool ListValue::Equals(const Value* other) const { - if (other->GetType() != GetType()) - return false; - - const ListValue* other_list = - static_cast(other); - const_iterator lhs_it, rhs_it; - for (lhs_it = begin(), rhs_it = other_list->begin(); - lhs_it != end() && rhs_it != other_list->end(); - ++lhs_it, ++rhs_it) { - if (!(*lhs_it)->Equals(*rhs_it)) - return false; - } - if (lhs_it != end() || rhs_it != other_list->end()) - return false; - - return true; -} - -ValueSerializer::~ValueSerializer() { -} - -std::ostream& operator<<(std::ostream& out, const Value& value) { - std::string json; - JSONWriter::WriteWithOptions(&value, - JSONWriter::OPTIONS_PRETTY_PRINT, - &json); - return out << json; -} - -} // namespace base diff --git a/base/values.h b/base/values.h deleted file mode 100644 index 4025c751ee..0000000000 --- a/base/values.h +++ /dev/null @@ -1,529 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -// This file specifies a recursive data storage class called Value intended for -// storing settings and other persistable data. -// -// A Value represents something that can be stored in JSON or passed to/from -// JavaScript. As such, it is NOT a generalized variant type, since only the -// types supported by JavaScript/JSON are supported. -// -// IN PARTICULAR this means that there is no support for int64 or unsigned -// numbers. Writing JSON with such types would violate the spec. If you need -// something like this, either use a double or make a string value containing -// the number you want. - -#ifndef BASE_VALUES_H_ -#define BASE_VALUES_H_ - -#include -#include -#include -#include - -#include "base/base_export.h" -#include "base/basictypes.h" -#include "base/compiler_specific.h" -#include "base/memory/scoped_ptr.h" -#include "base/strings/string16.h" - -// This file declares "using base::Value", etc. at the bottom, so that -// current code can use these classes without the base namespace. In -// new code, please always use base::Value, etc. or add your own -// "using" declaration. -// http://crbug.com/88666 -namespace base { - -class BinaryValue; -class DictionaryValue; -class FundamentalValue; -class ListValue; -class StringValue; -class Value; - -typedef std::vector ValueVector; -typedef std::map ValueMap; - -// The Value class is the base class for Values. A Value can be instantiated -// via the Create*Value() factory methods, or by directly creating instances of -// the subclasses. -// -// See the file-level comment above for more information. -class BASE_EXPORT Value { - public: - enum Type { - TYPE_NULL = 0, - TYPE_BOOLEAN, - TYPE_INTEGER, - TYPE_DOUBLE, - TYPE_STRING, - TYPE_BINARY, - TYPE_DICTIONARY, - TYPE_LIST - // Note: Do not add more types. See the file-level comment above for why. - }; - - virtual ~Value(); - - static Value* CreateNullValue(); - // DEPRECATED: Do not use the following 5 functions. Instead, use - // new FundamentalValue or new StringValue. - static FundamentalValue* CreateBooleanValue(bool in_value); - static FundamentalValue* CreateIntegerValue(int in_value); - static FundamentalValue* CreateDoubleValue(double in_value); - static StringValue* CreateStringValue(const std::string& in_value); - static StringValue* CreateStringValue(const string16& in_value); - - // Returns the type of the value stored by the current Value object. - // Each type will be implemented by only one subclass of Value, so it's - // safe to use the Type to determine whether you can cast from - // Value* to (Implementing Class)*. Also, a Value object never changes - // its type after construction. - Type GetType() const { return type_; } - - // Returns true if the current object represents a given type. - bool IsType(Type type) const { return type == type_; } - - // These methods allow the convenient retrieval of the contents of the Value. - // If the current object can be converted into the given type, the value is - // returned through the |out_value| parameter and true is returned; - // otherwise, false is returned and |out_value| is unchanged. - virtual bool GetAsBoolean(bool* out_value) const; - virtual bool GetAsInteger(int* out_value) const; - virtual bool GetAsDouble(double* out_value) const; - virtual bool GetAsString(std::string* out_value) const; - virtual bool GetAsString(string16* out_value) const; - virtual bool GetAsList(ListValue** out_value); - virtual bool GetAsList(const ListValue** out_value) const; - virtual bool GetAsDictionary(DictionaryValue** out_value); - virtual bool GetAsDictionary(const DictionaryValue** out_value) const; - // Note: Do not add more types. See the file-level comment above for why. - - // This creates a deep copy of the entire Value tree, and returns a pointer - // to the copy. The caller gets ownership of the copy, of course. - // - // Subclasses return their own type directly in their overrides; - // this works because C++ supports covariant return types. - virtual Value* DeepCopy() const; - - // Compares if two Value objects have equal contents. - virtual bool Equals(const Value* other) const; - - // Compares if two Value objects have equal contents. Can handle NULLs. - // NULLs are considered equal but different from Value::CreateNullValue(). - static bool Equals(const Value* a, const Value* b); - - protected: - // These aren't safe for end-users, but they are useful for subclasses. - explicit Value(Type type); - Value(const Value& that); - Value& operator=(const Value& that); - - private: - Type type_; -}; - -// FundamentalValue represents the simple fundamental types of values. -class BASE_EXPORT FundamentalValue : public Value { - public: - explicit FundamentalValue(bool in_value); - explicit FundamentalValue(int in_value); - explicit FundamentalValue(double in_value); - virtual ~FundamentalValue(); - - // Overridden from Value: - virtual bool GetAsBoolean(bool* out_value) const OVERRIDE; - virtual bool GetAsInteger(int* out_value) const OVERRIDE; - virtual bool GetAsDouble(double* out_value) const OVERRIDE; - virtual FundamentalValue* DeepCopy() const OVERRIDE; - virtual bool Equals(const Value* other) const OVERRIDE; - - private: - union { - bool boolean_value_; - int integer_value_; - double double_value_; - }; -}; - -class BASE_EXPORT StringValue : public Value { - public: - // Initializes a StringValue with a UTF-8 narrow character string. - explicit StringValue(const std::string& in_value); - - // Initializes a StringValue with a string16. - explicit StringValue(const string16& in_value); - - virtual ~StringValue(); - - // Overridden from Value: - virtual bool GetAsString(std::string* out_value) const OVERRIDE; - virtual bool GetAsString(string16* out_value) const OVERRIDE; - virtual StringValue* DeepCopy() const OVERRIDE; - virtual bool Equals(const Value* other) const OVERRIDE; - - private: - std::string value_; -}; - -class BASE_EXPORT BinaryValue: public Value { - public: - // Creates a BinaryValue with a null buffer and size of 0. - BinaryValue(); - - // Creates a BinaryValue, taking ownership of the bytes pointed to by - // |buffer|. - BinaryValue(scoped_ptr buffer, size_t size); - - virtual ~BinaryValue(); - - // For situations where you want to keep ownership of your buffer, this - // factory method creates a new BinaryValue by copying the contents of the - // buffer that's passed in. - static BinaryValue* CreateWithCopiedBuffer(const char* buffer, size_t size); - - size_t GetSize() const { return size_; } - - // May return NULL. - char* GetBuffer() { return buffer_.get(); } - const char* GetBuffer() const { return buffer_.get(); } - - // Overridden from Value: - virtual BinaryValue* DeepCopy() const OVERRIDE; - virtual bool Equals(const Value* other) const OVERRIDE; - - private: - scoped_ptr buffer_; - size_t size_; - - DISALLOW_COPY_AND_ASSIGN(BinaryValue); -}; - -// DictionaryValue provides a key-value dictionary with (optional) "path" -// parsing for recursive access; see the comment at the top of the file. Keys -// are |std::string|s and should be UTF-8 encoded. -class BASE_EXPORT DictionaryValue : public Value { - public: - DictionaryValue(); - virtual ~DictionaryValue(); - - // Overridden from Value: - virtual bool GetAsDictionary(DictionaryValue** out_value) OVERRIDE; - virtual bool GetAsDictionary( - const DictionaryValue** out_value) const OVERRIDE; - - // Returns true if the current dictionary has a value for the given key. - bool HasKey(const std::string& key) const; - - // Returns the number of Values in this dictionary. - size_t size() const { return dictionary_.size(); } - - // Returns whether the dictionary is empty. - bool empty() const { return dictionary_.empty(); } - - // Clears any current contents of this dictionary. - void Clear(); - - // Sets the Value associated with the given path starting from this object. - // A path has the form "" or "..[...]", where "." indexes - // into the next DictionaryValue down. Obviously, "." can't be used - // within a key, but there are no other restrictions on keys. - // If the key at any step of the way doesn't exist, or exists but isn't - // a DictionaryValue, a new DictionaryValue will be created and attached - // to the path in that location. - // Note that the dictionary takes ownership of the value referenced by - // |in_value|, and therefore |in_value| must be non-NULL. - void Set(const std::string& path, Value* in_value); - - // Convenience forms of Set(). These methods will replace any existing - // value at that path, even if it has a different type. - void SetBoolean(const std::string& path, bool in_value); - void SetInteger(const std::string& path, int in_value); - void SetDouble(const std::string& path, double in_value); - void SetString(const std::string& path, const std::string& in_value); - void SetString(const std::string& path, const string16& in_value); - - // Like Set(), but without special treatment of '.'. This allows e.g. URLs to - // be used as paths. - void SetWithoutPathExpansion(const std::string& key, Value* in_value); - - // Convenience forms of SetWithoutPathExpansion(). - void SetBooleanWithoutPathExpansion(const std::string& path, bool in_value); - void SetIntegerWithoutPathExpansion(const std::string& path, int in_value); - void SetDoubleWithoutPathExpansion(const std::string& path, double in_value); - void SetStringWithoutPathExpansion(const std::string& path, - const std::string& in_value); - void SetStringWithoutPathExpansion(const std::string& path, - const string16& in_value); - - // Gets the Value associated with the given path starting from this object. - // A path has the form "" or "..[...]", where "." indexes - // into the next DictionaryValue down. If the path can be resolved - // successfully, the value for the last key in the path will be returned - // through the |out_value| parameter, and the function will return true. - // Otherwise, it will return false and |out_value| will be untouched. - // Note that the dictionary always owns the value that's returned. - bool Get(const std::string& path, const Value** out_value) const; - bool Get(const std::string& path, Value** out_value); - - // These are convenience forms of Get(). The value will be retrieved - // and the return value will be true if the path is valid and the value at - // the end of the path can be returned in the form specified. - bool GetBoolean(const std::string& path, bool* out_value) const; - bool GetInteger(const std::string& path, int* out_value) const; - bool GetDouble(const std::string& path, double* out_value) const; - bool GetString(const std::string& path, std::string* out_value) const; - bool GetString(const std::string& path, string16* out_value) const; - bool GetStringASCII(const std::string& path, std::string* out_value) const; - bool GetBinary(const std::string& path, const BinaryValue** out_value) const; - bool GetBinary(const std::string& path, BinaryValue** out_value); - bool GetDictionary(const std::string& path, - const DictionaryValue** out_value) const; - bool GetDictionary(const std::string& path, DictionaryValue** out_value); - bool GetList(const std::string& path, const ListValue** out_value) const; - bool GetList(const std::string& path, ListValue** out_value); - - // Like Get(), but without special treatment of '.'. This allows e.g. URLs to - // be used as paths. - bool GetWithoutPathExpansion(const std::string& key, - const Value** out_value) const; - bool GetWithoutPathExpansion(const std::string& key, Value** out_value); - bool GetBooleanWithoutPathExpansion(const std::string& key, - bool* out_value) const; - bool GetIntegerWithoutPathExpansion(const std::string& key, - int* out_value) const; - bool GetDoubleWithoutPathExpansion(const std::string& key, - double* out_value) const; - bool GetStringWithoutPathExpansion(const std::string& key, - std::string* out_value) const; - bool GetStringWithoutPathExpansion(const std::string& key, - string16* out_value) const; - bool GetDictionaryWithoutPathExpansion( - const std::string& key, - const DictionaryValue** out_value) const; - bool GetDictionaryWithoutPathExpansion(const std::string& key, - DictionaryValue** out_value); - bool GetListWithoutPathExpansion(const std::string& key, - const ListValue** out_value) const; - bool GetListWithoutPathExpansion(const std::string& key, - ListValue** out_value); - - // Removes the Value with the specified path from this dictionary (or one - // of its child dictionaries, if the path is more than just a local key). - // If |out_value| is non-NULL, the removed Value will be passed out via - // |out_value|. If |out_value| is NULL, the removed value will be deleted. - // This method returns true if |path| is a valid path; otherwise it will - // return false and the DictionaryValue object will be unchanged. - virtual bool Remove(const std::string& path, scoped_ptr* out_value); - - // Like Remove(), but without special treatment of '.'. This allows e.g. URLs - // to be used as paths. - virtual bool RemoveWithoutPathExpansion(const std::string& key, - scoped_ptr* out_value); - - // Makes a copy of |this| but doesn't include empty dictionaries and lists in - // the copy. This never returns NULL, even if |this| itself is empty. - DictionaryValue* DeepCopyWithoutEmptyChildren(); - - // Merge |dictionary| into this dictionary. This is done recursively, i.e. any - // sub-dictionaries will be merged as well. In case of key collisions, the - // passed in dictionary takes precedence and data already present will be - // replaced. Values within |dictionary| are deep-copied, so |dictionary| may - // be freed any time after this call. - void MergeDictionary(const DictionaryValue* dictionary); - - // Swaps contents with the |other| dictionary. - virtual void Swap(DictionaryValue* other); - - // This class provides an iterator over both keys and values in the - // dictionary. It can't be used to modify the dictionary. - class BASE_EXPORT Iterator { - public: - explicit Iterator(const DictionaryValue& target); - - bool IsAtEnd() const { return it_ == target_.dictionary_.end(); } - void Advance() { ++it_; } - - const std::string& key() const { return it_->first; } - const Value& value() const { return *it_->second; } - - private: - const DictionaryValue& target_; - ValueMap::const_iterator it_; - }; - - // Overridden from Value: - virtual DictionaryValue* DeepCopy() const OVERRIDE; - virtual bool Equals(const Value* other) const OVERRIDE; - - private: - ValueMap dictionary_; - - DISALLOW_COPY_AND_ASSIGN(DictionaryValue); -}; - -// This type of Value represents a list of other Value values. -class BASE_EXPORT ListValue : public Value { - public: - typedef ValueVector::iterator iterator; - typedef ValueVector::const_iterator const_iterator; - - ListValue(); - virtual ~ListValue(); - - // Clears the contents of this ListValue - void Clear(); - - // Returns the number of Values in this list. - size_t GetSize() const { return list_.size(); } - - // Returns whether the list is empty. - bool empty() const { return list_.empty(); } - - // Sets the list item at the given index to be the Value specified by - // the value given. If the index beyond the current end of the list, null - // Values will be used to pad out the list. - // Returns true if successful, or false if the index was negative or - // the value is a null pointer. - bool Set(size_t index, Value* in_value); - - // Gets the Value at the given index. Modifies |out_value| (and returns true) - // only if the index falls within the current list range. - // Note that the list always owns the Value passed out via |out_value|. - bool Get(size_t index, const Value** out_value) const; - bool Get(size_t index, Value** out_value); - - // Convenience forms of Get(). Modifies |out_value| (and returns true) - // only if the index is valid and the Value at that index can be returned - // in the specified form. - bool GetBoolean(size_t index, bool* out_value) const; - bool GetInteger(size_t index, int* out_value) const; - bool GetDouble(size_t index, double* out_value) const; - bool GetString(size_t index, std::string* out_value) const; - bool GetString(size_t index, string16* out_value) const; - bool GetBinary(size_t index, const BinaryValue** out_value) const; - bool GetBinary(size_t index, BinaryValue** out_value); - bool GetDictionary(size_t index, const DictionaryValue** out_value) const; - bool GetDictionary(size_t index, DictionaryValue** out_value); - bool GetList(size_t index, const ListValue** out_value) const; - bool GetList(size_t index, ListValue** out_value); - - // Removes the Value with the specified index from this list. - // If |out_value| is non-NULL, the removed Value AND ITS OWNERSHIP will be - // passed out via |out_value|. If |out_value| is NULL, the removed value will - // be deleted. This method returns true if |index| is valid; otherwise - // it will return false and the ListValue object will be unchanged. - virtual bool Remove(size_t index, scoped_ptr* out_value); - - // Removes the first instance of |value| found in the list, if any, and - // deletes it. |index| is the location where |value| was found. Returns false - // if not found. - bool Remove(const Value& value, size_t* index); - - // Removes the element at |iter|. If |out_value| is NULL, the value will be - // deleted, otherwise ownership of the value is passed back to the caller. - // Returns an iterator pointing to the location of the element that - // followed the erased element. - iterator Erase(iterator iter, scoped_ptr* out_value); - - // Appends a Value to the end of the list. - void Append(Value* in_value); - - // Convenience forms of Append. - void AppendBoolean(bool in_value); - void AppendInteger(int in_value); - void AppendDouble(double in_value); - void AppendString(const std::string& in_value); - void AppendString(const string16& in_value); - void AppendStrings(const std::vector& in_values); - void AppendStrings(const std::vector& in_values); - - // Appends a Value if it's not already present. Takes ownership of the - // |in_value|. Returns true if successful, or false if the value was already - // present. If the value was already present the |in_value| is deleted. - bool AppendIfNotPresent(Value* in_value); - - // Insert a Value at index. - // Returns true if successful, or false if the index was out of range. - bool Insert(size_t index, Value* in_value); - - // Searches for the first instance of |value| in the list using the Equals - // method of the Value type. - // Returns a const_iterator to the found item or to end() if none exists. - const_iterator Find(const Value& value) const; - - // Swaps contents with the |other| list. - virtual void Swap(ListValue* other); - - // Iteration. - iterator begin() { return list_.begin(); } - iterator end() { return list_.end(); } - - const_iterator begin() const { return list_.begin(); } - const_iterator end() const { return list_.end(); } - - // Overridden from Value: - virtual bool GetAsList(ListValue** out_value) OVERRIDE; - virtual bool GetAsList(const ListValue** out_value) const OVERRIDE; - virtual ListValue* DeepCopy() const OVERRIDE; - virtual bool Equals(const Value* other) const OVERRIDE; - - private: - ValueVector list_; - - DISALLOW_COPY_AND_ASSIGN(ListValue); -}; - -// This interface is implemented by classes that know how to serialize and -// deserialize Value objects. -class BASE_EXPORT ValueSerializer { - public: - virtual ~ValueSerializer(); - - virtual bool Serialize(const Value& root) = 0; - - // This method deserializes the subclass-specific format into a Value object. - // If the return value is non-NULL, the caller takes ownership of returned - // Value. If the return value is NULL, and if error_code is non-NULL, - // error_code will be set with the underlying error. - // If |error_message| is non-null, it will be filled in with a formatted - // error message including the location of the error if appropriate. - virtual Value* Deserialize(int* error_code, std::string* error_str) = 0; -}; - -// Stream operator so Values can be used in assertion statements. In order that -// gtest uses this operator to print readable output on test failures, we must -// override each specific type. Otherwise, the default template implementation -// is preferred over an upcast. -BASE_EXPORT std::ostream& operator<<(std::ostream& out, const Value& value); - -BASE_EXPORT inline std::ostream& operator<<(std::ostream& out, - const FundamentalValue& value) { - return out << static_cast(value); -} - -BASE_EXPORT inline std::ostream& operator<<(std::ostream& out, - const StringValue& value) { - return out << static_cast(value); -} - -BASE_EXPORT inline std::ostream& operator<<(std::ostream& out, - const DictionaryValue& value) { - return out << static_cast(value); -} - -BASE_EXPORT inline std::ostream& operator<<(std::ostream& out, - const ListValue& value) { - return out << static_cast(value); -} - -} // namespace base - -// http://crbug.com/88666 -using base::DictionaryValue; -using base::ListValue; -using base::StringValue; -using base::Value; - -#endif // BASE_VALUES_H_ diff --git a/base/values_unittest.cc b/base/values_unittest.cc deleted file mode 100644 index 733c485d2b..0000000000 --- a/base/values_unittest.cc +++ /dev/null @@ -1,776 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include - -#include "base/memory/scoped_ptr.h" -#include "base/strings/string16.h" -#include "base/strings/utf_string_conversions.h" -#include "base/values.h" -#include "testing/gtest/include/gtest/gtest.h" - -namespace base { - -TEST(ValuesTest, Basic) { - // Test basic dictionary getting/setting - DictionaryValue settings; - std::string homepage = "http://google.com"; - ASSERT_FALSE(settings.GetString("global.homepage", &homepage)); - ASSERT_EQ(std::string("http://google.com"), homepage); - - ASSERT_FALSE(settings.Get("global", NULL)); - settings.Set("global", new FundamentalValue(true)); - ASSERT_TRUE(settings.Get("global", NULL)); - settings.SetString("global.homepage", "http://scurvy.com"); - ASSERT_TRUE(settings.Get("global", NULL)); - homepage = "http://google.com"; - ASSERT_TRUE(settings.GetString("global.homepage", &homepage)); - ASSERT_EQ(std::string("http://scurvy.com"), homepage); - - // Test storing a dictionary in a list. - ListValue* toolbar_bookmarks; - ASSERT_FALSE( - settings.GetList("global.toolbar.bookmarks", &toolbar_bookmarks)); - - toolbar_bookmarks = new ListValue; - settings.Set("global.toolbar.bookmarks", toolbar_bookmarks); - ASSERT_TRUE(settings.GetList("global.toolbar.bookmarks", &toolbar_bookmarks)); - - DictionaryValue* new_bookmark = new DictionaryValue; - new_bookmark->SetString("name", "Froogle"); - new_bookmark->SetString("url", "http://froogle.com"); - toolbar_bookmarks->Append(new_bookmark); - - ListValue* bookmark_list; - ASSERT_TRUE(settings.GetList("global.toolbar.bookmarks", &bookmark_list)); - DictionaryValue* bookmark; - ASSERT_EQ(1U, bookmark_list->GetSize()); - ASSERT_TRUE(bookmark_list->GetDictionary(0, &bookmark)); - std::string bookmark_name = "Unnamed"; - ASSERT_TRUE(bookmark->GetString("name", &bookmark_name)); - ASSERT_EQ(std::string("Froogle"), bookmark_name); - std::string bookmark_url; - ASSERT_TRUE(bookmark->GetString("url", &bookmark_url)); - ASSERT_EQ(std::string("http://froogle.com"), bookmark_url); -} - -TEST(ValuesTest, List) { - scoped_ptr mixed_list(new ListValue()); - mixed_list->Set(0, new FundamentalValue(true)); - mixed_list->Set(1, new FundamentalValue(42)); - mixed_list->Set(2, new FundamentalValue(88.8)); - mixed_list->Set(3, new StringValue("foo")); - ASSERT_EQ(4u, mixed_list->GetSize()); - - Value *value = NULL; - bool bool_value = false; - int int_value = 0; - double double_value = 0.0; - std::string string_value; - - ASSERT_FALSE(mixed_list->Get(4, &value)); - - ASSERT_FALSE(mixed_list->GetInteger(0, &int_value)); - ASSERT_EQ(0, int_value); - ASSERT_FALSE(mixed_list->GetBoolean(1, &bool_value)); - ASSERT_FALSE(bool_value); - ASSERT_FALSE(mixed_list->GetString(2, &string_value)); - ASSERT_EQ("", string_value); - ASSERT_FALSE(mixed_list->GetInteger(2, &int_value)); - ASSERT_EQ(0, int_value); - ASSERT_FALSE(mixed_list->GetBoolean(3, &bool_value)); - ASSERT_FALSE(bool_value); - - ASSERT_TRUE(mixed_list->GetBoolean(0, &bool_value)); - ASSERT_TRUE(bool_value); - ASSERT_TRUE(mixed_list->GetInteger(1, &int_value)); - ASSERT_EQ(42, int_value); - // implicit conversion from Integer to Double should be possible. - ASSERT_TRUE(mixed_list->GetDouble(1, &double_value)); - ASSERT_EQ(42, double_value); - ASSERT_TRUE(mixed_list->GetDouble(2, &double_value)); - ASSERT_EQ(88.8, double_value); - ASSERT_TRUE(mixed_list->GetString(3, &string_value)); - ASSERT_EQ("foo", string_value); - - // Try searching in the mixed list. - base::FundamentalValue sought_value(42); - base::FundamentalValue not_found_value(false); - - ASSERT_NE(mixed_list->end(), mixed_list->Find(sought_value)); - ASSERT_TRUE((*mixed_list->Find(sought_value))->GetAsInteger(&int_value)); - ASSERT_EQ(42, int_value); - ASSERT_EQ(mixed_list->end(), mixed_list->Find(not_found_value)); -} - -TEST(ValuesTest, BinaryValue) { - // Default constructor creates a BinaryValue with a null buffer and size 0. - scoped_ptr binary(new BinaryValue()); - ASSERT_TRUE(binary.get()); - ASSERT_EQ(NULL, binary->GetBuffer()); - ASSERT_EQ(0U, binary->GetSize()); - - // Test the common case of a non-empty buffer - char* buffer = new char[15]; - binary.reset(new BinaryValue(scoped_ptr(buffer), 15)); - ASSERT_TRUE(binary.get()); - ASSERT_TRUE(binary->GetBuffer()); - ASSERT_EQ(buffer, binary->GetBuffer()); - ASSERT_EQ(15U, binary->GetSize()); - - char stack_buffer[42]; - memset(stack_buffer, '!', 42); - binary.reset(BinaryValue::CreateWithCopiedBuffer(stack_buffer, 42)); - ASSERT_TRUE(binary.get()); - ASSERT_TRUE(binary->GetBuffer()); - ASSERT_NE(stack_buffer, binary->GetBuffer()); - ASSERT_EQ(42U, binary->GetSize()); - ASSERT_EQ(0, memcmp(stack_buffer, binary->GetBuffer(), binary->GetSize())); -} - -TEST(ValuesTest, StringValue) { - // Test overloaded CreateStringValue. - scoped_ptr narrow_value(new StringValue("narrow")); - ASSERT_TRUE(narrow_value.get()); - ASSERT_TRUE(narrow_value->IsType(Value::TYPE_STRING)); - scoped_ptr utf16_value(new StringValue(ASCIIToUTF16("utf16"))); - ASSERT_TRUE(utf16_value.get()); - ASSERT_TRUE(utf16_value->IsType(Value::TYPE_STRING)); - - // Test overloaded GetString. - std::string narrow = "http://google.com"; - string16 utf16 = ASCIIToUTF16("http://google.com"); - ASSERT_TRUE(narrow_value->GetAsString(&narrow)); - ASSERT_TRUE(narrow_value->GetAsString(&utf16)); - ASSERT_EQ(std::string("narrow"), narrow); - ASSERT_EQ(ASCIIToUTF16("narrow"), utf16); - - ASSERT_TRUE(utf16_value->GetAsString(&narrow)); - ASSERT_TRUE(utf16_value->GetAsString(&utf16)); - ASSERT_EQ(std::string("utf16"), narrow); - ASSERT_EQ(ASCIIToUTF16("utf16"), utf16); -} - -// This is a Value object that allows us to tell if it's been -// properly deleted by modifying the value of external flag on destruction. -class DeletionTestValue : public Value { - public: - explicit DeletionTestValue(bool* deletion_flag) : Value(TYPE_NULL) { - Init(deletion_flag); // Separate function so that we can use ASSERT_* - } - - void Init(bool* deletion_flag) { - ASSERT_TRUE(deletion_flag); - deletion_flag_ = deletion_flag; - *deletion_flag_ = false; - } - - virtual ~DeletionTestValue() { - *deletion_flag_ = true; - } - - private: - bool* deletion_flag_; -}; - -TEST(ValuesTest, ListDeletion) { - bool deletion_flag = true; - - { - ListValue list; - list.Append(new DeletionTestValue(&deletion_flag)); - EXPECT_FALSE(deletion_flag); - } - EXPECT_TRUE(deletion_flag); - - { - ListValue list; - list.Append(new DeletionTestValue(&deletion_flag)); - EXPECT_FALSE(deletion_flag); - list.Clear(); - EXPECT_TRUE(deletion_flag); - } - - { - ListValue list; - list.Append(new DeletionTestValue(&deletion_flag)); - EXPECT_FALSE(deletion_flag); - EXPECT_TRUE(list.Set(0, Value::CreateNullValue())); - EXPECT_TRUE(deletion_flag); - } -} - -TEST(ValuesTest, ListRemoval) { - bool deletion_flag = true; - scoped_ptr removed_item; - - { - ListValue list; - list.Append(new DeletionTestValue(&deletion_flag)); - EXPECT_FALSE(deletion_flag); - EXPECT_EQ(1U, list.GetSize()); - EXPECT_FALSE(list.Remove(std::numeric_limits::max(), - &removed_item)); - EXPECT_FALSE(list.Remove(1, &removed_item)); - EXPECT_TRUE(list.Remove(0, &removed_item)); - ASSERT_TRUE(removed_item); - EXPECT_EQ(0U, list.GetSize()); - } - EXPECT_FALSE(deletion_flag); - removed_item.reset(); - EXPECT_TRUE(deletion_flag); - - { - ListValue list; - list.Append(new DeletionTestValue(&deletion_flag)); - EXPECT_FALSE(deletion_flag); - EXPECT_TRUE(list.Remove(0, NULL)); - EXPECT_TRUE(deletion_flag); - EXPECT_EQ(0U, list.GetSize()); - } - - { - ListValue list; - DeletionTestValue* value = new DeletionTestValue(&deletion_flag); - list.Append(value); - EXPECT_FALSE(deletion_flag); - size_t index = 0; - list.Remove(*value, &index); - EXPECT_EQ(0U, index); - EXPECT_TRUE(deletion_flag); - EXPECT_EQ(0U, list.GetSize()); - } -} - -TEST(ValuesTest, DictionaryDeletion) { - std::string key = "test"; - bool deletion_flag = true; - - { - DictionaryValue dict; - dict.Set(key, new DeletionTestValue(&deletion_flag)); - EXPECT_FALSE(deletion_flag); - } - EXPECT_TRUE(deletion_flag); - - { - DictionaryValue dict; - dict.Set(key, new DeletionTestValue(&deletion_flag)); - EXPECT_FALSE(deletion_flag); - dict.Clear(); - EXPECT_TRUE(deletion_flag); - } - - { - DictionaryValue dict; - dict.Set(key, new DeletionTestValue(&deletion_flag)); - EXPECT_FALSE(deletion_flag); - dict.Set(key, Value::CreateNullValue()); - EXPECT_TRUE(deletion_flag); - } -} - -TEST(ValuesTest, DictionaryRemoval) { - std::string key = "test"; - bool deletion_flag = true; - scoped_ptr removed_item; - - { - DictionaryValue dict; - dict.Set(key, new DeletionTestValue(&deletion_flag)); - EXPECT_FALSE(deletion_flag); - EXPECT_TRUE(dict.HasKey(key)); - EXPECT_FALSE(dict.Remove("absent key", &removed_item)); - EXPECT_TRUE(dict.Remove(key, &removed_item)); - EXPECT_FALSE(dict.HasKey(key)); - ASSERT_TRUE(removed_item); - } - EXPECT_FALSE(deletion_flag); - removed_item.reset(); - EXPECT_TRUE(deletion_flag); - - { - DictionaryValue dict; - dict.Set(key, new DeletionTestValue(&deletion_flag)); - EXPECT_FALSE(deletion_flag); - EXPECT_TRUE(dict.HasKey(key)); - EXPECT_TRUE(dict.Remove(key, NULL)); - EXPECT_TRUE(deletion_flag); - EXPECT_FALSE(dict.HasKey(key)); - } -} - -TEST(ValuesTest, DictionaryWithoutPathExpansion) { - DictionaryValue dict; - dict.Set("this.is.expanded", Value::CreateNullValue()); - dict.SetWithoutPathExpansion("this.isnt.expanded", Value::CreateNullValue()); - - EXPECT_FALSE(dict.HasKey("this.is.expanded")); - EXPECT_TRUE(dict.HasKey("this")); - Value* value1; - EXPECT_TRUE(dict.Get("this", &value1)); - DictionaryValue* value2; - ASSERT_TRUE(dict.GetDictionaryWithoutPathExpansion("this", &value2)); - EXPECT_EQ(value1, value2); - EXPECT_EQ(1U, value2->size()); - - EXPECT_TRUE(dict.HasKey("this.isnt.expanded")); - Value* value3; - EXPECT_FALSE(dict.Get("this.isnt.expanded", &value3)); - Value* value4; - ASSERT_TRUE(dict.GetWithoutPathExpansion("this.isnt.expanded", &value4)); - EXPECT_EQ(Value::TYPE_NULL, value4->GetType()); -} - -TEST(ValuesTest, DeepCopy) { - DictionaryValue original_dict; - Value* original_null = Value::CreateNullValue(); - original_dict.Set("null", original_null); - FundamentalValue* original_bool = new FundamentalValue(true); - original_dict.Set("bool", original_bool); - FundamentalValue* original_int = new FundamentalValue(42); - original_dict.Set("int", original_int); - FundamentalValue* original_double = new FundamentalValue(3.14); - original_dict.Set("double", original_double); - StringValue* original_string = new StringValue("hello"); - original_dict.Set("string", original_string); - StringValue* original_string16 = new StringValue(ASCIIToUTF16("hello16")); - original_dict.Set("string16", original_string16); - - scoped_ptr original_buffer(new char[42]); - memset(original_buffer.get(), '!', 42); - BinaryValue* original_binary = new BinaryValue(original_buffer.Pass(), 42); - original_dict.Set("binary", original_binary); - - ListValue* original_list = new ListValue(); - FundamentalValue* original_list_element_0 = new FundamentalValue(0); - original_list->Append(original_list_element_0); - FundamentalValue* original_list_element_1 = new FundamentalValue(1); - original_list->Append(original_list_element_1); - original_dict.Set("list", original_list); - - DictionaryValue* original_nested_dictionary = new DictionaryValue(); - original_nested_dictionary->Set("key", new StringValue("value")); - original_dict.Set("dictionary", original_nested_dictionary); - - scoped_ptr copy_dict(original_dict.DeepCopy()); - ASSERT_TRUE(copy_dict.get()); - ASSERT_NE(copy_dict.get(), &original_dict); - - Value* copy_null = NULL; - ASSERT_TRUE(copy_dict->Get("null", ©_null)); - ASSERT_TRUE(copy_null); - ASSERT_NE(copy_null, original_null); - ASSERT_TRUE(copy_null->IsType(Value::TYPE_NULL)); - - Value* copy_bool = NULL; - ASSERT_TRUE(copy_dict->Get("bool", ©_bool)); - ASSERT_TRUE(copy_bool); - ASSERT_NE(copy_bool, original_bool); - ASSERT_TRUE(copy_bool->IsType(Value::TYPE_BOOLEAN)); - bool copy_bool_value = false; - ASSERT_TRUE(copy_bool->GetAsBoolean(©_bool_value)); - ASSERT_TRUE(copy_bool_value); - - Value* copy_int = NULL; - ASSERT_TRUE(copy_dict->Get("int", ©_int)); - ASSERT_TRUE(copy_int); - ASSERT_NE(copy_int, original_int); - ASSERT_TRUE(copy_int->IsType(Value::TYPE_INTEGER)); - int copy_int_value = 0; - ASSERT_TRUE(copy_int->GetAsInteger(©_int_value)); - ASSERT_EQ(42, copy_int_value); - - Value* copy_double = NULL; - ASSERT_TRUE(copy_dict->Get("double", ©_double)); - ASSERT_TRUE(copy_double); - ASSERT_NE(copy_double, original_double); - ASSERT_TRUE(copy_double->IsType(Value::TYPE_DOUBLE)); - double copy_double_value = 0; - ASSERT_TRUE(copy_double->GetAsDouble(©_double_value)); - ASSERT_EQ(3.14, copy_double_value); - - Value* copy_string = NULL; - ASSERT_TRUE(copy_dict->Get("string", ©_string)); - ASSERT_TRUE(copy_string); - ASSERT_NE(copy_string, original_string); - ASSERT_TRUE(copy_string->IsType(Value::TYPE_STRING)); - std::string copy_string_value; - string16 copy_string16_value; - ASSERT_TRUE(copy_string->GetAsString(©_string_value)); - ASSERT_TRUE(copy_string->GetAsString(©_string16_value)); - ASSERT_EQ(std::string("hello"), copy_string_value); - ASSERT_EQ(ASCIIToUTF16("hello"), copy_string16_value); - - Value* copy_string16 = NULL; - ASSERT_TRUE(copy_dict->Get("string16", ©_string16)); - ASSERT_TRUE(copy_string16); - ASSERT_NE(copy_string16, original_string16); - ASSERT_TRUE(copy_string16->IsType(Value::TYPE_STRING)); - ASSERT_TRUE(copy_string16->GetAsString(©_string_value)); - ASSERT_TRUE(copy_string16->GetAsString(©_string16_value)); - ASSERT_EQ(std::string("hello16"), copy_string_value); - ASSERT_EQ(ASCIIToUTF16("hello16"), copy_string16_value); - - Value* copy_binary = NULL; - ASSERT_TRUE(copy_dict->Get("binary", ©_binary)); - ASSERT_TRUE(copy_binary); - ASSERT_NE(copy_binary, original_binary); - ASSERT_TRUE(copy_binary->IsType(Value::TYPE_BINARY)); - ASSERT_NE(original_binary->GetBuffer(), - static_cast(copy_binary)->GetBuffer()); - ASSERT_EQ(original_binary->GetSize(), - static_cast(copy_binary)->GetSize()); - ASSERT_EQ(0, memcmp(original_binary->GetBuffer(), - static_cast(copy_binary)->GetBuffer(), - original_binary->GetSize())); - - Value* copy_value = NULL; - ASSERT_TRUE(copy_dict->Get("list", ©_value)); - ASSERT_TRUE(copy_value); - ASSERT_NE(copy_value, original_list); - ASSERT_TRUE(copy_value->IsType(Value::TYPE_LIST)); - ListValue* copy_list = NULL; - ASSERT_TRUE(copy_value->GetAsList(©_list)); - ASSERT_TRUE(copy_list); - ASSERT_EQ(2U, copy_list->GetSize()); - - Value* copy_list_element_0; - ASSERT_TRUE(copy_list->Get(0, ©_list_element_0)); - ASSERT_TRUE(copy_list_element_0); - ASSERT_NE(copy_list_element_0, original_list_element_0); - int copy_list_element_0_value; - ASSERT_TRUE(copy_list_element_0->GetAsInteger(©_list_element_0_value)); - ASSERT_EQ(0, copy_list_element_0_value); - - Value* copy_list_element_1; - ASSERT_TRUE(copy_list->Get(1, ©_list_element_1)); - ASSERT_TRUE(copy_list_element_1); - ASSERT_NE(copy_list_element_1, original_list_element_1); - int copy_list_element_1_value; - ASSERT_TRUE(copy_list_element_1->GetAsInteger(©_list_element_1_value)); - ASSERT_EQ(1, copy_list_element_1_value); - - copy_value = NULL; - ASSERT_TRUE(copy_dict->Get("dictionary", ©_value)); - ASSERT_TRUE(copy_value); - ASSERT_NE(copy_value, original_nested_dictionary); - ASSERT_TRUE(copy_value->IsType(Value::TYPE_DICTIONARY)); - DictionaryValue* copy_nested_dictionary = NULL; - ASSERT_TRUE(copy_value->GetAsDictionary(©_nested_dictionary)); - ASSERT_TRUE(copy_nested_dictionary); - EXPECT_TRUE(copy_nested_dictionary->HasKey("key")); -} - -TEST(ValuesTest, Equals) { - Value* null1 = Value::CreateNullValue(); - Value* null2 = Value::CreateNullValue(); - EXPECT_NE(null1, null2); - EXPECT_TRUE(null1->Equals(null2)); - - Value* boolean = new FundamentalValue(false); - EXPECT_FALSE(null1->Equals(boolean)); - delete null1; - delete null2; - delete boolean; - - DictionaryValue dv; - dv.SetBoolean("a", false); - dv.SetInteger("b", 2); - dv.SetDouble("c", 2.5); - dv.SetString("d1", "string"); - dv.SetString("d2", ASCIIToUTF16("http://google.com")); - dv.Set("e", Value::CreateNullValue()); - - scoped_ptr copy; - copy.reset(dv.DeepCopy()); - EXPECT_TRUE(dv.Equals(copy.get())); - - ListValue* list = new ListValue; - list->Append(Value::CreateNullValue()); - list->Append(new DictionaryValue); - dv.Set("f", list); - - EXPECT_FALSE(dv.Equals(copy.get())); - copy->Set("f", list->DeepCopy()); - EXPECT_TRUE(dv.Equals(copy.get())); - - list->Append(new FundamentalValue(true)); - EXPECT_FALSE(dv.Equals(copy.get())); - - // Check if Equals detects differences in only the keys. - copy.reset(dv.DeepCopy()); - EXPECT_TRUE(dv.Equals(copy.get())); - copy->Remove("a", NULL); - copy->SetBoolean("aa", false); - EXPECT_FALSE(dv.Equals(copy.get())); -} - -TEST(ValuesTest, StaticEquals) { - scoped_ptr null1(Value::CreateNullValue()); - scoped_ptr null2(Value::CreateNullValue()); - EXPECT_TRUE(Value::Equals(null1.get(), null2.get())); - EXPECT_TRUE(Value::Equals(NULL, NULL)); - - scoped_ptr i42(new FundamentalValue(42)); - scoped_ptr j42(new FundamentalValue(42)); - scoped_ptr i17(new FundamentalValue(17)); - EXPECT_TRUE(Value::Equals(i42.get(), i42.get())); - EXPECT_TRUE(Value::Equals(j42.get(), i42.get())); - EXPECT_TRUE(Value::Equals(i42.get(), j42.get())); - EXPECT_FALSE(Value::Equals(i42.get(), i17.get())); - EXPECT_FALSE(Value::Equals(i42.get(), NULL)); - EXPECT_FALSE(Value::Equals(NULL, i42.get())); - - // NULL and Value::CreateNullValue() are intentionally different: We need - // support for NULL as a return value for "undefined" without caring for - // ownership of the pointer. - EXPECT_FALSE(Value::Equals(null1.get(), NULL)); - EXPECT_FALSE(Value::Equals(NULL, null1.get())); -} - -TEST(ValuesTest, DeepCopyCovariantReturnTypes) { - DictionaryValue original_dict; - Value* original_null = Value::CreateNullValue(); - original_dict.Set("null", original_null); - FundamentalValue* original_bool = new FundamentalValue(true); - original_dict.Set("bool", original_bool); - FundamentalValue* original_int = new FundamentalValue(42); - original_dict.Set("int", original_int); - FundamentalValue* original_double = new FundamentalValue(3.14); - original_dict.Set("double", original_double); - StringValue* original_string = new StringValue("hello"); - original_dict.Set("string", original_string); - StringValue* original_string16 = new StringValue(ASCIIToUTF16("hello16")); - original_dict.Set("string16", original_string16); - - scoped_ptr original_buffer(new char[42]); - memset(original_buffer.get(), '!', 42); - BinaryValue* original_binary = new BinaryValue(original_buffer.Pass(), 42); - original_dict.Set("binary", original_binary); - - ListValue* original_list = new ListValue(); - FundamentalValue* original_list_element_0 = new FundamentalValue(0); - original_list->Append(original_list_element_0); - FundamentalValue* original_list_element_1 = new FundamentalValue(1); - original_list->Append(original_list_element_1); - original_dict.Set("list", original_list); - - Value* original_dict_value = &original_dict; - Value* original_bool_value = original_bool; - Value* original_int_value = original_int; - Value* original_double_value = original_double; - Value* original_string_value = original_string; - Value* original_string16_value = original_string16; - Value* original_binary_value = original_binary; - Value* original_list_value = original_list; - - scoped_ptr copy_dict_value(original_dict_value->DeepCopy()); - scoped_ptr copy_bool_value(original_bool_value->DeepCopy()); - scoped_ptr copy_int_value(original_int_value->DeepCopy()); - scoped_ptr copy_double_value(original_double_value->DeepCopy()); - scoped_ptr copy_string_value(original_string_value->DeepCopy()); - scoped_ptr copy_string16_value(original_string16_value->DeepCopy()); - scoped_ptr copy_binary_value(original_binary_value->DeepCopy()); - scoped_ptr copy_list_value(original_list_value->DeepCopy()); - - EXPECT_TRUE(original_dict_value->Equals(copy_dict_value.get())); - EXPECT_TRUE(original_bool_value->Equals(copy_bool_value.get())); - EXPECT_TRUE(original_int_value->Equals(copy_int_value.get())); - EXPECT_TRUE(original_double_value->Equals(copy_double_value.get())); - EXPECT_TRUE(original_string_value->Equals(copy_string_value.get())); - EXPECT_TRUE(original_string16_value->Equals(copy_string16_value.get())); - EXPECT_TRUE(original_binary_value->Equals(copy_binary_value.get())); - EXPECT_TRUE(original_list_value->Equals(copy_list_value.get())); -} - -TEST(ValuesTest, RemoveEmptyChildren) { - scoped_ptr root(new DictionaryValue); - // Remove empty lists and dictionaries. - root->Set("empty_dict", new DictionaryValue); - root->Set("empty_list", new ListValue); - root->SetWithoutPathExpansion("a.b.c.d.e", new DictionaryValue); - root.reset(root->DeepCopyWithoutEmptyChildren()); - EXPECT_TRUE(root->empty()); - - // Make sure we don't prune too much. - root->SetBoolean("bool", true); - root->Set("empty_dict", new DictionaryValue); - root->SetString("empty_string", std::string()); - root.reset(root->DeepCopyWithoutEmptyChildren()); - EXPECT_EQ(2U, root->size()); - - // Should do nothing. - root.reset(root->DeepCopyWithoutEmptyChildren()); - EXPECT_EQ(2U, root->size()); - - // Nested test cases. These should all reduce back to the bool and string - // set above. - { - root->Set("a.b.c.d.e", new DictionaryValue); - root.reset(root->DeepCopyWithoutEmptyChildren()); - EXPECT_EQ(2U, root->size()); - } - { - DictionaryValue* inner = new DictionaryValue; - root->Set("dict_with_emtpy_children", inner); - inner->Set("empty_dict", new DictionaryValue); - inner->Set("empty_list", new ListValue); - root.reset(root->DeepCopyWithoutEmptyChildren()); - EXPECT_EQ(2U, root->size()); - } - { - ListValue* inner = new ListValue; - root->Set("list_with_empty_children", inner); - inner->Append(new DictionaryValue); - inner->Append(new ListValue); - root.reset(root->DeepCopyWithoutEmptyChildren()); - EXPECT_EQ(2U, root->size()); - } - - // Nested with siblings. - { - ListValue* inner = new ListValue; - root->Set("list_with_empty_children", inner); - inner->Append(new DictionaryValue); - inner->Append(new ListValue); - DictionaryValue* inner2 = new DictionaryValue; - root->Set("dict_with_empty_children", inner2); - inner2->Set("empty_dict", new DictionaryValue); - inner2->Set("empty_list", new ListValue); - root.reset(root->DeepCopyWithoutEmptyChildren()); - EXPECT_EQ(2U, root->size()); - } - - // Make sure nested values don't get pruned. - { - ListValue* inner = new ListValue; - root->Set("list_with_empty_children", inner); - ListValue* inner2 = new ListValue; - inner->Append(new DictionaryValue); - inner->Append(inner2); - inner2->Append(new StringValue("hello")); - root.reset(root->DeepCopyWithoutEmptyChildren()); - EXPECT_EQ(3U, root->size()); - EXPECT_TRUE(root->GetList("list_with_empty_children", &inner)); - EXPECT_EQ(1U, inner->GetSize()); // Dictionary was pruned. - EXPECT_TRUE(inner->GetList(0, &inner2)); - EXPECT_EQ(1U, inner2->GetSize()); - } -} - -TEST(ValuesTest, MergeDictionary) { - scoped_ptr base(new DictionaryValue); - base->SetString("base_key", "base_key_value_base"); - base->SetString("collide_key", "collide_key_value_base"); - DictionaryValue* base_sub_dict = new DictionaryValue; - base_sub_dict->SetString("sub_base_key", "sub_base_key_value_base"); - base_sub_dict->SetString("sub_collide_key", "sub_collide_key_value_base"); - base->Set("sub_dict_key", base_sub_dict); - - scoped_ptr merge(new DictionaryValue); - merge->SetString("merge_key", "merge_key_value_merge"); - merge->SetString("collide_key", "collide_key_value_merge"); - DictionaryValue* merge_sub_dict = new DictionaryValue; - merge_sub_dict->SetString("sub_merge_key", "sub_merge_key_value_merge"); - merge_sub_dict->SetString("sub_collide_key", "sub_collide_key_value_merge"); - merge->Set("sub_dict_key", merge_sub_dict); - - base->MergeDictionary(merge.get()); - - EXPECT_EQ(4U, base->size()); - std::string base_key_value; - EXPECT_TRUE(base->GetString("base_key", &base_key_value)); - EXPECT_EQ("base_key_value_base", base_key_value); // Base value preserved. - std::string collide_key_value; - EXPECT_TRUE(base->GetString("collide_key", &collide_key_value)); - EXPECT_EQ("collide_key_value_merge", collide_key_value); // Replaced. - std::string merge_key_value; - EXPECT_TRUE(base->GetString("merge_key", &merge_key_value)); - EXPECT_EQ("merge_key_value_merge", merge_key_value); // Merged in. - - DictionaryValue* res_sub_dict; - EXPECT_TRUE(base->GetDictionary("sub_dict_key", &res_sub_dict)); - EXPECT_EQ(3U, res_sub_dict->size()); - std::string sub_base_key_value; - EXPECT_TRUE(res_sub_dict->GetString("sub_base_key", &sub_base_key_value)); - EXPECT_EQ("sub_base_key_value_base", sub_base_key_value); // Preserved. - std::string sub_collide_key_value; - EXPECT_TRUE(res_sub_dict->GetString("sub_collide_key", - &sub_collide_key_value)); - EXPECT_EQ("sub_collide_key_value_merge", sub_collide_key_value); // Replaced. - std::string sub_merge_key_value; - EXPECT_TRUE(res_sub_dict->GetString("sub_merge_key", &sub_merge_key_value)); - EXPECT_EQ("sub_merge_key_value_merge", sub_merge_key_value); // Merged in. -} - -TEST(ValuesTest, MergeDictionaryDeepCopy) { - DictionaryValue* child = new DictionaryValue; - child->SetString("test", "value"); - EXPECT_EQ(1U, child->size()); - - std::string value; - EXPECT_TRUE(child->GetString("test", &value)); - EXPECT_EQ("value", value); - - scoped_ptr base(new DictionaryValue); - base->Set("dict", child); - EXPECT_EQ(1U, base->size()); - - DictionaryValue* ptr; - EXPECT_TRUE(base->GetDictionary("dict", &ptr)); - EXPECT_EQ(child, ptr); - - scoped_ptr merged(new DictionaryValue); - merged->MergeDictionary(base.get()); - EXPECT_EQ(1U, merged->size()); - EXPECT_TRUE(merged->GetDictionary("dict", &ptr)); - EXPECT_NE(child, ptr); - EXPECT_TRUE(ptr->GetString("test", &value)); - EXPECT_EQ("value", value); - - child->SetString("test", "overwrite"); - base.reset(); - EXPECT_TRUE(ptr->GetString("test", &value)); - EXPECT_EQ("value", value); -} - -TEST(ValuesTest, DictionaryIterator) { - DictionaryValue dict; - for (DictionaryValue::Iterator it(dict); !it.IsAtEnd(); it.Advance()) { - ADD_FAILURE(); - } - - StringValue value1("value1"); - dict.Set("key1", value1.DeepCopy()); - bool seen1 = false; - for (DictionaryValue::Iterator it(dict); !it.IsAtEnd(); it.Advance()) { - EXPECT_FALSE(seen1); - EXPECT_EQ("key1", it.key()); - EXPECT_TRUE(value1.Equals(&it.value())); - seen1 = true; - } - EXPECT_TRUE(seen1); - - StringValue value2("value2"); - dict.Set("key2", value2.DeepCopy()); - bool seen2 = seen1 = false; - for (DictionaryValue::Iterator it(dict); !it.IsAtEnd(); it.Advance()) { - if (it.key() == "key1") { - EXPECT_FALSE(seen1); - EXPECT_TRUE(value1.Equals(&it.value())); - seen1 = true; - } else if (it.key() == "key2") { - EXPECT_FALSE(seen2); - EXPECT_TRUE(value2.Equals(&it.value())); - seen2 = true; - } else { - ADD_FAILURE(); - } - } - EXPECT_TRUE(seen1); - EXPECT_TRUE(seen2); -} - -} // namespace base diff --git a/base/version.cc b/base/version.cc deleted file mode 100644 index 70d35c192c..0000000000 --- a/base/version.cc +++ /dev/null @@ -1,176 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "base/version.h" - -#include - -#include "base/logging.h" -#include "base/strings/string_number_conversions.h" -#include "base/strings/string_split.h" -#include "base/strings/string_util.h" - -namespace base { - -namespace { - -// Parses the |numbers| vector representing the different numbers -// inside the version string and constructs a vector of valid integers. It stops -// when it reaches an invalid item (including the wildcard character). |parsed| -// is the resulting integer vector. Function returns true if all numbers were -// parsed successfully, false otherwise. -bool ParseVersionNumbers(const std::string& version_str, - std::vector* parsed) { - std::vector numbers; - SplitString(version_str, '.', &numbers); - if (numbers.empty()) - return false; - - for (std::vector::const_iterator it = numbers.begin(); - it != numbers.end(); ++it) { - int num; - if (!StringToInt(*it, &num)) - return false; - - if (num < 0) - return false; - - const uint16 max = 0xFFFF; - if (num > max) - return false; - - // This throws out things like +3, or 032. - if (IntToString(num) != *it) - return false; - - parsed->push_back(static_cast(num)); - } - return true; -} - -// Compares version components in |components1| with components in -// |components2|. Returns -1, 0 or 1 if |components1| is less than, equal to, -// or greater than |components2|, respectively. -int CompareVersionComponents(const std::vector& components1, - const std::vector& components2) { - const size_t count = std::min(components1.size(), components2.size()); - for (size_t i = 0; i < count; ++i) { - if (components1[i] > components2[i]) - return 1; - if (components1[i] < components2[i]) - return -1; - } - if (components1.size() > components2.size()) { - for (size_t i = count; i < components1.size(); ++i) { - if (components1[i] > 0) - return 1; - } - } else if (components1.size() < components2.size()) { - for (size_t i = count; i < components2.size(); ++i) { - if (components2[i] > 0) - return -1; - } - } - return 0; -} - -} // namespace - -Version::Version() { -} - -Version::~Version() { -} - -Version::Version(const std::string& version_str) { - std::vector parsed; - if (!ParseVersionNumbers(version_str, &parsed)) - return; - - components_.swap(parsed); -} - -bool Version::IsValid() const { - return (!components_.empty()); -} - -// static -bool Version::IsValidWildcardString(const std::string& wildcard_string) { - std::string version_string = wildcard_string; - if (EndsWith(wildcard_string.c_str(), ".*", false)) - version_string = wildcard_string.substr(0, wildcard_string.size() - 2); - - Version version(version_string); - return version.IsValid(); -} - -bool Version::IsOlderThan(const std::string& version_str) const { - Version proposed_ver(version_str); - if (!proposed_ver.IsValid()) - return false; - return (CompareTo(proposed_ver) < 0); -} - -int Version::CompareToWildcardString(const std::string& wildcard_string) const { - DCHECK(IsValid()); - DCHECK(Version::IsValidWildcardString(wildcard_string)); - - // Default behavior if the string doesn't end with a wildcard. - if (!EndsWith(wildcard_string.c_str(), ".*", false)) { - Version version(wildcard_string); - DCHECK(version.IsValid()); - return CompareTo(version); - } - - std::vector parsed; - const bool success = ParseVersionNumbers( - wildcard_string.substr(0, wildcard_string.length() - 2), &parsed); - DCHECK(success); - const int comparison = CompareVersionComponents(components_, parsed); - // If the version is smaller than the wildcard version's |parsed| vector, - // then the wildcard has no effect (e.g. comparing 1.2.3 and 1.3.*) and the - // version is still smaller. Same logic for equality (e.g. comparing 1.2.2 to - // 1.2.2.* is 0 regardless of the wildcard). Under this logic, - // 1.2.0.0.0.0 compared to 1.2.* is 0. - if (comparison == -1 || comparison == 0) - return comparison; - - // Catch the case where the digits of |parsed| are found in |components_|, - // which means that the two are equal since |parsed| has a trailing "*". - // (e.g. 1.2.3 vs. 1.2.* will return 0). All other cases return 1 since - // components is greater (e.g. 3.2.3 vs 1.*). - DCHECK_GT(parsed.size(), 0UL); - const size_t min_num_comp = std::min(components_.size(), parsed.size()); - for (size_t i = 0; i < min_num_comp; ++i) { - if (components_[i] != parsed[i]) - return 1; - } - return 0; -} - -bool Version::Equals(const Version& that) const { - DCHECK(IsValid()); - DCHECK(that.IsValid()); - return (CompareTo(that) == 0); -} - -int Version::CompareTo(const Version& other) const { - DCHECK(IsValid()); - DCHECK(other.IsValid()); - return CompareVersionComponents(components_, other.components_); -} - -const std::string Version::GetString() const { - DCHECK(IsValid()); - std::string version_str; - size_t count = components_.size(); - for (size_t i = 0; i < count - 1; ++i) { - version_str.append(IntToString(components_[i])); - version_str.append("."); - } - version_str.append(IntToString(components_[count - 1])); - return version_str; -} - -} // namespace base diff --git a/base/version.h b/base/version.h deleted file mode 100644 index b3012eb921..0000000000 --- a/base/version.h +++ /dev/null @@ -1,72 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef BASE_VERSION_H_ -#define BASE_VERSION_H_ - -#include -#include - -#include "base/base_export.h" -#include "base/basictypes.h" - -namespace base { - -// Version represents a dotted version number, like "1.2.3.4", supporting -// parsing and comparison. -class BASE_EXPORT Version { - public: - // The only thing you can legally do to a default constructed - // Version object is assign to it. - Version(); - - ~Version(); - - // Initializes from a decimal dotted version number, like "0.1.1". - // Each component is limited to a uint16. Call IsValid() to learn - // the outcome. - explicit Version(const std::string& version_str); - - // Returns true if the object contains a valid version number. - bool IsValid() const; - - // Returns true if the version wildcard string is valid. The version wildcard - // string may end with ".*" (e.g. 1.2.*, 1.*). Any other arrangement with "*" - // is invalid (e.g. 1.*.3 or 1.2.3*). This functions defaults to standard - // Version behavior (IsValid) if no wildcard is present. - static bool IsValidWildcardString(const std::string& wildcard_string); - - // Commonly used pattern. Given a valid version object, compare if a - // |version_str| results in a newer version. Returns true if the - // string represents valid version and if the version is greater than - // than the version of this object. - bool IsOlderThan(const std::string& version_str) const; - - bool Equals(const Version& other) const; - - // Returns -1, 0, 1 for <, ==, >. - int CompareTo(const Version& other) const; - - // Given a valid version object, compare if a |wildcard_string| results in a - // newer version. This function will default to CompareTo if the string does - // not end in wildcard sequence ".*". IsValidWildcard(wildcard_string) must be - // true before using this function. - int CompareToWildcardString(const std::string& wildcard_string) const; - - // Return the string representation of this version. - const std::string GetString() const; - - const std::vector& components() const { return components_; } - - private: - std::vector components_; -}; - -} // namespace base - -// TODO(xhwang) remove this when all users are updated to explicitly use the -// namespace -using base::Version; - -#endif // BASE_VERSION_H_ diff --git a/base/version_unittest.cc b/base/version_unittest.cc deleted file mode 100644 index 2a2309ea31..0000000000 --- a/base/version_unittest.cc +++ /dev/null @@ -1,141 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "base/version.h" - -#include "testing/gtest/include/gtest/gtest.h" - -namespace { - -TEST(VersionTest, DefaultConstructor) { - Version v; - EXPECT_FALSE(v.IsValid()); -} - -TEST(VersionTest, ValueSemantics) { - Version v1("1.2.3.4"); - EXPECT_TRUE(v1.IsValid()); - Version v3; - EXPECT_FALSE(v3.IsValid()); - { - Version v2(v1); - v3 = v2; - EXPECT_TRUE(v2.IsValid()); - EXPECT_TRUE(v1.Equals(v2)); - } - EXPECT_TRUE(v3.Equals(v1)); -} - -TEST(VersionTest, GetVersionFromString) { - static const struct version_string { - const char* input; - size_t parts; - bool success; - } cases[] = { - {"", 0, false}, - {" ", 0, false}, - {"\t", 0, false}, - {"\n", 0, false}, - {" ", 0, false}, - {".", 0, false}, - {" . ", 0, false}, - {"0", 1, true}, - {"0.0", 2, true}, - {"65537.0", 0, false}, - {"-1.0", 0, false}, - {"1.-1.0", 0, false}, - {"+1.0", 0, false}, - {"1.+1.0", 0, false}, - {"1.0a", 0, false}, - {"1.2.3.4.5.6.7.8.9.0", 10, true}, - {"02.1", 0, false}, - {"f.1", 0, false}, - }; - - for (size_t i = 0; i < ARRAYSIZE_UNSAFE(cases); ++i) { - Version version(cases[i].input); - EXPECT_EQ(cases[i].success, version.IsValid()); - if (cases[i].success) - EXPECT_EQ(cases[i].parts, version.components().size()); - } -} - -TEST(VersionTest, Compare) { - static const struct version_compare { - const char* lhs; - const char* rhs; - int expected; - } cases[] = { - {"1.0", "1.0", 0}, - {"1.0", "0.0", 1}, - {"1.0", "2.0", -1}, - {"1.0", "1.1", -1}, - {"1.1", "1.0", 1}, - {"1.0", "1.0.1", -1}, - {"1.1", "1.0.1", 1}, - {"1.1", "1.0.1", 1}, - {"1.0.0", "1.0", 0}, - {"1.0.3", "1.0.20", -1}, - }; - for (size_t i = 0; i < ARRAYSIZE_UNSAFE(cases); ++i) { - Version lhs(cases[i].lhs); - Version rhs(cases[i].rhs); - EXPECT_EQ(lhs.CompareTo(rhs), cases[i].expected) << - cases[i].lhs << " ? " << cases[i].rhs; - - EXPECT_EQ(lhs.IsOlderThan(cases[i].rhs), (cases[i].expected == -1)); - } -} - -TEST(VersionTest, CompareToWildcardString) { - static const struct version_compare { - const char* lhs; - const char* rhs; - int expected; - } cases[] = { - {"1.0", "1.*", 0}, - {"1.0", "0.*", 1}, - {"1.0", "2.*", -1}, - {"1.2.3", "1.2.3.*", 0}, - {"10.0", "1.0.*", 1}, - {"1.0", "3.0.*", -1}, - {"1.4", "1.3.0.*", 1}, - {"1.3.9", "1.3.*", 0}, - {"1.4.1", "1.3.*", 1}, - {"1.3", "1.4.5.*", -1}, - {"1.5", "1.4.5.*", 1}, - {"1.3.9", "1.3.*", 0}, - {"1.2.0.0.0.0", "1.2.*", 0}, - }; - for (size_t i = 0; i < ARRAYSIZE_UNSAFE(cases); ++i) { - const Version version(cases[i].lhs); - const int result = version.CompareToWildcardString(cases[i].rhs); - EXPECT_EQ(result, cases[i].expected) << cases[i].lhs << "?" << cases[i].rhs; - } -} - -TEST(VersionTest, IsValidWildcardString) { - static const struct version_compare { - const char* version; - bool expected; - } cases[] = { - {"1.0", true}, - {"", false}, - {"1.2.3.4.5.6", true}, - {"1.2.3.*", true}, - {"1.2.3.5*", false}, - {"1.2.3.56*", false}, - {"1.*.3", false}, - {"20.*", true}, - {"+2.*", false}, - {"*", false}, - {"*.2", false}, - }; - for (size_t i = 0; i < ARRAYSIZE_UNSAFE(cases); ++i) { - EXPECT_EQ(Version::IsValidWildcardString(cases[i].version), - cases[i].expected) << cases[i].version << "?" << cases[i].expected; - } -} - -} // namespace diff --git a/base/vlog.cc b/base/vlog.cc deleted file mode 100644 index 946505497c..0000000000 --- a/base/vlog.cc +++ /dev/null @@ -1,177 +0,0 @@ -// Copyright (c) 2010 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "base/vlog.h" - -#include "base/basictypes.h" -#include "base/logging.h" -#include "base/strings/string_number_conversions.h" -#include "base/strings/string_split.h" - -namespace logging { - -const int VlogInfo::kDefaultVlogLevel = 0; - -struct VlogInfo::VmodulePattern { - enum MatchTarget { MATCH_MODULE, MATCH_FILE }; - - explicit VmodulePattern(const std::string& pattern); - - VmodulePattern(); - - std::string pattern; - int vlog_level; - MatchTarget match_target; -}; - -VlogInfo::VmodulePattern::VmodulePattern(const std::string& pattern) - : pattern(pattern), - vlog_level(VlogInfo::kDefaultVlogLevel), - match_target(MATCH_MODULE) { - // If the pattern contains a {forward,back} slash, we assume that - // it's meant to be tested against the entire __FILE__ string. - std::string::size_type first_slash = pattern.find_first_of("\\/"); - if (first_slash != std::string::npos) - match_target = MATCH_FILE; -} - -VlogInfo::VmodulePattern::VmodulePattern() - : vlog_level(VlogInfo::kDefaultVlogLevel), - match_target(MATCH_MODULE) {} - -VlogInfo::VlogInfo(const std::string& v_switch, - const std::string& vmodule_switch, - int* min_log_level) - : min_log_level_(min_log_level) { - DCHECK(min_log_level != NULL); - - typedef std::pair KVPair; - int vlog_level = 0; - if (!v_switch.empty()) { - if (base::StringToInt(v_switch, &vlog_level)) { - SetMaxVlogLevel(vlog_level); - } else { - DLOG(WARNING) << "Could not parse v switch \"" << v_switch << "\""; - } - } - - std::vector kv_pairs; - if (!base::SplitStringIntoKeyValuePairs( - vmodule_switch, '=', ',', &kv_pairs)) { - DLOG(WARNING) << "Could not fully parse vmodule switch \"" - << vmodule_switch << "\""; - } - for (std::vector::const_iterator it = kv_pairs.begin(); - it != kv_pairs.end(); ++it) { - VmodulePattern pattern(it->first); - if (!base::StringToInt(it->second, &pattern.vlog_level)) { - DLOG(WARNING) << "Parsed vlog level for \"" - << it->first << "=" << it->second - << "\" as " << pattern.vlog_level; - } - vmodule_levels_.push_back(pattern); - } -} - -VlogInfo::~VlogInfo() {} - -namespace { - -// Given a path, returns the basename with the extension chopped off -// (and any -inl suffix). We avoid using FilePath to minimize the -// number of dependencies the logging system has. -base::StringPiece GetModule(const base::StringPiece& file) { - base::StringPiece module(file); - base::StringPiece::size_type last_slash_pos = - module.find_last_of("\\/"); - if (last_slash_pos != base::StringPiece::npos) - module.remove_prefix(last_slash_pos + 1); - base::StringPiece::size_type extension_start = module.rfind('.'); - module = module.substr(0, extension_start); - static const char kInlSuffix[] = "-inl"; - static const int kInlSuffixLen = arraysize(kInlSuffix) - 1; - if (module.ends_with(kInlSuffix)) - module.remove_suffix(kInlSuffixLen); - return module; -} - -} // namespace - -int VlogInfo::GetVlogLevel(const base::StringPiece& file) const { - if (!vmodule_levels_.empty()) { - base::StringPiece module(GetModule(file)); - for (std::vector::const_iterator it = - vmodule_levels_.begin(); it != vmodule_levels_.end(); ++it) { - base::StringPiece target( - (it->match_target == VmodulePattern::MATCH_FILE) ? file : module); - if (MatchVlogPattern(target, it->pattern)) - return it->vlog_level; - } - } - return GetMaxVlogLevel(); -} - -void VlogInfo::SetMaxVlogLevel(int level) { - // Log severity is the negative verbosity. - *min_log_level_ = -level; -} - -int VlogInfo::GetMaxVlogLevel() const { - return -*min_log_level_; -} - -bool MatchVlogPattern(const base::StringPiece& string, - const base::StringPiece& vlog_pattern) { - base::StringPiece p(vlog_pattern); - base::StringPiece s(string); - // Consume characters until the next star. - while (!p.empty() && !s.empty() && (p[0] != '*')) { - switch (p[0]) { - // A slash (forward or back) must match a slash (forward or back). - case '/': - case '\\': - if ((s[0] != '/') && (s[0] != '\\')) - return false; - break; - - // A '?' matches anything. - case '?': - break; - - // Anything else must match literally. - default: - if (p[0] != s[0]) - return false; - break; - } - p.remove_prefix(1), s.remove_prefix(1); - } - - // An empty pattern here matches only an empty string. - if (p.empty()) - return s.empty(); - - // Coalesce runs of consecutive stars. There should be at least - // one. - while (!p.empty() && (p[0] == '*')) - p.remove_prefix(1); - - // Since we moved past the stars, an empty pattern here matches - // anything. - if (p.empty()) - return true; - - // Since we moved past the stars and p is non-empty, if some - // non-empty substring of s matches p, then we ourselves match. - while (!s.empty()) { - if (MatchVlogPattern(s, p)) - return true; - s.remove_prefix(1); - } - - // Otherwise, we couldn't find a match. - return false; -} - -} // namespace diff --git a/base/vlog.h b/base/vlog.h deleted file mode 100644 index 4ef173ef20..0000000000 --- a/base/vlog.h +++ /dev/null @@ -1,78 +0,0 @@ -// Copyright (c) 2011 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef BASE_VLOG_H_ -#define BASE_VLOG_H_ - -#include -#include -#include - -#include "base/base_export.h" -#include "base/basictypes.h" -#include "base/strings/string_piece.h" - -namespace logging { - -// A helper class containing all the settings for vlogging. -class BASE_EXPORT VlogInfo { - public: - static const int kDefaultVlogLevel; - - // |v_switch| gives the default maximal active V-logging level; 0 is - // the default. Normally positive values are used for V-logging - // levels. - // - // |vmodule_switch| gives the per-module maximal V-logging levels to - // override the value given by |v_switch|. - // E.g. "my_module=2,foo*=3" would change the logging level for all - // code in source files "my_module.*" and "foo*.*" ("-inl" suffixes - // are also disregarded for this matching). - // - // |log_severity| points to an int that stores the log level. If a valid - // |v_switch| is provided, it will set the log level, and the default - // vlog severity will be read from there.. - // - // Any pattern containing a forward or backward slash will be tested - // against the whole pathname and not just the module. E.g., - // "*/foo/bar/*=2" would change the logging level for all code in - // source files under a "foo/bar" directory. - VlogInfo(const std::string& v_switch, - const std::string& vmodule_switch, - int* min_log_level); - ~VlogInfo(); - - // Returns the vlog level for a given file (usually taken from - // __FILE__). - int GetVlogLevel(const base::StringPiece& file) const; - - private: - void SetMaxVlogLevel(int level); - int GetMaxVlogLevel() const; - - // VmodulePattern holds all the information for each pattern parsed - // from |vmodule_switch|. - struct VmodulePattern; - std::vector vmodule_levels_; - int* min_log_level_; - - DISALLOW_COPY_AND_ASSIGN(VlogInfo); -}; - -// Returns true if the string passed in matches the vlog pattern. The -// vlog pattern string can contain wildcards like * and ?. ? matches -// exactly one character while * matches 0 or more characters. Also, -// as a special case, a / or \ character matches either / or \. -// -// Examples: -// "kh?n" matches "khan" but not "khn" or "khaan" -// "kh*n" matches "khn", "khan", or even "khaaaaan" -// "/foo\bar" matches "/foo/bar", "\foo\bar", or "/foo\bar" -// (disregarding C escaping rules) -BASE_EXPORT bool MatchVlogPattern(const base::StringPiece& string, - const base::StringPiece& vlog_pattern); - -} // namespace logging - -#endif // BASE_VLOG_H_ diff --git a/base/vlog_unittest.cc b/base/vlog_unittest.cc deleted file mode 100644 index 3a37cd9573..0000000000 --- a/base/vlog_unittest.cc +++ /dev/null @@ -1,126 +0,0 @@ -// Copyright (c) 2010 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "base/vlog.h" - -#include "base/basictypes.h" -#include "base/logging.h" -#include "base/third_party/dynamic_annotations/dynamic_annotations.h" -#include "base/time/time.h" -#include "testing/gtest/include/gtest/gtest.h" - -namespace logging { - -namespace { - -TEST(VlogTest, NoVmodule) { - int min_log_level = 0; - EXPECT_EQ(0, - VlogInfo(std::string(), std::string(), &min_log_level) - .GetVlogLevel("test1")); - EXPECT_EQ(0, - VlogInfo("0", std::string(), &min_log_level).GetVlogLevel("test2")); - EXPECT_EQ( - 0, VlogInfo("blah", std::string(), &min_log_level).GetVlogLevel("test3")); - EXPECT_EQ( - 0, - VlogInfo("0blah1", std::string(), &min_log_level).GetVlogLevel("test4")); - EXPECT_EQ(1, - VlogInfo("1", std::string(), &min_log_level).GetVlogLevel("test5")); - EXPECT_EQ(5, - VlogInfo("5", std::string(), &min_log_level).GetVlogLevel("test6")); -} - -TEST(VlogTest, MatchVlogPattern) { - // Degenerate cases. - EXPECT_TRUE(MatchVlogPattern("", "")); - EXPECT_TRUE(MatchVlogPattern("", "****")); - EXPECT_FALSE(MatchVlogPattern("", "x")); - EXPECT_FALSE(MatchVlogPattern("x", "")); - - // Basic. - EXPECT_TRUE(MatchVlogPattern("blah", "blah")); - - // ? should match exactly one character. - EXPECT_TRUE(MatchVlogPattern("blah", "bl?h")); - EXPECT_FALSE(MatchVlogPattern("blh", "bl?h")); - EXPECT_FALSE(MatchVlogPattern("blaah", "bl?h")); - EXPECT_TRUE(MatchVlogPattern("blah", "?lah")); - EXPECT_FALSE(MatchVlogPattern("lah", "?lah")); - EXPECT_FALSE(MatchVlogPattern("bblah", "?lah")); - - // * can match any number (even 0) of characters. - EXPECT_TRUE(MatchVlogPattern("blah", "bl*h")); - EXPECT_TRUE(MatchVlogPattern("blabcdefh", "bl*h")); - EXPECT_TRUE(MatchVlogPattern("blh", "bl*h")); - EXPECT_TRUE(MatchVlogPattern("blah", "*blah")); - EXPECT_TRUE(MatchVlogPattern("ohblah", "*blah")); - EXPECT_TRUE(MatchVlogPattern("blah", "blah*")); - EXPECT_TRUE(MatchVlogPattern("blahhhh", "blah*")); - EXPECT_TRUE(MatchVlogPattern("blahhhh", "blah*")); - EXPECT_TRUE(MatchVlogPattern("blah", "*blah*")); - EXPECT_TRUE(MatchVlogPattern("blahhhh", "*blah*")); - EXPECT_TRUE(MatchVlogPattern("bbbblahhhh", "*blah*")); - - // Multiple *s should work fine. - EXPECT_TRUE(MatchVlogPattern("ballaah", "b*la*h")); - EXPECT_TRUE(MatchVlogPattern("blah", "b*la*h")); - EXPECT_TRUE(MatchVlogPattern("bbbblah", "b*la*h")); - EXPECT_TRUE(MatchVlogPattern("blaaah", "b*la*h")); - - // There should be no escaping going on. - EXPECT_TRUE(MatchVlogPattern("bl\\ah", "bl\\?h")); - EXPECT_FALSE(MatchVlogPattern("bl?h", "bl\\?h")); - EXPECT_TRUE(MatchVlogPattern("bl\\aaaah", "bl\\*h")); - EXPECT_FALSE(MatchVlogPattern("bl*h", "bl\\*h")); - - // Any slash matches any slash. - EXPECT_TRUE(MatchVlogPattern("/b\\lah", "/b\\lah")); - EXPECT_TRUE(MatchVlogPattern("\\b/lah", "/b\\lah")); -} - -TEST(VlogTest, VmoduleBasic) { - const char kVSwitch[] = "-1"; - const char kVModuleSwitch[] = - "foo=,bar=0,baz=blah,,qux=0blah1,quux=1,corge.ext=5"; - int min_log_level = 0; - VlogInfo vlog_info(kVSwitch, kVModuleSwitch, &min_log_level); - EXPECT_EQ(-1, vlog_info.GetVlogLevel("/path/to/grault.cc")); - EXPECT_EQ(0, vlog_info.GetVlogLevel("/path/to/foo.cc")); - EXPECT_EQ(0, vlog_info.GetVlogLevel("D:\\Path\\To\\bar-inl.mm")); - EXPECT_EQ(-1, vlog_info.GetVlogLevel("D:\\path\\to what/bar_unittest.m")); - EXPECT_EQ(0, vlog_info.GetVlogLevel("baz.h")); - EXPECT_EQ(0, vlog_info.GetVlogLevel("/another/path/to/qux.h")); - EXPECT_EQ(1, vlog_info.GetVlogLevel("/path/to/quux")); - EXPECT_EQ(5, vlog_info.GetVlogLevel("c:\\path/to/corge.ext.h")); -} - -TEST(VlogTest, VmoduleDirs) { - const char kVModuleSwitch[] = - "foo/bar.cc=1,baz\\*\\qux.cc=2,*quux/*=3,*/*-inl.h=4"; - int min_log_level = 0; - VlogInfo vlog_info(std::string(), kVModuleSwitch, &min_log_level); - EXPECT_EQ(0, vlog_info.GetVlogLevel("/foo/bar.cc")); - EXPECT_EQ(0, vlog_info.GetVlogLevel("bar.cc")); - EXPECT_EQ(1, vlog_info.GetVlogLevel("foo/bar.cc")); - - EXPECT_EQ(0, vlog_info.GetVlogLevel("baz/grault/qux.h")); - EXPECT_EQ(0, vlog_info.GetVlogLevel("/baz/grault/qux.cc")); - EXPECT_EQ(2, vlog_info.GetVlogLevel("baz/grault/qux.cc")); - EXPECT_EQ(2, vlog_info.GetVlogLevel("baz/grault/blah/qux.cc")); - EXPECT_EQ(2, vlog_info.GetVlogLevel("baz\\grault\\qux.cc")); - EXPECT_EQ(2, vlog_info.GetVlogLevel("baz\\grault//blah\\qux.cc")); - - EXPECT_EQ(0, vlog_info.GetVlogLevel("/foo/bar/baz/quux.cc")); - EXPECT_EQ(3, vlog_info.GetVlogLevel("/foo/bar/baz/quux/grault.cc")); - EXPECT_EQ(3, vlog_info.GetVlogLevel("/foo\\bar/baz\\quux/grault.cc")); - - EXPECT_EQ(0, vlog_info.GetVlogLevel("foo/bar/test-inl.cc")); - EXPECT_EQ(4, vlog_info.GetVlogLevel("foo/bar/test-inl.h")); - EXPECT_EQ(4, vlog_info.GetVlogLevel("foo/bar/baz/blah-inl.h")); -} - -} // namespace - -} // namespace logging diff --git a/base/win/OWNERS b/base/win/OWNERS deleted file mode 100644 index 3aae3d6bec..0000000000 --- a/base/win/OWNERS +++ /dev/null @@ -1 +0,0 @@ -cpu@chromium.org diff --git a/base/win/dllmain.cc b/base/win/dllmain.cc deleted file mode 100644 index 9d2a6dc76c..0000000000 --- a/base/win/dllmain.cc +++ /dev/null @@ -1,123 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -// Windows doesn't support pthread_key_create's destr_function, and in fact -// it's a bit tricky to get code to run when a thread exits. This is -// cargo-cult magic from http://www.codeproject.com/threads/tls.asp. -// We are trying to be compatible with both a LoadLibrary style invocation, as -// well as static linking. This code only needs to be included if we use -// LoadLibrary, but it hooks into the "standard" set of TLS callbacks that are -// provided for static linking. - -// This code is deliberately written to match the style of calls seen in -// base/threading/thread_local_storage_win.cc. Please keep the two in sync if -// coding conventions are changed. - -// WARNING: Do *NOT* try to include this in the construction of the base -// library, even though it potentially drives code in -// base/threading/thread_local_storage_win.cc. If you do, some users will end -// up getting duplicate definition of DllMain() in some of their later links. - -// Force a reference to _tls_used to make the linker create the TLS directory -// if it's not already there (that is, even if __declspec(thread) is not used). -// Force a reference to p_thread_callback_dllmain_typical_entry to prevent whole -// program optimization from discarding the variables. - -#include - -#include "base/compiler_specific.h" -#include "base/win/win_util.h" - -// Indicate if another service is scanning the callbacks. When this becomes -// set to true, then DllMain() will stop supporting the callback service. This -// value is set to true the first time any of our callbacks are called, as that -// shows that some other service is handling callbacks. -static bool linker_notifications_are_active = false; - -// This will be our mostly no-op callback that we'll list. We won't -// deliberately call it, and if it is called, that means we don't need to do any -// of the callbacks anymore. We expect such a call to arrive via a -// THREAD_ATTACH message, long before we'd have to perform our THREAD_DETACH -// callbacks. -static void NTAPI on_callback(PVOID h, DWORD reason, PVOID reserved); - -#ifdef _WIN64 - -#pragma comment(linker, "/INCLUDE:_tls_used") -#pragma comment(linker, "/INCLUDE:p_thread_callback_dllmain_typical_entry") - -#else // _WIN64 - -#pragma comment(linker, "/INCLUDE:__tls_used") -#pragma comment(linker, "/INCLUDE:_p_thread_callback_dllmain_typical_entry") - -#endif // _WIN64 - -// Explicitly depend on tlssup.cc variable to bracket the list of TLS callbacks. -extern "C" PIMAGE_TLS_CALLBACK __xl_a; -extern "C" PIMAGE_TLS_CALLBACK __xl_z; - -// extern "C" suppresses C++ name mangling so we know the symbol names for the -// linker /INCLUDE:symbol pragmas above. -extern "C" { -#ifdef _WIN64 - -// .CRT section is merged with .rdata on x64 so it must be constant data. -#pragma data_seg(push, old_seg) -// Use a typical possible name in the .CRT$XL? list of segments. -#pragma const_seg(".CRT$XLB") -// When defining a const variable, it must have external linkage to be sure the -// linker doesn't discard it. -extern const PIMAGE_TLS_CALLBACK p_thread_callback_dllmain_typical_entry; -const PIMAGE_TLS_CALLBACK p_thread_callback_dllmain_typical_entry = on_callback; -#pragma data_seg(pop, old_seg) - -#else // _WIN64 - -#pragma data_seg(push, old_seg) -// Use a typical possible name in the .CRT$XL? list of segments. -#pragma data_seg(".CRT$XLB") -PIMAGE_TLS_CALLBACK p_thread_callback_dllmain_typical_entry = on_callback; -#pragma data_seg(pop, old_seg) - -#endif // _WIN64 -} // extern "C" - -// Custom crash code to get a unique entry in crash reports. -NOINLINE static void CrashOnProcessDetach() { - *static_cast(0) = 0x356; -} - -// Make DllMain call the listed callbacks. This way any third parties that are -// linked in will also be called. -BOOL WINAPI DllMain(PVOID h, DWORD reason, PVOID reserved) { - if (DLL_PROCESS_DETACH == reason && base::win::ShouldCrashOnProcessDetach()) - CrashOnProcessDetach(); - - if (DLL_THREAD_DETACH != reason && DLL_PROCESS_DETACH != reason) - return true; // We won't service THREAD_ATTACH calls. - - if (linker_notifications_are_active) - return true; // Some other service is doing this work. - - for (PIMAGE_TLS_CALLBACK* it = &__xl_a; it < &__xl_z; ++it) { - if (*it == NULL || *it == on_callback) - continue; // Don't bother to call our own callback. - (*it)(h, reason, reserved); - } - return true; -} - -static void NTAPI on_callback(PVOID h, DWORD reason, PVOID reserved) { - // Do nothing. We were just a place holder in the list used to test that we - // call all items. - // If we are called, it means that some other system is scanning the callbacks - // and we don't need to do so in DllMain(). - linker_notifications_are_active = true; - // Note: If some other routine some how plays this same game... we could both - // decide not to do the scanning , but this trick should suppress - // duplicate calls on Vista, where the runtime takes care of the callbacks, - // and allow us to do the callbacks on XP, where we are currently devoid of - // callbacks (due to an explicit LoadLibrary call). -} diff --git a/base/win/enum_variant.cc b/base/win/enum_variant.cc deleted file mode 100644 index 2975560a9e..0000000000 --- a/base/win/enum_variant.cc +++ /dev/null @@ -1,83 +0,0 @@ -// Copyright (c) 2011 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "base/win/enum_variant.h" - -#include - -#include "base/logging.h" - -namespace base { -namespace win { - -EnumVariant::EnumVariant(unsigned long count) - : items_(new VARIANT[count]), - count_(count), - current_index_(0) { -} - -EnumVariant::~EnumVariant() { -} - -VARIANT* EnumVariant::ItemAt(unsigned long index) { - DCHECK(index < count_); - return &items_[index]; -} - -ULONG STDMETHODCALLTYPE EnumVariant::AddRef() { - return IUnknownImpl::AddRef(); -} - -ULONG STDMETHODCALLTYPE EnumVariant::Release() { - return IUnknownImpl::Release(); -} - -STDMETHODIMP EnumVariant::QueryInterface(REFIID riid, void** ppv) { - if (riid == IID_IEnumVARIANT) { - *ppv = static_cast(this); - AddRef(); - return S_OK; - } - - return IUnknownImpl::QueryInterface(riid, ppv); -} - -STDMETHODIMP EnumVariant::Next(ULONG requested_count, - VARIANT* out_elements, - ULONG* out_elements_received) { - unsigned long count = std::min(requested_count, count_ - current_index_); - for (unsigned long i = 0; i < count; ++i) - out_elements[i] = items_[current_index_ + i]; - current_index_ += count; - *out_elements_received = count; - - return (count == requested_count ? S_OK : S_FALSE); -} - -STDMETHODIMP EnumVariant::Skip(ULONG skip_count) { - unsigned long count = skip_count; - if (current_index_ + count > count_) - count = count_ - current_index_; - - current_index_ += count; - return (count == skip_count ? S_OK : S_FALSE); -} - -STDMETHODIMP EnumVariant::Reset() { - current_index_ = 0; - return S_OK; -} - -STDMETHODIMP EnumVariant::Clone(IEnumVARIANT** out_cloned_object) { - EnumVariant* other = new EnumVariant(count_); - if (count_ > 0) - memcpy(other->ItemAt(0), &items_[0], count_ * sizeof(VARIANT)); - other->Skip(current_index_); - other->AddRef(); - *out_cloned_object = other; - return S_OK; -} - -} // namespace win -} // namespace base diff --git a/base/win/enum_variant.h b/base/win/enum_variant.h deleted file mode 100644 index 82f8750c2a..0000000000 --- a/base/win/enum_variant.h +++ /dev/null @@ -1,52 +0,0 @@ -// Copyright (c) 2011 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef BASE_WIN_ENUM_VARIANT_H_ -#define BASE_WIN_ENUM_VARIANT_H_ - -#include - -#include "base/memory/scoped_ptr.h" -#include "base/win/iunknown_impl.h" - -namespace base { -namespace win { - -// A simple implementation of IEnumVARIANT. -class BASE_EXPORT EnumVariant - : public IEnumVARIANT, - public IUnknownImpl { - public: - // The constructor allocates an array of size |count|. Then use - // ItemAt to set the value of each item in the array to initialize it. - explicit EnumVariant(unsigned long count); - - // Returns a mutable pointer to the item at position |index|. - VARIANT* ItemAt(unsigned long index); - - // IUnknown. - ULONG STDMETHODCALLTYPE AddRef() OVERRIDE; - ULONG STDMETHODCALLTYPE Release() OVERRIDE; - STDMETHODIMP QueryInterface(REFIID riid, void** ppv) OVERRIDE; - - // IEnumVARIANT. - STDMETHODIMP Next(ULONG requested_count, - VARIANT* out_elements, - ULONG* out_elements_received); - STDMETHODIMP Skip(ULONG skip_count); - STDMETHODIMP Reset(); - STDMETHODIMP Clone(IEnumVARIANT** out_cloned_object); - - private: - ~EnumVariant(); - - scoped_ptr items_; - unsigned long count_; - unsigned long current_index_; -}; - -} // namespace win -} // namespace base - -#endif // BASE_WIN_ENUM_VARIANT_H_ diff --git a/base/win/enum_variant_unittest.cc b/base/win/enum_variant_unittest.cc deleted file mode 100644 index 99645a2650..0000000000 --- a/base/win/enum_variant_unittest.cc +++ /dev/null @@ -1,118 +0,0 @@ -// Copyright (c) 2011 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "base/win/enum_variant.h" - -#include "base/win/scoped_com_initializer.h" -#include "testing/gtest/include/gtest/gtest.h" - -namespace base { -namespace win { - -TEST(EnumVariantTest, EmptyEnumVariant) { - ScopedCOMInitializer com_initializer; - - EnumVariant* ev = new EnumVariant(0); - ev->AddRef(); - - IUnknown* iunknown; - EXPECT_TRUE(SUCCEEDED( - ev->QueryInterface(IID_IUnknown, reinterpret_cast(&iunknown)))); - iunknown->Release(); - - IEnumVARIANT* ienumvariant; - EXPECT_TRUE(SUCCEEDED( - ev->QueryInterface(IID_IEnumVARIANT, - reinterpret_cast(&ienumvariant)))); - EXPECT_EQ(ev, ienumvariant); - ienumvariant->Release(); - - VARIANT out_element; - ULONG out_received = 0; - EXPECT_EQ(S_FALSE, ev->Next(1, &out_element, &out_received)); - EXPECT_EQ(0, out_received); - - EXPECT_EQ(S_FALSE, ev->Skip(1)); - - EXPECT_EQ(S_OK, ev->Reset()); - - IEnumVARIANT* ev2 = NULL; - EXPECT_EQ(S_OK, ev->Clone(&ev2)); - - EXPECT_NE(static_cast(NULL), ev2); - EXPECT_NE(ev, ev2); - EXPECT_EQ(S_FALSE, ev2->Skip(1)); - EXPECT_EQ(S_OK, ev2->Reset()); - - ULONG ev2_finalrefcount = ev2->Release(); - EXPECT_EQ(0, ev2_finalrefcount); - - ULONG ev_finalrefcount = ev->Release(); - EXPECT_EQ(0, ev_finalrefcount); -} - -TEST(EnumVariantTest, SimpleEnumVariant) { - ScopedCOMInitializer com_initializer; - - EnumVariant* ev = new EnumVariant(3); - ev->AddRef(); - ev->ItemAt(0)->vt = VT_I4; - ev->ItemAt(0)->lVal = 10; - ev->ItemAt(1)->vt = VT_I4; - ev->ItemAt(1)->lVal = 20; - ev->ItemAt(2)->vt = VT_I4; - ev->ItemAt(2)->lVal = 30; - - // Get elements one at a time. - VARIANT out_element; - ULONG out_received = 0; - EXPECT_EQ(S_OK, ev->Next(1, &out_element, &out_received)); - EXPECT_EQ(1, out_received); - EXPECT_EQ(VT_I4, out_element.vt); - EXPECT_EQ(10, out_element.lVal); - EXPECT_EQ(S_OK, ev->Skip(1)); - EXPECT_EQ(S_OK, ev->Next(1, &out_element, &out_received)); - EXPECT_EQ(1, out_received); - EXPECT_EQ(VT_I4, out_element.vt); - EXPECT_EQ(30, out_element.lVal); - EXPECT_EQ(S_FALSE, ev->Next(1, &out_element, &out_received)); - - // Reset and get all elements at once. - VARIANT out_elements[3]; - EXPECT_EQ(S_OK, ev->Reset()); - EXPECT_EQ(S_OK, ev->Next(3, out_elements, &out_received)); - EXPECT_EQ(3, out_received); - EXPECT_EQ(VT_I4, out_elements[0].vt); - EXPECT_EQ(10, out_elements[0].lVal); - EXPECT_EQ(VT_I4, out_elements[1].vt); - EXPECT_EQ(20, out_elements[1].lVal); - EXPECT_EQ(VT_I4, out_elements[2].vt); - EXPECT_EQ(30, out_elements[2].lVal); - EXPECT_EQ(S_FALSE, ev->Next(1, &out_element, &out_received)); - - // Clone it. - IEnumVARIANT* ev2 = NULL; - EXPECT_EQ(S_OK, ev->Clone(&ev2)); - EXPECT_TRUE(ev2 != NULL); - EXPECT_EQ(S_FALSE, ev->Next(1, &out_element, &out_received)); - EXPECT_EQ(S_OK, ev2->Reset()); - EXPECT_EQ(S_OK, ev2->Next(3, out_elements, &out_received)); - EXPECT_EQ(3, out_received); - EXPECT_EQ(VT_I4, out_elements[0].vt); - EXPECT_EQ(10, out_elements[0].lVal); - EXPECT_EQ(VT_I4, out_elements[1].vt); - EXPECT_EQ(20, out_elements[1].lVal); - EXPECT_EQ(VT_I4, out_elements[2].vt); - EXPECT_EQ(30, out_elements[2].lVal); - EXPECT_EQ(S_FALSE, ev2->Next(1, &out_element, &out_received)); - - ULONG ev2_finalrefcount = ev2->Release(); - EXPECT_EQ(0, ev2_finalrefcount); - - ULONG ev_finalrefcount = ev->Release(); - EXPECT_EQ(0, ev_finalrefcount); -} - -} // namespace win -} // namespace base diff --git a/base/win/event_trace_consumer.h b/base/win/event_trace_consumer.h deleted file mode 100644 index c1b42b4fd9..0000000000 --- a/base/win/event_trace_consumer.h +++ /dev/null @@ -1,148 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. -// -// Declaration of a Windows event trace consumer base class. -#ifndef BASE_WIN_EVENT_TRACE_CONSUMER_H_ -#define BASE_WIN_EVENT_TRACE_CONSUMER_H_ - -#include -#include -#include -#include -#include "base/basictypes.h" - -namespace base { -namespace win { - -// This class is a base class that makes it easier to consume events -// from realtime or file sessions. Concrete consumers need to sublass -// a specialization of this class and override the ProcessEvent and/or -// the ProcessBuffer methods to implement the event consumption logic. -// Usage might look like: -// class MyConsumer: public EtwTraceConsumerBase { -// protected: -// static VOID WINAPI ProcessEvent(PEVENT_TRACE event); -// }; -// -// MyConsumer consumer; -// consumer.OpenFileSession(file_path); -// consumer.Consume(); -template -class EtwTraceConsumerBase { - public: - // Constructs a closed consumer. - EtwTraceConsumerBase() { - } - - ~EtwTraceConsumerBase() { - Close(); - } - - // Opens the named realtime session, which must be existent. - // Note: You can use OpenRealtimeSession or OpenFileSession - // to open as many as MAXIMUM_WAIT_OBJECTS (63) sessions at - // any one time, though only one of them may be a realtime - // session. - HRESULT OpenRealtimeSession(const wchar_t* session_name); - - // Opens the event trace log in "file_name", which must be a full or - // relative path to an existing event trace log file. - // Note: You can use OpenRealtimeSession or OpenFileSession - // to open as many as kNumSessions at any one time. - HRESULT OpenFileSession(const wchar_t* file_name); - - // Consume all open sessions from beginning to end. - HRESULT Consume(); - - // Close all open sessions. - HRESULT Close(); - - protected: - // Override in subclasses to handle events. - static void ProcessEvent(EVENT_TRACE* event) { - } - // Override in subclasses to handle buffers. - static bool ProcessBuffer(EVENT_TRACE_LOGFILE* buffer) { - return true; // keep going - } - - protected: - // Currently open sessions. - std::vector trace_handles_; - - private: - // These delegate to ImplClass callbacks with saner signatures. - static void WINAPI ProcessEventCallback(EVENT_TRACE* event) { - ImplClass::ProcessEvent(event); - } - static ULONG WINAPI ProcessBufferCallback(PEVENT_TRACE_LOGFILE buffer) { - return ImplClass::ProcessBuffer(buffer); - } - - DISALLOW_COPY_AND_ASSIGN(EtwTraceConsumerBase); -}; - -template inline -HRESULT EtwTraceConsumerBase::OpenRealtimeSession( - const wchar_t* session_name) { - EVENT_TRACE_LOGFILE logfile = {}; - logfile.LoggerName = const_cast(session_name); - logfile.LogFileMode = EVENT_TRACE_REAL_TIME_MODE; - logfile.BufferCallback = &ProcessBufferCallback; - logfile.EventCallback = &ProcessEventCallback; - logfile.Context = this; - TRACEHANDLE trace_handle = ::OpenTrace(&logfile); - if (reinterpret_cast(INVALID_HANDLE_VALUE) == trace_handle) - return HRESULT_FROM_WIN32(::GetLastError()); - - trace_handles_.push_back(trace_handle); - return S_OK; -} - -template inline -HRESULT EtwTraceConsumerBase::OpenFileSession( - const wchar_t* file_name) { - EVENT_TRACE_LOGFILE logfile = {}; - logfile.LogFileName = const_cast(file_name); - logfile.BufferCallback = &ProcessBufferCallback; - logfile.EventCallback = &ProcessEventCallback; - logfile.Context = this; - TRACEHANDLE trace_handle = ::OpenTrace(&logfile); - if (reinterpret_cast(INVALID_HANDLE_VALUE) == trace_handle) - return HRESULT_FROM_WIN32(::GetLastError()); - - trace_handles_.push_back(trace_handle); - return S_OK; -} - -template inline -HRESULT EtwTraceConsumerBase::Consume() { - ULONG err = ::ProcessTrace(&trace_handles_[0], - trace_handles_.size(), - NULL, - NULL); - return HRESULT_FROM_WIN32(err); -} - -template inline -HRESULT EtwTraceConsumerBase::Close() { - HRESULT hr = S_OK; - for (size_t i = 0; i < trace_handles_.size(); ++i) { - if (NULL != trace_handles_[i]) { - ULONG ret = ::CloseTrace(trace_handles_[i]); - trace_handles_[i] = NULL; - - if (FAILED(HRESULT_FROM_WIN32(ret))) - hr = HRESULT_FROM_WIN32(ret); - } - } - trace_handles_.clear(); - - return hr; -} - -} // namespace win -} // namespace base - -#endif // BASE_WIN_EVENT_TRACE_CONSUMER_H_ diff --git a/base/win/event_trace_consumer_unittest.cc b/base/win/event_trace_consumer_unittest.cc deleted file mode 100644 index d238192c4f..0000000000 --- a/base/win/event_trace_consumer_unittest.cc +++ /dev/null @@ -1,383 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. -// -// Unit tests for event trace consumer base class. -#include "base/win/event_trace_consumer.h" - -#include - -#include - -#include "base/basictypes.h" -#include "base/file_util.h" -#include "base/files/file_path.h" -#include "base/files/scoped_temp_dir.h" -#include "base/logging.h" -#include "base/process/process.h" -#include "base/strings/stringprintf.h" -#include "base/win/event_trace_controller.h" -#include "base/win/event_trace_provider.h" -#include "base/win/scoped_handle.h" -#include "testing/gtest/include/gtest/gtest.h" - -#include // NOLINT - has to be last - -namespace base { -namespace win { - -namespace { - -typedef std::list EventQueue; - -class TestConsumer: public EtwTraceConsumerBase { - public: - TestConsumer() { - sank_event_.Set(::CreateEvent(NULL, TRUE, FALSE, NULL)); - ClearQueue(); - } - - ~TestConsumer() { - ClearQueue(); - sank_event_.Close(); - } - - void ClearQueue() { - EventQueue::const_iterator it(events_.begin()), end(events_.end()); - - for (; it != end; ++it) { - delete [] it->MofData; - } - - events_.clear(); - } - - static void EnqueueEvent(EVENT_TRACE* event) { - events_.push_back(*event); - EVENT_TRACE& back = events_.back(); - - if (NULL != event->MofData && 0 != event->MofLength) { - back.MofData = new char[event->MofLength]; - memcpy(back.MofData, event->MofData, event->MofLength); - } - } - - static void ProcessEvent(EVENT_TRACE* event) { - EnqueueEvent(event); - ::SetEvent(sank_event_.Get()); - } - - static ScopedHandle sank_event_; - static EventQueue events_; - - private: - DISALLOW_COPY_AND_ASSIGN(TestConsumer); -}; - -ScopedHandle TestConsumer::sank_event_; -EventQueue TestConsumer::events_; - -class EtwTraceConsumerBaseTest: public testing::Test { - public: - EtwTraceConsumerBaseTest() - : session_name_(StringPrintf(L"TestSession-%d", - Process::Current().pid())) { - } - - virtual void SetUp() { - // Cleanup any potentially dangling sessions. - EtwTraceProperties ignore; - EtwTraceController::Stop(session_name_.c_str(), &ignore); - - // Allocate a new GUID for each provider test. - ASSERT_HRESULT_SUCCEEDED(::CoCreateGuid(&test_provider_)); - } - - virtual void TearDown() { - // Cleanup any potentially danging sessions. - EtwTraceProperties ignore; - EtwTraceController::Stop(session_name_.c_str(), &ignore); - } - - protected: - GUID test_provider_; - std::wstring session_name_; -}; - -} // namespace - -TEST_F(EtwTraceConsumerBaseTest, Initialize) { - TestConsumer consumer_; -} - -TEST_F(EtwTraceConsumerBaseTest, OpenRealtimeSucceedsWhenNoSession) { - TestConsumer consumer_; - - ASSERT_HRESULT_SUCCEEDED( - consumer_.OpenRealtimeSession(session_name_.c_str())); -} - -TEST_F(EtwTraceConsumerBaseTest, ConsumerImmediateFailureWhenNoSession) { - TestConsumer consumer_; - - ASSERT_HRESULT_SUCCEEDED( - consumer_.OpenRealtimeSession(session_name_.c_str())); - ASSERT_HRESULT_FAILED(consumer_.Consume()); -} - -namespace { - -class EtwTraceConsumerRealtimeTest: public EtwTraceConsumerBaseTest { - public: - virtual void SetUp() { - EtwTraceConsumerBaseTest::SetUp(); - - ASSERT_HRESULT_SUCCEEDED( - consumer_.OpenRealtimeSession(session_name_.c_str())); - } - - virtual void TearDown() { - consumer_.Close(); - - EtwTraceConsumerBaseTest::TearDown(); - } - - DWORD ConsumerThread() { - ::SetEvent(consumer_ready_.Get()); - - HRESULT hr = consumer_.Consume(); - return hr; - } - - static DWORD WINAPI ConsumerThreadMainProc(void* arg) { - return reinterpret_cast(arg)-> - ConsumerThread(); - } - - HRESULT StartConsumerThread() { - consumer_ready_.Set(::CreateEvent(NULL, TRUE, FALSE, NULL)); - EXPECT_TRUE(consumer_ready_ != NULL); - consumer_thread_.Set(::CreateThread(NULL, 0, ConsumerThreadMainProc, - this, 0, NULL)); - if (NULL == consumer_thread_.Get()) - return HRESULT_FROM_WIN32(::GetLastError()); - - HRESULT hr = S_OK; - HANDLE events[] = { consumer_ready_, consumer_thread_ }; - DWORD result = ::WaitForMultipleObjects(arraysize(events), events, - FALSE, INFINITE); - switch (result) { - case WAIT_OBJECT_0: - // The event was set, the consumer_ is ready. - return S_OK; - case WAIT_OBJECT_0 + 1: { - // The thread finished. This may race with the event, so check - // explicitly for the event here, before concluding there's trouble. - if (WAIT_OBJECT_0 == ::WaitForSingleObject(consumer_ready_, 0)) - return S_OK; - DWORD exit_code = 0; - if (::GetExitCodeThread(consumer_thread_, &exit_code)) - return exit_code; - else - return HRESULT_FROM_WIN32(::GetLastError()); - break; - } - default: - return E_UNEXPECTED; - break; - } - - return hr; - } - - // Waits for consumer_ thread to exit, and returns its exit code. - HRESULT JoinConsumerThread() { - if (WAIT_OBJECT_0 != ::WaitForSingleObject(consumer_thread_, INFINITE)) - return HRESULT_FROM_WIN32(::GetLastError()); - - DWORD exit_code = 0; - if (::GetExitCodeThread(consumer_thread_, &exit_code)) - return exit_code; - - return HRESULT_FROM_WIN32(::GetLastError()); - } - - TestConsumer consumer_; - ScopedHandle consumer_ready_; - ScopedHandle consumer_thread_; -}; - -} // namespace - -TEST_F(EtwTraceConsumerRealtimeTest, ConsumerReturnsWhenSessionClosed) { - EtwTraceController controller; - - HRESULT hr = controller.StartRealtimeSession(session_name_.c_str(), - 100 * 1024); - if (hr == E_ACCESSDENIED) { - VLOG(1) << "You must be an administrator to run this test on Vista"; - return; - } - - // Start the consumer_. - ASSERT_HRESULT_SUCCEEDED(StartConsumerThread()); - - // Wait around for the consumer_ thread a bit. - ASSERT_EQ(WAIT_TIMEOUT, ::WaitForSingleObject(consumer_thread_, 50)); - - ASSERT_HRESULT_SUCCEEDED(controller.Stop(NULL)); - - // The consumer_ returns success on session stop. - ASSERT_HRESULT_SUCCEEDED(JoinConsumerThread()); -} - -namespace { - -// {57E47923-A549-476f-86CA-503D57F59E62} -DEFINE_GUID(kTestEventType, - 0x57e47923, 0xa549, 0x476f, 0x86, 0xca, 0x50, 0x3d, 0x57, 0xf5, 0x9e, 0x62); - -} // namespace - -TEST_F(EtwTraceConsumerRealtimeTest, ConsumeEvent) { - EtwTraceController controller; - HRESULT hr = controller.StartRealtimeSession(session_name_.c_str(), - 100 * 1024); - if (hr == E_ACCESSDENIED) { - VLOG(1) << "You must be an administrator to run this test on Vista"; - return; - } - - ASSERT_HRESULT_SUCCEEDED(controller.EnableProvider(test_provider_, - TRACE_LEVEL_VERBOSE, 0xFFFFFFFF)); - - EtwTraceProvider provider(test_provider_); - ASSERT_EQ(ERROR_SUCCESS, provider.Register()); - - // Start the consumer_. - ASSERT_HRESULT_SUCCEEDED(StartConsumerThread()); - - ASSERT_EQ(0, TestConsumer::events_.size()); - - EtwMofEvent<1> event(kTestEventType, 1, TRACE_LEVEL_ERROR); - EXPECT_EQ(ERROR_SUCCESS, provider.Log(&event.header)); - - EXPECT_EQ(WAIT_OBJECT_0, ::WaitForSingleObject(TestConsumer::sank_event_, - INFINITE)); - ASSERT_HRESULT_SUCCEEDED(controller.Stop(NULL)); - ASSERT_HRESULT_SUCCEEDED(JoinConsumerThread()); - ASSERT_NE(0u, TestConsumer::events_.size()); -} - -namespace { - -// We run events through a file session to assert that -// the content comes through. -class EtwTraceConsumerDataTest: public EtwTraceConsumerBaseTest { - public: - EtwTraceConsumerDataTest() { - } - - virtual void SetUp() { - EtwTraceConsumerBaseTest::SetUp(); - - EtwTraceProperties prop; - EtwTraceController::Stop(session_name_.c_str(), &prop); - - // Create a temp dir for this test. - ASSERT_TRUE(temp_dir_.CreateUniqueTempDir()); - // Construct a temp file name in our dir. - temp_file_ = temp_dir_.path().Append(L"test.etl"); - } - - virtual void TearDown() { - EXPECT_TRUE(base::DeleteFile(temp_file_, false)); - - EtwTraceConsumerBaseTest::TearDown(); - } - - HRESULT LogEventToTempSession(PEVENT_TRACE_HEADER header) { - EtwTraceController controller; - - // Set up a file session. - HRESULT hr = controller.StartFileSession(session_name_.c_str(), - temp_file_.value().c_str()); - if (FAILED(hr)) - return hr; - - // Enable our provider. - EXPECT_HRESULT_SUCCEEDED(controller.EnableProvider(test_provider_, - TRACE_LEVEL_VERBOSE, 0xFFFFFFFF)); - - EtwTraceProvider provider(test_provider_); - // Then register our provider, means we get a session handle immediately. - EXPECT_EQ(ERROR_SUCCESS, provider.Register()); - // Trace the event, it goes to the temp file. - EXPECT_EQ(ERROR_SUCCESS, provider.Log(header)); - EXPECT_HRESULT_SUCCEEDED(controller.DisableProvider(test_provider_)); - EXPECT_HRESULT_SUCCEEDED(provider.Unregister()); - EXPECT_HRESULT_SUCCEEDED(controller.Flush(NULL)); - EXPECT_HRESULT_SUCCEEDED(controller.Stop(NULL)); - - return S_OK; - } - - HRESULT ConsumeEventFromTempSession() { - // Now consume the event(s). - TestConsumer consumer_; - HRESULT hr = consumer_.OpenFileSession(temp_file_.value().c_str()); - if (SUCCEEDED(hr)) - hr = consumer_.Consume(); - consumer_.Close(); - // And nab the result. - events_.swap(TestConsumer::events_); - return hr; - } - - HRESULT RoundTripEvent(PEVENT_TRACE_HEADER header, PEVENT_TRACE* trace) { - base::DeleteFile(temp_file_, false); - - HRESULT hr = LogEventToTempSession(header); - if (SUCCEEDED(hr)) - hr = ConsumeEventFromTempSession(); - - if (FAILED(hr)) - return hr; - - // We should now have the event in the queue. - if (events_.empty()) - return E_FAIL; - - *trace = &events_.back(); - return S_OK; - } - - EventQueue events_; - ScopedTempDir temp_dir_; - FilePath temp_file_; -}; - -} // namespace - - -TEST_F(EtwTraceConsumerDataTest, RoundTrip) { - EtwMofEvent<1> event(kTestEventType, 1, TRACE_LEVEL_ERROR); - - static const char kData[] = "This is but test data"; - event.fields[0].DataPtr = reinterpret_cast(kData); - event.fields[0].Length = sizeof(kData); - - PEVENT_TRACE trace = NULL; - HRESULT hr = RoundTripEvent(&event.header, &trace); - if (hr == E_ACCESSDENIED) { - VLOG(1) << "You must be an administrator to run this test on Vista"; - return; - } - ASSERT_HRESULT_SUCCEEDED(hr) << "RoundTripEvent failed"; - ASSERT_TRUE(NULL != trace); - ASSERT_EQ(sizeof(kData), trace->MofLength); - ASSERT_STREQ(kData, reinterpret_cast(trace->MofData)); -} - -} // namespace win -} // namespace base diff --git a/base/win/event_trace_controller.cc b/base/win/event_trace_controller.cc deleted file mode 100644 index 0391fbc301..0000000000 --- a/base/win/event_trace_controller.cc +++ /dev/null @@ -1,173 +0,0 @@ -// Copyright (c) 2009 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. -// -// Implementation of a Windows event trace controller class. -#include "base/win/event_trace_controller.h" -#include "base/logging.h" - -namespace base { -namespace win { - -EtwTraceProperties::EtwTraceProperties() { - memset(buffer_, 0, sizeof(buffer_)); - EVENT_TRACE_PROPERTIES* prop = get(); - - prop->Wnode.BufferSize = sizeof(buffer_); - prop->Wnode.Flags = WNODE_FLAG_TRACED_GUID; - prop->LoggerNameOffset = sizeof(EVENT_TRACE_PROPERTIES); - prop->LogFileNameOffset = sizeof(EVENT_TRACE_PROPERTIES) + - sizeof(wchar_t) * kMaxStringLen; -} - -HRESULT EtwTraceProperties::SetLoggerName(const wchar_t* logger_name) { - size_t len = wcslen(logger_name) + 1; - if (kMaxStringLen < len) - return E_INVALIDARG; - - memcpy(buffer_ + get()->LoggerNameOffset, - logger_name, - sizeof(wchar_t) * len); - return S_OK; -} - -HRESULT EtwTraceProperties::SetLoggerFileName(const wchar_t* logger_file_name) { - size_t len = wcslen(logger_file_name) + 1; - if (kMaxStringLen < len) - return E_INVALIDARG; - - memcpy(buffer_ + get()->LogFileNameOffset, - logger_file_name, - sizeof(wchar_t) * len); - return S_OK; -} - -EtwTraceController::EtwTraceController() : session_(NULL) { -} - -EtwTraceController::~EtwTraceController() { - Stop(NULL); -} - -HRESULT EtwTraceController::Start(const wchar_t* session_name, - EtwTraceProperties* prop) { - DCHECK(NULL == session_ && session_name_.empty()); - EtwTraceProperties ignore; - if (prop == NULL) - prop = &ignore; - - HRESULT hr = Start(session_name, prop, &session_); - if (SUCCEEDED(hr)) - session_name_ = session_name; - - return hr; -} - -HRESULT EtwTraceController::StartFileSession(const wchar_t* session_name, - const wchar_t* logfile_path, bool realtime) { - DCHECK(NULL == session_ && session_name_.empty()); - - EtwTraceProperties prop; - prop.SetLoggerFileName(logfile_path); - EVENT_TRACE_PROPERTIES& p = *prop.get(); - p.Wnode.ClientContext = 1; // QPC timer accuracy. - p.LogFileMode = EVENT_TRACE_FILE_MODE_SEQUENTIAL; // Sequential log. - if (realtime) - p.LogFileMode |= EVENT_TRACE_REAL_TIME_MODE; - - p.MaximumFileSize = 100; // 100M file size. - p.FlushTimer = 30; // 30 seconds flush lag. - return Start(session_name, &prop); -} - -HRESULT EtwTraceController::StartRealtimeSession(const wchar_t* session_name, - size_t buffer_size) { - DCHECK(NULL == session_ && session_name_.empty()); - EtwTraceProperties prop; - EVENT_TRACE_PROPERTIES& p = *prop.get(); - p.LogFileMode = EVENT_TRACE_REAL_TIME_MODE | EVENT_TRACE_USE_PAGED_MEMORY; - p.FlushTimer = 1; // flush every second. - p.BufferSize = 16; // 16 K buffers. - p.LogFileNameOffset = 0; - return Start(session_name, &prop); -} - -HRESULT EtwTraceController::EnableProvider(REFGUID provider, UCHAR level, - ULONG flags) { - ULONG error = ::EnableTrace(TRUE, flags, level, &provider, session_); - return HRESULT_FROM_WIN32(error); -} - -HRESULT EtwTraceController::DisableProvider(REFGUID provider) { - ULONG error = ::EnableTrace(FALSE, 0, 0, &provider, session_); - return HRESULT_FROM_WIN32(error); -} - -HRESULT EtwTraceController::Stop(EtwTraceProperties* properties) { - EtwTraceProperties ignore; - if (properties == NULL) - properties = &ignore; - - ULONG error = ::ControlTrace(session_, NULL, properties->get(), - EVENT_TRACE_CONTROL_STOP); - if (ERROR_SUCCESS != error) - return HRESULT_FROM_WIN32(error); - - session_ = NULL; - session_name_.clear(); - return S_OK; -} - -HRESULT EtwTraceController::Flush(EtwTraceProperties* properties) { - EtwTraceProperties ignore; - if (properties == NULL) - properties = &ignore; - - ULONG error = ::ControlTrace(session_, NULL, properties->get(), - EVENT_TRACE_CONTROL_FLUSH); - if (ERROR_SUCCESS != error) - return HRESULT_FROM_WIN32(error); - - return S_OK; -} - -HRESULT EtwTraceController::Start(const wchar_t* session_name, - EtwTraceProperties* properties, TRACEHANDLE* session_handle) { - DCHECK(properties != NULL); - ULONG err = ::StartTrace(session_handle, session_name, properties->get()); - return HRESULT_FROM_WIN32(err); -} - -HRESULT EtwTraceController::Query(const wchar_t* session_name, - EtwTraceProperties* properties) { - ULONG err = ::ControlTrace(NULL, session_name, properties->get(), - EVENT_TRACE_CONTROL_QUERY); - return HRESULT_FROM_WIN32(err); -}; - -HRESULT EtwTraceController::Update(const wchar_t* session_name, - EtwTraceProperties* properties) { - DCHECK(properties != NULL); - ULONG err = ::ControlTrace(NULL, session_name, properties->get(), - EVENT_TRACE_CONTROL_UPDATE); - return HRESULT_FROM_WIN32(err); -} - -HRESULT EtwTraceController::Stop(const wchar_t* session_name, - EtwTraceProperties* properties) { - DCHECK(properties != NULL); - ULONG err = ::ControlTrace(NULL, session_name, properties->get(), - EVENT_TRACE_CONTROL_STOP); - return HRESULT_FROM_WIN32(err); -} - -HRESULT EtwTraceController::Flush(const wchar_t* session_name, - EtwTraceProperties* properties) { - DCHECK(properties != NULL); - ULONG err = ::ControlTrace(NULL, session_name, properties->get(), - EVENT_TRACE_CONTROL_FLUSH); - return HRESULT_FROM_WIN32(err); -} - -} // namespace win -} // namespace base diff --git a/base/win/event_trace_controller.h b/base/win/event_trace_controller.h deleted file mode 100644 index 69e755b468..0000000000 --- a/base/win/event_trace_controller.h +++ /dev/null @@ -1,151 +0,0 @@ -// Copyright (c) 2011 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. -// -// Declaration of a Windows event trace controller class. -// The controller takes care of creating and manipulating event trace -// sessions. -// -// Event tracing for Windows is a system-provided service that provides -// logging control and high-performance transport for generic, binary trace -// events. Event trace providers register with the system by their name, -// which is a GUID, and can from that point forward receive callbacks that -// start or end tracing and that change their trace level and enable mask. -// -// A trace controller can create an event tracing session, which either -// sends events to a binary file, or to a realtime consumer, or both. -// -// A trace consumer consumes events from zero or one realtime session, -// as well as potentially from multiple binary trace files. -#ifndef BASE_WIN_EVENT_TRACE_CONTROLLER_H_ -#define BASE_WIN_EVENT_TRACE_CONTROLLER_H_ - -#include -#include -#include -#include - -#include "base/base_export.h" -#include "base/basictypes.h" - -namespace base { -namespace win { - -// Utility class to make it easier to work with EVENT_TRACE_PROPERTIES. -// The EVENT_TRACE_PROPERTIES structure contains information about an -// event tracing session. -class BASE_EXPORT EtwTraceProperties { - public: - EtwTraceProperties(); - - EVENT_TRACE_PROPERTIES* get() { - return &properties_; - } - - const EVENT_TRACE_PROPERTIES* get() const { - return reinterpret_cast(&properties_); - } - - const wchar_t* GetLoggerName() const { - return reinterpret_cast(buffer_ + get()->LoggerNameOffset); - } - - // Copies logger_name to the properties structure. - HRESULT SetLoggerName(const wchar_t* logger_name); - const wchar_t* GetLoggerFileName() const { - return reinterpret_cast(buffer_ + get()->LogFileNameOffset); - } - - // Copies logger_file_name to the properties structure. - HRESULT SetLoggerFileName(const wchar_t* logger_file_name); - - // Max string len for name and session name is 1024 per documentation. - static const size_t kMaxStringLen = 1024; - // Properties buffer allocates space for header and for - // max length for name and session name. - static const size_t kBufSize = sizeof(EVENT_TRACE_PROPERTIES) - + 2 * sizeof(wchar_t) * (kMaxStringLen); - - private: - // The EVENT_TRACE_PROPERTIES structure needs to be overlaid on a - // larger buffer to allow storing the logger name and logger file - // name contiguously with the structure. - union { - public: - // Our properties header. - EVENT_TRACE_PROPERTIES properties_; - // The actual size of the buffer is forced by this member. - char buffer_[kBufSize]; - }; - - DISALLOW_COPY_AND_ASSIGN(EtwTraceProperties); -}; - -// This class implements an ETW controller, which knows how to start and -// stop event tracing sessions, as well as controlling ETW provider -// log levels and enable bit masks under the session. -class BASE_EXPORT EtwTraceController { - public: - EtwTraceController(); - ~EtwTraceController(); - - // Start a session with given name and properties. - HRESULT Start(const wchar_t* session_name, EtwTraceProperties* prop); - - // Starts a session tracing to a file with some default properties. - HRESULT StartFileSession(const wchar_t* session_name, - const wchar_t* logfile_path, - bool realtime = false); - - // Starts a realtime session with some default properties. - HRESULT StartRealtimeSession(const wchar_t* session_name, - size_t buffer_size); - - // Enables "provider" at "level" for this session. - // This will cause all providers registered with the GUID - // "provider" to start tracing at the new level, systemwide. - HRESULT EnableProvider(const GUID& provider, UCHAR level, - ULONG flags = 0xFFFFFFFF); - // Disables "provider". - HRESULT DisableProvider(const GUID& provider); - - // Stops our session and retrieve the new properties of the session, - // properties may be NULL. - HRESULT Stop(EtwTraceProperties* properties); - - // Flushes our session and retrieve the current properties, - // properties may be NULL. - HRESULT Flush(EtwTraceProperties* properties); - - // Static utility functions for controlling - // sessions we don't necessarily own. - static HRESULT Start(const wchar_t* session_name, - EtwTraceProperties* properties, - TRACEHANDLE* session_handle); - - static HRESULT Query(const wchar_t* session_name, - EtwTraceProperties* properties); - - static HRESULT Update(const wchar_t* session_name, - EtwTraceProperties* properties); - - static HRESULT Stop(const wchar_t* session_name, - EtwTraceProperties* properties); - static HRESULT Flush(const wchar_t* session_name, - EtwTraceProperties* properties); - - // Accessors. - TRACEHANDLE session() const { return session_; } - const wchar_t* session_name() const { return session_name_.c_str(); } - - private: - std::wstring session_name_; - TRACEHANDLE session_; - - DISALLOW_COPY_AND_ASSIGN(EtwTraceController); -}; - -} // namespace win -} // namespace base - -#endif // BASE_WIN_EVENT_TRACE_CONTROLLER_H_ diff --git a/base/win/event_trace_controller_unittest.cc b/base/win/event_trace_controller_unittest.cc deleted file mode 100644 index 16bf1e134a..0000000000 --- a/base/win/event_trace_controller_unittest.cc +++ /dev/null @@ -1,239 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. -// -// Unit tests for event trace controller. - -#include -#include - -#include "base/file_util.h" -#include "base/files/file_path.h" -#include "base/files/scoped_temp_dir.h" -#include "base/logging.h" -#include "base/process/process.h" -#include "base/strings/stringprintf.h" -#include "base/sys_info.h" -#include "base/win/event_trace_controller.h" -#include "base/win/event_trace_provider.h" -#include "base/win/scoped_handle.h" -#include "testing/gtest/include/gtest/gtest.h" - -namespace base { -namespace win { - -namespace { - -DEFINE_GUID(kGuidNull, - 0x0000000, 0x0000, 0x0000, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0); - -const ULONG kTestProviderFlags = 0xCAFEBABE; - -class TestingProvider: public EtwTraceProvider { - public: - explicit TestingProvider(const GUID& provider_name) - : EtwTraceProvider(provider_name) { - callback_event_.Set(::CreateEvent(NULL, TRUE, FALSE, NULL)); - } - - void WaitForCallback() { - ::WaitForSingleObject(callback_event_.Get(), INFINITE); - ::ResetEvent(callback_event_.Get()); - } - - private: - virtual void OnEventsEnabled() { - ::SetEvent(callback_event_.Get()); - } - virtual void PostEventsDisabled() { - ::SetEvent(callback_event_.Get()); - } - - ScopedHandle callback_event_; - - DISALLOW_COPY_AND_ASSIGN(TestingProvider); -}; - -} // namespace - -TEST(EtwTracePropertiesTest, Initialization) { - EtwTraceProperties prop; - - EVENT_TRACE_PROPERTIES* p = prop.get(); - EXPECT_NE(0u, p->Wnode.BufferSize); - EXPECT_EQ(0u, p->Wnode.ProviderId); - EXPECT_EQ(0u, p->Wnode.HistoricalContext); - - EXPECT_TRUE(kGuidNull == p->Wnode.Guid); - EXPECT_EQ(0, p->Wnode.ClientContext); - EXPECT_EQ(WNODE_FLAG_TRACED_GUID, p->Wnode.Flags); - - EXPECT_EQ(0, p->BufferSize); - EXPECT_EQ(0, p->MinimumBuffers); - EXPECT_EQ(0, p->MaximumBuffers); - EXPECT_EQ(0, p->MaximumFileSize); - EXPECT_EQ(0, p->LogFileMode); - EXPECT_EQ(0, p->FlushTimer); - EXPECT_EQ(0, p->EnableFlags); - EXPECT_EQ(0, p->AgeLimit); - - EXPECT_EQ(0, p->NumberOfBuffers); - EXPECT_EQ(0, p->FreeBuffers); - EXPECT_EQ(0, p->EventsLost); - EXPECT_EQ(0, p->BuffersWritten); - EXPECT_EQ(0, p->LogBuffersLost); - EXPECT_EQ(0, p->RealTimeBuffersLost); - EXPECT_EQ(0, p->LoggerThreadId); - EXPECT_NE(0u, p->LogFileNameOffset); - EXPECT_NE(0u, p->LoggerNameOffset); -} - -TEST(EtwTracePropertiesTest, Strings) { - EtwTraceProperties prop; - - ASSERT_STREQ(L"", prop.GetLoggerFileName()); - ASSERT_STREQ(L"", prop.GetLoggerName()); - - std::wstring name(1023, L'A'); - ASSERT_HRESULT_SUCCEEDED(prop.SetLoggerFileName(name.c_str())); - ASSERT_HRESULT_SUCCEEDED(prop.SetLoggerName(name.c_str())); - ASSERT_STREQ(name.c_str(), prop.GetLoggerFileName()); - ASSERT_STREQ(name.c_str(), prop.GetLoggerName()); - - std::wstring name2(1024, L'A'); - ASSERT_HRESULT_FAILED(prop.SetLoggerFileName(name2.c_str())); - ASSERT_HRESULT_FAILED(prop.SetLoggerName(name2.c_str())); -} - -namespace { - -class EtwTraceControllerTest : public testing::Test { - public: - EtwTraceControllerTest() - : session_name_( - StringPrintf(L"TestSession-%d", Process::Current().pid())) { - } - - virtual void SetUp() { - EtwTraceProperties ignore; - EtwTraceController::Stop(session_name_.c_str(), &ignore); - - // Allocate a new provider name GUID for each test. - ASSERT_HRESULT_SUCCEEDED(::CoCreateGuid(&test_provider_)); - } - - virtual void TearDown() { - EtwTraceProperties prop; - EtwTraceController::Stop(session_name_.c_str(), &prop); - } - - protected: - GUID test_provider_; - std::wstring session_name_; -}; - -} // namespace - -TEST_F(EtwTraceControllerTest, Initialize) { - EtwTraceController controller; - - EXPECT_EQ(NULL, controller.session()); - EXPECT_STREQ(L"", controller.session_name()); -} - - -TEST_F(EtwTraceControllerTest, StartRealTimeSession) { - EtwTraceController controller; - - HRESULT hr = controller.StartRealtimeSession(session_name_.c_str(), - 100 * 1024); - if (hr == E_ACCESSDENIED) { - VLOG(1) << "You must be an administrator to run this test on Vista"; - return; - } - - EXPECT_TRUE(NULL != controller.session()); - EXPECT_STREQ(session_name_.c_str(), controller.session_name()); - - EXPECT_HRESULT_SUCCEEDED(controller.Stop(NULL)); - EXPECT_EQ(NULL, controller.session()); - EXPECT_STREQ(L"", controller.session_name()); -} - -TEST_F(EtwTraceControllerTest, StartFileSession) { - ScopedTempDir temp_dir; - ASSERT_TRUE(temp_dir.CreateUniqueTempDir()); - FilePath temp; - ASSERT_TRUE(file_util::CreateTemporaryFileInDir(temp_dir.path(), &temp)); - - EtwTraceController controller; - HRESULT hr = controller.StartFileSession(session_name_.c_str(), - temp.value().c_str()); - if (hr == E_ACCESSDENIED) { - VLOG(1) << "You must be an administrator to run this test on Vista"; - base::DeleteFile(temp, false); - return; - } - - EXPECT_TRUE(NULL != controller.session()); - EXPECT_STREQ(session_name_.c_str(), controller.session_name()); - - EXPECT_HRESULT_SUCCEEDED(controller.Stop(NULL)); - EXPECT_EQ(NULL, controller.session()); - EXPECT_STREQ(L"", controller.session_name()); - base::DeleteFile(temp, false); -} - -TEST_F(EtwTraceControllerTest, EnableDisable) { - TestingProvider provider(test_provider_); - - EXPECT_EQ(ERROR_SUCCESS, provider.Register()); - EXPECT_EQ(NULL, provider.session_handle()); - - EtwTraceController controller; - HRESULT hr = controller.StartRealtimeSession(session_name_.c_str(), - 100 * 1024); - if (hr == E_ACCESSDENIED) { - VLOG(1) << "You must be an administrator to run this test on Vista"; - return; - } - - EXPECT_HRESULT_SUCCEEDED(controller.EnableProvider(test_provider_, - TRACE_LEVEL_VERBOSE, kTestProviderFlags)); - - provider.WaitForCallback(); - - EXPECT_EQ(TRACE_LEVEL_VERBOSE, provider.enable_level()); - EXPECT_EQ(kTestProviderFlags, provider.enable_flags()); - - EXPECT_HRESULT_SUCCEEDED(controller.DisableProvider(test_provider_)); - - provider.WaitForCallback(); - - EXPECT_EQ(0, provider.enable_level()); - EXPECT_EQ(0, provider.enable_flags()); - - EXPECT_EQ(ERROR_SUCCESS, provider.Unregister()); - - // Enable the provider again, before registering. - EXPECT_HRESULT_SUCCEEDED(controller.EnableProvider(test_provider_, - TRACE_LEVEL_VERBOSE, kTestProviderFlags)); - - // Register the provider again, the settings above - // should take immediate effect. - EXPECT_EQ(ERROR_SUCCESS, provider.Register()); - - EXPECT_EQ(TRACE_LEVEL_VERBOSE, provider.enable_level()); - EXPECT_EQ(kTestProviderFlags, provider.enable_flags()); - - EXPECT_HRESULT_SUCCEEDED(controller.Stop(NULL)); - - provider.WaitForCallback(); - - // Session should have wound down. - EXPECT_EQ(0, provider.enable_level()); - EXPECT_EQ(0, provider.enable_flags()); -} - -} // namespace win -} // namespace base diff --git a/base/win/event_trace_provider.cc b/base/win/event_trace_provider.cc deleted file mode 100644 index 8fcf67d3d7..0000000000 --- a/base/win/event_trace_provider.cc +++ /dev/null @@ -1,134 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. -// -#include "base/win/event_trace_provider.h" -#include -#include - -namespace base { -namespace win { - -TRACE_GUID_REGISTRATION EtwTraceProvider::obligatory_guid_registration_ = { - &GUID_NULL, - NULL -}; - -EtwTraceProvider::EtwTraceProvider(const GUID& provider_name) - : provider_name_(provider_name), registration_handle_(NULL), - session_handle_(NULL), enable_flags_(0), enable_level_(0) { -} - -EtwTraceProvider::EtwTraceProvider() - : provider_name_(GUID_NULL), registration_handle_(NULL), - session_handle_(NULL), enable_flags_(0), enable_level_(0) { -} - -EtwTraceProvider::~EtwTraceProvider() { - Unregister(); -} - -ULONG EtwTraceProvider::EnableEvents(void* buffer) { - session_handle_ = ::GetTraceLoggerHandle(buffer); - if (NULL == session_handle_) { - return ::GetLastError(); - } - - enable_flags_ = ::GetTraceEnableFlags(session_handle_); - enable_level_ = ::GetTraceEnableLevel(session_handle_); - - // Give subclasses a chance to digest the state change. - OnEventsEnabled(); - - return ERROR_SUCCESS; -} - -ULONG EtwTraceProvider::DisableEvents() { - // Give subclasses a chance to digest the state change. - OnEventsDisabled(); - - enable_level_ = 0; - enable_flags_ = 0; - session_handle_ = NULL; - - PostEventsDisabled(); - - return ERROR_SUCCESS; -} - -ULONG EtwTraceProvider::Callback(WMIDPREQUESTCODE request, void* buffer) { - switch (request) { - case WMI_ENABLE_EVENTS: - return EnableEvents(buffer); - case WMI_DISABLE_EVENTS: - return DisableEvents(); - default: - return ERROR_INVALID_PARAMETER; - } - // Not reached. -} - -ULONG WINAPI EtwTraceProvider::ControlCallback(WMIDPREQUESTCODE request, - void* context, ULONG *reserved, void* buffer) { - EtwTraceProvider *provider = reinterpret_cast(context); - - return provider->Callback(request, buffer); -} - -ULONG EtwTraceProvider::Register() { - if (provider_name_ == GUID_NULL) - return ERROR_INVALID_NAME; - - return ::RegisterTraceGuids(ControlCallback, this, &provider_name_, - 1, &obligatory_guid_registration_, NULL, NULL, ®istration_handle_); -} - -ULONG EtwTraceProvider::Unregister() { - // If a session is active, notify subclasses that it's going away. - if (session_handle_ != NULL) - DisableEvents(); - - ULONG ret = ::UnregisterTraceGuids(registration_handle_); - - registration_handle_ = NULL; - - return ret; -} - -ULONG EtwTraceProvider::Log(const EtwEventClass& event_class, - EtwEventType type, EtwEventLevel level, const char *message) { - if (NULL == session_handle_ || enable_level_ < level) - return ERROR_SUCCESS; // No one listening. - - EtwMofEvent<1> event(event_class, type, level); - - event.fields[0].DataPtr = reinterpret_cast(message); - event.fields[0].Length = message ? - static_cast(sizeof(message[0]) * (1 + strlen(message))) : 0; - - return ::TraceEvent(session_handle_, &event.header); -} - -ULONG EtwTraceProvider::Log(const EtwEventClass& event_class, - EtwEventType type, EtwEventLevel level, const wchar_t *message) { - if (NULL == session_handle_ || enable_level_ < level) - return ERROR_SUCCESS; // No one listening. - - EtwMofEvent<1> event(event_class, type, level); - - event.fields[0].DataPtr = reinterpret_cast(message); - event.fields[0].Length = message ? - static_cast(sizeof(message[0]) * (1 + wcslen(message))) : 0; - - return ::TraceEvent(session_handle_, &event.header); -} - -ULONG EtwTraceProvider::Log(EVENT_TRACE_HEADER* event) { - if (enable_level_ < event->Class.Level) - return ERROR_SUCCESS; - - return ::TraceEvent(session_handle_, event); -} - -} // namespace win -} // namespace base diff --git a/base/win/event_trace_provider.h b/base/win/event_trace_provider.h deleted file mode 100644 index 7907347b72..0000000000 --- a/base/win/event_trace_provider.h +++ /dev/null @@ -1,180 +0,0 @@ -// Copyright (c) 2011 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. -// -// Declaration of a Windows event trace provider class, to allow using -// Windows Event Tracing for logging transport and control. -#ifndef BASE_WIN_EVENT_TRACE_PROVIDER_H_ -#define BASE_WIN_EVENT_TRACE_PROVIDER_H_ - -#include -#include -#include - -#include "base/base_export.h" -#include "base/basictypes.h" - -namespace base { -namespace win { - -typedef GUID EtwEventClass; -typedef UCHAR EtwEventType; -typedef UCHAR EtwEventLevel; -typedef USHORT EtwEventVersion; -typedef ULONG EtwEventFlags; - -// Base class is a POD for correctness. -template struct EtwMofEventBase { - EVENT_TRACE_HEADER header; - MOF_FIELD fields[N]; -}; - -// Utility class to auto-initialize event trace header structures. -template class EtwMofEvent: public EtwMofEventBase { - public: - typedef EtwMofEventBase Super; - - // Clang and the C++ standard don't allow unqualified lookup into dependent - // bases, hence these using decls to explicitly pull the names out. - using EtwMofEventBase::header; - using EtwMofEventBase::fields; - - EtwMofEvent() { - memset(static_cast(this), 0, sizeof(Super)); - } - - EtwMofEvent(const EtwEventClass& event_class, EtwEventType type, - EtwEventLevel level) { - memset(static_cast(this), 0, sizeof(Super)); - header.Size = sizeof(Super); - header.Guid = event_class; - header.Class.Type = type; - header.Class.Level = level; - header.Flags = WNODE_FLAG_TRACED_GUID | WNODE_FLAG_USE_MOF_PTR; - } - - EtwMofEvent(const EtwEventClass& event_class, EtwEventType type, - EtwEventVersion version, EtwEventLevel level) { - memset(static_cast(this), 0, sizeof(Super)); - header.Size = sizeof(Super); - header.Guid = event_class; - header.Class.Type = type; - header.Class.Version = version; - header.Class.Level = level; - header.Flags = WNODE_FLAG_TRACED_GUID | WNODE_FLAG_USE_MOF_PTR; - } - - void SetField(int field, size_t size, const void *data) { - // DCHECK(field < N); - if ((field < N) && (size <= kuint32max)) { - fields[field].DataPtr = reinterpret_cast(data); - fields[field].Length = static_cast(size); - } - } - - EVENT_TRACE_HEADER* get() { return& header; } - - private: - DISALLOW_COPY_AND_ASSIGN(EtwMofEvent); -}; - -// Trace provider with Event Tracing for Windows. The trace provider -// registers with ETW by its name which is a GUID. ETW calls back to -// the object whenever the trace level or enable flags for this provider -// name changes. -// Users of this class can test whether logging is currently enabled at -// a particular trace level, and whether particular enable flags are set, -// before other resources are consumed to generate and issue the log -// messages themselves. -class BASE_EXPORT EtwTraceProvider { - public: - // Creates an event trace provider identified by provider_name, which - // will be the name registered with Event Tracing for Windows (ETW). - explicit EtwTraceProvider(const GUID& provider_name); - - // Creates an unnamed event trace provider, the provider must be given - // a name before registration. - EtwTraceProvider(); - virtual ~EtwTraceProvider(); - - // Registers the trace provider with Event Tracing for Windows. - // Note: from this point forward ETW may call the provider's control - // callback. If the provider's name is enabled in some trace session - // already, the callback may occur recursively from this call, so - // call this only when you're ready to handle callbacks. - ULONG Register(); - // Unregisters the trace provider with ETW. - ULONG Unregister(); - - // Accessors. - void set_provider_name(const GUID& provider_name) { - provider_name_ = provider_name; - } - const GUID& provider_name() const { return provider_name_; } - TRACEHANDLE registration_handle() const { return registration_handle_; } - TRACEHANDLE session_handle() const { return session_handle_; } - EtwEventFlags enable_flags() const { return enable_flags_; } - EtwEventLevel enable_level() const { return enable_level_; } - - // Returns true iff logging should be performed for "level" and "flags". - // Note: flags is treated as a bitmask, and should normally have a single - // bit set, to test whether to log for a particular sub "facility". - bool ShouldLog(EtwEventLevel level, EtwEventFlags flags) { - return NULL != session_handle_ && level >= enable_level_ && - (0 != (flags & enable_flags_)); - } - - // Simple wrappers to log Unicode and ANSI strings. - // Do nothing if !ShouldLog(level, 0xFFFFFFFF). - ULONG Log(const EtwEventClass& event_class, EtwEventType type, - EtwEventLevel level, const char *message); - ULONG Log(const EtwEventClass& event_class, EtwEventType type, - EtwEventLevel level, const wchar_t *message); - - // Log the provided event. - ULONG Log(EVENT_TRACE_HEADER* event); - - protected: - // Called after events have been enabled, override in subclasses - // to set up state or log at the start of a session. - // Note: This function may be called ETW's thread and may be racy, - // bring your own locking if needed. - virtual void OnEventsEnabled() {} - - // Called just before events are disabled, override in subclasses - // to tear down state or log at the end of a session. - // Note: This function may be called ETW's thread and may be racy, - // bring your own locking if needed. - virtual void OnEventsDisabled() {} - - // Called just after events have been disabled, override in subclasses - // to tear down state at the end of a session. At this point it's - // to late to log anything to the session. - // Note: This function may be called ETW's thread and may be racy, - // bring your own locking if needed. - virtual void PostEventsDisabled() {} - - private: - ULONG EnableEvents(PVOID buffer); - ULONG DisableEvents(); - ULONG Callback(WMIDPREQUESTCODE request, PVOID buffer); - static ULONG WINAPI ControlCallback(WMIDPREQUESTCODE request, PVOID context, - ULONG *reserved, PVOID buffer); - - GUID provider_name_; - TRACEHANDLE registration_handle_; - TRACEHANDLE session_handle_; - EtwEventFlags enable_flags_; - EtwEventLevel enable_level_; - - // We don't use this, but on XP we're obliged to pass one in to - // RegisterTraceGuids. Non-const, because that's how the API needs it. - static TRACE_GUID_REGISTRATION obligatory_guid_registration_; - - DISALLOW_COPY_AND_ASSIGN(EtwTraceProvider); -}; - -} // namespace win -} // namespace base - -#endif // BASE_WIN_EVENT_TRACE_PROVIDER_H_ diff --git a/base/win/event_trace_provider_unittest.cc b/base/win/event_trace_provider_unittest.cc deleted file mode 100644 index 55b5ae6aed..0000000000 --- a/base/win/event_trace_provider_unittest.cc +++ /dev/null @@ -1,110 +0,0 @@ -// Copyright (c) 2010 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. -// -// Unit tests for event trace provider. -#include "base/win/event_trace_provider.h" -#include -#include "testing/gtest/include/gtest/gtest.h" -#include // NOLINT - has to be last - -namespace { - -using base::win::EtwTraceProvider; -using base::win::EtwMofEvent; - -// {7F0FD37F-FA3C-4cd6-9242-DF60967A2CB2} -DEFINE_GUID(kTestProvider, - 0x7f0fd37f, 0xfa3c, 0x4cd6, 0x92, 0x42, 0xdf, 0x60, 0x96, 0x7a, 0x2c, 0xb2); - -// {7F0FD37F-FA3C-4cd6-9242-DF60967A2CB2} -DEFINE_GUID(kTestEventClass, - 0x7f0fd37f, 0xfa3c, 0x4cd6, 0x92, 0x42, 0xdf, 0x60, 0x96, 0x7a, 0x2c, 0xb2); - -} // namespace - -TEST(EtwTraceProviderTest, ToleratesPreCreateInvocations) { - // Because the trace provider is used in logging, it's important that - // it be possible to use static provider instances without regard to - // whether they've been constructed or destructed. - // The interface of the class is designed to tolerate this usage. - char buf[sizeof(EtwTraceProvider)] = {0}; - EtwTraceProvider& provider = reinterpret_cast(buf); - - EXPECT_EQ(NULL, provider.registration_handle()); - EXPECT_EQ(NULL, provider.session_handle()); - EXPECT_EQ(0, provider.enable_flags()); - EXPECT_EQ(0, provider.enable_level()); - - EXPECT_FALSE(provider.ShouldLog(TRACE_LEVEL_FATAL, 0xfffffff)); - - // We expect these not to crash. - provider.Log(kTestEventClass, 0, TRACE_LEVEL_FATAL, "foo"); - provider.Log(kTestEventClass, 0, TRACE_LEVEL_FATAL, L"foo"); - - EtwMofEvent<1> dummy(kTestEventClass, 0, TRACE_LEVEL_FATAL); - DWORD data = 0; - dummy.SetField(0, sizeof(data), &data); - provider.Log(dummy.get()); - - // Placement-new the provider into our buffer. - new (buf) EtwTraceProvider(kTestProvider); - - // Registration is now safe. - EXPECT_EQ(ERROR_SUCCESS, provider.Register()); - - // Destruct the instance, this should unregister it. - provider.EtwTraceProvider::~EtwTraceProvider(); - - // And post-destruction, all of the above should still be safe. - EXPECT_EQ(NULL, provider.registration_handle()); - EXPECT_EQ(NULL, provider.session_handle()); - EXPECT_EQ(0, provider.enable_flags()); - EXPECT_EQ(0, provider.enable_level()); - - EXPECT_FALSE(provider.ShouldLog(TRACE_LEVEL_FATAL, 0xfffffff)); - - // We expect these not to crash. - provider.Log(kTestEventClass, 0, TRACE_LEVEL_FATAL, "foo"); - provider.Log(kTestEventClass, 0, TRACE_LEVEL_FATAL, L"foo"); - provider.Log(dummy.get()); -} - -TEST(EtwTraceProviderTest, Initialize) { - EtwTraceProvider provider(kTestProvider); - - EXPECT_EQ(NULL, provider.registration_handle()); - EXPECT_EQ(NULL, provider.session_handle()); - EXPECT_EQ(0, provider.enable_flags()); - EXPECT_EQ(0, provider.enable_level()); -} - -TEST(EtwTraceProviderTest, Register) { - EtwTraceProvider provider(kTestProvider); - - ASSERT_EQ(ERROR_SUCCESS, provider.Register()); - EXPECT_NE(NULL, provider.registration_handle()); - ASSERT_EQ(ERROR_SUCCESS, provider.Unregister()); - EXPECT_EQ(NULL, provider.registration_handle()); -} - -TEST(EtwTraceProviderTest, RegisterWithNoNameFails) { - EtwTraceProvider provider; - - EXPECT_TRUE(provider.Register() != ERROR_SUCCESS); -} - -TEST(EtwTraceProviderTest, Enable) { - EtwTraceProvider provider(kTestProvider); - - ASSERT_EQ(ERROR_SUCCESS, provider.Register()); - EXPECT_NE(NULL, provider.registration_handle()); - - // No session so far. - EXPECT_EQ(NULL, provider.session_handle()); - EXPECT_EQ(0, provider.enable_flags()); - EXPECT_EQ(0, provider.enable_level()); - - ASSERT_EQ(ERROR_SUCCESS, provider.Unregister()); - EXPECT_EQ(NULL, provider.registration_handle()); -} diff --git a/base/win/i18n.cc b/base/win/i18n.cc deleted file mode 100644 index 9e523a15cb..0000000000 --- a/base/win/i18n.cc +++ /dev/null @@ -1,169 +0,0 @@ -// Copyright (c) 2010 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "base/win/i18n.h" - -#include - -#include "base/logging.h" - -namespace { - -// Keep this enum in sync with kLanguageFunctionNames. -enum LanguageFunction { - SYSTEM_LANGUAGES, - USER_LANGUAGES, - PROCESS_LANGUAGES, - THREAD_LANGUAGES, - NUM_FUNCTIONS -}; - -const char kSystemLanguagesFunctionName[] = "GetSystemPreferredUILanguages"; -const char kUserLanguagesFunctionName[] = "GetUserPreferredUILanguages"; -const char kProcessLanguagesFunctionName[] = "GetProcessPreferredUILanguages"; -const char kThreadLanguagesFunctionName[] = "GetThreadPreferredUILanguages"; - -// Keep this array in sync with enum LanguageFunction. -const char *const kLanguageFunctionNames[] = { - &kSystemLanguagesFunctionName[0], - &kUserLanguagesFunctionName[0], - &kProcessLanguagesFunctionName[0], - &kThreadLanguagesFunctionName[0] -}; - -COMPILE_ASSERT(NUM_FUNCTIONS == arraysize(kLanguageFunctionNames), - language_function_enum_and_names_out_of_sync); - -// Calls one of the MUI Get*PreferredUILanguages functions, placing the result -// in |languages|. |function| identifies the function to call and |flags| is -// the function-specific flags (callers must not specify MUI_LANGUAGE_ID or -// MUI_LANGUAGE_NAME). Returns true if at least one language is placed in -// |languages|. -bool GetMUIPreferredUILanguageList(LanguageFunction function, ULONG flags, - std::vector* languages) { - DCHECK(0 <= function && NUM_FUNCTIONS > function); - DCHECK_EQ(0U, (flags & (MUI_LANGUAGE_ID | MUI_LANGUAGE_NAME))); - DCHECK(languages); - - HMODULE kernel32 = GetModuleHandle(L"kernel32.dll"); - if (NULL != kernel32) { - typedef BOOL (WINAPI* GetPreferredUILanguages_Fn)( - DWORD, PULONG, PZZWSTR, PULONG); - GetPreferredUILanguages_Fn get_preferred_ui_languages = - reinterpret_cast( - GetProcAddress(kernel32, kLanguageFunctionNames[function])); - if (NULL != get_preferred_ui_languages) { - const ULONG call_flags = flags | MUI_LANGUAGE_NAME; - ULONG language_count = 0; - ULONG buffer_length = 0; - if (get_preferred_ui_languages(call_flags, &language_count, NULL, - &buffer_length) && - 0 != buffer_length) { - languages->resize(buffer_length); - if (get_preferred_ui_languages(call_flags, &language_count, - &(*languages)[0], &buffer_length) && - 0 != language_count) { - DCHECK(languages->size() == buffer_length); - return true; - } else { - DPCHECK(0 == language_count) - << "Failed getting preferred UI languages."; - } - } else { - DPCHECK(0 == buffer_length) - << "Failed getting size of preferred UI languages."; - } - } else { - DVLOG(2) << "MUI not available."; - } - } else { - NOTREACHED() << "kernel32.dll not found."; - } - - return false; -} - -bool GetUserDefaultUILanguage(std::wstring* language, std::wstring* region) { - DCHECK(language); - - LANGID lang_id = ::GetUserDefaultUILanguage(); - if (LOCALE_CUSTOM_UI_DEFAULT != lang_id) { - const LCID locale_id = MAKELCID(lang_id, SORT_DEFAULT); - // max size for LOCALE_SISO639LANGNAME and LOCALE_SISO3166CTRYNAME is 9 - wchar_t result_buffer[9]; - int result_length = - GetLocaleInfo(locale_id, LOCALE_SISO639LANGNAME, &result_buffer[0], - arraysize(result_buffer)); - DPCHECK(0 != result_length) << "Failed getting language id"; - if (1 < result_length) { - language->assign(&result_buffer[0], result_length - 1); - region->clear(); - if (SUBLANG_NEUTRAL != SUBLANGID(lang_id)) { - result_length = - GetLocaleInfo(locale_id, LOCALE_SISO3166CTRYNAME, &result_buffer[0], - arraysize(result_buffer)); - DPCHECK(0 != result_length) << "Failed getting region id"; - if (1 < result_length) - region->assign(&result_buffer[0], result_length - 1); - } - return true; - } - } else { - // This is entirely unexpected on pre-Vista, which is the only time we - // should try GetUserDefaultUILanguage anyway. - NOTREACHED() << "Cannot determine language for a supplemental locale."; - } - return false; -} - -bool GetPreferredUILanguageList(LanguageFunction function, ULONG flags, - std::vector* languages) { - std::vector buffer; - std::wstring language; - std::wstring region; - - if (GetMUIPreferredUILanguageList(function, flags, &buffer)) { - std::vector::const_iterator scan = buffer.begin(); - language.assign(&*scan); - while (!language.empty()) { - languages->push_back(language); - scan += language.size() + 1; - language.assign(&*scan); - } - } else if (GetUserDefaultUILanguage(&language, ®ion)) { - // Mimic the MUI behavior of putting the neutral version of the lang after - // the regional one (e.g., "fr-CA, fr"). - if (!region.empty()) - languages->push_back(std::wstring(language) - .append(1, L'-') - .append(region)); - languages->push_back(language); - } else { - return false; - } - - return true; -} - -} // namespace - -namespace base { -namespace win { -namespace i18n { - -bool GetUserPreferredUILanguageList(std::vector* languages) { - DCHECK(languages); - return GetPreferredUILanguageList(USER_LANGUAGES, 0, languages); -} - -bool GetThreadPreferredUILanguageList(std::vector* languages) { - DCHECK(languages); - return GetPreferredUILanguageList( - THREAD_LANGUAGES, MUI_MERGE_SYSTEM_FALLBACK | MUI_MERGE_USER_FALLBACK, - languages); -} - -} // namespace i18n -} // namespace win -} // namespace base diff --git a/base/win/i18n.h b/base/win/i18n.h deleted file mode 100644 index c0379c1559..0000000000 --- a/base/win/i18n.h +++ /dev/null @@ -1,34 +0,0 @@ -// Copyright (c) 2011 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef BASE_WIN_I18N_H_ -#define BASE_WIN_I18N_H_ - -#include -#include - -#include "base/base_export.h" -#include "base/basictypes.h" - -namespace base { -namespace win { -namespace i18n { - -// Adds to |languages| the list of user preferred UI languages from MUI, if -// available, falling-back on the user default UI language otherwise. Returns -// true if at least one language is added. -BASE_EXPORT bool GetUserPreferredUILanguageList( - std::vector* languages); - -// Adds to |languages| the list of thread, process, user, and system preferred -// UI languages from MUI, if available, falling-back on the user default UI -// language otherwise. Returns true if at least one language is added. -BASE_EXPORT bool GetThreadPreferredUILanguageList( - std::vector* languages); - -} // namespace i18n -} // namespace win -} // namespace base - -#endif // BASE_WIN_I18N_H_ diff --git a/base/win/i18n_unittest.cc b/base/win/i18n_unittest.cc deleted file mode 100644 index 781fc39db3..0000000000 --- a/base/win/i18n_unittest.cc +++ /dev/null @@ -1,42 +0,0 @@ -// Copyright (c) 2010 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -// This file contains unit tests for Windows internationalization funcs. - -#include "testing/gtest/include/gtest/gtest.h" - -#include "base/win/i18n.h" -#include "base/win/windows_version.h" - -namespace base { -namespace win { -namespace i18n { - -// Tests that at least one user preferred UI language can be obtained. -TEST(I18NTest, GetUserPreferredUILanguageList) { - std::vector languages; - EXPECT_TRUE(GetUserPreferredUILanguageList(&languages)); - EXPECT_NE(static_cast::size_type>(0), - languages.size()); - for (std::vector::const_iterator scan = languages.begin(), - end = languages.end(); scan != end; ++scan) { - EXPECT_FALSE((*scan).empty()); - } -} - -// Tests that at least one thread preferred UI language can be obtained. -TEST(I18NTest, GetThreadPreferredUILanguageList) { - std::vector languages; - EXPECT_TRUE(GetThreadPreferredUILanguageList(&languages)); - EXPECT_NE(static_cast::size_type>(0), - languages.size()); - for (std::vector::const_iterator scan = languages.begin(), - end = languages.end(); scan != end; ++scan) { - EXPECT_FALSE((*scan).empty()); - } -} - -} // namespace i18n -} // namespace win -} // namespace base diff --git a/base/win/iat_patch_function.cc b/base/win/iat_patch_function.cc deleted file mode 100644 index a4a89028b8..0000000000 --- a/base/win/iat_patch_function.cc +++ /dev/null @@ -1,278 +0,0 @@ -// Copyright (c) 2011 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "base/win/iat_patch_function.h" - -#include "base/logging.h" -#include "base/win/pe_image.h" - -namespace base { -namespace win { - -namespace { - -struct InterceptFunctionInformation { - bool finished_operation; - const char* imported_from_module; - const char* function_name; - void* new_function; - void** old_function; - IMAGE_THUNK_DATA** iat_thunk; - DWORD return_code; -}; - -void* GetIATFunction(IMAGE_THUNK_DATA* iat_thunk) { - if (NULL == iat_thunk) { - NOTREACHED(); - return NULL; - } - - // Works around the 64 bit portability warning: - // The Function member inside IMAGE_THUNK_DATA is really a pointer - // to the IAT function. IMAGE_THUNK_DATA correctly maps to IMAGE_THUNK_DATA32 - // or IMAGE_THUNK_DATA64 for correct pointer size. - union FunctionThunk { - IMAGE_THUNK_DATA thunk; - void* pointer; - } iat_function; - - iat_function.thunk = *iat_thunk; - return iat_function.pointer; -} -// Change the page protection (of code pages) to writable and copy -// the data at the specified location -// -// Arguments: -// old_code Target location to copy -// new_code Source -// length Number of bytes to copy -// -// Returns: Windows error code (winerror.h). NO_ERROR if successful -DWORD ModifyCode(void* old_code, void* new_code, int length) { - if ((NULL == old_code) || (NULL == new_code) || (0 == length)) { - NOTREACHED(); - return ERROR_INVALID_PARAMETER; - } - - // Change the page protection so that we can write. - DWORD error = NO_ERROR; - DWORD old_page_protection = 0; - if (VirtualProtect(old_code, - length, - PAGE_READWRITE, - &old_page_protection)) { - - // Write the data. - CopyMemory(old_code, new_code, length); - - // Restore the old page protection. - error = ERROR_SUCCESS; - VirtualProtect(old_code, - length, - old_page_protection, - &old_page_protection); - } else { - error = GetLastError(); - NOTREACHED(); - } - - return error; -} - -bool InterceptEnumCallback(const base::win::PEImage& image, const char* module, - DWORD ordinal, const char* name, DWORD hint, - IMAGE_THUNK_DATA* iat, void* cookie) { - InterceptFunctionInformation* intercept_information = - reinterpret_cast(cookie); - - if (NULL == intercept_information) { - NOTREACHED(); - return false; - } - - DCHECK(module); - - if ((0 == lstrcmpiA(module, intercept_information->imported_from_module)) && - (NULL != name) && - (0 == lstrcmpiA(name, intercept_information->function_name))) { - // Save the old pointer. - if (NULL != intercept_information->old_function) { - *(intercept_information->old_function) = GetIATFunction(iat); - } - - if (NULL != intercept_information->iat_thunk) { - *(intercept_information->iat_thunk) = iat; - } - - // portability check - COMPILE_ASSERT(sizeof(iat->u1.Function) == - sizeof(intercept_information->new_function), unknown_IAT_thunk_format); - - // Patch the function. - intercept_information->return_code = - ModifyCode(&(iat->u1.Function), - &(intercept_information->new_function), - sizeof(intercept_information->new_function)); - - // Terminate further enumeration. - intercept_information->finished_operation = true; - return false; - } - - return true; -} - -// Helper to intercept a function in an import table of a specific -// module. -// -// Arguments: -// module_handle Module to be intercepted -// imported_from_module Module that exports the symbol -// function_name Name of the API to be intercepted -// new_function Interceptor function -// old_function Receives the original function pointer -// iat_thunk Receives pointer to IAT_THUNK_DATA -// for the API from the import table. -// -// Returns: Returns NO_ERROR on success or Windows error code -// as defined in winerror.h -DWORD InterceptImportedFunction(HMODULE module_handle, - const char* imported_from_module, - const char* function_name, void* new_function, - void** old_function, - IMAGE_THUNK_DATA** iat_thunk) { - if ((NULL == module_handle) || (NULL == imported_from_module) || - (NULL == function_name) || (NULL == new_function)) { - NOTREACHED(); - return ERROR_INVALID_PARAMETER; - } - - base::win::PEImage target_image(module_handle); - if (!target_image.VerifyMagic()) { - NOTREACHED(); - return ERROR_INVALID_PARAMETER; - } - - InterceptFunctionInformation intercept_information = { - false, - imported_from_module, - function_name, - new_function, - old_function, - iat_thunk, - ERROR_GEN_FAILURE}; - - // First go through the IAT. If we don't find the import we are looking - // for in IAT, search delay import table. - target_image.EnumAllImports(InterceptEnumCallback, &intercept_information); - if (!intercept_information.finished_operation) { - target_image.EnumAllDelayImports(InterceptEnumCallback, - &intercept_information); - } - - return intercept_information.return_code; -} - -// Restore intercepted IAT entry with the original function. -// -// Arguments: -// intercept_function Interceptor function -// original_function Receives the original function pointer -// -// Returns: Returns NO_ERROR on success or Windows error code -// as defined in winerror.h -DWORD RestoreImportedFunction(void* intercept_function, - void* original_function, - IMAGE_THUNK_DATA* iat_thunk) { - if ((NULL == intercept_function) || (NULL == original_function) || - (NULL == iat_thunk)) { - NOTREACHED(); - return ERROR_INVALID_PARAMETER; - } - - if (GetIATFunction(iat_thunk) != intercept_function) { - // Check if someone else has intercepted on top of us. - // We cannot unpatch in this case, just raise a red flag. - NOTREACHED(); - return ERROR_INVALID_FUNCTION; - } - - return ModifyCode(&(iat_thunk->u1.Function), - &original_function, - sizeof(original_function)); -} - -} // namespace - -IATPatchFunction::IATPatchFunction() - : module_handle_(NULL), - original_function_(NULL), - iat_thunk_(NULL), - intercept_function_(NULL) { -} - -IATPatchFunction::~IATPatchFunction() { - if (NULL != intercept_function_) { - DWORD error = Unpatch(); - DCHECK_EQ(static_cast(NO_ERROR), error); - } -} - -DWORD IATPatchFunction::Patch(const wchar_t* module, - const char* imported_from_module, - const char* function_name, - void* new_function) { - DCHECK_EQ(static_cast(NULL), original_function_); - DCHECK_EQ(static_cast(NULL), iat_thunk_); - DCHECK_EQ(static_cast(NULL), intercept_function_); - - HMODULE module_handle = LoadLibraryW(module); - - if (module_handle == NULL) { - NOTREACHED(); - return GetLastError(); - } - - DWORD error = InterceptImportedFunction(module_handle, - imported_from_module, - function_name, - new_function, - &original_function_, - &iat_thunk_); - - if (NO_ERROR == error) { - DCHECK_NE(original_function_, intercept_function_); - module_handle_ = module_handle; - intercept_function_ = new_function; - } else { - FreeLibrary(module_handle); - } - - return error; -} - -DWORD IATPatchFunction::Unpatch() { - DWORD error = RestoreImportedFunction(intercept_function_, - original_function_, - iat_thunk_); - DCHECK_EQ(static_cast(NO_ERROR), error); - - // Hands off the intercept if we fail to unpatch. - // If IATPatchFunction::Unpatch fails during RestoreImportedFunction - // it means that we cannot safely unpatch the import address table - // patch. In this case its better to be hands off the intercept as - // trying to unpatch again in the destructor of IATPatchFunction is - // not going to be any safer - if (module_handle_) - FreeLibrary(module_handle_); - module_handle_ = NULL; - intercept_function_ = NULL; - original_function_ = NULL; - iat_thunk_ = NULL; - - return error; -} - -} // namespace win -} // namespace base diff --git a/base/win/iat_patch_function.h b/base/win/iat_patch_function.h deleted file mode 100644 index 3ae1f3c460..0000000000 --- a/base/win/iat_patch_function.h +++ /dev/null @@ -1,72 +0,0 @@ -// Copyright (c) 2011 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef BASE_WIN_IAT_PATCH_FUNCTION_H_ -#define BASE_WIN_IAT_PATCH_FUNCTION_H_ - -#include - -#include "base/base_export.h" -#include "base/basictypes.h" - -namespace base { -namespace win { - -// A class that encapsulates Import Address Table patching helpers and restores -// the original function in the destructor. -// -// It will intercept functions for a specific DLL imported from another DLL. -// This is the case when, for example, we want to intercept -// CertDuplicateCertificateContext function (exported from crypt32.dll) called -// by wininet.dll. -class BASE_EXPORT IATPatchFunction { - public: - IATPatchFunction(); - ~IATPatchFunction(); - - // Intercept a function in an import table of a specific - // module. Save the original function and the import - // table address. These values will be used later - // during Unpatch - // - // Arguments: - // module Module to be intercepted - // imported_from_module Module that exports the 'function_name' - // function_name Name of the API to be intercepted - // - // Returns: Windows error code (winerror.h). NO_ERROR if successful - // - // Note: Patching a function will make the IAT patch take some "ownership" on - // |module|. It will LoadLibrary(module) to keep the DLL alive until a call - // to Unpatch(), which will call FreeLibrary() and allow the module to be - // unloaded. The idea is to help prevent the DLL from going away while a - // patch is still active. - DWORD Patch(const wchar_t* module, - const char* imported_from_module, - const char* function_name, - void* new_function); - - // Unpatch the IAT entry using internally saved original - // function. - // - // Returns: Windows error code (winerror.h). NO_ERROR if successful - DWORD Unpatch(); - - bool is_patched() const { - return (NULL != intercept_function_); - } - - private: - HMODULE module_handle_; - void* intercept_function_; - void* original_function_; - IMAGE_THUNK_DATA* iat_thunk_; - - DISALLOW_COPY_AND_ASSIGN(IATPatchFunction); -}; - -} // namespace win -} // namespace base - -#endif // BASE_WIN_IAT_PATCH_FUNCTION_H_ diff --git a/base/win/iunknown_impl.cc b/base/win/iunknown_impl.cc deleted file mode 100644 index 9baa0f3d67..0000000000 --- a/base/win/iunknown_impl.cc +++ /dev/null @@ -1,42 +0,0 @@ -// Copyright (c) 2011 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "base/win/iunknown_impl.h" - -namespace base { -namespace win { - -IUnknownImpl::IUnknownImpl() - : ref_count_(0) { -} - -IUnknownImpl::~IUnknownImpl() { -} - -ULONG STDMETHODCALLTYPE IUnknownImpl::AddRef() { - base::AtomicRefCountInc(&ref_count_); - return 1; -} - -ULONG STDMETHODCALLTYPE IUnknownImpl::Release() { - if (!base::AtomicRefCountDec(&ref_count_)) { - delete this; - return 0; - } - return 1; -} - -STDMETHODIMP IUnknownImpl::QueryInterface(REFIID riid, void** ppv) { - if (riid == IID_IUnknown) { - *ppv = static_cast(this); - AddRef(); - return S_OK; - } - - *ppv = NULL; - return E_NOINTERFACE; -} - -} // namespace win -} // namespace base diff --git a/base/win/iunknown_impl.h b/base/win/iunknown_impl.h deleted file mode 100644 index ff7e87039b..0000000000 --- a/base/win/iunknown_impl.h +++ /dev/null @@ -1,38 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef BASE_WIN_IUNKNOWN_IMPL_H_ -#define BASE_WIN_IUNKNOWN_IMPL_H_ - -#include - -#include "base/atomic_ref_count.h" -#include "base/base_export.h" -#include "base/compiler_specific.h" - -namespace base { -namespace win { - -// IUnknown implementation for other classes to derive from. -class BASE_EXPORT IUnknownImpl : public IUnknown { - public: - IUnknownImpl(); - - virtual ULONG STDMETHODCALLTYPE AddRef() OVERRIDE; - virtual ULONG STDMETHODCALLTYPE Release() OVERRIDE; - - // Subclasses should extend this to return any interfaces they provide. - virtual STDMETHODIMP QueryInterface(REFIID riid, void** ppv) OVERRIDE; - - protected: - virtual ~IUnknownImpl(); - - private: - AtomicRefCount ref_count_; -}; - -} // namespace win -} // namespace base - -#endif // BASE_WIN_IUNKNOWN_IMPL_H_ diff --git a/base/win/iunknown_impl_unittest.cc b/base/win/iunknown_impl_unittest.cc deleted file mode 100644 index db86214daf..0000000000 --- a/base/win/iunknown_impl_unittest.cc +++ /dev/null @@ -1,51 +0,0 @@ -// Copyright (c) 2011 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "base/win/iunknown_impl.h" - -#include "base/win/scoped_com_initializer.h" -#include "testing/gtest/include/gtest/gtest.h" - -namespace base { -namespace win { - -class TestIUnknownImplSubclass : public IUnknownImpl { - public: - TestIUnknownImplSubclass() { - ++instance_count; - } - virtual ~TestIUnknownImplSubclass() { - --instance_count; - } - static int instance_count; -}; - -// static -int TestIUnknownImplSubclass::instance_count = 0; - -TEST(IUnknownImplTest, IUnknownImpl) { - ScopedCOMInitializer com_initializer; - - EXPECT_EQ(0, TestIUnknownImplSubclass::instance_count); - IUnknown* u = new TestIUnknownImplSubclass(); - - EXPECT_EQ(1, TestIUnknownImplSubclass::instance_count); - - EXPECT_EQ(1, u->AddRef()); - EXPECT_EQ(1, u->AddRef()); - - IUnknown* other = NULL; - EXPECT_EQ(E_NOINTERFACE, u->QueryInterface( - IID_IDispatch, reinterpret_cast(&other))); - EXPECT_EQ(S_OK, u->QueryInterface( - IID_IUnknown, reinterpret_cast(&other))); - other->Release(); - - EXPECT_EQ(1, u->Release()); - EXPECT_EQ(0, u->Release()); - EXPECT_EQ(0, TestIUnknownImplSubclass::instance_count); -} - -} // namespace win -} // namespace base diff --git a/base/win/message_window.cc b/base/win/message_window.cc deleted file mode 100644 index 56660740fc..0000000000 --- a/base/win/message_window.cc +++ /dev/null @@ -1,165 +0,0 @@ -// Copyright 2013 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "base/win/message_window.h" - -#include "base/lazy_instance.h" -#include "base/logging.h" -#include "base/process/memory.h" -#include "base/win/wrapped_window_proc.h" - -const wchar_t kMessageWindowClassName[] = L"Chrome_MessageWindow"; - -namespace base { -namespace win { - -// Used along with LazyInstance to register a window class for message-only -// windows created by MessageWindow. -class MessageWindow::WindowClass { - public: - WindowClass(); - ~WindowClass(); - - ATOM atom() { return atom_; } - HINSTANCE instance() { return instance_; } - - private: - ATOM atom_; - HINSTANCE instance_; - - DISALLOW_COPY_AND_ASSIGN(WindowClass); -}; - -static LazyInstance g_window_class = - LAZY_INSTANCE_INITIALIZER; - -MessageWindow::WindowClass::WindowClass() - : atom_(0), - instance_(base::GetModuleFromAddress(&MessageWindow::WindowProc)) { - WNDCLASSEX window_class; - window_class.cbSize = sizeof(window_class); - window_class.style = 0; - window_class.lpfnWndProc = &base::win::WrappedWindowProc; - window_class.cbClsExtra = 0; - window_class.cbWndExtra = 0; - window_class.hInstance = instance_; - window_class.hIcon = NULL; - window_class.hCursor = NULL; - window_class.hbrBackground = NULL; - window_class.lpszMenuName = NULL; - window_class.lpszClassName = kMessageWindowClassName; - window_class.hIconSm = NULL; - atom_ = RegisterClassEx(&window_class); - if (atom_ == 0) { - LOG_GETLASTERROR(ERROR) - << "Failed to register the window class for a message-only window"; - } -} - -MessageWindow::WindowClass::~WindowClass() { - if (atom_ != 0) { - BOOL result = UnregisterClass(MAKEINTATOM(atom_), instance_); - // Hitting this DCHECK usually means that some MessageWindow objects were - // leaked. For example not calling - // ui::Clipboard::DestroyClipboardForCurrentThread() results in a leaked - // MessageWindow. - DCHECK(result); - } -} - -MessageWindow::MessageWindow() - : window_(NULL) { -} - -MessageWindow::~MessageWindow() { - DCHECK(CalledOnValidThread()); - - if (window_ != NULL) { - BOOL result = DestroyWindow(window_); - DCHECK(result); - } -} - -bool MessageWindow::Create(const MessageCallback& message_callback) { - return DoCreate(message_callback, NULL); -} - -bool MessageWindow::CreateNamed(const MessageCallback& message_callback, - const string16& window_name) { - return DoCreate(message_callback, window_name.c_str()); -} - -// static -HWND MessageWindow::FindWindow(const string16& window_name) { - return FindWindowEx(HWND_MESSAGE, NULL, kMessageWindowClassName, - window_name.c_str()); -} - -bool MessageWindow::DoCreate(const MessageCallback& message_callback, - const wchar_t* window_name) { - DCHECK(CalledOnValidThread()); - DCHECK(message_callback_.is_null()); - DCHECK(!window_); - - message_callback_ = message_callback; - - WindowClass& window_class = g_window_class.Get(); - window_ = CreateWindow(MAKEINTATOM(window_class.atom()), window_name, 0, 0, 0, - 0, 0, HWND_MESSAGE, 0, window_class.instance(), this); - if (!window_) { - LOG_GETLASTERROR(ERROR) << "Failed to create a message-only window"; - return false; - } - - return true; -} - -// static -LRESULT CALLBACK MessageWindow::WindowProc(HWND hwnd, - UINT message, - WPARAM wparam, - LPARAM lparam) { - MessageWindow* self = reinterpret_cast( - GetWindowLongPtr(hwnd, GWLP_USERDATA)); - - switch (message) { - // Set up the self before handling WM_CREATE. - case WM_CREATE: { - CREATESTRUCT* cs = reinterpret_cast(lparam); - self = reinterpret_cast(cs->lpCreateParams); - - // Make |hwnd| available to the message handler. At this point the control - // hasn't returned from CreateWindow() yet. - self->window_ = hwnd; - - // Store pointer to the self to the window's user data. - SetLastError(ERROR_SUCCESS); - LONG_PTR result = SetWindowLongPtr( - hwnd, GWLP_USERDATA, reinterpret_cast(self)); - CHECK(result != 0 || GetLastError() == ERROR_SUCCESS); - break; - } - - // Clear the pointer to stop calling the self once WM_DESTROY is - // received. - case WM_DESTROY: { - SetLastError(ERROR_SUCCESS); - LONG_PTR result = SetWindowLongPtr(hwnd, GWLP_USERDATA, NULL); - CHECK(result != 0 || GetLastError() == ERROR_SUCCESS); - break; - } - } - - // Handle the message. - if (self) { - LRESULT message_result; - if (self->message_callback_.Run(message, wparam, lparam, &message_result)) - return message_result; - } - - return DefWindowProc(hwnd, message, wparam, lparam); -} - -} // namespace win -} // namespace base diff --git a/base/win/message_window.h b/base/win/message_window.h deleted file mode 100644 index ae0c6f0bc7..0000000000 --- a/base/win/message_window.h +++ /dev/null @@ -1,75 +0,0 @@ -// Copyright 2013 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef BASE_WIN_MESSAGE_WINDOW_H_ -#define BASE_WIN_MESSAGE_WINDOW_H_ - -#include - -#include "base/base_export.h" -#include "base/basictypes.h" -#include "base/callback.h" -#include "base/compiler_specific.h" -#include "base/strings/string16.h" -#include "base/threading/non_thread_safe.h" - -namespace base { -namespace win { - -// Implements a message-only window. -class BASE_EXPORT MessageWindow : public base::NonThreadSafe { - public: - // Used to register a process-wide message window class. - class WindowClass; - - // Implement this callback to handle messages received by the message window. - // If the callback returns |false|, the first four parameters are passed to - // DefWindowProc(). Otherwise, |*result| is returned by the window procedure. - typedef base::Callback MessageCallback; - - MessageWindow(); - ~MessageWindow(); - - // Creates a message-only window. The incoming messages will be passed by - // |message_callback|. |message_callback| must outlive |this|. - bool Create(const MessageCallback& message_callback); - - // Same as Create() but assigns the name to the created window. - bool CreateNamed(const MessageCallback& message_callback, - const string16& window_name); - - HWND hwnd() const { return window_; } - - // Retrieves a handle of the first message-only window with matching - // |window_name|. - static HWND FindWindow(const string16& window_name); - - private: - // Give |WindowClass| access to WindowProc(). - friend class WindowClass; - - // Contains the actual window creation code. - bool DoCreate(const MessageCallback& message_callback, - const wchar_t* window_name); - - // Invoked by the OS to process incoming window messages. - static LRESULT CALLBACK WindowProc(HWND hwnd, UINT message, WPARAM wparam, - LPARAM lparam); - - // Invoked to handle messages received by the window. - MessageCallback message_callback_; - - // Handle of the input window. - HWND window_; - - DISALLOW_COPY_AND_ASSIGN(MessageWindow); -}; - -} // namespace win -} // namespace base - -#endif // BASE_WIN_MESSAGE_WINDOW_H_ diff --git a/base/win/message_window_unittest.cc b/base/win/message_window_unittest.cc deleted file mode 100644 index 00248bfd36..0000000000 --- a/base/win/message_window_unittest.cc +++ /dev/null @@ -1,61 +0,0 @@ -// Copyright 2013 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "base/bind.h" -#include "base/guid.h" -#include "base/strings/utf_string_conversions.h" -#include "base/win/message_window.h" -#include "testing/gmock/include/gmock/gmock.h" -#include "testing/gtest/include/gtest/gtest.h" - -namespace base { - -namespace { - -bool HandleMessage( - UINT message, WPARAM wparam, LPARAM lparam, LRESULT* result) { - // Return |wparam| as the result of WM_USER message. - if (message == WM_USER) { - *result = wparam; - return true; - } - - return false; -} - -} // namespace - -// Checks that a window can be created. -TEST(MessageWindowTest, Create) { - win::MessageWindow window; - EXPECT_TRUE(window.Create(base::Bind(&HandleMessage))); -} - -// Checks that a named window can be created. -TEST(MessageWindowTest, CreateNamed) { - win::MessageWindow window; - EXPECT_TRUE(window.CreateNamed(base::Bind(&HandleMessage), - UTF8ToUTF16("test_message_window"))); -} - -// Verifies that the created window can receive messages. -TEST(MessageWindowTest, SendMessage) { - win::MessageWindow window; - EXPECT_TRUE(window.Create(base::Bind(&HandleMessage))); - - EXPECT_EQ(SendMessage(window.hwnd(), WM_USER, 100, 0), 100); -} - -// Verifies that a named window can be found by name. -TEST(MessageWindowTest, FindWindow) { - string16 name = UTF8ToUTF16(base::GenerateGUID()); - win::MessageWindow window; - EXPECT_TRUE(window.CreateNamed(base::Bind(&HandleMessage), name)); - - HWND hwnd = win::MessageWindow::FindWindow(name); - EXPECT_TRUE(hwnd != NULL); - EXPECT_EQ(SendMessage(hwnd, WM_USER, 200, 0), 200); -} - -} // namespace base diff --git a/base/win/metro.cc b/base/win/metro.cc deleted file mode 100644 index afe4fcecb8..0000000000 --- a/base/win/metro.cc +++ /dev/null @@ -1,187 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "base/win/metro.h" - -#include "base/message_loop/message_loop.h" -#include "base/strings/string_util.h" -#include "base/win/scoped_comptr.h" -#include "base/win/windows_version.h" - -namespace base { -namespace win { - -namespace { -bool g_should_tsf_aware_required = false; -} - -HMODULE GetMetroModule() { - const HMODULE kUninitialized = reinterpret_cast(1); - static HMODULE metro_module = kUninitialized; - - if (metro_module == kUninitialized) { - // Initialize the cache, note that the initialization is idempotent - // under the assumption that metro_driver is never unloaded, so the - // race to this assignment is safe. - metro_module = GetModuleHandleA("metro_driver.dll"); - if (metro_module != NULL) { - // This must be a metro process if the metro_driver is loaded. - DCHECK(IsMetroProcess()); - } - } - - DCHECK(metro_module != kUninitialized); - return metro_module; -} - -bool IsMetroProcess() { - enum ImmersiveState { - kImmersiveUnknown, - kImmersiveTrue, - kImmersiveFalse - }; - // The immersive state of a process can never change. - // Look it up once and cache it here. - static ImmersiveState state = kImmersiveUnknown; - - if (state == kImmersiveUnknown) { - if (IsProcessImmersive(::GetCurrentProcess())) { - state = kImmersiveTrue; - } else { - state = kImmersiveFalse; - } - } - DCHECK_NE(kImmersiveUnknown, state); - return state == kImmersiveTrue; -} - -bool IsProcessImmersive(HANDLE process) { - typedef BOOL (WINAPI* IsImmersiveProcessFunc)(HANDLE process); - HMODULE user32 = ::GetModuleHandleA("user32.dll"); - DCHECK(user32 != NULL); - - IsImmersiveProcessFunc is_immersive_process = - reinterpret_cast( - ::GetProcAddress(user32, "IsImmersiveProcess")); - - if (is_immersive_process) - return is_immersive_process(process) ? true: false; - return false; -} - -bool IsTSFAwareRequired() { -#if defined(USE_AURA) - if (base::win::GetVersion() >= base::win::VERSION_WIN8) - return true; -#endif - // Although this function is equal to IsMetroProcess at this moment, - // Chrome for Win7 and Vista may support TSF in the future. - return g_should_tsf_aware_required || IsMetroProcess(); -} - -void SetForceToUseTSF() { - g_should_tsf_aware_required = true; - - // Since Windows 8 Metro mode disables CUAS (Cicero Unaware Application - // Support) via ImmDisableLegacyIME API, Chrome must be fully TSF-aware on - // Metro mode. For debugging purposes, explicitly call ImmDisableLegacyIME so - // that one can test TSF functionality even on Windows 8 desktop mode. Note - // that CUAS cannot be disabled on Windows Vista/7 where ImmDisableLegacyIME - // is not available. - typedef BOOL (* ImmDisableLegacyIMEFunc)(); - HMODULE imm32 = ::GetModuleHandleA("imm32.dll"); - if (imm32 == NULL) - return; - - ImmDisableLegacyIMEFunc imm_disable_legacy_ime = - reinterpret_cast( - ::GetProcAddress(imm32, "ImmDisableLegacyIME")); - - if (imm_disable_legacy_ime == NULL) { - // Unsupported API, just do nothing. - return; - } - - if (!imm_disable_legacy_ime()) { - DVLOG(1) << "Failed to disable legacy IME."; - } -} - -wchar_t* LocalAllocAndCopyString(const string16& src) { - size_t dest_size = (src.length() + 1) * sizeof(wchar_t); - wchar_t* dest = reinterpret_cast(LocalAlloc(LPTR, dest_size)); - base::wcslcpy(dest, src.c_str(), dest_size); - return dest; -} - -bool IsParentalControlActivityLoggingOn() { - // Query this info on Windows Vista and above. - if (base::win::GetVersion() < base::win::VERSION_VISTA) - return false; - - static bool parental_control_logging_required = false; - static bool parental_control_status_determined = false; - - if (parental_control_status_determined) - return parental_control_logging_required; - - parental_control_status_determined = true; - - ScopedComPtr parent_controls; - HRESULT hr = parent_controls.CreateInstance( - __uuidof(WindowsParentalControls)); - if (FAILED(hr)) - return false; - - ScopedComPtr settings; - hr = parent_controls->GetUserSettings(NULL, settings.Receive()); - if (FAILED(hr)) - return false; - - unsigned long restrictions = 0; - settings->GetRestrictions(&restrictions); - - parental_control_logging_required = - (restrictions & WPCFLAG_LOGGING_REQUIRED) == WPCFLAG_LOGGING_REQUIRED; - return parental_control_logging_required; -} - -// Metro driver exports for getting the launch type, initial url, initial -// search term, etc. -extern "C" { -typedef const wchar_t* (*GetInitialUrl)(); -typedef const wchar_t* (*GetInitialSearchString)(); -typedef base::win::MetroLaunchType (*GetLaunchType)( - base::win::MetroPreviousExecutionState* previous_state); -} - -MetroLaunchType GetMetroLaunchParams(string16* params) { - HMODULE metro = base::win::GetMetroModule(); - if (!metro) - return base::win::METRO_LAUNCH_ERROR; - - GetLaunchType get_launch_type = reinterpret_cast( - ::GetProcAddress(metro, "GetLaunchType")); - DCHECK(get_launch_type); - - base::win::MetroLaunchType launch_type = get_launch_type(NULL); - - if ((launch_type == base::win::METRO_PROTOCOL) || - (launch_type == base::win::METRO_LAUNCH)) { - GetInitialUrl initial_metro_url = reinterpret_cast( - ::GetProcAddress(metro, "GetInitialUrl")); - DCHECK(initial_metro_url); - *params = initial_metro_url(); - } else if (launch_type == base::win::METRO_SEARCH) { - GetInitialSearchString initial_search_string = - reinterpret_cast( - ::GetProcAddress(metro, "GetInitialSearchString")); - DCHECK(initial_search_string); - *params = initial_search_string(); - } - return launch_type; -} - -} // namespace win -} // namespace base diff --git a/base/win/metro.h b/base/win/metro.h deleted file mode 100644 index b2208fcb49..0000000000 --- a/base/win/metro.h +++ /dev/null @@ -1,142 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef BASE_WIN_METRO_H_ -#define BASE_WIN_METRO_H_ - -#include -#include - -#include "base/base_export.h" -#include "base/callback.h" -#include "base/files/file_path.h" -#include "base/strings/string16.h" - -namespace base { -namespace win { - -// Identifies the type of the metro launch. -enum MetroLaunchType { - METRO_LAUNCH, - METRO_SEARCH, - METRO_SHARE, - METRO_FILE, - METRO_PROTOCOL, - METRO_LAUNCH_ERROR, - METRO_LASTLAUNCHTYPE, -}; - -// In metro mode, this enum identifies the last execution state, i.e. whether -// we crashed, terminated, etc. -enum MetroPreviousExecutionState { - NOTRUNNING, - RUNNING, - SUSPENDED, - TERMINATED, - CLOSEDBYUSER, - LASTEXECUTIONSTATE, -}; - -// Enum values for UMA histogram reporting of site-specific tile pinning. -// TODO(tapted): Move this to win8/util when ready (http://crbug.com/160288). -enum MetroSecondaryTilePinUmaResult { - METRO_PIN_STATE_NONE, - METRO_PIN_INITIATED, - METRO_PIN_LOGO_READY, - METRO_PIN_REQUEST_SHOW_ERROR, - METRO_PIN_RESULT_CANCEL, - METRO_PIN_RESULT_OK, - METRO_PIN_RESULT_OTHER, - METRO_PIN_RESULT_ERROR, - METRO_UNPIN_INITIATED, - METRO_UNPIN_REQUEST_SHOW_ERROR, - METRO_UNPIN_RESULT_CANCEL, - METRO_UNPIN_RESULT_OK, - METRO_UNPIN_RESULT_OTHER, - METRO_UNPIN_RESULT_ERROR, - METRO_PIN_STATE_LIMIT -}; - -// Contains information about the currently displayed tab in metro mode. -struct CurrentTabInfo { - wchar_t* title; - wchar_t* url; -}; - -// Returns the handle to the metro dll loaded in the process. A NULL return -// indicates that the metro dll was not loaded in the process. -BASE_EXPORT HMODULE GetMetroModule(); - -// Returns true if this process is running as an immersive program -// in Windows Metro mode. -BASE_EXPORT bool IsMetroProcess(); - -// Returns true if the process identified by the handle passed in is an -// immersive (Metro) process. -BASE_EXPORT bool IsProcessImmersive(HANDLE process); - -// Returns true if this process is running under Text Services Framework (TSF) -// and browser must be TSF-aware. -BASE_EXPORT bool IsTSFAwareRequired(); - -// Sets browser to use Text Services Framework (TSF) regardless of process -// status. On Windows 8, this function also disables CUAS (Cicero Unaware -// Application Support) to emulate Windows Metro mode in terms of IME -// functionality. This should be beneficial in QA process because on can test -// IME functionality in Windows 8 desktop mode. -BASE_EXPORT void SetForceToUseTSF(); - -// Allocates and returns the destination string via the LocalAlloc API after -// copying the src to it. -BASE_EXPORT wchar_t* LocalAllocAndCopyString(const string16& src); - -// Returns true if Windows Parental control activity logging is enabled. This -// feature is available on Windows Vista and beyond. -// This function should ideally be called on the UI thread. -BASE_EXPORT bool IsParentalControlActivityLoggingOn(); - -// Returns the type of launch and the activation params. For example if the -// the launch is for METRO_PROTOCOL then the params is a url. -BASE_EXPORT MetroLaunchType GetMetroLaunchParams(string16* params); - -// Handler function for the buttons on a metro dialog box -typedef void (*MetroDialogButtonPressedHandler)(); - -// Handler function invoked when a metro style notification is clicked. -typedef void (*MetroNotificationClickedHandler)(const wchar_t* context); - -// Function to display metro style notifications. -typedef void (*MetroNotification)(const char* origin_url, - const char* icon_url, - const wchar_t* title, - const wchar_t* body, - const wchar_t* display_source, - const char* notification_id, - MetroNotificationClickedHandler handler, - const wchar_t* handler_context); - -// Function to cancel displayed notification. -typedef bool (*MetroCancelNotification)(const char* notification_id); - -// Callback for UMA invoked by Metro Pin and UnPin functions after user gesture. -typedef base::Callback - MetroPinUmaResultCallback; - -// Function to pin a site-specific tile (bookmark) to the start screen. -typedef void (*MetroPinToStartScreen)( - const string16& tile_id, - const string16& title, - const string16& url, - const FilePath& logo_path, - const MetroPinUmaResultCallback& callback); - -// Function to un-pin a site-specific tile (bookmark) from the start screen. -typedef void (*MetroUnPinFromStartScreen)( - const string16& title_id, - const MetroPinUmaResultCallback& callback); - -} // namespace win -} // namespace base - -#endif // BASE_WIN_METRO_H_ diff --git a/base/win/object_watcher.cc b/base/win/object_watcher.cc deleted file mode 100644 index 078f5b9fa1..0000000000 --- a/base/win/object_watcher.cc +++ /dev/null @@ -1,111 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "base/win/object_watcher.h" - -#include "base/bind.h" -#include "base/logging.h" - -namespace base { -namespace win { - -//----------------------------------------------------------------------------- - -ObjectWatcher::ObjectWatcher() - : weak_factory_(this), - object_(NULL), - wait_object_(NULL), - origin_loop_(NULL) { -} - -ObjectWatcher::~ObjectWatcher() { - StopWatching(); -} - -bool ObjectWatcher::StartWatching(HANDLE object, Delegate* delegate) { - CHECK(delegate); - if (wait_object_) { - NOTREACHED() << "Already watching an object"; - return false; - } - - // Since our job is to just notice when an object is signaled and report the - // result back to this thread, we can just run on a Windows wait thread. - DWORD wait_flags = WT_EXECUTEINWAITTHREAD | WT_EXECUTEONLYONCE; - - // DoneWaiting can be synchronously called from RegisterWaitForSingleObject, - // so set up all state now. - callback_ = base::Bind(&ObjectWatcher::Signal, weak_factory_.GetWeakPtr(), - delegate); - object_ = object; - origin_loop_ = MessageLoop::current(); - - if (!RegisterWaitForSingleObject(&wait_object_, object, DoneWaiting, - this, INFINITE, wait_flags)) { - DLOG_GETLASTERROR(FATAL) << "RegisterWaitForSingleObject failed"; - object_ = NULL; - wait_object_ = NULL; - return false; - } - - // We need to know if the current message loop is going away so we can - // prevent the wait thread from trying to access a dead message loop. - MessageLoop::current()->AddDestructionObserver(this); - return true; -} - -bool ObjectWatcher::StopWatching() { - if (!wait_object_) - return false; - - // Make sure ObjectWatcher is used in a single-threaded fashion. - DCHECK_EQ(origin_loop_, MessageLoop::current()); - - // Blocking call to cancel the wait. Any callbacks already in progress will - // finish before we return from this call. - if (!UnregisterWaitEx(wait_object_, INVALID_HANDLE_VALUE)) { - DLOG_GETLASTERROR(FATAL) << "UnregisterWaitEx failed"; - return false; - } - - weak_factory_.InvalidateWeakPtrs(); - object_ = NULL; - wait_object_ = NULL; - - MessageLoop::current()->RemoveDestructionObserver(this); - return true; -} - -HANDLE ObjectWatcher::GetWatchedObject() { - return object_; -} - -// static -void CALLBACK ObjectWatcher::DoneWaiting(void* param, BOOLEAN timed_out) { - DCHECK(!timed_out); - - // The destructor blocks on any callbacks that are in flight, so we know that - // that is always a pointer to a valid ObjectWater. - ObjectWatcher* that = static_cast(param); - that->origin_loop_->PostTask(FROM_HERE, that->callback_); - that->callback_.Reset(); -} - -void ObjectWatcher::Signal(Delegate* delegate) { - // Signaling the delegate may result in our destruction or a nested call to - // StartWatching(). As a result, we save any state we need and clear previous - // watcher state before signaling the delegate. - HANDLE object = object_; - StopWatching(); - delegate->OnObjectSignaled(object); -} - -void ObjectWatcher::WillDestroyCurrentMessageLoop() { - // Need to shutdown the watch so that we don't try to access the MessageLoop - // after this point. - StopWatching(); -} - -} // namespace win -} // namespace base diff --git a/base/win/object_watcher.h b/base/win/object_watcher.h deleted file mode 100644 index 4222c20069..0000000000 --- a/base/win/object_watcher.h +++ /dev/null @@ -1,103 +0,0 @@ -// Copyright (c) 2011 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef BASE_WIN_OBJECT_WATCHER_H_ -#define BASE_WIN_OBJECT_WATCHER_H_ - -#include - -#include "base/base_export.h" -#include "base/callback.h" -#include "base/memory/weak_ptr.h" -#include "base/message_loop/message_loop.h" - -namespace base { -namespace win { - -// A class that provides a means to asynchronously wait for a Windows object to -// become signaled. It is an abstraction around RegisterWaitForSingleObject -// that provides a notification callback, OnObjectSignaled, that runs back on -// the origin thread (i.e., the thread that called StartWatching). -// -// This class acts like a smart pointer such that when it goes out-of-scope, -// UnregisterWaitEx is automatically called, and any in-flight notification is -// suppressed. -// -// Typical usage: -// -// class MyClass : public base::ObjectWatcher::Delegate { -// public: -// void DoStuffWhenSignaled(HANDLE object) { -// watcher_.StartWatching(object, this); -// } -// virtual void OnObjectSignaled(HANDLE object) { -// // OK, time to do stuff! -// } -// private: -// base::ObjectWatcher watcher_; -// }; -// -// In the above example, MyClass wants to "do stuff" when object becomes -// signaled. ObjectWatcher makes this task easy. When MyClass goes out of -// scope, the watcher_ will be destroyed, and there is no need to worry about -// OnObjectSignaled being called on a deleted MyClass pointer. Easy! -// If the object is already signaled before being watched, OnObjectSignaled is -// still called after (but not necessarily immediately after) watch is started. -// -class BASE_EXPORT ObjectWatcher : public MessageLoop::DestructionObserver { - public: - class BASE_EXPORT Delegate { - public: - virtual ~Delegate() {} - // Called from the MessageLoop when a signaled object is detected. To - // continue watching the object, StartWatching must be called again. - virtual void OnObjectSignaled(HANDLE object) = 0; - }; - - ObjectWatcher(); - ~ObjectWatcher(); - - // When the object is signaled, the given delegate is notified on the thread - // where StartWatching is called. The ObjectWatcher is not responsible for - // deleting the delegate. - // - // Returns true if the watch was started. Otherwise, false is returned. - // - bool StartWatching(HANDLE object, Delegate* delegate); - - // Stops watching. Does nothing if the watch has already completed. If the - // watch is still active, then it is canceled, and the associated delegate is - // not notified. - // - // Returns true if the watch was canceled. Otherwise, false is returned. - // - bool StopWatching(); - - // Returns the handle of the object being watched, or NULL if the object - // watcher is stopped. - HANDLE GetWatchedObject(); - - private: - // Called on a background thread when done waiting. - static void CALLBACK DoneWaiting(void* param, BOOLEAN timed_out); - - void Signal(Delegate* delegate); - - // MessageLoop::DestructionObserver implementation: - virtual void WillDestroyCurrentMessageLoop(); - - // Internal state. - WeakPtrFactory weak_factory_; - Closure callback_; - HANDLE object_; // The object being watched - HANDLE wait_object_; // Returned by RegisterWaitForSingleObject - MessageLoop* origin_loop_; // Used to get back to the origin thread - - DISALLOW_COPY_AND_ASSIGN(ObjectWatcher); -}; - -} // namespace win -} // namespace base - -#endif // BASE_OBJECT_WATCHER_H_ diff --git a/base/win/object_watcher_unittest.cc b/base/win/object_watcher_unittest.cc deleted file mode 100644 index 46b98de524..0000000000 --- a/base/win/object_watcher_unittest.cc +++ /dev/null @@ -1,174 +0,0 @@ -// Copyright (c) 2011 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "base/win/object_watcher.h" - -#include - -#include "base/message_loop/message_loop.h" -#include "base/run_loop.h" -#include "testing/gtest/include/gtest/gtest.h" - -namespace base { -namespace win { - -namespace { - -class QuitDelegate : public ObjectWatcher::Delegate { - public: - virtual void OnObjectSignaled(HANDLE object) { - MessageLoop::current()->QuitWhenIdle(); - } -}; - -class DecrementCountDelegate : public ObjectWatcher::Delegate { - public: - explicit DecrementCountDelegate(int* counter) : counter_(counter) { - } - virtual void OnObjectSignaled(HANDLE object) { - --(*counter_); - } - private: - int* counter_; -}; - -void RunTest_BasicSignal(MessageLoop::Type message_loop_type) { - MessageLoop message_loop(message_loop_type); - - ObjectWatcher watcher; - EXPECT_EQ(NULL, watcher.GetWatchedObject()); - - // A manual-reset event that is not yet signaled. - HANDLE event = CreateEvent(NULL, TRUE, FALSE, NULL); - - QuitDelegate delegate; - bool ok = watcher.StartWatching(event, &delegate); - EXPECT_TRUE(ok); - EXPECT_EQ(event, watcher.GetWatchedObject()); - - SetEvent(event); - - MessageLoop::current()->Run(); - - EXPECT_EQ(NULL, watcher.GetWatchedObject()); - CloseHandle(event); -} - -void RunTest_BasicCancel(MessageLoop::Type message_loop_type) { - MessageLoop message_loop(message_loop_type); - - ObjectWatcher watcher; - - // A manual-reset event that is not yet signaled. - HANDLE event = CreateEvent(NULL, TRUE, FALSE, NULL); - - QuitDelegate delegate; - bool ok = watcher.StartWatching(event, &delegate); - EXPECT_TRUE(ok); - - watcher.StopWatching(); - - CloseHandle(event); -} - -void RunTest_CancelAfterSet(MessageLoop::Type message_loop_type) { - MessageLoop message_loop(message_loop_type); - - ObjectWatcher watcher; - - int counter = 1; - DecrementCountDelegate delegate(&counter); - - // A manual-reset event that is not yet signaled. - HANDLE event = CreateEvent(NULL, TRUE, FALSE, NULL); - - bool ok = watcher.StartWatching(event, &delegate); - EXPECT_TRUE(ok); - - SetEvent(event); - - // Let the background thread do its business - Sleep(30); - - watcher.StopWatching(); - - RunLoop().RunUntilIdle(); - - // Our delegate should not have fired. - EXPECT_EQ(1, counter); - - CloseHandle(event); -} - -void RunTest_SignalBeforeWatch(MessageLoop::Type message_loop_type) { - MessageLoop message_loop(message_loop_type); - - ObjectWatcher watcher; - - // A manual-reset event that is signaled before we begin watching. - HANDLE event = CreateEvent(NULL, TRUE, TRUE, NULL); - - QuitDelegate delegate; - bool ok = watcher.StartWatching(event, &delegate); - EXPECT_TRUE(ok); - - MessageLoop::current()->Run(); - - EXPECT_EQ(NULL, watcher.GetWatchedObject()); - CloseHandle(event); -} - -void RunTest_OutlivesMessageLoop(MessageLoop::Type message_loop_type) { - // Simulate a MessageLoop that dies before an ObjectWatcher. This ordinarily - // doesn't happen when people use the Thread class, but it can happen when - // people use the Singleton pattern or atexit. - HANDLE event = CreateEvent(NULL, TRUE, FALSE, NULL); // not signaled - { - ObjectWatcher watcher; - { - MessageLoop message_loop(message_loop_type); - - QuitDelegate delegate; - watcher.StartWatching(event, &delegate); - } - } - CloseHandle(event); -} - -} // namespace - -//----------------------------------------------------------------------------- - -TEST(ObjectWatcherTest, BasicSignal) { - RunTest_BasicSignal(MessageLoop::TYPE_DEFAULT); - RunTest_BasicSignal(MessageLoop::TYPE_IO); - RunTest_BasicSignal(MessageLoop::TYPE_UI); -} - -TEST(ObjectWatcherTest, BasicCancel) { - RunTest_BasicCancel(MessageLoop::TYPE_DEFAULT); - RunTest_BasicCancel(MessageLoop::TYPE_IO); - RunTest_BasicCancel(MessageLoop::TYPE_UI); -} - -TEST(ObjectWatcherTest, CancelAfterSet) { - RunTest_CancelAfterSet(MessageLoop::TYPE_DEFAULT); - RunTest_CancelAfterSet(MessageLoop::TYPE_IO); - RunTest_CancelAfterSet(MessageLoop::TYPE_UI); -} - -TEST(ObjectWatcherTest, SignalBeforeWatch) { - RunTest_SignalBeforeWatch(MessageLoop::TYPE_DEFAULT); - RunTest_SignalBeforeWatch(MessageLoop::TYPE_IO); - RunTest_SignalBeforeWatch(MessageLoop::TYPE_UI); -} - -TEST(ObjectWatcherTest, OutlivesMessageLoop) { - RunTest_OutlivesMessageLoop(MessageLoop::TYPE_DEFAULT); - RunTest_OutlivesMessageLoop(MessageLoop::TYPE_IO); - RunTest_OutlivesMessageLoop(MessageLoop::TYPE_UI); -} - -} // namespace win -} // namespace base diff --git a/base/win/pe_image.cc b/base/win/pe_image.cc deleted file mode 100644 index d8a2a4b797..0000000000 --- a/base/win/pe_image.cc +++ /dev/null @@ -1,571 +0,0 @@ -// Copyright (c) 2010 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -// This file implements PEImage, a generic class to manipulate PE files. -// This file was adapted from GreenBorder's Code. - -#include "base/win/pe_image.h" - -namespace base { -namespace win { - -#if defined(_WIN64) && !defined(NACL_WIN64) -// TODO(jschuh): crbug.com/167707 Make sure this is ok. -#pragma message ("Warning: \ - This code is not tested on x64. Please make sure all the base unit tests\ - pass before doing any real work. The current unit tests don't test the\ - differences between 32- and 64-bits implementations. Bugs may slip through.\ - You need to improve the coverage before continuing.") -#endif - -// Structure to perform imports enumerations. -struct EnumAllImportsStorage { - PEImage::EnumImportsFunction callback; - PVOID cookie; -}; - -namespace { - - // Compare two strings byte by byte on an unsigned basis. - // if s1 == s2, return 0 - // if s1 < s2, return negative - // if s1 > s2, return positive - // Exception if inputs are invalid. - int StrCmpByByte(LPCSTR s1, LPCSTR s2) { - while (*s1 != '\0' && *s1 == *s2) { - ++s1; - ++s2; - } - - return (*reinterpret_cast(s1) - - *reinterpret_cast(s2)); - } - -} // namespace - -// Callback used to enumerate imports. See EnumImportChunksFunction. -bool ProcessImportChunk(const PEImage &image, LPCSTR module, - PIMAGE_THUNK_DATA name_table, - PIMAGE_THUNK_DATA iat, PVOID cookie) { - EnumAllImportsStorage &storage = *reinterpret_cast( - cookie); - - return image.EnumOneImportChunk(storage.callback, module, name_table, iat, - storage.cookie); -} - -// Callback used to enumerate delay imports. See EnumDelayImportChunksFunction. -bool ProcessDelayImportChunk(const PEImage &image, - PImgDelayDescr delay_descriptor, - LPCSTR module, PIMAGE_THUNK_DATA name_table, - PIMAGE_THUNK_DATA iat, PIMAGE_THUNK_DATA bound_iat, - PIMAGE_THUNK_DATA unload_iat, PVOID cookie) { - EnumAllImportsStorage &storage = *reinterpret_cast( - cookie); - - return image.EnumOneDelayImportChunk(storage.callback, delay_descriptor, - module, name_table, iat, bound_iat, - unload_iat, storage.cookie); -} - -void PEImage::set_module(HMODULE module) { - module_ = module; -} - -PIMAGE_DOS_HEADER PEImage::GetDosHeader() const { - return reinterpret_cast(module_); -} - -PIMAGE_NT_HEADERS PEImage::GetNTHeaders() const { - PIMAGE_DOS_HEADER dos_header = GetDosHeader(); - - return reinterpret_cast( - reinterpret_cast(dos_header) + dos_header->e_lfanew); -} - -PIMAGE_SECTION_HEADER PEImage::GetSectionHeader(UINT section) const { - PIMAGE_NT_HEADERS nt_headers = GetNTHeaders(); - PIMAGE_SECTION_HEADER first_section = IMAGE_FIRST_SECTION(nt_headers); - - if (section < nt_headers->FileHeader.NumberOfSections) - return first_section + section; - else - return NULL; -} - -WORD PEImage::GetNumSections() const { - return GetNTHeaders()->FileHeader.NumberOfSections; -} - -DWORD PEImage::GetImageDirectoryEntrySize(UINT directory) const { - PIMAGE_NT_HEADERS nt_headers = GetNTHeaders(); - - return nt_headers->OptionalHeader.DataDirectory[directory].Size; -} - -PVOID PEImage::GetImageDirectoryEntryAddr(UINT directory) const { - PIMAGE_NT_HEADERS nt_headers = GetNTHeaders(); - - return RVAToAddr( - nt_headers->OptionalHeader.DataDirectory[directory].VirtualAddress); -} - -PIMAGE_SECTION_HEADER PEImage::GetImageSectionFromAddr(PVOID address) const { - PBYTE target = reinterpret_cast(address); - PIMAGE_SECTION_HEADER section; - - for (UINT i = 0; NULL != (section = GetSectionHeader(i)); i++) { - // Don't use the virtual RVAToAddr. - PBYTE start = reinterpret_cast( - PEImage::RVAToAddr(section->VirtualAddress)); - - DWORD size = section->Misc.VirtualSize; - - if ((start <= target) && (start + size > target)) - return section; - } - - return NULL; -} - -PIMAGE_SECTION_HEADER PEImage::GetImageSectionHeaderByName( - LPCSTR section_name) const { - if (NULL == section_name) - return NULL; - - PIMAGE_SECTION_HEADER ret = NULL; - int num_sections = GetNumSections(); - - for (int i = 0; i < num_sections; i++) { - PIMAGE_SECTION_HEADER section = GetSectionHeader(i); - if (0 == _strnicmp(reinterpret_cast(section->Name), section_name, - sizeof(section->Name))) { - ret = section; - break; - } - } - - return ret; -} - -PDWORD PEImage::GetExportEntry(LPCSTR name) const { - PIMAGE_EXPORT_DIRECTORY exports = GetExportDirectory(); - - if (NULL == exports) - return NULL; - - WORD ordinal = 0; - if (!GetProcOrdinal(name, &ordinal)) - return NULL; - - PDWORD functions = reinterpret_cast( - RVAToAddr(exports->AddressOfFunctions)); - - return functions + ordinal - exports->Base; -} - -FARPROC PEImage::GetProcAddress(LPCSTR function_name) const { - PDWORD export_entry = GetExportEntry(function_name); - if (NULL == export_entry) - return NULL; - - PBYTE function = reinterpret_cast(RVAToAddr(*export_entry)); - - PBYTE exports = reinterpret_cast( - GetImageDirectoryEntryAddr(IMAGE_DIRECTORY_ENTRY_EXPORT)); - DWORD size = GetImageDirectoryEntrySize(IMAGE_DIRECTORY_ENTRY_EXPORT); - - // Check for forwarded exports as a special case. - if (exports <= function && exports + size > function) -#pragma warning(push) -#pragma warning(disable: 4312) - // This cast generates a warning because it is 32 bit specific. - return reinterpret_cast(0xFFFFFFFF); -#pragma warning(pop) - - return reinterpret_cast(function); -} - -bool PEImage::GetProcOrdinal(LPCSTR function_name, WORD *ordinal) const { - if (NULL == ordinal) - return false; - - PIMAGE_EXPORT_DIRECTORY exports = GetExportDirectory(); - - if (NULL == exports) - return false; - - if (IsOrdinal(function_name)) { - *ordinal = ToOrdinal(function_name); - } else { - PDWORD names = reinterpret_cast(RVAToAddr(exports->AddressOfNames)); - PDWORD lower = names; - PDWORD upper = names + exports->NumberOfNames; - int cmp = -1; - - // Binary Search for the name. - while (lower != upper) { - PDWORD middle = lower + (upper - lower) / 2; - LPCSTR name = reinterpret_cast(RVAToAddr(*middle)); - - // This may be called by sandbox before MSVCRT dll loads, so can't use - // CRT function here. - cmp = StrCmpByByte(function_name, name); - - if (cmp == 0) { - lower = middle; - break; - } - - if (cmp > 0) - lower = middle + 1; - else - upper = middle; - } - - if (cmp != 0) - return false; - - - PWORD ordinals = reinterpret_cast( - RVAToAddr(exports->AddressOfNameOrdinals)); - - *ordinal = ordinals[lower - names] + static_cast(exports->Base); - } - - return true; -} - -bool PEImage::EnumSections(EnumSectionsFunction callback, PVOID cookie) const { - PIMAGE_NT_HEADERS nt_headers = GetNTHeaders(); - UINT num_sections = nt_headers->FileHeader.NumberOfSections; - PIMAGE_SECTION_HEADER section = GetSectionHeader(0); - - for (UINT i = 0; i < num_sections; i++, section++) { - PVOID section_start = RVAToAddr(section->VirtualAddress); - DWORD size = section->Misc.VirtualSize; - - if (!callback(*this, section, section_start, size, cookie)) - return false; - } - - return true; -} - -bool PEImage::EnumExports(EnumExportsFunction callback, PVOID cookie) const { - PVOID directory = GetImageDirectoryEntryAddr(IMAGE_DIRECTORY_ENTRY_EXPORT); - DWORD size = GetImageDirectoryEntrySize(IMAGE_DIRECTORY_ENTRY_EXPORT); - - // Check if there are any exports at all. - if (NULL == directory || 0 == size) - return true; - - PIMAGE_EXPORT_DIRECTORY exports = reinterpret_cast( - directory); - UINT ordinal_base = exports->Base; - UINT num_funcs = exports->NumberOfFunctions; - UINT num_names = exports->NumberOfNames; - PDWORD functions = reinterpret_cast(RVAToAddr( - exports->AddressOfFunctions)); - PDWORD names = reinterpret_cast(RVAToAddr(exports->AddressOfNames)); - PWORD ordinals = reinterpret_cast(RVAToAddr( - exports->AddressOfNameOrdinals)); - - for (UINT count = 0; count < num_funcs; count++) { - PVOID func = RVAToAddr(functions[count]); - if (NULL == func) - continue; - - // Check for a name. - LPCSTR name = NULL; - UINT hint; - for (hint = 0; hint < num_names; hint++) { - if (ordinals[hint] == count) { - name = reinterpret_cast(RVAToAddr(names[hint])); - break; - } - } - - if (name == NULL) - hint = 0; - - // Check for forwarded exports. - LPCSTR forward = NULL; - if (reinterpret_cast(func) >= reinterpret_cast(directory) && - reinterpret_cast(func) <= reinterpret_cast(directory) + - size) { - forward = reinterpret_cast(func); - func = 0; - } - - if (!callback(*this, ordinal_base + count, hint, name, func, forward, - cookie)) - return false; - } - - return true; -} - -bool PEImage::EnumRelocs(EnumRelocsFunction callback, PVOID cookie) const { - PVOID directory = GetImageDirectoryEntryAddr(IMAGE_DIRECTORY_ENTRY_BASERELOC); - DWORD size = GetImageDirectoryEntrySize(IMAGE_DIRECTORY_ENTRY_BASERELOC); - PIMAGE_BASE_RELOCATION base = reinterpret_cast( - directory); - - if (directory == NULL || size < sizeof(IMAGE_BASE_RELOCATION)) - return true; - - while (base->SizeOfBlock) { - PWORD reloc = reinterpret_cast(base + 1); - UINT num_relocs = (base->SizeOfBlock - sizeof(IMAGE_BASE_RELOCATION)) / - sizeof(WORD); - - for (UINT i = 0; i < num_relocs; i++, reloc++) { - WORD type = *reloc >> 12; - PVOID address = RVAToAddr(base->VirtualAddress + (*reloc & 0x0FFF)); - - if (!callback(*this, type, address, cookie)) - return false; - } - - base = reinterpret_cast( - reinterpret_cast(base) + base->SizeOfBlock); - } - - return true; -} - -bool PEImage::EnumImportChunks(EnumImportChunksFunction callback, - PVOID cookie) const { - DWORD size = GetImageDirectoryEntrySize(IMAGE_DIRECTORY_ENTRY_IMPORT); - PIMAGE_IMPORT_DESCRIPTOR import = GetFirstImportChunk(); - - if (import == NULL || size < sizeof(IMAGE_IMPORT_DESCRIPTOR)) - return true; - - for (; import->FirstThunk; import++) { - LPCSTR module_name = reinterpret_cast(RVAToAddr(import->Name)); - PIMAGE_THUNK_DATA name_table = reinterpret_cast( - RVAToAddr(import->OriginalFirstThunk)); - PIMAGE_THUNK_DATA iat = reinterpret_cast( - RVAToAddr(import->FirstThunk)); - - if (!callback(*this, module_name, name_table, iat, cookie)) - return false; - } - - return true; -} - -bool PEImage::EnumOneImportChunk(EnumImportsFunction callback, - LPCSTR module_name, - PIMAGE_THUNK_DATA name_table, - PIMAGE_THUNK_DATA iat, PVOID cookie) const { - if (NULL == name_table) - return false; - - for (; name_table && name_table->u1.Ordinal; name_table++, iat++) { - LPCSTR name = NULL; - WORD ordinal = 0; - WORD hint = 0; - - if (IMAGE_SNAP_BY_ORDINAL(name_table->u1.Ordinal)) { - ordinal = static_cast(IMAGE_ORDINAL32(name_table->u1.Ordinal)); - } else { - PIMAGE_IMPORT_BY_NAME import = reinterpret_cast( - RVAToAddr(name_table->u1.ForwarderString)); - - hint = import->Hint; - name = reinterpret_cast(&import->Name); - } - - if (!callback(*this, module_name, ordinal, name, hint, iat, cookie)) - return false; - } - - return true; -} - -bool PEImage::EnumAllImports(EnumImportsFunction callback, PVOID cookie) const { - EnumAllImportsStorage temp = { callback, cookie }; - return EnumImportChunks(ProcessImportChunk, &temp); -} - -bool PEImage::EnumDelayImportChunks(EnumDelayImportChunksFunction callback, - PVOID cookie) const { - PVOID directory = GetImageDirectoryEntryAddr( - IMAGE_DIRECTORY_ENTRY_DELAY_IMPORT); - DWORD size = GetImageDirectoryEntrySize(IMAGE_DIRECTORY_ENTRY_DELAY_IMPORT); - PImgDelayDescr delay_descriptor = reinterpret_cast(directory); - - if (directory == NULL || size == 0) - return true; - - for (; delay_descriptor->rvaHmod; delay_descriptor++) { - PIMAGE_THUNK_DATA name_table; - PIMAGE_THUNK_DATA iat; - PIMAGE_THUNK_DATA bound_iat; // address of the optional bound IAT - PIMAGE_THUNK_DATA unload_iat; // address of optional copy of original IAT - LPCSTR module_name; - - // check if VC7-style imports, using RVAs instead of - // VC6-style addresses. - bool rvas = (delay_descriptor->grAttrs & dlattrRva) != 0; - - if (rvas) { - module_name = reinterpret_cast( - RVAToAddr(delay_descriptor->rvaDLLName)); - name_table = reinterpret_cast( - RVAToAddr(delay_descriptor->rvaINT)); - iat = reinterpret_cast( - RVAToAddr(delay_descriptor->rvaIAT)); - bound_iat = reinterpret_cast( - RVAToAddr(delay_descriptor->rvaBoundIAT)); - unload_iat = reinterpret_cast( - RVAToAddr(delay_descriptor->rvaUnloadIAT)); - } else { -#pragma warning(push) -#pragma warning(disable: 4312) - // These casts generate warnings because they are 32 bit specific. - module_name = reinterpret_cast(delay_descriptor->rvaDLLName); - name_table = reinterpret_cast( - delay_descriptor->rvaINT); - iat = reinterpret_cast(delay_descriptor->rvaIAT); - bound_iat = reinterpret_cast( - delay_descriptor->rvaBoundIAT); - unload_iat = reinterpret_cast( - delay_descriptor->rvaUnloadIAT); -#pragma warning(pop) - } - - if (!callback(*this, delay_descriptor, module_name, name_table, iat, - bound_iat, unload_iat, cookie)) - return false; - } - - return true; -} - -bool PEImage::EnumOneDelayImportChunk(EnumImportsFunction callback, - PImgDelayDescr delay_descriptor, - LPCSTR module_name, - PIMAGE_THUNK_DATA name_table, - PIMAGE_THUNK_DATA iat, - PIMAGE_THUNK_DATA bound_iat, - PIMAGE_THUNK_DATA unload_iat, - PVOID cookie) const { - UNREFERENCED_PARAMETER(bound_iat); - UNREFERENCED_PARAMETER(unload_iat); - - for (; name_table->u1.Ordinal; name_table++, iat++) { - LPCSTR name = NULL; - WORD ordinal = 0; - WORD hint = 0; - - if (IMAGE_SNAP_BY_ORDINAL(name_table->u1.Ordinal)) { - ordinal = static_cast(IMAGE_ORDINAL32(name_table->u1.Ordinal)); - } else { - PIMAGE_IMPORT_BY_NAME import; - bool rvas = (delay_descriptor->grAttrs & dlattrRva) != 0; - - if (rvas) { - import = reinterpret_cast( - RVAToAddr(name_table->u1.ForwarderString)); - } else { -#pragma warning(push) -#pragma warning(disable: 4312) - // This cast generates a warning because it is 32 bit specific. - import = reinterpret_cast( - name_table->u1.ForwarderString); -#pragma warning(pop) - } - - hint = import->Hint; - name = reinterpret_cast(&import->Name); - } - - if (!callback(*this, module_name, ordinal, name, hint, iat, cookie)) - return false; - } - - return true; -} - -bool PEImage::EnumAllDelayImports(EnumImportsFunction callback, - PVOID cookie) const { - EnumAllImportsStorage temp = { callback, cookie }; - return EnumDelayImportChunks(ProcessDelayImportChunk, &temp); -} - -bool PEImage::VerifyMagic() const { - PIMAGE_DOS_HEADER dos_header = GetDosHeader(); - - if (dos_header->e_magic != IMAGE_DOS_SIGNATURE) - return false; - - PIMAGE_NT_HEADERS nt_headers = GetNTHeaders(); - - if (nt_headers->Signature != IMAGE_NT_SIGNATURE) - return false; - - if (nt_headers->FileHeader.SizeOfOptionalHeader != - sizeof(IMAGE_OPTIONAL_HEADER)) - return false; - - if (nt_headers->OptionalHeader.Magic != IMAGE_NT_OPTIONAL_HDR_MAGIC) - return false; - - return true; -} - -bool PEImage::ImageRVAToOnDiskOffset(DWORD rva, DWORD *on_disk_offset) const { - LPVOID address = RVAToAddr(rva); - return ImageAddrToOnDiskOffset(address, on_disk_offset); -} - -bool PEImage::ImageAddrToOnDiskOffset(LPVOID address, - DWORD *on_disk_offset) const { - if (NULL == address) - return false; - - // Get the section that this address belongs to. - PIMAGE_SECTION_HEADER section_header = GetImageSectionFromAddr(address); - if (NULL == section_header) - return false; - -#pragma warning(push) -#pragma warning(disable: 4311) - // These casts generate warnings because they are 32 bit specific. - // Don't follow the virtual RVAToAddr, use the one on the base. - DWORD offset_within_section = reinterpret_cast(address) - - reinterpret_cast(PEImage::RVAToAddr( - section_header->VirtualAddress)); -#pragma warning(pop) - - *on_disk_offset = section_header->PointerToRawData + offset_within_section; - return true; -} - -PVOID PEImage::RVAToAddr(DWORD rva) const { - if (rva == 0) - return NULL; - - return reinterpret_cast(module_) + rva; -} - -PVOID PEImageAsData::RVAToAddr(DWORD rva) const { - if (rva == 0) - return NULL; - - PVOID in_memory = PEImage::RVAToAddr(rva); - DWORD disk_offset; - - if (!ImageAddrToOnDiskOffset(in_memory, &disk_offset)) - return NULL; - - return PEImage::RVAToAddr(disk_offset); -} - -} // namespace win -} // namespace base diff --git a/base/win/pe_image.h b/base/win/pe_image.h deleted file mode 100644 index 878ef528c9..0000000000 --- a/base/win/pe_image.h +++ /dev/null @@ -1,268 +0,0 @@ -// Copyright (c) 2010 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -// This file was adapted from GreenBorder's Code. -// To understand what this class is about (for other than well known functions -// as GetProcAddress), a good starting point is "An In-Depth Look into the -// Win32 Portable Executable File Format" by Matt Pietrek: -// http://msdn.microsoft.com/msdnmag/issues/02/02/PE/default.aspx - -#ifndef BASE_WIN_PE_IMAGE_H_ -#define BASE_WIN_PE_IMAGE_H_ - -#include - -#if defined(_WIN32_WINNT_WIN8) -// The Windows 8 SDK defines FACILITY_VISUALCPP in winerror.h. -#undef FACILITY_VISUALCPP -#endif -#include - -namespace base { -namespace win { - -// This class is a wrapper for the Portable Executable File Format (PE). -// It's main purpose is to provide an easy way to work with imports and exports -// from a file, mapped in memory as image. -class PEImage { - public: - // Callback to enumerate sections. - // cookie is the value passed to the enumerate method. - // Returns true to continue the enumeration. - typedef bool (*EnumSectionsFunction)(const PEImage &image, - PIMAGE_SECTION_HEADER header, - PVOID section_start, DWORD section_size, - PVOID cookie); - - // Callback to enumerate exports. - // function is the actual address of the symbol. If forward is not null, it - // contains the dll and symbol to forward this export to. cookie is the value - // passed to the enumerate method. - // Returns true to continue the enumeration. - typedef bool (*EnumExportsFunction)(const PEImage &image, DWORD ordinal, - DWORD hint, LPCSTR name, PVOID function, - LPCSTR forward, PVOID cookie); - - // Callback to enumerate import blocks. - // name_table and iat point to the imports name table and address table for - // this block. cookie is the value passed to the enumerate method. - // Returns true to continue the enumeration. - typedef bool (*EnumImportChunksFunction)(const PEImage &image, LPCSTR module, - PIMAGE_THUNK_DATA name_table, - PIMAGE_THUNK_DATA iat, PVOID cookie); - - // Callback to enumerate imports. - // module is the dll that exports this symbol. cookie is the value passed to - // the enumerate method. - // Returns true to continue the enumeration. - typedef bool (*EnumImportsFunction)(const PEImage &image, LPCSTR module, - DWORD ordinal, LPCSTR name, DWORD hint, - PIMAGE_THUNK_DATA iat, PVOID cookie); - - // Callback to enumerate dalayed import blocks. - // module is the dll that exports this block of symbols. cookie is the value - // passed to the enumerate method. - // Returns true to continue the enumeration. - typedef bool (*EnumDelayImportChunksFunction)(const PEImage &image, - PImgDelayDescr delay_descriptor, - LPCSTR module, - PIMAGE_THUNK_DATA name_table, - PIMAGE_THUNK_DATA iat, - PIMAGE_THUNK_DATA bound_iat, - PIMAGE_THUNK_DATA unload_iat, - PVOID cookie); - - // Callback to enumerate relocations. - // cookie is the value passed to the enumerate method. - // Returns true to continue the enumeration. - typedef bool (*EnumRelocsFunction)(const PEImage &image, WORD type, - PVOID address, PVOID cookie); - - explicit PEImage(HMODULE module) : module_(module) {} - explicit PEImage(const void* module) { - module_ = reinterpret_cast(const_cast(module)); - } - - // Gets the HMODULE for this object. - HMODULE module() const; - - // Sets this object's HMODULE. - void set_module(HMODULE module); - - // Checks if this symbol is actually an ordinal. - static bool IsOrdinal(LPCSTR name); - - // Converts a named symbol to the corresponding ordinal. - static WORD ToOrdinal(LPCSTR name); - - // Returns the DOS_HEADER for this PE. - PIMAGE_DOS_HEADER GetDosHeader() const; - - // Returns the NT_HEADER for this PE. - PIMAGE_NT_HEADERS GetNTHeaders() const; - - // Returns number of sections of this PE. - WORD GetNumSections() const; - - // Returns the header for a given section. - // returns NULL if there is no such section. - PIMAGE_SECTION_HEADER GetSectionHeader(UINT section) const; - - // Returns the size of a given directory entry. - DWORD GetImageDirectoryEntrySize(UINT directory) const; - - // Returns the address of a given directory entry. - PVOID GetImageDirectoryEntryAddr(UINT directory) const; - - // Returns the section header for a given address. - // Use: s = image.GetImageSectionFromAddr(a); - // Post: 's' is the section header of the section that contains 'a' - // or NULL if there is no such section. - PIMAGE_SECTION_HEADER GetImageSectionFromAddr(PVOID address) const; - - // Returns the section header for a given section. - PIMAGE_SECTION_HEADER GetImageSectionHeaderByName(LPCSTR section_name) const; - - // Returns the first block of imports. - PIMAGE_IMPORT_DESCRIPTOR GetFirstImportChunk() const; - - // Returns the exports directory. - PIMAGE_EXPORT_DIRECTORY GetExportDirectory() const; - - // Returns a given export entry. - // Use: e = image.GetExportEntry(f); - // Pre: 'f' is either a zero terminated string or ordinal - // Post: 'e' is a pointer to the export directory entry - // that contains 'f's export RVA, or NULL if 'f' - // is not exported from this image - PDWORD GetExportEntry(LPCSTR name) const; - - // Returns the address for a given exported symbol. - // Use: p = image.GetProcAddress(f); - // Pre: 'f' is either a zero terminated string or ordinal. - // Post: if 'f' is a non-forwarded export from image, 'p' is - // the exported function. If 'f' is a forwarded export - // then p is the special value 0xFFFFFFFF. In this case - // RVAToAddr(*GetExportEntry) can be used to resolve - // the string that describes the forward. - FARPROC GetProcAddress(LPCSTR function_name) const; - - // Retrieves the ordinal for a given exported symbol. - // Returns true if the symbol was found. - bool GetProcOrdinal(LPCSTR function_name, WORD *ordinal) const; - - // Enumerates PE sections. - // cookie is a generic cookie to pass to the callback. - // Returns true on success. - bool EnumSections(EnumSectionsFunction callback, PVOID cookie) const; - - // Enumerates PE exports. - // cookie is a generic cookie to pass to the callback. - // Returns true on success. - bool EnumExports(EnumExportsFunction callback, PVOID cookie) const; - - // Enumerates PE imports. - // cookie is a generic cookie to pass to the callback. - // Returns true on success. - bool EnumAllImports(EnumImportsFunction callback, PVOID cookie) const; - - // Enumerates PE import blocks. - // cookie is a generic cookie to pass to the callback. - // Returns true on success. - bool EnumImportChunks(EnumImportChunksFunction callback, PVOID cookie) const; - - // Enumerates the imports from a single PE import block. - // cookie is a generic cookie to pass to the callback. - // Returns true on success. - bool EnumOneImportChunk(EnumImportsFunction callback, LPCSTR module_name, - PIMAGE_THUNK_DATA name_table, PIMAGE_THUNK_DATA iat, - PVOID cookie) const; - - - // Enumerates PE delay imports. - // cookie is a generic cookie to pass to the callback. - // Returns true on success. - bool EnumAllDelayImports(EnumImportsFunction callback, PVOID cookie) const; - - // Enumerates PE delay import blocks. - // cookie is a generic cookie to pass to the callback. - // Returns true on success. - bool EnumDelayImportChunks(EnumDelayImportChunksFunction callback, - PVOID cookie) const; - - // Enumerates imports from a single PE delay import block. - // cookie is a generic cookie to pass to the callback. - // Returns true on success. - bool EnumOneDelayImportChunk(EnumImportsFunction callback, - PImgDelayDescr delay_descriptor, - LPCSTR module_name, - PIMAGE_THUNK_DATA name_table, - PIMAGE_THUNK_DATA iat, - PIMAGE_THUNK_DATA bound_iat, - PIMAGE_THUNK_DATA unload_iat, - PVOID cookie) const; - - // Enumerates PE relocation entries. - // cookie is a generic cookie to pass to the callback. - // Returns true on success. - bool EnumRelocs(EnumRelocsFunction callback, PVOID cookie) const; - - // Verifies the magic values on the PE file. - // Returns true if all values are correct. - bool VerifyMagic() const; - - // Converts an rva value to the appropriate address. - virtual PVOID RVAToAddr(DWORD rva) const; - - // Converts an rva value to an offset on disk. - // Returns true on success. - bool ImageRVAToOnDiskOffset(DWORD rva, DWORD *on_disk_offset) const; - - // Converts an address to an offset on disk. - // Returns true on success. - bool ImageAddrToOnDiskOffset(LPVOID address, DWORD *on_disk_offset) const; - - private: - HMODULE module_; -}; - -// This class is an extension to the PEImage class that allows working with PE -// files mapped as data instead of as image file. -class PEImageAsData : public PEImage { - public: - explicit PEImageAsData(HMODULE hModule) : PEImage(hModule) {} - - virtual PVOID RVAToAddr(DWORD rva) const; -}; - -inline bool PEImage::IsOrdinal(LPCSTR name) { -#pragma warning(push) -#pragma warning(disable: 4311) - // This cast generates a warning because it is 32 bit specific. - return reinterpret_cast(name) <= 0xFFFF; -#pragma warning(pop) -} - -inline WORD PEImage::ToOrdinal(LPCSTR name) { - return reinterpret_cast(name); -} - -inline HMODULE PEImage::module() const { - return module_; -} - -inline PIMAGE_IMPORT_DESCRIPTOR PEImage::GetFirstImportChunk() const { - return reinterpret_cast( - GetImageDirectoryEntryAddr(IMAGE_DIRECTORY_ENTRY_IMPORT)); -} - -inline PIMAGE_EXPORT_DIRECTORY PEImage::GetExportDirectory() const { - return reinterpret_cast( - GetImageDirectoryEntryAddr(IMAGE_DIRECTORY_ENTRY_EXPORT)); -} - -} // namespace win -} // namespace base - -#endif // BASE_WIN_PE_IMAGE_H_ diff --git a/base/win/pe_image_unittest.cc b/base/win/pe_image_unittest.cc deleted file mode 100644 index 238c924f62..0000000000 --- a/base/win/pe_image_unittest.cc +++ /dev/null @@ -1,271 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -// This file contains unit tests for PEImage. - -#include "testing/gtest/include/gtest/gtest.h" -#include "base/win/pe_image.h" -#include "base/win/windows_version.h" - -namespace base { -namespace win { - -// Just counts the number of invocations. -bool ExportsCallback(const PEImage &image, - DWORD ordinal, - DWORD hint, - LPCSTR name, - PVOID function, - LPCSTR forward, - PVOID cookie) { - int* count = reinterpret_cast(cookie); - (*count)++; - return true; -} - -// Just counts the number of invocations. -bool ImportsCallback(const PEImage &image, - LPCSTR module, - DWORD ordinal, - LPCSTR name, - DWORD hint, - PIMAGE_THUNK_DATA iat, - PVOID cookie) { - int* count = reinterpret_cast(cookie); - (*count)++; - return true; -} - -// Just counts the number of invocations. -bool SectionsCallback(const PEImage &image, - PIMAGE_SECTION_HEADER header, - PVOID section_start, - DWORD section_size, - PVOID cookie) { - int* count = reinterpret_cast(cookie); - (*count)++; - return true; -} - -// Just counts the number of invocations. -bool RelocsCallback(const PEImage &image, - WORD type, - PVOID address, - PVOID cookie) { - int* count = reinterpret_cast(cookie); - (*count)++; - return true; -} - -// Just counts the number of invocations. -bool ImportChunksCallback(const PEImage &image, - LPCSTR module, - PIMAGE_THUNK_DATA name_table, - PIMAGE_THUNK_DATA iat, - PVOID cookie) { - int* count = reinterpret_cast(cookie); - (*count)++; - return true; -} - -// Just counts the number of invocations. -bool DelayImportChunksCallback(const PEImage &image, - PImgDelayDescr delay_descriptor, - LPCSTR module, - PIMAGE_THUNK_DATA name_table, - PIMAGE_THUNK_DATA iat, - PIMAGE_THUNK_DATA bound_iat, - PIMAGE_THUNK_DATA unload_iat, - PVOID cookie) { - int* count = reinterpret_cast(cookie); - (*count)++; - return true; -} - -// Identifiers for the set of supported expectations. -enum ExpectationSet { - WIN_2K_SET, - WIN_XP_SET, - WIN_VISTA_SET, - WIN_7_SET, - WIN_8_SET, - UNSUPPORTED_SET, -}; - -// We'll be using some known values for the tests. -enum Value { - sections = 0, - imports_dlls, - delay_dlls, - exports, - imports, - delay_imports, - relocs -}; - -ExpectationSet GetExpectationSet(DWORD os) { - if (os == 50) - return WIN_2K_SET; - if (os == 51) - return WIN_XP_SET; - if (os == 60) - return WIN_VISTA_SET; - if (os == 61) - return WIN_7_SET; - if (os >= 62) - return WIN_8_SET; - return UNSUPPORTED_SET; -} - -// Retrieves the expected value from advapi32.dll based on the OS. -int GetExpectedValue(Value value, DWORD os) { - const int xp_delay_dlls = 2; - const int xp_exports = 675; - const int xp_imports = 422; - const int xp_delay_imports = 8; - const int xp_relocs = 9180; - const int vista_delay_dlls = 4; - const int vista_exports = 799; - const int vista_imports = 476; - const int vista_delay_imports = 24; - const int vista_relocs = 10188; - const int w2k_delay_dlls = 0; - const int w2k_exports = 566; - const int w2k_imports = 357; - const int w2k_delay_imports = 0; - const int w2k_relocs = 7388; - const int win7_delay_dlls = 7; - const int win7_exports = 806; - const int win7_imports = 568; - const int win7_delay_imports = 71; - int win7_relocs = 7812; - int win7_sections = 4; - const int win8_delay_dlls = 9; - const int win8_exports = 806; - const int win8_imports = 568; - const int win8_delay_imports = 113; - const int win8_relocs = 9478; - int win8_sections = 4; - int win8_import_dlls = 17; - - base::win::OSInfo* os_info = base::win::OSInfo::GetInstance(); - // 32-bit process on a 32-bit system. - if (os_info->architecture() == base::win::OSInfo::X86_ARCHITECTURE) { - win8_sections = 5; - win8_import_dlls = 19; - - // 64-bit process on a 64-bit system. - } else if (os_info->wow64_status() == base::win::OSInfo::WOW64_DISABLED) { - win7_sections = 6; - win7_relocs = 2712; - } - - // Contains the expected value, for each enumerated property (Value), and the - // OS version: [Value][os_version] - const int expected[][5] = { - {4, 4, 4, win7_sections, win8_sections}, - {3, 3, 3, 13, win8_import_dlls}, - {w2k_delay_dlls, xp_delay_dlls, vista_delay_dlls, win7_delay_dlls, - win8_delay_dlls}, - {w2k_exports, xp_exports, vista_exports, win7_exports, win8_exports}, - {w2k_imports, xp_imports, vista_imports, win7_imports, win8_imports}, - {w2k_delay_imports, xp_delay_imports, - vista_delay_imports, win7_delay_imports, win8_delay_imports}, - {w2k_relocs, xp_relocs, vista_relocs, win7_relocs, win8_relocs} - }; - COMPILE_ASSERT(arraysize(expected[0]) == UNSUPPORTED_SET, - expected_value_set_mismatch); - - if (value > relocs) - return 0; - ExpectationSet expected_set = GetExpectationSet(os); - if (expected_set >= arraysize(expected)) { - // This should never happen. Log a failure if it does. - EXPECT_NE(UNSUPPORTED_SET, expected_set); - expected_set = WIN_2K_SET; - } - - return expected[value][expected_set]; -} - - -// TODO(jschuh): crbug.com/167707 Need to fix test on Win64 bots -#if defined(OS_WIN) && defined(ARCH_CPU_X86_64) -#define MAYBE_EnumeratesPE DISABLED_EnumeratesPE -#else -#define MAYBE_EnumeratesPE EnumeratesPE -#endif - -// Tests that we are able to enumerate stuff from a PE file, and that -// the actual number of items found is within the expected range. -TEST(PEImageTest, MAYBE_EnumeratesPE) { - HMODULE module = LoadLibrary(L"advapi32.dll"); - ASSERT_TRUE(NULL != module); - - PEImage pe(module); - int count = 0; - EXPECT_TRUE(pe.VerifyMagic()); - - DWORD os = pe.GetNTHeaders()->OptionalHeader.MajorOperatingSystemVersion; - os = os * 10 + pe.GetNTHeaders()->OptionalHeader.MinorOperatingSystemVersion; - - // Skip this test for unsupported OS versions. - if (GetExpectationSet(os) == UNSUPPORTED_SET) - return; - - pe.EnumSections(SectionsCallback, &count); - EXPECT_EQ(GetExpectedValue(sections, os), count); - - count = 0; - pe.EnumImportChunks(ImportChunksCallback, &count); - EXPECT_EQ(GetExpectedValue(imports_dlls, os), count); - - count = 0; - pe.EnumDelayImportChunks(DelayImportChunksCallback, &count); - EXPECT_EQ(GetExpectedValue(delay_dlls, os), count); - - count = 0; - pe.EnumExports(ExportsCallback, &count); - EXPECT_GT(count, GetExpectedValue(exports, os) - 20); - EXPECT_LT(count, GetExpectedValue(exports, os) + 100); - - count = 0; - pe.EnumAllImports(ImportsCallback, &count); - EXPECT_GT(count, GetExpectedValue(imports, os) - 20); - EXPECT_LT(count, GetExpectedValue(imports, os) + 100); - - count = 0; - pe.EnumAllDelayImports(ImportsCallback, &count); - EXPECT_GT(count, GetExpectedValue(delay_imports, os) - 2); - EXPECT_LT(count, GetExpectedValue(delay_imports, os) + 8); - - count = 0; - pe.EnumRelocs(RelocsCallback, &count); - EXPECT_GT(count, GetExpectedValue(relocs, os) - 150); - EXPECT_LT(count, GetExpectedValue(relocs, os) + 1500); - - FreeLibrary(module); -} - -// Tests that we can locate an specific exported symbol, by name and by ordinal. -TEST(PEImageTest, RetrievesExports) { - HMODULE module = LoadLibrary(L"advapi32.dll"); - ASSERT_TRUE(NULL != module); - - PEImage pe(module); - WORD ordinal; - - EXPECT_TRUE(pe.GetProcOrdinal("RegEnumKeyExW", &ordinal)); - - FARPROC address1 = pe.GetProcAddress("RegEnumKeyExW"); - FARPROC address2 = pe.GetProcAddress(reinterpret_cast(ordinal)); - EXPECT_TRUE(address1 != NULL); - EXPECT_TRUE(address2 != NULL); - EXPECT_TRUE(address1 == address2); - - FreeLibrary(module); -} - -} // namespace win -} // namespace base diff --git a/base/win/registry.cc b/base/win/registry.cc deleted file mode 100644 index 8bfe432971..0000000000 --- a/base/win/registry.cc +++ /dev/null @@ -1,483 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "base/win/registry.h" - -#include -#include - -#include "base/logging.h" -#include "base/strings/string_util.h" -#include "base/threading/thread_restrictions.h" - -#pragma comment(lib, "shlwapi.lib") // for SHDeleteKey - -namespace base { -namespace win { - -namespace { - -// RegEnumValue() reports the number of characters from the name that were -// written to the buffer, not how many there are. This constant is the maximum -// name size, such that a buffer with this size should read any name. -const DWORD MAX_REGISTRY_NAME_SIZE = 16384; - -// Registry values are read as BYTE* but can have wchar_t* data whose last -// wchar_t is truncated. This function converts the reported |byte_size| to -// a size in wchar_t that can store a truncated wchar_t if necessary. -inline DWORD to_wchar_size(DWORD byte_size) { - return (byte_size + sizeof(wchar_t) - 1) / sizeof(wchar_t); -} - -} // namespace - -// RegKey ---------------------------------------------------------------------- - -RegKey::RegKey() - : key_(NULL), - watch_event_(0) { -} - -RegKey::RegKey(HKEY key) - : key_(key), - watch_event_(0) { -} - -RegKey::RegKey(HKEY rootkey, const wchar_t* subkey, REGSAM access) - : key_(NULL), - watch_event_(0) { - if (rootkey) { - if (access & (KEY_SET_VALUE | KEY_CREATE_SUB_KEY | KEY_CREATE_LINK)) - Create(rootkey, subkey, access); - else - Open(rootkey, subkey, access); - } else { - DCHECK(!subkey); - } -} - -RegKey::~RegKey() { - Close(); -} - -LONG RegKey::Create(HKEY rootkey, const wchar_t* subkey, REGSAM access) { - DWORD disposition_value; - return CreateWithDisposition(rootkey, subkey, &disposition_value, access); -} - -LONG RegKey::CreateWithDisposition(HKEY rootkey, const wchar_t* subkey, - DWORD* disposition, REGSAM access) { - DCHECK(rootkey && subkey && access && disposition); - Close(); - - LONG result = RegCreateKeyEx(rootkey, subkey, 0, NULL, - REG_OPTION_NON_VOLATILE, access, NULL, &key_, - disposition); - return result; -} - -LONG RegKey::CreateKey(const wchar_t* name, REGSAM access) { - DCHECK(name && access); - HKEY subkey = NULL; - LONG result = RegCreateKeyEx(key_, name, 0, NULL, REG_OPTION_NON_VOLATILE, - access, NULL, &subkey, NULL); - Close(); - - key_ = subkey; - return result; -} - -LONG RegKey::Open(HKEY rootkey, const wchar_t* subkey, REGSAM access) { - DCHECK(rootkey && subkey && access); - Close(); - - LONG result = RegOpenKeyEx(rootkey, subkey, 0, access, &key_); - return result; -} - -LONG RegKey::OpenKey(const wchar_t* relative_key_name, REGSAM access) { - DCHECK(relative_key_name && access); - HKEY subkey = NULL; - LONG result = RegOpenKeyEx(key_, relative_key_name, 0, access, &subkey); - - // We have to close the current opened key before replacing it with the new - // one. - Close(); - - key_ = subkey; - return result; -} - -void RegKey::Close() { - StopWatching(); - if (key_) { - ::RegCloseKey(key_); - key_ = NULL; - } -} - -void RegKey::Set(HKEY key) { - if (key_ != key) { - Close(); - key_ = key; - } -} - -HKEY RegKey::Take() { - StopWatching(); - HKEY key = key_; - key_ = NULL; - return key; -} - -bool RegKey::HasValue(const wchar_t* name) const { - return RegQueryValueEx(key_, name, 0, NULL, NULL, NULL) == ERROR_SUCCESS; -} - -DWORD RegKey::GetValueCount() const { - DWORD count = 0; - LONG result = RegQueryInfoKey(key_, NULL, 0, NULL, NULL, NULL, NULL, &count, - NULL, NULL, NULL, NULL); - return (result == ERROR_SUCCESS) ? count : 0; -} - -LONG RegKey::GetValueNameAt(int index, std::wstring* name) const { - wchar_t buf[256]; - DWORD bufsize = arraysize(buf); - LONG r = ::RegEnumValue(key_, index, buf, &bufsize, NULL, NULL, NULL, NULL); - if (r == ERROR_SUCCESS) - *name = buf; - - return r; -} - -LONG RegKey::DeleteKey(const wchar_t* name) { - DCHECK(key_); - DCHECK(name); - LONG result = SHDeleteKey(key_, name); - return result; -} - -LONG RegKey::DeleteValue(const wchar_t* value_name) { - DCHECK(key_); - LONG result = RegDeleteValue(key_, value_name); - return result; -} - -LONG RegKey::ReadValueDW(const wchar_t* name, DWORD* out_value) const { - DCHECK(out_value); - DWORD type = REG_DWORD; - DWORD size = sizeof(DWORD); - DWORD local_value = 0; - LONG result = ReadValue(name, &local_value, &size, &type); - if (result == ERROR_SUCCESS) { - if ((type == REG_DWORD || type == REG_BINARY) && size == sizeof(DWORD)) - *out_value = local_value; - else - result = ERROR_CANTREAD; - } - - return result; -} - -LONG RegKey::ReadInt64(const wchar_t* name, int64* out_value) const { - DCHECK(out_value); - DWORD type = REG_QWORD; - int64 local_value = 0; - DWORD size = sizeof(local_value); - LONG result = ReadValue(name, &local_value, &size, &type); - if (result == ERROR_SUCCESS) { - if ((type == REG_QWORD || type == REG_BINARY) && - size == sizeof(local_value)) - *out_value = local_value; - else - result = ERROR_CANTREAD; - } - - return result; -} - -LONG RegKey::ReadValue(const wchar_t* name, std::wstring* out_value) const { - DCHECK(out_value); - const size_t kMaxStringLength = 1024; // This is after expansion. - // Use the one of the other forms of ReadValue if 1024 is too small for you. - wchar_t raw_value[kMaxStringLength]; - DWORD type = REG_SZ, size = sizeof(raw_value); - LONG result = ReadValue(name, raw_value, &size, &type); - if (result == ERROR_SUCCESS) { - if (type == REG_SZ) { - *out_value = raw_value; - } else if (type == REG_EXPAND_SZ) { - wchar_t expanded[kMaxStringLength]; - size = ExpandEnvironmentStrings(raw_value, expanded, kMaxStringLength); - // Success: returns the number of wchar_t's copied - // Fail: buffer too small, returns the size required - // Fail: other, returns 0 - if (size == 0 || size > kMaxStringLength) { - result = ERROR_MORE_DATA; - } else { - *out_value = expanded; - } - } else { - // Not a string. Oops. - result = ERROR_CANTREAD; - } - } - - return result; -} - -LONG RegKey::ReadValue(const wchar_t* name, - void* data, - DWORD* dsize, - DWORD* dtype) const { - LONG result = RegQueryValueEx(key_, name, 0, dtype, - reinterpret_cast(data), dsize); - return result; -} - -LONG RegKey::ReadValues(const wchar_t* name, - std::vector* values) { - values->clear(); - - DWORD type = REG_MULTI_SZ; - DWORD size = 0; - LONG result = ReadValue(name, NULL, &size, &type); - if (FAILED(result) || size == 0) - return result; - - if (type != REG_MULTI_SZ) - return ERROR_CANTREAD; - - std::vector buffer(size / sizeof(wchar_t)); - result = ReadValue(name, &buffer[0], &size, NULL); - if (FAILED(result) || size == 0) - return result; - - // Parse the double-null-terminated list of strings. - // Note: This code is paranoid to not read outside of |buf|, in the case where - // it may not be properly terminated. - const wchar_t* entry = &buffer[0]; - const wchar_t* buffer_end = entry + (size / sizeof(wchar_t)); - while (entry < buffer_end && entry[0] != '\0') { - const wchar_t* entry_end = std::find(entry, buffer_end, L'\0'); - values->push_back(std::wstring(entry, entry_end)); - entry = entry_end + 1; - } - return 0; -} - -LONG RegKey::WriteValue(const wchar_t* name, DWORD in_value) { - return WriteValue( - name, &in_value, static_cast(sizeof(in_value)), REG_DWORD); -} - -LONG RegKey::WriteValue(const wchar_t * name, const wchar_t* in_value) { - return WriteValue(name, in_value, - static_cast(sizeof(*in_value) * (wcslen(in_value) + 1)), REG_SZ); -} - -LONG RegKey::WriteValue(const wchar_t* name, - const void* data, - DWORD dsize, - DWORD dtype) { - DCHECK(data || !dsize); - - LONG result = RegSetValueEx(key_, name, 0, dtype, - reinterpret_cast(const_cast(data)), dsize); - return result; -} - -LONG RegKey::StartWatching() { - DCHECK(key_); - if (!watch_event_) - watch_event_ = CreateEvent(NULL, TRUE, FALSE, NULL); - - DWORD filter = REG_NOTIFY_CHANGE_NAME | - REG_NOTIFY_CHANGE_ATTRIBUTES | - REG_NOTIFY_CHANGE_LAST_SET | - REG_NOTIFY_CHANGE_SECURITY; - - // Watch the registry key for a change of value. - LONG result = RegNotifyChangeKeyValue(key_, TRUE, filter, watch_event_, TRUE); - if (result != ERROR_SUCCESS) { - CloseHandle(watch_event_); - watch_event_ = 0; - } - - return result; -} - -bool RegKey::HasChanged() { - if (watch_event_) { - if (WaitForSingleObject(watch_event_, 0) == WAIT_OBJECT_0) { - StartWatching(); - return true; - } - } - return false; -} - -LONG RegKey::StopWatching() { - LONG result = ERROR_INVALID_HANDLE; - if (watch_event_) { - CloseHandle(watch_event_); - watch_event_ = 0; - result = ERROR_SUCCESS; - } - return result; -} - -// RegistryValueIterator ------------------------------------------------------ - -RegistryValueIterator::RegistryValueIterator(HKEY root_key, - const wchar_t* folder_key) - : name_(MAX_PATH, L'\0'), - value_(MAX_PATH, L'\0') { - LONG result = RegOpenKeyEx(root_key, folder_key, 0, KEY_READ, &key_); - if (result != ERROR_SUCCESS) { - key_ = NULL; - } else { - DWORD count = 0; - result = ::RegQueryInfoKey(key_, NULL, 0, NULL, NULL, NULL, NULL, &count, - NULL, NULL, NULL, NULL); - - if (result != ERROR_SUCCESS) { - ::RegCloseKey(key_); - key_ = NULL; - } else { - index_ = count - 1; - } - } - - Read(); -} - -RegistryValueIterator::~RegistryValueIterator() { - if (key_) - ::RegCloseKey(key_); -} - -DWORD RegistryValueIterator::ValueCount() const { - DWORD count = 0; - LONG result = ::RegQueryInfoKey(key_, NULL, 0, NULL, NULL, NULL, NULL, - &count, NULL, NULL, NULL, NULL); - if (result != ERROR_SUCCESS) - return 0; - - return count; -} - -bool RegistryValueIterator::Valid() const { - return key_ != NULL && index_ >= 0; -} - -void RegistryValueIterator::operator++() { - --index_; - Read(); -} - -bool RegistryValueIterator::Read() { - if (Valid()) { - DWORD capacity = static_cast(name_.capacity()); - DWORD name_size = capacity; - // |value_size_| is in bytes. Reserve the last character for a NUL. - value_size_ = static_cast((value_.size() - 1) * sizeof(wchar_t)); - LONG result = ::RegEnumValue( - key_, index_, WriteInto(&name_, name_size), &name_size, NULL, &type_, - reinterpret_cast(vector_as_array(&value_)), &value_size_); - - if (result == ERROR_MORE_DATA) { - // Registry key names are limited to 255 characters and fit within - // MAX_PATH (which is 260) but registry value names can use up to 16,383 - // characters and the value itself is not limited - // (from http://msdn.microsoft.com/en-us/library/windows/desktop/ - // ms724872(v=vs.85).aspx). - // Resize the buffers and retry if their size caused the failure. - DWORD value_size_in_wchars = to_wchar_size(value_size_); - if (value_size_in_wchars + 1 > value_.size()) - value_.resize(value_size_in_wchars + 1, L'\0'); - value_size_ = static_cast((value_.size() - 1) * sizeof(wchar_t)); - name_size = name_size == capacity ? MAX_REGISTRY_NAME_SIZE : capacity; - result = ::RegEnumValue( - key_, index_, WriteInto(&name_, name_size), &name_size, NULL, &type_, - reinterpret_cast(vector_as_array(&value_)), &value_size_); - } - - if (result == ERROR_SUCCESS) { - DCHECK_LT(to_wchar_size(value_size_), value_.size()); - value_[to_wchar_size(value_size_)] = L'\0'; - return true; - } - } - - name_[0] = L'\0'; - value_[0] = L'\0'; - value_size_ = 0; - return false; -} - -// RegistryKeyIterator -------------------------------------------------------- - -RegistryKeyIterator::RegistryKeyIterator(HKEY root_key, - const wchar_t* folder_key) { - LONG result = RegOpenKeyEx(root_key, folder_key, 0, KEY_READ, &key_); - if (result != ERROR_SUCCESS) { - key_ = NULL; - } else { - DWORD count = 0; - LONG result = ::RegQueryInfoKey(key_, NULL, 0, NULL, &count, NULL, NULL, - NULL, NULL, NULL, NULL, NULL); - - if (result != ERROR_SUCCESS) { - ::RegCloseKey(key_); - key_ = NULL; - } else { - index_ = count - 1; - } - } - - Read(); -} - -RegistryKeyIterator::~RegistryKeyIterator() { - if (key_) - ::RegCloseKey(key_); -} - -DWORD RegistryKeyIterator::SubkeyCount() const { - DWORD count = 0; - LONG result = ::RegQueryInfoKey(key_, NULL, 0, NULL, &count, NULL, NULL, - NULL, NULL, NULL, NULL, NULL); - if (result != ERROR_SUCCESS) - return 0; - - return count; -} - -bool RegistryKeyIterator::Valid() const { - return key_ != NULL && index_ >= 0; -} - -void RegistryKeyIterator::operator++() { - --index_; - Read(); -} - -bool RegistryKeyIterator::Read() { - if (Valid()) { - DWORD ncount = arraysize(name_); - FILETIME written; - LONG r = ::RegEnumKeyEx(key_, index_, name_, &ncount, NULL, NULL, - NULL, &written); - if (ERROR_SUCCESS == r) - return true; - } - - name_[0] = '\0'; - return false; -} - -} // namespace win -} // namespace base diff --git a/base/win/registry.h b/base/win/registry.h deleted file mode 100644 index f97f4f5a37..0000000000 --- a/base/win/registry.h +++ /dev/null @@ -1,219 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef BASE_WIN_REGISTRY_H_ -#define BASE_WIN_REGISTRY_H_ - -#include -#include -#include - -#include "base/base_export.h" -#include "base/basictypes.h" -#include "base/stl_util.h" - -namespace base { -namespace win { - -// Utility class to read, write and manipulate the Windows Registry. -// Registry vocabulary primer: a "key" is like a folder, in which there -// are "values", which are pairs, with an associated data type. -// -// Note: -// ReadValue family of functions guarantee that the return arguments -// are not touched in case of failure. -class BASE_EXPORT RegKey { - public: - RegKey(); - explicit RegKey(HKEY key); - RegKey(HKEY rootkey, const wchar_t* subkey, REGSAM access); - ~RegKey(); - - LONG Create(HKEY rootkey, const wchar_t* subkey, REGSAM access); - - LONG CreateWithDisposition(HKEY rootkey, const wchar_t* subkey, - DWORD* disposition, REGSAM access); - - // Creates a subkey or open it if it already exists. - LONG CreateKey(const wchar_t* name, REGSAM access); - - // Opens an existing reg key. - LONG Open(HKEY rootkey, const wchar_t* subkey, REGSAM access); - - // Opens an existing reg key, given the relative key name. - LONG OpenKey(const wchar_t* relative_key_name, REGSAM access); - - // Closes this reg key. - void Close(); - - // Replaces the handle of the registry key and takes ownership of the handle. - void Set(HKEY key); - - // Transfers ownership away from this object. - HKEY Take(); - - // Returns false if this key does not have the specified value, of if an error - // occurrs while attempting to access it. - bool HasValue(const wchar_t* value_name) const; - - // Returns the number of values for this key, of 0 if the number cannot be - // determined. - DWORD GetValueCount() const; - - // Determine the nth value's name. - LONG GetValueNameAt(int index, std::wstring* name) const; - - // True while the key is valid. - bool Valid() const { return key_ != NULL; } - - // Kill a key and everything that live below it; please be careful when using - // it. - LONG DeleteKey(const wchar_t* name); - - // Deletes a single value within the key. - LONG DeleteValue(const wchar_t* name); - - // Getters: - - // Returns an int32 value. If |name| is NULL or empty, returns the default - // value, if any. - LONG ReadValueDW(const wchar_t* name, DWORD* out_value) const; - - // Returns an int64 value. If |name| is NULL or empty, returns the default - // value, if any. - LONG ReadInt64(const wchar_t* name, int64* out_value) const; - - // Returns a string value. If |name| is NULL or empty, returns the default - // value, if any. - LONG ReadValue(const wchar_t* name, std::wstring* out_value) const; - - // Reads a REG_MULTI_SZ registry field into a vector of strings. Clears - // |values| initially and adds further strings to the list. Returns - // ERROR_CANTREAD if type is not REG_MULTI_SZ. - LONG ReadValues(const wchar_t* name, std::vector* values); - - // Returns raw data. If |name| is NULL or empty, returns the default - // value, if any. - LONG ReadValue(const wchar_t* name, - void* data, - DWORD* dsize, - DWORD* dtype) const; - - // Setters: - - // Sets an int32 value. - LONG WriteValue(const wchar_t* name, DWORD in_value); - - // Sets a string value. - LONG WriteValue(const wchar_t* name, const wchar_t* in_value); - - // Sets raw data, including type. - LONG WriteValue(const wchar_t* name, - const void* data, - DWORD dsize, - DWORD dtype); - - // Starts watching the key to see if any of its values have changed. - // The key must have been opened with the KEY_NOTIFY access privilege. - LONG StartWatching(); - - // If StartWatching hasn't been called, always returns false. - // Otherwise, returns true if anything under the key has changed. - // This can't be const because the |watch_event_| may be refreshed. - bool HasChanged(); - - // Will automatically be called by destructor if not manually called - // beforehand. Returns true if it was watching, false otherwise. - LONG StopWatching(); - - inline bool IsWatching() const { return watch_event_ != 0; } - HANDLE watch_event() const { return watch_event_; } - HKEY Handle() const { return key_; } - - private: - HKEY key_; // The registry key being iterated. - HANDLE watch_event_; - - DISALLOW_COPY_AND_ASSIGN(RegKey); -}; - -// Iterates the entries found in a particular folder on the registry. -class BASE_EXPORT RegistryValueIterator { - public: - RegistryValueIterator(HKEY root_key, const wchar_t* folder_key); - - ~RegistryValueIterator(); - - DWORD ValueCount() const; - - // True while the iterator is valid. - bool Valid() const; - - // Advances to the next registry entry. - void operator++(); - - const wchar_t* Name() const { return name_.c_str(); } - const wchar_t* Value() const { return vector_as_array(&value_); } - // ValueSize() is in bytes. - DWORD ValueSize() const { return value_size_; } - DWORD Type() const { return type_; } - - int Index() const { return index_; } - - private: - // Read in the current values. - bool Read(); - - // The registry key being iterated. - HKEY key_; - - // Current index of the iteration. - int index_; - - // Current values. - std::wstring name_; - std::vector value_; - DWORD value_size_; - DWORD type_; - - DISALLOW_COPY_AND_ASSIGN(RegistryValueIterator); -}; - -class BASE_EXPORT RegistryKeyIterator { - public: - RegistryKeyIterator(HKEY root_key, const wchar_t* folder_key); - - ~RegistryKeyIterator(); - - DWORD SubkeyCount() const; - - // True while the iterator is valid. - bool Valid() const; - - // Advances to the next entry in the folder. - void operator++(); - - const wchar_t* Name() const { return name_; } - - int Index() const { return index_; } - - private: - // Read in the current values. - bool Read(); - - // The registry key being iterated. - HKEY key_; - - // Current index of the iteration. - int index_; - - wchar_t name_[MAX_PATH]; - - DISALLOW_COPY_AND_ASSIGN(RegistryKeyIterator); -}; - -} // namespace win -} // namespace base - -#endif // BASE_WIN_REGISTRY_H_ diff --git a/base/win/registry_unittest.cc b/base/win/registry_unittest.cc deleted file mode 100644 index 155402a351..0000000000 --- a/base/win/registry_unittest.cc +++ /dev/null @@ -1,164 +0,0 @@ -// Copyright (c) 2011 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "base/win/registry.h" - -#include -#include - -#include "base/compiler_specific.h" -#include "base/stl_util.h" -#include "testing/gtest/include/gtest/gtest.h" - -namespace base { -namespace win { - -namespace { - -const wchar_t kRootKey[] = L"Base_Registry_Unittest"; - -class RegistryTest : public testing::Test { - public: - RegistryTest() {} - - protected: - virtual void SetUp() OVERRIDE { - // Create a temporary key. - RegKey key(HKEY_CURRENT_USER, L"", KEY_ALL_ACCESS); - key.DeleteKey(kRootKey); - ASSERT_NE(ERROR_SUCCESS, key.Open(HKEY_CURRENT_USER, kRootKey, KEY_READ)); - ASSERT_EQ(ERROR_SUCCESS, key.Create(HKEY_CURRENT_USER, kRootKey, KEY_READ)); - } - - virtual void TearDown() OVERRIDE { - // Clean up the temporary key. - RegKey key(HKEY_CURRENT_USER, L"", KEY_SET_VALUE); - ASSERT_EQ(ERROR_SUCCESS, key.DeleteKey(kRootKey)); - } - - private: - DISALLOW_COPY_AND_ASSIGN(RegistryTest); -}; - -TEST_F(RegistryTest, ValueTest) { - RegKey key; - - std::wstring foo_key(kRootKey); - foo_key += L"\\Foo"; - ASSERT_EQ(ERROR_SUCCESS, key.Create(HKEY_CURRENT_USER, foo_key.c_str(), - KEY_READ)); - - { - ASSERT_EQ(ERROR_SUCCESS, key.Open(HKEY_CURRENT_USER, foo_key.c_str(), - KEY_READ | KEY_SET_VALUE)); - ASSERT_TRUE(key.Valid()); - - const wchar_t kStringValueName[] = L"StringValue"; - const wchar_t kDWORDValueName[] = L"DWORDValue"; - const wchar_t kInt64ValueName[] = L"Int64Value"; - const wchar_t kStringData[] = L"string data"; - const DWORD kDWORDData = 0xdeadbabe; - const int64 kInt64Data = 0xdeadbabedeadbabeLL; - - // Test value creation - ASSERT_EQ(ERROR_SUCCESS, key.WriteValue(kStringValueName, kStringData)); - ASSERT_EQ(ERROR_SUCCESS, key.WriteValue(kDWORDValueName, kDWORDData)); - ASSERT_EQ(ERROR_SUCCESS, key.WriteValue(kInt64ValueName, &kInt64Data, - sizeof(kInt64Data), REG_QWORD)); - EXPECT_EQ(3U, key.GetValueCount()); - EXPECT_TRUE(key.HasValue(kStringValueName)); - EXPECT_TRUE(key.HasValue(kDWORDValueName)); - EXPECT_TRUE(key.HasValue(kInt64ValueName)); - - // Test Read - std::wstring string_value; - DWORD dword_value = 0; - int64 int64_value = 0; - ASSERT_EQ(ERROR_SUCCESS, key.ReadValue(kStringValueName, &string_value)); - ASSERT_EQ(ERROR_SUCCESS, key.ReadValueDW(kDWORDValueName, &dword_value)); - ASSERT_EQ(ERROR_SUCCESS, key.ReadInt64(kInt64ValueName, &int64_value)); - EXPECT_STREQ(kStringData, string_value.c_str()); - EXPECT_EQ(kDWORDData, dword_value); - EXPECT_EQ(kInt64Data, int64_value); - - // Make sure out args are not touched if ReadValue fails - const wchar_t* kNonExistent = L"NonExistent"; - ASSERT_NE(ERROR_SUCCESS, key.ReadValue(kNonExistent, &string_value)); - ASSERT_NE(ERROR_SUCCESS, key.ReadValueDW(kNonExistent, &dword_value)); - ASSERT_NE(ERROR_SUCCESS, key.ReadInt64(kNonExistent, &int64_value)); - EXPECT_STREQ(kStringData, string_value.c_str()); - EXPECT_EQ(kDWORDData, dword_value); - EXPECT_EQ(kInt64Data, int64_value); - - // Test delete - ASSERT_EQ(ERROR_SUCCESS, key.DeleteValue(kStringValueName)); - ASSERT_EQ(ERROR_SUCCESS, key.DeleteValue(kDWORDValueName)); - ASSERT_EQ(ERROR_SUCCESS, key.DeleteValue(kInt64ValueName)); - EXPECT_EQ(0U, key.GetValueCount()); - EXPECT_FALSE(key.HasValue(kStringValueName)); - EXPECT_FALSE(key.HasValue(kDWORDValueName)); - EXPECT_FALSE(key.HasValue(kInt64ValueName)); - } -} - -TEST_F(RegistryTest, BigValueIteratorTest) { - RegKey key; - std::wstring foo_key(kRootKey); - foo_key += L"\\Foo"; - ASSERT_EQ(ERROR_SUCCESS, key.Create(HKEY_CURRENT_USER, foo_key.c_str(), - KEY_READ)); - ASSERT_EQ(ERROR_SUCCESS, key.Open(HKEY_CURRENT_USER, foo_key.c_str(), - KEY_READ | KEY_SET_VALUE)); - ASSERT_TRUE(key.Valid()); - - // Create a test value that is larger than MAX_PATH. - std::wstring data(MAX_PATH * 2, L'a'); - - ASSERT_EQ(ERROR_SUCCESS, key.WriteValue(data.c_str(), data.c_str())); - - RegistryValueIterator iterator(HKEY_CURRENT_USER, foo_key.c_str()); - ASSERT_TRUE(iterator.Valid()); - EXPECT_STREQ(data.c_str(), iterator.Name()); - EXPECT_STREQ(data.c_str(), iterator.Value()); - // ValueSize() is in bytes, including NUL. - EXPECT_EQ((MAX_PATH * 2 + 1) * sizeof(wchar_t), iterator.ValueSize()); - ++iterator; - EXPECT_FALSE(iterator.Valid()); -} - -TEST_F(RegistryTest, TruncatedCharTest) { - RegKey key; - std::wstring foo_key(kRootKey); - foo_key += L"\\Foo"; - ASSERT_EQ(ERROR_SUCCESS, key.Create(HKEY_CURRENT_USER, foo_key.c_str(), - KEY_READ)); - ASSERT_EQ(ERROR_SUCCESS, key.Open(HKEY_CURRENT_USER, foo_key.c_str(), - KEY_READ | KEY_SET_VALUE)); - ASSERT_TRUE(key.Valid()); - - const wchar_t kName[] = L"name"; - // kData size is not a multiple of sizeof(wchar_t). - const uint8 kData[] = { 1, 2, 3, 4, 5 }; - EXPECT_EQ(5, arraysize(kData)); - ASSERT_EQ(ERROR_SUCCESS, key.WriteValue(kName, kData, - arraysize(kData), REG_BINARY)); - - RegistryValueIterator iterator(HKEY_CURRENT_USER, foo_key.c_str()); - ASSERT_TRUE(iterator.Valid()); - EXPECT_STREQ(kName, iterator.Name()); - // ValueSize() is in bytes. - ASSERT_EQ(arraysize(kData), iterator.ValueSize()); - // Value() is NUL terminated. - int end = (iterator.ValueSize() + sizeof(wchar_t) - 1) / sizeof(wchar_t); - EXPECT_NE(L'\0', iterator.Value()[end-1]); - EXPECT_EQ(L'\0', iterator.Value()[end]); - EXPECT_EQ(0, std::memcmp(kData, iterator.Value(), arraysize(kData))); - ++iterator; - EXPECT_FALSE(iterator.Valid()); -} - -} // namespace - -} // namespace win -} // namespace base diff --git a/base/win/resource_util.cc b/base/win/resource_util.cc deleted file mode 100644 index 0c100785e7..0000000000 --- a/base/win/resource_util.cc +++ /dev/null @@ -1,51 +0,0 @@ -// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "base/logging.h" -#include "base/win/resource_util.h" - -namespace base { -namespace win { - -bool GetResourceFromModule(HMODULE module, - int resource_id, - LPCTSTR resource_type, - void** data, - size_t* length) { - if (!module) - return false; - - if (!IS_INTRESOURCE(resource_id)) { - NOTREACHED(); - return false; - } - - HRSRC hres_info = FindResource(module, MAKEINTRESOURCE(resource_id), - resource_type); - if (NULL == hres_info) - return false; - - DWORD data_size = SizeofResource(module, hres_info); - HGLOBAL hres = LoadResource(module, hres_info); - if (!hres) - return false; - - void* resource = LockResource(hres); - if (!resource) - return false; - - *data = resource; - *length = static_cast(data_size); - return true; -} - -bool GetDataResourceFromModule(HMODULE module, - int resource_id, - void** data, - size_t* length) { - return GetResourceFromModule(module, resource_id, L"BINDATA", data, length); -} - -} // namespace win -} // namespace base diff --git a/base/win/resource_util.h b/base/win/resource_util.h deleted file mode 100644 index f3444ae79f..0000000000 --- a/base/win/resource_util.h +++ /dev/null @@ -1,39 +0,0 @@ -// Copyright (c) 2011 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -// This file contains utility functions for accessing resources in external -// files (DLLs) or embedded in the executable itself. - -#ifndef BASE_WIN_RESOURCE_UTIL_H__ -#define BASE_WIN_RESOURCE_UTIL_H__ - -#include - -#include "base/base_export.h" -#include "base/basictypes.h" - -namespace base { -namespace win { - -// Function for getting a data resource of the specified |resource_type| from -// a dll. Some resources are optional, especially in unit tests, so this -// returns false but doesn't raise an error if the resource can't be loaded. -bool BASE_EXPORT GetResourceFromModule(HMODULE module, - int resource_id, - LPCTSTR resource_type, - void** data, - size_t* length); - -// Function for getting a data resource (BINDATA) from a dll. Some -// resources are optional, especially in unit tests, so this returns false -// but doesn't raise an error if the resource can't be loaded. -bool BASE_EXPORT GetDataResourceFromModule(HMODULE module, - int resource_id, - void** data, - size_t* length); - -} // namespace win -} // namespace base - -#endif // BASE_WIN_RESOURCE_UTIL_H__ diff --git a/base/win/sampling_profiler.cc b/base/win/sampling_profiler.cc deleted file mode 100644 index 150452c447..0000000000 --- a/base/win/sampling_profiler.cc +++ /dev/null @@ -1,238 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "base/win/sampling_profiler.h" - -#include // for NTSTATUS. - -#include "base/lazy_instance.h" - -// Copied from wdm.h in the WDK as we don't want to take -// a dependency on the WDK. -typedef enum _KPROFILE_SOURCE { - ProfileTime, - ProfileAlignmentFixup, - ProfileTotalIssues, - ProfilePipelineDry, - ProfileLoadInstructions, - ProfilePipelineFrozen, - ProfileBranchInstructions, - ProfileTotalNonissues, - ProfileDcacheMisses, - ProfileIcacheMisses, - ProfileCacheMisses, - ProfileBranchMispredictions, - ProfileStoreInstructions, - ProfileFpInstructions, - ProfileIntegerInstructions, - Profile2Issue, - Profile3Issue, - Profile4Issue, - ProfileSpecialInstructions, - ProfileTotalCycles, - ProfileIcacheIssues, - ProfileDcacheAccesses, - ProfileMemoryBarrierCycles, - ProfileLoadLinkedIssues, - ProfileMaximum -} KPROFILE_SOURCE; - - -namespace { - -// Signatures for the native functions we need to access the sampling profiler. -typedef NTSTATUS (NTAPI *ZwSetIntervalProfileFunc)(ULONG, KPROFILE_SOURCE); -typedef NTSTATUS (NTAPI *ZwQueryIntervalProfileFunc)(KPROFILE_SOURCE, PULONG); - -typedef NTSTATUS (NTAPI *ZwCreateProfileFunc)(PHANDLE profile, - HANDLE process, - PVOID code_start, - ULONG code_size, - ULONG eip_bucket_shift, - PULONG buckets, - ULONG buckets_byte_size, - KPROFILE_SOURCE source, - DWORD_PTR processor_mask); - -typedef NTSTATUS (NTAPI *ZwStartProfileFunc)(HANDLE); -typedef NTSTATUS (NTAPI *ZwStopProfileFunc)(HANDLE); - -// This class is used to lazy-initialize pointers to the native -// functions we need to access. -class ProfilerFuncs { - public: - ProfilerFuncs(); - - ZwSetIntervalProfileFunc ZwSetIntervalProfile; - ZwQueryIntervalProfileFunc ZwQueryIntervalProfile; - ZwCreateProfileFunc ZwCreateProfile; - ZwStartProfileFunc ZwStartProfile; - ZwStopProfileFunc ZwStopProfile; - - // True iff all of the function pointers above were successfully initialized. - bool initialized_; -}; - -ProfilerFuncs::ProfilerFuncs() - : ZwSetIntervalProfile(NULL), - ZwQueryIntervalProfile(NULL), - ZwCreateProfile(NULL), - ZwStartProfile(NULL), - ZwStopProfile(NULL), - initialized_(false) { - HMODULE ntdll = ::GetModuleHandle(L"ntdll.dll"); - if (ntdll != NULL) { - ZwSetIntervalProfile = reinterpret_cast( - ::GetProcAddress(ntdll, "ZwSetIntervalProfile")); - ZwQueryIntervalProfile = reinterpret_cast( - ::GetProcAddress(ntdll, "ZwQueryIntervalProfile")); - ZwCreateProfile = reinterpret_cast( - ::GetProcAddress(ntdll, "ZwCreateProfile")); - ZwStartProfile = reinterpret_cast( - ::GetProcAddress(ntdll, "ZwStartProfile")); - ZwStopProfile = reinterpret_cast( - ::GetProcAddress(ntdll, "ZwStopProfile")); - - if (ZwSetIntervalProfile && - ZwQueryIntervalProfile && - ZwCreateProfile && - ZwStartProfile && - ZwStopProfile) { - initialized_ = true; - } - } -} - -base::LazyInstance::Leaky funcs = LAZY_INSTANCE_INITIALIZER; - -} // namespace - - -namespace base { -namespace win { - -SamplingProfiler::SamplingProfiler() : is_started_(false) { -} - -SamplingProfiler::~SamplingProfiler() { - if (is_started_) { - CHECK(Stop()) << - "Unable to stop sampling profiler, this will cause memory corruption."; - } -} - -bool SamplingProfiler::Initialize(HANDLE process, - void* start, - size_t size, - size_t log2_bucket_size) { - // You only get to initialize each instance once. - DCHECK(!profile_handle_.IsValid()); - DCHECK(!is_started_); - DCHECK(start != NULL); - DCHECK_NE(0U, size); - DCHECK_LE(2, log2_bucket_size); - DCHECK_GE(32, log2_bucket_size); - - // Bail if the native functions weren't found. - if (!funcs.Get().initialized_) - return false; - - size_t bucket_size = 1 << log2_bucket_size; - size_t num_buckets = (size + bucket_size - 1) / bucket_size; - DCHECK(num_buckets != 0); - buckets_.resize(num_buckets); - - // Get our affinity mask for the call below. - DWORD_PTR process_affinity = 0; - DWORD_PTR system_affinity = 0; - if (!::GetProcessAffinityMask(process, &process_affinity, &system_affinity)) { - LOG(ERROR) << "Failed to get process affinity mask."; - return false; - } - - HANDLE profile = NULL; - NTSTATUS status = - funcs.Get().ZwCreateProfile(&profile, - process, - start, - static_cast(size), - static_cast(log2_bucket_size), - &buckets_[0], - static_cast( - sizeof(buckets_[0]) * num_buckets), - ProfileTime, - process_affinity); - - if (!NT_SUCCESS(status)) { - // Might as well deallocate the buckets. - buckets_.resize(0); - LOG(ERROR) << "Failed to create profile, error 0x" << std::hex << status; - return false; - } - - DCHECK(profile != NULL); - profile_handle_.Set(profile); - - return true; -} - -bool SamplingProfiler::Start() { - DCHECK(profile_handle_.IsValid()); - DCHECK(!is_started_); - DCHECK(funcs.Get().initialized_); - - NTSTATUS status = funcs.Get().ZwStartProfile(profile_handle_.Get()); - if (!NT_SUCCESS(status)) - return false; - - is_started_ = true; - - return true; -} - -bool SamplingProfiler::Stop() { - DCHECK(profile_handle_.IsValid()); - DCHECK(is_started_); - DCHECK(funcs.Get().initialized_); - - NTSTATUS status = funcs.Get().ZwStopProfile(profile_handle_.Get()); - if (!NT_SUCCESS(status)) - return false; - is_started_ = false; - - return true; -} - -bool SamplingProfiler::SetSamplingInterval(base::TimeDelta sampling_interval) { - if (!funcs.Get().initialized_) - return false; - - // According to Nebbet, the sampling interval is in units of 100ns. - ULONG interval = sampling_interval.InMicroseconds() * 10; - NTSTATUS status = funcs.Get().ZwSetIntervalProfile(interval, ProfileTime); - if (!NT_SUCCESS(status)) - return false; - - return true; -} - -bool SamplingProfiler::GetSamplingInterval(base::TimeDelta* sampling_interval) { - DCHECK(sampling_interval != NULL); - - if (!funcs.Get().initialized_) - return false; - - ULONG interval = 0; - NTSTATUS status = funcs.Get().ZwQueryIntervalProfile(ProfileTime, &interval); - if (!NT_SUCCESS(status)) - return false; - - // According to Nebbet, the sampling interval is in units of 100ns. - *sampling_interval = base::TimeDelta::FromMicroseconds(interval / 10); - - return true; -} - -} // namespace win -} // namespace base diff --git a/base/win/sampling_profiler.h b/base/win/sampling_profiler.h deleted file mode 100644 index 1950ef5256..0000000000 --- a/base/win/sampling_profiler.h +++ /dev/null @@ -1,73 +0,0 @@ -// Copyright (c) 2011 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef BASE_WIN_SAMPLING_PROFILER_H_ -#define BASE_WIN_SAMPLING_PROFILER_H_ - -#include - -#include "base/basictypes.h" -#include "base/time/time.h" -#include "base/win/scoped_handle.h" - -namespace base { -namespace win { - -// This class exposes the functionality of Window's built-in sampling profiler. -// Each profiler instance covers a range of memory, and while the profiler is -// running, its buckets will count the number of times the instruction counter -// lands in the associated range of memory on a sample. -// The sampling interval is settable, but the setting is system-wide. -class BASE_EXPORT SamplingProfiler { - public: - // Create an uninitialized sampling profiler. - SamplingProfiler(); - ~SamplingProfiler(); - - // Initializes the profiler to cover the memory range |start| through - // |start| + |size|, in the process |process_handle| with bucket size - // |2^log2_bucket_size|, |log2_bucket_size| must be in the range 2-31, - // for bucket sizes of 4 bytes to 2 gigabytes. - // The process handle must grant at least PROCESS_QUERY_INFORMATION. - // The memory range should be exectuable code, like e.g. the text segment - // of an exectuable (whether DLL or EXE). - // Returns true on success. - bool Initialize(HANDLE process_handle, - void* start, - size_t size, - size_t log2_bucket_size); - - // Start this profiler, which must be initialized and not started. - bool Start(); - // Stop this profiler, which must be started. - bool Stop(); - - // Get and set the sampling interval. - // Note that this is a system-wide setting. - static bool SetSamplingInterval(base::TimeDelta sampling_interval); - static bool GetSamplingInterval(base::TimeDelta* sampling_interval); - - // Accessors. - bool is_started() const { return is_started_; } - - // It is safe to read the counts in the sampling buckets at any time. - // Note however that there's no guarantee that you'll read consistent counts - // until the profiler has been stopped, as the counts may be updating on other - // CPU cores. - const std::vector& buckets() const { return buckets_; } - - private: - // Handle to the corresponding kernel object. - ScopedHandle profile_handle_; - // True iff this profiler is started. - bool is_started_; - std::vector buckets_; - - DISALLOW_COPY_AND_ASSIGN(SamplingProfiler); -}; - -} // namespace win -} // namespace base - -#endif // BASE_WIN_SAMPLING_PROFILER_H_ diff --git a/base/win/sampling_profiler_unittest.cc b/base/win/sampling_profiler_unittest.cc deleted file mode 100644 index d022026342..0000000000 --- a/base/win/sampling_profiler_unittest.cc +++ /dev/null @@ -1,120 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "base/logging.h" -#include "base/test/test_timeouts.h" -#include "base/win/sampling_profiler.h" -#include "base/win/pe_image.h" -#include "base/win/scoped_handle.h" -#include "base/win/windows_version.h" -#include "testing/gtest/include/gtest/gtest.h" - -// The address of our image base. -extern "C" IMAGE_DOS_HEADER __ImageBase; - -namespace base { -namespace win { - -namespace { - -class SamplingProfilerTest : public testing::Test { - public: - SamplingProfilerTest() : code_start(NULL), code_size(0) { - } - - virtual void SetUp() { - process.Set(::OpenProcess(PROCESS_QUERY_INFORMATION, - FALSE, - ::GetCurrentProcessId())); - ASSERT_TRUE(process.IsValid()); - - PEImage image(&__ImageBase); - - // Get the address of the .text section, which is the first section output - // by the VS tools. - ASSERT_TRUE(image.GetNumSections() > 0); - const IMAGE_SECTION_HEADER* text_section = image.GetSectionHeader(0); - ASSERT_EQ(0, strncmp(".text", - reinterpret_cast(text_section->Name), - arraysize(text_section->Name))); - ASSERT_NE(0U, text_section->Characteristics & IMAGE_SCN_MEM_EXECUTE); - - code_start = reinterpret_cast(&__ImageBase) + - text_section->VirtualAddress; - code_size = text_section->Misc.VirtualSize; - } - - protected: - ScopedHandle process; - void* code_start; - size_t code_size; -}; - -} // namespace - -TEST_F(SamplingProfilerTest, Initialize) { - SamplingProfiler profiler; - - ASSERT_TRUE(profiler.Initialize(process.Get(), code_start, code_size, 8)); -} - -TEST_F(SamplingProfilerTest, Sample) { - if (base::win::GetVersion() == base::win::VERSION_WIN8) { - LOG(INFO) << "Not running test on Windows 8"; - return; - } - SamplingProfiler profiler; - - // Initialize with a huge bucket size, aiming for a single bucket. - ASSERT_TRUE( - profiler.Initialize(process.Get(), code_start, code_size, 31)); - - ASSERT_EQ(1, profiler.buckets().size()); - ASSERT_EQ(0, profiler.buckets()[0]); - - // We use a roomy timeout to make sure this test is not flaky. - // On the buildbots, there may not be a whole lot of CPU time - // allotted to our process in this wall-clock time duration, - // and samples will only accrue while this thread is busy on - // a CPU core. - base::TimeDelta spin_time = TestTimeouts::action_timeout(); - - base::TimeDelta save_sampling_interval; - ASSERT_TRUE(SamplingProfiler::GetSamplingInterval(&save_sampling_interval)); - - // Sample every 0.5 millisecs. - ASSERT_TRUE(SamplingProfiler::SetSamplingInterval( - base::TimeDelta::FromMicroseconds(500))); - - ASSERT_TRUE(SamplingProfiler::SetSamplingInterval( - base::TimeDelta::FromMicroseconds(500))); - - // Start the profiler. - ASSERT_TRUE(profiler.Start()); - - // Get a volatile pointer to our bucket to make sure that the compiler - // doesn't optimize out the test in the loop that follows. - volatile const ULONG* bucket_ptr = &profiler.buckets()[0]; - - // Spin for spin_time wall-clock seconds, or until we get some samples. - // Note that sleeping isn't going to do us any good, the samples only - // accrue while we're executing code. - base::Time start = base::Time::Now(); - base::TimeDelta elapsed; - do { - elapsed = base::Time::Now() - start; - } while((elapsed < spin_time) && *bucket_ptr == 0); - - // Stop the profiler. - ASSERT_TRUE(profiler.Stop()); - - // Restore the sampling interval we found. - ASSERT_TRUE(SamplingProfiler::SetSamplingInterval(save_sampling_interval)); - - // Check that we got some samples. - ASSERT_NE(0U, profiler.buckets()[0]); -} - -} // namespace win -} // namespace base diff --git a/base/win/scoped_bstr.cc b/base/win/scoped_bstr.cc deleted file mode 100644 index 63ade0cb42..0000000000 --- a/base/win/scoped_bstr.cc +++ /dev/null @@ -1,71 +0,0 @@ -// Copyright (c) 2010 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "base/win/scoped_bstr.h" - -#include "base/logging.h" - -namespace base { -namespace win { - -ScopedBstr::ScopedBstr(const char16* non_bstr) - : bstr_(SysAllocString(non_bstr)) { -} - -ScopedBstr::~ScopedBstr() { - COMPILE_ASSERT(sizeof(ScopedBstr) == sizeof(BSTR), ScopedBstrSize); - SysFreeString(bstr_); -} - -void ScopedBstr::Reset(BSTR bstr) { - if (bstr != bstr_) { - // if |bstr_| is NULL, SysFreeString does nothing. - SysFreeString(bstr_); - bstr_ = bstr; - } -} - -BSTR ScopedBstr::Release() { - BSTR bstr = bstr_; - bstr_ = NULL; - return bstr; -} - -void ScopedBstr::Swap(ScopedBstr& bstr2) { - BSTR tmp = bstr_; - bstr_ = bstr2.bstr_; - bstr2.bstr_ = tmp; -} - -BSTR* ScopedBstr::Receive() { - DCHECK(!bstr_) << "BSTR leak."; - return &bstr_; -} - -BSTR ScopedBstr::Allocate(const char16* str) { - Reset(SysAllocString(str)); - return bstr_; -} - -BSTR ScopedBstr::AllocateBytes(size_t bytes) { - Reset(SysAllocStringByteLen(NULL, static_cast(bytes))); - return bstr_; -} - -void ScopedBstr::SetByteLen(size_t bytes) { - DCHECK(bstr_ != NULL) << "attempting to modify a NULL bstr"; - uint32* data = reinterpret_cast(bstr_); - data[-1] = static_cast(bytes); -} - -size_t ScopedBstr::Length() const { - return SysStringLen(bstr_); -} - -size_t ScopedBstr::ByteLength() const { - return SysStringByteLen(bstr_); -} - -} // namespace win -} // namespace base diff --git a/base/win/scoped_bstr.h b/base/win/scoped_bstr.h deleted file mode 100644 index d703f62dac..0000000000 --- a/base/win/scoped_bstr.h +++ /dev/null @@ -1,97 +0,0 @@ -// Copyright (c) 2011 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef BASE_WIN_SCOPED_BSTR_H_ -#define BASE_WIN_SCOPED_BSTR_H_ - -#include -#include - -#include "base/base_export.h" -#include "base/logging.h" -#include "base/strings/string16.h" - -namespace base { -namespace win { - -// Manages a BSTR string pointer. -// The class interface is based on scoped_ptr. -class BASE_EXPORT ScopedBstr { - public: - ScopedBstr() : bstr_(NULL) { - } - - // Constructor to create a new BSTR. - // - // NOTE: Do not pass a BSTR to this constructor expecting ownership to - // be transferred - even though it compiles! ;-) - explicit ScopedBstr(const char16* non_bstr); - ~ScopedBstr(); - - // Give ScopedBstr ownership over an already allocated BSTR or NULL. - // If you need to allocate a new BSTR instance, use |allocate| instead. - void Reset(BSTR bstr = NULL); - - // Releases ownership of the BSTR to the caller. - BSTR Release(); - - // Creates a new BSTR from a 16-bit C-style string. - // - // If you already have a BSTR and want to transfer ownership to the - // ScopedBstr instance, call |reset| instead. - // - // Returns a pointer to the new BSTR, or NULL if allocation failed. - BSTR Allocate(const char16* str); - - // Allocates a new BSTR with the specified number of bytes. - // Returns a pointer to the new BSTR, or NULL if allocation failed. - BSTR AllocateBytes(size_t bytes); - - // Sets the allocated length field of the already-allocated BSTR to be - // |bytes|. This is useful when the BSTR was preallocated with e.g. - // SysAllocStringLen or SysAllocStringByteLen (call |AllocateBytes|) and then - // not all the bytes are being used. - // - // Note that if you want to set the length to a specific number of - // characters, you need to multiply by sizeof(wchar_t). Oddly, there's no - // public API to set the length, so we do this ourselves by hand. - // - // NOTE: The actual allocated size of the BSTR MUST be >= bytes. That - // responsibility is with the caller. - void SetByteLen(size_t bytes); - - // Swap values of two ScopedBstr's. - void Swap(ScopedBstr& bstr2); - - // Retrieves the pointer address. - // Used to receive BSTRs as out arguments (and take ownership). - // The function DCHECKs on the current value being NULL. - // Usage: GetBstr(bstr.Receive()); - BSTR* Receive(); - - // Returns number of chars in the BSTR. - size_t Length() const; - - // Returns the number of bytes allocated for the BSTR. - size_t ByteLength() const; - - operator BSTR() const { - return bstr_; - } - - protected: - BSTR bstr_; - - private: - // Forbid comparison of ScopedBstr types. You should never have the same - // BSTR owned by two different scoped_ptrs. - bool operator==(const ScopedBstr& bstr2) const; - bool operator!=(const ScopedBstr& bstr2) const; - DISALLOW_COPY_AND_ASSIGN(ScopedBstr); -}; - -} // namespace win -} // namespace base - -#endif // BASE_SCOPED_BSTR_H_ diff --git a/base/win/scoped_bstr_unittest.cc b/base/win/scoped_bstr_unittest.cc deleted file mode 100644 index 5f6f7dffe4..0000000000 --- a/base/win/scoped_bstr_unittest.cc +++ /dev/null @@ -1,77 +0,0 @@ -// Copyright (c) 2010 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "base/win/scoped_bstr.h" -#include "testing/gtest/include/gtest/gtest.h" - -namespace base { -namespace win { - -namespace { - -static const wchar_t kTestString1[] = L"123"; -static const wchar_t kTestString2[] = L"456789"; -size_t test1_len = arraysize(kTestString1) - 1; -size_t test2_len = arraysize(kTestString2) - 1; - -void DumbBstrTests() { - ScopedBstr b; - EXPECT_TRUE(b == NULL); - EXPECT_EQ(0, b.Length()); - EXPECT_EQ(0, b.ByteLength()); - b.Reset(NULL); - EXPECT_TRUE(b == NULL); - EXPECT_TRUE(b.Release() == NULL); - ScopedBstr b2; - b.Swap(b2); - EXPECT_TRUE(b2 == NULL); -} - -void GiveMeABstr(BSTR* ret) { - *ret = SysAllocString(kTestString1); -} - -void BasicBstrTests() { - ScopedBstr b1(kTestString1); - EXPECT_EQ(test1_len, b1.Length()); - EXPECT_EQ(test1_len * sizeof(kTestString1[0]), b1.ByteLength()); - - ScopedBstr b2; - b1.Swap(b2); - EXPECT_EQ(test1_len, b2.Length()); - EXPECT_EQ(0, b1.Length()); - EXPECT_EQ(0, lstrcmp(b2, kTestString1)); - BSTR tmp = b2.Release(); - EXPECT_TRUE(tmp != NULL); - EXPECT_EQ(0, lstrcmp(tmp, kTestString1)); - EXPECT_TRUE(b2 == NULL); - SysFreeString(tmp); - - GiveMeABstr(b2.Receive()); - EXPECT_TRUE(b2 != NULL); - b2.Reset(); - EXPECT_TRUE(b2.AllocateBytes(100) != NULL); - EXPECT_EQ(100, b2.ByteLength()); - EXPECT_EQ(100 / sizeof(kTestString1[0]), b2.Length()); - lstrcpy(static_cast(b2), kTestString1); - EXPECT_EQ(test1_len, lstrlen(b2)); - EXPECT_EQ(100 / sizeof(kTestString1[0]), b2.Length()); - b2.SetByteLen(lstrlen(b2) * sizeof(kTestString2[0])); - EXPECT_EQ(b2.Length(), lstrlen(b2)); - - EXPECT_TRUE(b1.Allocate(kTestString2) != NULL); - EXPECT_EQ(test2_len, b1.Length()); - b1.SetByteLen((test2_len - 1) * sizeof(kTestString2[0])); - EXPECT_EQ(test2_len - 1, b1.Length()); -} - -} // namespace - -TEST(ScopedBstrTest, ScopedBstr) { - DumbBstrTests(); - BasicBstrTests(); -} - -} // namespace win -} // namespace base diff --git a/base/win/scoped_co_mem.h b/base/win/scoped_co_mem.h deleted file mode 100644 index 572999a26c..0000000000 --- a/base/win/scoped_co_mem.h +++ /dev/null @@ -1,64 +0,0 @@ -// Copyright (c) 2011 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef BASE_WIN_SCOPED_CO_MEM_H_ -#define BASE_WIN_SCOPED_CO_MEM_H_ - -#include - -#include "base/basictypes.h" -#include "base/logging.h" - -namespace base { -namespace win { - -// Simple scoped memory releaser class for COM allocated memory. -// Example: -// base::win::ScopedCoMem file_item; -// SHGetSomeInfo(&file_item, ...); -// ... -// return; <-- memory released -template -class ScopedCoMem { - public: - ScopedCoMem() : mem_ptr_(NULL) {} - ~ScopedCoMem() { - Reset(NULL); - } - - T** operator&() { // NOLINT - DCHECK(mem_ptr_ == NULL); // To catch memory leaks. - return &mem_ptr_; - } - - operator T*() { - return mem_ptr_; - } - - T* operator->() { - DCHECK(mem_ptr_ != NULL); - return mem_ptr_; - } - - const T* operator->() const { - DCHECK(mem_ptr_ != NULL); - return mem_ptr_; - } - - void Reset(T* ptr) { - if (mem_ptr_) - CoTaskMemFree(mem_ptr_); - mem_ptr_ = ptr; - } - - private: - T* mem_ptr_; - - DISALLOW_COPY_AND_ASSIGN(ScopedCoMem); -}; - -} // namespace win -} // namespace base - -#endif // BASE_WIN_SCOPED_CO_MEM_H_ diff --git a/base/win/scoped_com_initializer.h b/base/win/scoped_com_initializer.h deleted file mode 100644 index 392c351cc7..0000000000 --- a/base/win/scoped_com_initializer.h +++ /dev/null @@ -1,74 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef BASE_WIN_SCOPED_COM_INITIALIZER_H_ -#define BASE_WIN_SCOPED_COM_INITIALIZER_H_ - -#include - -#include "base/basictypes.h" -#include "base/logging.h" -#include "build/build_config.h" - -namespace base { -namespace win { - -// Initializes COM in the constructor (STA or MTA), and uninitializes COM in the -// destructor. -class ScopedCOMInitializer { - public: - // Enum value provided to initialize the thread as an MTA instead of STA. - enum SelectMTA { kMTA }; - - // Constructor for STA initialization. - ScopedCOMInitializer() { - Initialize(COINIT_APARTMENTTHREADED); - } - - // Constructor for MTA initialization. - explicit ScopedCOMInitializer(SelectMTA mta) { - Initialize(COINIT_MULTITHREADED); - } - - ~ScopedCOMInitializer() { -#ifndef NDEBUG - // Using the windows API directly to avoid dependency on platform_thread. - DCHECK_EQ(GetCurrentThreadId(), thread_id_); -#endif - if (succeeded()) - CoUninitialize(); - } - - bool succeeded() const { return SUCCEEDED(hr_); } - - private: - void Initialize(COINIT init) { -#ifndef NDEBUG - thread_id_ = GetCurrentThreadId(); -#endif - hr_ = CoInitializeEx(NULL, init); -#ifndef NDEBUG - if (hr_ == S_FALSE) - LOG(ERROR) << "Multiple CoInitialize() calls for thread " << thread_id_; - else - DCHECK_NE(RPC_E_CHANGED_MODE, hr_) << "Invalid COM thread model change"; -#endif - } - - HRESULT hr_; -#ifndef NDEBUG - // In debug builds we use this variable to catch a potential bug where a - // ScopedCOMInitializer instance is deleted on a different thread than it - // was initially created on. If that ever happens it can have bad - // consequences and the cause can be tricky to track down. - DWORD thread_id_; -#endif - - DISALLOW_COPY_AND_ASSIGN(ScopedCOMInitializer); -}; - -} // namespace win -} // namespace base - -#endif // BASE_WIN_SCOPED_COM_INITIALIZER_H_ diff --git a/base/win/scoped_comptr.h b/base/win/scoped_comptr.h deleted file mode 100644 index 98cea0ff4c..0000000000 --- a/base/win/scoped_comptr.h +++ /dev/null @@ -1,168 +0,0 @@ -// Copyright (c) 2011 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef BASE_WIN_SCOPED_COMPTR_H_ -#define BASE_WIN_SCOPED_COMPTR_H_ - -#include - -#include "base/logging.h" -#include "base/memory/ref_counted.h" - -namespace base { -namespace win { - -// A fairly minimalistic smart class for COM interface pointers. -// Uses scoped_refptr for the basic smart pointer functionality -// and adds a few IUnknown specific services. -template -class ScopedComPtr : public scoped_refptr { - public: - // Utility template to prevent users of ScopedComPtr from calling AddRef - // and/or Release() without going through the ScopedComPtr class. - class BlockIUnknownMethods : public Interface { - private: - STDMETHOD(QueryInterface)(REFIID iid, void** object) = 0; - STDMETHOD_(ULONG, AddRef)() = 0; - STDMETHOD_(ULONG, Release)() = 0; - }; - - typedef scoped_refptr ParentClass; - - ScopedComPtr() { - } - - explicit ScopedComPtr(Interface* p) : ParentClass(p) { - } - - ScopedComPtr(const ScopedComPtr& p) - : ParentClass(p) { - } - - ~ScopedComPtr() { - // We don't want the smart pointer class to be bigger than the pointer - // it wraps. - COMPILE_ASSERT(sizeof(ScopedComPtr) == - sizeof(Interface*), ScopedComPtrSize); - } - - // Explicit Release() of the held object. Useful for reuse of the - // ScopedComPtr instance. - // Note that this function equates to IUnknown::Release and should not - // be confused with e.g. scoped_ptr::release(). - void Release() { - if (ptr_ != NULL) { - ptr_->Release(); - ptr_ = NULL; - } - } - - // Sets the internal pointer to NULL and returns the held object without - // releasing the reference. - Interface* Detach() { - Interface* p = ptr_; - ptr_ = NULL; - return p; - } - - // Accepts an interface pointer that has already been addref-ed. - void Attach(Interface* p) { - DCHECK(!ptr_); - ptr_ = p; - } - - // Retrieves the pointer address. - // Used to receive object pointers as out arguments (and take ownership). - // The function DCHECKs on the current value being NULL. - // Usage: Foo(p.Receive()); - Interface** Receive() { - DCHECK(!ptr_) << "Object leak. Pointer must be NULL"; - return &ptr_; - } - - // A convenience for whenever a void pointer is needed as an out argument. - void** ReceiveVoid() { - return reinterpret_cast(Receive()); - } - - template - HRESULT QueryInterface(Query** p) { - DCHECK(p != NULL); - DCHECK(ptr_ != NULL); - // IUnknown already has a template version of QueryInterface - // so the iid parameter is implicit here. The only thing this - // function adds are the DCHECKs. - return ptr_->QueryInterface(p); - } - - // QI for times when the IID is not associated with the type. - HRESULT QueryInterface(const IID& iid, void** obj) { - DCHECK(obj != NULL); - DCHECK(ptr_ != NULL); - return ptr_->QueryInterface(iid, obj); - } - - // Queries |other| for the interface this object wraps and returns the - // error code from the other->QueryInterface operation. - HRESULT QueryFrom(IUnknown* object) { - DCHECK(object != NULL); - return object->QueryInterface(Receive()); - } - - // Convenience wrapper around CoCreateInstance - HRESULT CreateInstance(const CLSID& clsid, IUnknown* outer = NULL, - DWORD context = CLSCTX_ALL) { - DCHECK(!ptr_); - HRESULT hr = ::CoCreateInstance(clsid, outer, context, *interface_id, - reinterpret_cast(&ptr_)); - return hr; - } - - // Checks if the identity of |other| and this object is the same. - bool IsSameObject(IUnknown* other) { - if (!other && !ptr_) - return true; - - if (!other || !ptr_) - return false; - - ScopedComPtr my_identity; - QueryInterface(my_identity.Receive()); - - ScopedComPtr other_identity; - other->QueryInterface(other_identity.Receive()); - - return static_cast(my_identity) == - static_cast(other_identity); - } - - // Provides direct access to the interface. - // Here we use a well known trick to make sure we block access to - // IUnknown methods so that something bad like this doesn't happen: - // ScopedComPtr p(Foo()); - // p->Release(); - // ... later the destructor runs, which will Release() again. - // and to get the benefit of the DCHECKs we add to QueryInterface. - // There's still a way to call these methods if you absolutely must - // by statically casting the ScopedComPtr instance to the wrapped interface - // and then making the call... but generally that shouldn't be necessary. - BlockIUnknownMethods* operator->() const { - DCHECK(ptr_ != NULL); - return reinterpret_cast(ptr_); - } - - // Pull in operator=() from the parent class. - using scoped_refptr::operator=; - - // static methods - - static const IID& iid() { - return *interface_id; - } -}; - -} // namespace win -} // namespace base - -#endif // BASE_WIN_SCOPED_COMPTR_H_ diff --git a/base/win/scoped_comptr_unittest.cc b/base/win/scoped_comptr_unittest.cc deleted file mode 100644 index d8d12be87d..0000000000 --- a/base/win/scoped_comptr_unittest.cc +++ /dev/null @@ -1,111 +0,0 @@ -// Copyright (c) 2011 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "base/win/scoped_comptr.h" - -#include - -#include "base/memory/scoped_ptr.h" -#include "base/win/scoped_com_initializer.h" -#include "testing/gtest/include/gtest/gtest.h" - -namespace base { -namespace win { - -namespace { - -struct Dummy { - Dummy() : adds(0), releases(0) { } - void AddRef() { ++adds; } - void Release() { ++releases; } - - int adds; - int releases; -}; - -extern const IID dummy_iid; -const IID dummy_iid = { 0x12345678u, 0x1234u, 0x5678u, 01, 23, 45, 67, 89, - 01, 23, 45 }; - -} // namespace - -TEST(ScopedComPtrTest, ScopedComPtr) { - EXPECT_TRUE(memcmp(&ScopedComPtr::iid(), &IID_IUnknown, - sizeof(IID)) == 0); - - base::win::ScopedCOMInitializer com_initializer; - EXPECT_TRUE(com_initializer.succeeded()); - - ScopedComPtr unk; - EXPECT_TRUE(SUCCEEDED(unk.CreateInstance(CLSID_ShellLink))); - ScopedComPtr unk2; - unk2.Attach(unk.Detach()); - EXPECT_TRUE(unk == NULL); - EXPECT_TRUE(unk2 != NULL); - - ScopedComPtr mem_alloc; - EXPECT_TRUE(SUCCEEDED(CoGetMalloc(1, mem_alloc.Receive()))); - - ScopedComPtr qi_test; - EXPECT_HRESULT_SUCCEEDED(mem_alloc.QueryInterface(IID_IUnknown, - reinterpret_cast(qi_test.Receive()))); - EXPECT_TRUE(qi_test.get() != NULL); - qi_test.Release(); - - // test ScopedComPtr& constructor - ScopedComPtr copy1(mem_alloc); - EXPECT_TRUE(copy1.IsSameObject(mem_alloc)); - EXPECT_FALSE(copy1.IsSameObject(unk2)); // unk2 is valid but different - EXPECT_FALSE(copy1.IsSameObject(unk)); // unk is NULL - - IMalloc* naked_copy = copy1.Detach(); - copy1 = naked_copy; // Test the =(T*) operator. - naked_copy->Release(); - - copy1.Release(); - EXPECT_FALSE(copy1.IsSameObject(unk2)); // unk2 is valid, copy1 is not - - // test Interface* constructor - ScopedComPtr copy2(static_cast(mem_alloc)); - EXPECT_TRUE(copy2.IsSameObject(mem_alloc)); - - EXPECT_TRUE(SUCCEEDED(unk.QueryFrom(mem_alloc))); - EXPECT_TRUE(unk != NULL); - unk.Release(); - EXPECT_TRUE(unk == NULL); - EXPECT_TRUE(unk.IsSameObject(copy1)); // both are NULL -} - -TEST(ScopedComPtrTest, ScopedComPtrVector) { - // Verify we don't get error C2558. - typedef ScopedComPtr Ptr; - std::vector bleh; - - scoped_ptr p(new Dummy); - { - Ptr p2(p.get()); - EXPECT_EQ(p->adds, 1); - EXPECT_EQ(p->releases, 0); - Ptr p3 = p2; - EXPECT_EQ(p->adds, 2); - EXPECT_EQ(p->releases, 0); - p3 = p2; - EXPECT_EQ(p->adds, 3); - EXPECT_EQ(p->releases, 1); - // To avoid hitting a reallocation. - bleh.reserve(1); - bleh.push_back(p2); - EXPECT_EQ(p->adds, 4); - EXPECT_EQ(p->releases, 1); - EXPECT_EQ(bleh[0], p.get()); - bleh.pop_back(); - EXPECT_EQ(p->adds, 4); - EXPECT_EQ(p->releases, 2); - } - EXPECT_EQ(p->adds, 4); - EXPECT_EQ(p->releases, 4); -} - -} // namespace win -} // namespace base diff --git a/base/win/scoped_gdi_object.h b/base/win/scoped_gdi_object.h deleted file mode 100644 index d44310a159..0000000000 --- a/base/win/scoped_gdi_object.h +++ /dev/null @@ -1,77 +0,0 @@ -// Copyright (c) 2010 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef BASE_WIN_SCOPED_GDI_OBJECT_H_ -#define BASE_WIN_SCOPED_GDI_OBJECT_H_ - -#include - -#include "base/basictypes.h" -#include "base/logging.h" - -namespace base { -namespace win { - -// Like ScopedHandle but for GDI objects. -template -class ScopedGDIObject { - public: - ScopedGDIObject() : object_(NULL) {} - explicit ScopedGDIObject(T object) : object_(object) {} - - ~ScopedGDIObject() { - Close(); - } - - T Get() { - return object_; - } - - void Set(T object) { - if (object_ && object != object_) - Close(); - object_ = object; - } - - ScopedGDIObject& operator=(T object) { - Set(object); - return *this; - } - - T release() { - T object = object_; - object_ = NULL; - return object; - } - - operator T() { return object_; } - - private: - void Close() { - if (object_) - DeleteObject(object_); - } - - T object_; - DISALLOW_COPY_AND_ASSIGN(ScopedGDIObject); -}; - -// An explicit specialization for HICON because we have to call DestroyIcon() -// instead of DeleteObject() for HICON. -template<> -void ScopedGDIObject::Close() { - if (object_) - DestroyIcon(object_); -} - -// Typedefs for some common use cases. -typedef ScopedGDIObject ScopedBitmap; -typedef ScopedGDIObject ScopedRegion; -typedef ScopedGDIObject ScopedHFONT; -typedef ScopedGDIObject ScopedHICON; - -} // namespace win -} // namespace base - -#endif // BASE_WIN_SCOPED_GDI_OBJECT_H_ diff --git a/base/win/scoped_handle.cc b/base/win/scoped_handle.cc deleted file mode 100644 index 7b38369d5a..0000000000 --- a/base/win/scoped_handle.cc +++ /dev/null @@ -1,68 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "base/win/scoped_handle.h" - -#include - -#include "base/debug/alias.h" -#include "base/lazy_instance.h" -#include "base/synchronization/lock.h" -#include "base/win/windows_version.h" - -namespace { - -struct Info { - const void* owner; - const void* pc1; - const void* pc2; - DWORD thread_id; -}; -typedef std::map HandleMap; - -base::LazyInstance::Leaky g_handle_map = LAZY_INSTANCE_INITIALIZER; -base::LazyInstance::Leaky g_lock = LAZY_INSTANCE_INITIALIZER; - -} // namespace - -namespace base { -namespace win { - -// Static. -void VerifierTraits::StartTracking(HANDLE handle, const void* owner, - const void* pc1, const void* pc2) { - // Grab the thread id before the lock. - DWORD thread_id = GetCurrentThreadId(); - - AutoLock lock(g_lock.Get()); - - Info handle_info = { owner, pc1, pc2, thread_id }; - std::pair item(handle, handle_info); - std::pair result = g_handle_map.Get().insert(item); - if (!result.second) { - Info other = result.first->second; - debug::Alias(&other); - CHECK(false); - } -} - -// Static. -void VerifierTraits::StopTracking(HANDLE handle, const void* owner, - const void* pc1, const void* pc2) { - AutoLock lock(g_lock.Get()); - HandleMap::iterator i = g_handle_map.Get().find(handle); - if (i == g_handle_map.Get().end()) - CHECK(false); - - Info other = i->second; - if (other.owner != owner) { - debug::Alias(&other); - CHECK(false); - } - - g_handle_map.Get().erase(i); -} - -} // namespace win -} // namespace base diff --git a/base/win/scoped_handle.h b/base/win/scoped_handle.h deleted file mode 100644 index d236a70beb..0000000000 --- a/base/win/scoped_handle.h +++ /dev/null @@ -1,205 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef BASE_WIN_SCOPED_HANDLE_H_ -#define BASE_WIN_SCOPED_HANDLE_H_ - -#include - -#include "base/base_export.h" -#include "base/basictypes.h" -#include "base/location.h" -#include "base/logging.h" -#include "base/move.h" - -namespace base { -namespace win { - -// TODO(rvargas): remove this with the rest of the verifier. -#if defined(COMPILER_MSVC) -// MSDN says to #include , but that breaks the VS2005 build. -extern "C" { - void* _ReturnAddress(); -} -#define BASE_WIN_GET_CALLER _ReturnAddress() -#elif defined(COMPILER_GCC) -#define BASE_WIN_GET_CALLER __builtin_extract_return_addr(\\ - __builtin_return_address(0)) -#endif - -// Generic wrapper for raw handles that takes care of closing handles -// automatically. The class interface follows the style of -// the ScopedStdioHandle class with a few additions: -// - IsValid() method can tolerate multiple invalid handle values such as NULL -// and INVALID_HANDLE_VALUE (-1) for Win32 handles. -// - Receive() method allows to receive a handle value from a function that -// takes a raw handle pointer only. -template -class GenericScopedHandle { - MOVE_ONLY_TYPE_FOR_CPP_03(GenericScopedHandle, RValue) - - public: - typedef typename Traits::Handle Handle; - - // Helper object to contain the effect of Receive() to the function that needs - // a pointer, and allow proper tracking of the handle. - class Receiver { - public: - explicit Receiver(GenericScopedHandle* owner) - : handle_(Traits::NullHandle()), - owner_(owner) {} - ~Receiver() { owner_->Set(handle_); } - - operator Handle*() { return &handle_; } - - private: - Handle handle_; - GenericScopedHandle* owner_; - }; - - GenericScopedHandle() : handle_(Traits::NullHandle()) {} - - explicit GenericScopedHandle(Handle handle) : handle_(Traits::NullHandle()) { - Set(handle); - } - - // Move constructor for C++03 move emulation of this type. - GenericScopedHandle(RValue other) : handle_(Traits::NullHandle()) { - Set(other.object->Take()); - } - - ~GenericScopedHandle() { - Close(); - } - - bool IsValid() const { - return Traits::IsHandleValid(handle_); - } - - // Move operator= for C++03 move emulation of this type. - GenericScopedHandle& operator=(RValue other) { - if (this != other.object) { - Set(other.object->Take()); - } - return *this; - } - - void Set(Handle handle) { - if (handle_ != handle) { - Close(); - - if (Traits::IsHandleValid(handle)) { - handle_ = handle; - Verifier::StartTracking(handle, this, BASE_WIN_GET_CALLER, - tracked_objects::GetProgramCounter()); - } - } - } - - Handle Get() const { - return handle_; - } - - operator Handle() const { - return handle_; - } - - // This method is intended to be used with functions that require a pointer to - // a destination handle, like so: - // void CreateRequiredHandle(Handle* out_handle); - // ScopedHandle a; - // CreateRequiredHandle(a.Receive()); - Receiver Receive() { - DCHECK(!Traits::IsHandleValid(handle_)) << "Handle must be NULL"; - return Receiver(this); - } - - // Transfers ownership away from this object. - Handle Take() { - Handle temp = handle_; - handle_ = Traits::NullHandle(); - if (Traits::IsHandleValid(temp)) { - Verifier::StopTracking(temp, this, BASE_WIN_GET_CALLER, - tracked_objects::GetProgramCounter()); - } - return temp; - } - - // Explicitly closes the owned handle. - void Close() { - if (Traits::IsHandleValid(handle_)) { - Verifier::StopTracking(handle_, this, BASE_WIN_GET_CALLER, - tracked_objects::GetProgramCounter()); - - if (!Traits::CloseHandle(handle_)) - CHECK(false); - - handle_ = Traits::NullHandle(); - } - } - - private: - Handle handle_; -}; - -#undef BASE_WIN_GET_CALLER - -// The traits class for Win32 handles that can be closed via CloseHandle() API. -class HandleTraits { - public: - typedef HANDLE Handle; - - // Closes the handle. - static bool CloseHandle(HANDLE handle) { - return ::CloseHandle(handle) != FALSE; - } - - // Returns true if the handle value is valid. - static bool IsHandleValid(HANDLE handle) { - return handle != NULL && handle != INVALID_HANDLE_VALUE; - } - - // Returns NULL handle value. - static HANDLE NullHandle() { - return NULL; - } - - private: - DISALLOW_IMPLICIT_CONSTRUCTORS(HandleTraits); -}; - -// Do-nothing verifier. -class DummyVerifierTraits { - public: - typedef HANDLE Handle; - - static void StartTracking(HANDLE handle, const void* owner, - const void* pc1, const void* pc2) {} - static void StopTracking(HANDLE handle, const void* owner, - const void* pc1, const void* pc2) {} - - private: - DISALLOW_IMPLICIT_CONSTRUCTORS(DummyVerifierTraits); -}; - -// Performs actual run-time tracking. -class BASE_EXPORT VerifierTraits { - public: - typedef HANDLE Handle; - - static void StartTracking(HANDLE handle, const void* owner, - const void* pc1, const void* pc2); - static void StopTracking(HANDLE handle, const void* owner, - const void* pc1, const void* pc2); - - private: - DISALLOW_IMPLICIT_CONSTRUCTORS(VerifierTraits); -}; - -typedef GenericScopedHandle ScopedHandle; - -} // namespace win -} // namespace base - -#endif // BASE_SCOPED_HANDLE_WIN_H_ diff --git a/base/win/scoped_handle_unittest.cc b/base/win/scoped_handle_unittest.cc deleted file mode 100644 index ee2a551d63..0000000000 --- a/base/win/scoped_handle_unittest.cc +++ /dev/null @@ -1,31 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "base/win/scoped_handle.h" -#include "testing/gtest/include/gtest/gtest.h" - -void CreateHandle(int value, HANDLE* result) { - *result = reinterpret_cast(value); -} - -TEST(ScopedHandleTest, Receive) { - base::win::ScopedHandle handle; - int value = 51; - - { - // This is not really the expected use case, but it is a very explicit test. - base::win::ScopedHandle::Receiver a = handle.Receive(); - HANDLE* pointer = a; - *pointer = reinterpret_cast(value); - } - - EXPECT_EQ(handle.Get(), reinterpret_cast(value)); - HANDLE to_discard = handle.Take(); - - // The standard use case: - value = 183; - CreateHandle(value, handle.Receive()); - EXPECT_EQ(handle.Get(), reinterpret_cast(value)); - to_discard = handle.Take(); -} diff --git a/base/win/scoped_hdc.h b/base/win/scoped_hdc.h deleted file mode 100644 index 9aead96792..0000000000 --- a/base/win/scoped_hdc.h +++ /dev/null @@ -1,76 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef BASE_WIN_SCOPED_HDC_H_ -#define BASE_WIN_SCOPED_HDC_H_ - -#include - -#include "base/basictypes.h" -#include "base/logging.h" -#include "base/win/scoped_handle.h" - -namespace base { -namespace win { - -// Like ScopedHandle but for HDC. Only use this on HDCs returned from -// GetDC. -class ScopedGetDC { - public: - explicit ScopedGetDC(HWND hwnd) - : hwnd_(hwnd), - hdc_(GetDC(hwnd)) { - if (hwnd_) { - DCHECK(IsWindow(hwnd_)); - DCHECK(hdc_); - } else { - // If GetDC(NULL) returns NULL, something really bad has happened, like - // GDI handle exhaustion. In this case Chrome is going to behave badly no - // matter what, so we may as well just force a crash now. - CHECK(hdc_); - } - } - - ~ScopedGetDC() { - if (hdc_) - ReleaseDC(hwnd_, hdc_); - } - - operator HDC() { return hdc_; } - - private: - HWND hwnd_; - HDC hdc_; - - DISALLOW_COPY_AND_ASSIGN(ScopedGetDC); -}; - -// Like ScopedHandle but for HDC. Only use this on HDCs returned from -// CreateCompatibleDC, CreateDC and CreateIC. -class CreateDCTraits { - public: - typedef HDC Handle; - - static bool CloseHandle(HDC handle) { - return ::DeleteDC(handle) != FALSE; - } - - static bool IsHandleValid(HDC handle) { - return handle != NULL; - } - - static HDC NullHandle() { - return NULL; - } - - private: - DISALLOW_IMPLICIT_CONSTRUCTORS(CreateDCTraits); -}; - -typedef GenericScopedHandle ScopedCreateDC; - -} // namespace win -} // namespace base - -#endif // BASE_WIN_SCOPED_HDC_H_ diff --git a/base/win/scoped_hglobal.h b/base/win/scoped_hglobal.h deleted file mode 100644 index 891e6cdfc8..0000000000 --- a/base/win/scoped_hglobal.h +++ /dev/null @@ -1,52 +0,0 @@ -// Copyright (c) 2010 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef BASE_WIN_SCOPED_HGLOBAL_H_ -#define BASE_WIN_SCOPED_HGLOBAL_H_ - -#include - -#include "base/basictypes.h" - -namespace base { -namespace win { - -// Like ScopedHandle except for HGLOBAL. -template -class ScopedHGlobal { - public: - explicit ScopedHGlobal(HGLOBAL glob) : glob_(glob) { - data_ = static_cast(GlobalLock(glob_)); - } - ~ScopedHGlobal() { - GlobalUnlock(glob_); - } - - T* get() { return data_; } - - size_t Size() const { return GlobalSize(glob_); } - - T* operator->() const { - assert(data_ != 0); - return data_; - } - - T* release() { - T* data = data_; - data_ = NULL; - return data; - } - - private: - HGLOBAL glob_; - - T* data_; - - DISALLOW_COPY_AND_ASSIGN(ScopedHGlobal); -}; - -} // namespace win -} // namespace base - -#endif // BASE_WIN_SCOPED_HGLOBAL_H_ diff --git a/base/win/scoped_process_information.cc b/base/win/scoped_process_information.cc deleted file mode 100644 index cb7a30e2f5..0000000000 --- a/base/win/scoped_process_information.cc +++ /dev/null @@ -1,110 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "base/win/scoped_process_information.h" - -#include "base/logging.h" -#include "base/win/scoped_handle.h" - -namespace base { -namespace win { - -namespace { - -// Duplicates source into target, returning true upon success. |target| is -// guaranteed to be untouched in case of failure. Succeeds with no side-effects -// if source is NULL. -bool CheckAndDuplicateHandle(HANDLE source, HANDLE* target) { - if (!source) - return true; - - HANDLE temp = NULL; - if (!::DuplicateHandle(::GetCurrentProcess(), source, - ::GetCurrentProcess(), &temp, 0, FALSE, - DUPLICATE_SAME_ACCESS)) { - DPLOG(ERROR) << "Failed to duplicate a handle."; - return false; - } - *target = temp; - return true; -} - -} // namespace - -ScopedProcessInformation::ScopedProcessInformation() - : process_id_(0), thread_id_(0) { -} - -ScopedProcessInformation::~ScopedProcessInformation() { - Close(); -} - -ScopedProcessInformation::Receiver ScopedProcessInformation::Receive() { - DCHECK(!IsValid()) << "process_information_ must be NULL"; - return Receiver(this); -} - -bool ScopedProcessInformation::IsValid() const { - return process_id_ || process_handle_.Get() || - thread_id_ || thread_handle_.Get(); -} - -void ScopedProcessInformation::Close() { - process_handle_.Close(); - thread_handle_.Close(); - process_id_ = 0; - thread_id_ = 0; -} - -void ScopedProcessInformation::Set(const PROCESS_INFORMATION& process_info) { - if (IsValid()) - Close(); - - process_handle_.Set(process_info.hProcess); - thread_handle_.Set(process_info.hThread); - process_id_ = process_info.dwProcessId; - thread_id_ = process_info.dwThreadId; -} - -bool ScopedProcessInformation::DuplicateFrom( - const ScopedProcessInformation& other) { - DCHECK(!IsValid()) << "target ScopedProcessInformation must be NULL"; - DCHECK(other.IsValid()) << "source ScopedProcessInformation must be valid"; - - if (CheckAndDuplicateHandle(other.process_handle(), - process_handle_.Receive()) && - CheckAndDuplicateHandle(other.thread_handle(), - thread_handle_.Receive())) { - process_id_ = other.process_id(); - thread_id_ = other.thread_id(); - return true; - } - - return false; -} - -PROCESS_INFORMATION ScopedProcessInformation::Take() { - PROCESS_INFORMATION process_information = {}; - process_information.hProcess = process_handle_.Take(); - process_information.hThread = thread_handle_.Take(); - process_information.dwProcessId = process_id(); - process_information.dwThreadId = thread_id(); - process_id_ = 0; - thread_id_ = 0; - - return process_information; -} - -HANDLE ScopedProcessInformation::TakeProcessHandle() { - process_id_ = 0; - return process_handle_.Take(); -} - -HANDLE ScopedProcessInformation::TakeThreadHandle() { - thread_id_ = 0; - return thread_handle_.Take(); -} - -} // namespace win -} // namespace base diff --git a/base/win/scoped_process_information.h b/base/win/scoped_process_information.h deleted file mode 100644 index 1f404c2dba..0000000000 --- a/base/win/scoped_process_information.h +++ /dev/null @@ -1,106 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef BASE_WIN_SCOPED_PROCESS_INFORMATION_H_ -#define BASE_WIN_SCOPED_PROCESS_INFORMATION_H_ - -#include - -#include "base/basictypes.h" -#include "base/base_export.h" -#include "base/win/scoped_handle.h" - -namespace base { -namespace win { - -// Manages the closing of process and thread handles from PROCESS_INFORMATION -// structures. Allows clients to take ownership of either handle independently. -class BASE_EXPORT ScopedProcessInformation { - public: - // Helper object to contain the effect of Receive() to the funtion that needs - // a pointer. - class Receiver { - public: - explicit Receiver(ScopedProcessInformation* owner) - : info_(), - owner_(owner) {} - ~Receiver() { owner_->Set(info_); } - - operator PROCESS_INFORMATION*() { return &info_; } - - private: - PROCESS_INFORMATION info_; - ScopedProcessInformation* owner_; - }; - - ScopedProcessInformation(); - ~ScopedProcessInformation(); - - // Returns an object that may be passed to API calls such as CreateProcess. - // DCHECKs that the object is not currently holding any handles. - // HANDLEs stored in the returned PROCESS_INFORMATION will be owned by this - // instance. - // The intended use case is something like this: - // if (::CreateProcess(..., startup_info, scoped_proces_info.Receive())) - Receiver Receive(); - - // Returns true iff this instance is holding a thread and/or process handle. - bool IsValid() const; - - // Closes the held thread and process handles, if any. - void Close(); - - // Populates this instance with the provided |process_info|. - void Set(const PROCESS_INFORMATION& process_info); - - // Populates this instance with duplicate handles and the thread/process IDs - // from |other|. Returns false in case of failure, in which case this instance - // will be completely unpopulated. - bool DuplicateFrom(const ScopedProcessInformation& other); - - // Transfers ownership of the held PROCESS_INFORMATION, if any, away from this - // instance. - PROCESS_INFORMATION Take(); - - // Transfers ownership of the held process handle, if any, away from this - // instance. Note that the related process_id will also be cleared. - HANDLE TakeProcessHandle(); - - // Transfers ownership of the held thread handle, if any, away from this - // instance. Note that the related thread_id will also be cleared. - HANDLE TakeThreadHandle(); - - // Returns the held process handle, if any, while retaining ownership. - HANDLE process_handle() const { - return process_handle_.Get(); - } - - // Returns the held thread handle, if any, while retaining ownership. - HANDLE thread_handle() const { - return thread_handle_.Get(); - } - - // Returns the held process id, if any. - DWORD process_id() const { - return process_id_; - } - - // Returns the held thread id, if any. - DWORD thread_id() const { - return thread_id_; - } - - private: - ScopedHandle process_handle_; - ScopedHandle thread_handle_; - DWORD process_id_; - DWORD thread_id_; - - DISALLOW_COPY_AND_ASSIGN(ScopedProcessInformation); -}; - -} // namespace win -} // namespace base - -#endif // BASE_WIN_SCOPED_PROCESS_INFORMATION_H_ diff --git a/base/win/scoped_process_information_unittest.cc b/base/win/scoped_process_information_unittest.cc deleted file mode 100644 index b8ffc4427c..0000000000 --- a/base/win/scoped_process_information_unittest.cc +++ /dev/null @@ -1,160 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include - -#include - -#include "base/command_line.h" -#include "base/process/kill.h" -#include "base/test/multiprocess_test.h" -#include "base/win/scoped_process_information.h" -#include "testing/multiprocess_func_list.h" - -namespace { - -const DWORD kProcessId = 4321; -const DWORD kThreadId = 1234; -const HANDLE kProcessHandle = reinterpret_cast(7651); -const HANDLE kThreadHandle = reinterpret_cast(1567); - -void MockCreateProcess(PROCESS_INFORMATION* process_info) { - process_info->dwProcessId = kProcessId; - process_info->dwThreadId = kThreadId; - process_info->hProcess = kProcessHandle; - process_info->hThread = kThreadHandle; -} - -} // namespace - -class ScopedProcessInformationTest : public base::MultiProcessTest { - protected: - void DoCreateProcess(const std::string& main_id, - PROCESS_INFORMATION* process_handle); -}; - -MULTIPROCESS_TEST_MAIN(ReturnSeven) { - return 7; -} - -MULTIPROCESS_TEST_MAIN(ReturnNine) { - return 9; -} - -void ScopedProcessInformationTest::DoCreateProcess( - const std::string& main_id, PROCESS_INFORMATION* process_handle) { - std::wstring cmd_line = - this->MakeCmdLine(main_id, false).GetCommandLineString(); - STARTUPINFO startup_info = {}; - startup_info.cb = sizeof(startup_info); - - EXPECT_TRUE(::CreateProcess(NULL, - const_cast(cmd_line.c_str()), - NULL, NULL, false, 0, NULL, NULL, - &startup_info, process_handle)); -} - -TEST_F(ScopedProcessInformationTest, InitiallyInvalid) { - base::win::ScopedProcessInformation process_info; - ASSERT_FALSE(process_info.IsValid()); -} - -TEST_F(ScopedProcessInformationTest, Receive) { - base::win::ScopedProcessInformation process_info; - MockCreateProcess(process_info.Receive()); - - EXPECT_TRUE(process_info.IsValid()); - EXPECT_EQ(kProcessId, process_info.process_id()); - EXPECT_EQ(kThreadId, process_info.thread_id()); - EXPECT_EQ(kProcessHandle, process_info.process_handle()); - EXPECT_EQ(kThreadHandle, process_info.thread_handle()); - PROCESS_INFORMATION to_discard = process_info.Take(); -} - -TEST_F(ScopedProcessInformationTest, TakeProcess) { - base::win::ScopedProcessInformation process_info; - MockCreateProcess(process_info.Receive()); - - HANDLE process = process_info.TakeProcessHandle(); - EXPECT_EQ(kProcessHandle, process); - EXPECT_EQ(NULL, process_info.process_handle()); - EXPECT_EQ(0, process_info.process_id()); - EXPECT_TRUE(process_info.IsValid()); - PROCESS_INFORMATION to_discard = process_info.Take(); -} - -TEST_F(ScopedProcessInformationTest, TakeThread) { - base::win::ScopedProcessInformation process_info; - MockCreateProcess(process_info.Receive()); - - HANDLE thread = process_info.TakeThreadHandle(); - EXPECT_EQ(kThreadHandle, thread); - EXPECT_EQ(NULL, process_info.thread_handle()); - EXPECT_EQ(0, process_info.thread_id()); - EXPECT_TRUE(process_info.IsValid()); - PROCESS_INFORMATION to_discard = process_info.Take(); -} - -TEST_F(ScopedProcessInformationTest, TakeBoth) { - base::win::ScopedProcessInformation process_info; - MockCreateProcess(process_info.Receive()); - - HANDLE process = process_info.TakeProcessHandle(); - HANDLE thread = process_info.TakeThreadHandle(); - EXPECT_FALSE(process_info.IsValid()); - PROCESS_INFORMATION to_discard = process_info.Take(); -} - -TEST_F(ScopedProcessInformationTest, TakeWholeStruct) { - base::win::ScopedProcessInformation process_info; - MockCreateProcess(process_info.Receive()); - - PROCESS_INFORMATION to_discard = process_info.Take(); - EXPECT_EQ(kProcessId, to_discard.dwProcessId); - EXPECT_EQ(kThreadId, to_discard.dwThreadId); - EXPECT_EQ(kProcessHandle, to_discard.hProcess); - EXPECT_EQ(kThreadHandle, to_discard.hThread); - EXPECT_FALSE(process_info.IsValid()); -} - -TEST_F(ScopedProcessInformationTest, Duplicate) { - base::win::ScopedProcessInformation process_info; - DoCreateProcess("ReturnSeven", process_info.Receive()); - base::win::ScopedProcessInformation duplicate; - duplicate.DuplicateFrom(process_info); - - ASSERT_TRUE(process_info.IsValid()); - ASSERT_NE(0u, process_info.process_id()); - ASSERT_EQ(duplicate.process_id(), process_info.process_id()); - ASSERT_NE(0u, process_info.thread_id()); - ASSERT_EQ(duplicate.thread_id(), process_info.thread_id()); - - // Validate that we have separate handles that are good. - int exit_code = 0; - ASSERT_TRUE(base::WaitForExitCode(process_info.TakeProcessHandle(), - &exit_code)); - ASSERT_EQ(7, exit_code); - - exit_code = 0; - ASSERT_TRUE(base::WaitForExitCode(duplicate.TakeProcessHandle(), - &exit_code)); - ASSERT_EQ(7, exit_code); - - ASSERT_TRUE(::CloseHandle(process_info.TakeThreadHandle())); - ASSERT_TRUE(::CloseHandle(duplicate.TakeThreadHandle())); -} - -TEST_F(ScopedProcessInformationTest, Set) { - PROCESS_INFORMATION base_process_info = {}; - MockCreateProcess(&base_process_info); - - base::win::ScopedProcessInformation process_info; - process_info.Set(base_process_info); - - EXPECT_EQ(kProcessId, process_info.process_id()); - EXPECT_EQ(kThreadId, process_info.thread_id()); - EXPECT_EQ(kProcessHandle, process_info.process_handle()); - EXPECT_EQ(kThreadHandle, process_info.thread_handle()); - base_process_info = process_info.Take(); -} diff --git a/base/win/scoped_propvariant.h b/base/win/scoped_propvariant.h deleted file mode 100644 index 711d51adb4..0000000000 --- a/base/win/scoped_propvariant.h +++ /dev/null @@ -1,59 +0,0 @@ -// Copyright (c) 2013 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef BASE_WIN_SCOPED_PROPVARIANT_H_ -#define BASE_WIN_SCOPED_PROPVARIANT_H_ - -#include - -#include "base/basictypes.h" -#include "base/logging.h" - -namespace base { -namespace win { - -// A PROPVARIANT that is automatically initialized and cleared upon respective -// construction and destruction of this class. -class ScopedPropVariant { - public: - ScopedPropVariant() { - PropVariantInit(&pv_); - } - - ~ScopedPropVariant() { - Reset(); - } - - // Returns a pointer to the underlying PROPVARIANT for use as an out param in - // a function call. - PROPVARIANT* Receive() { - DCHECK_EQ(pv_.vt, VT_EMPTY); - return &pv_; - } - - // Clears the instance to prepare it for re-use (e.g., via Receive). - void Reset() { - if (pv_.vt != VT_EMPTY) { - HRESULT result = PropVariantClear(&pv_); - DCHECK_EQ(result, S_OK); - } - } - - const PROPVARIANT& get() const { return pv_; } - - const PROPVARIANT* operator&() const { return &pv_; } - - private: - PROPVARIANT pv_; - - // Comparison operators for ScopedPropVariant are not supported at this point. - bool operator==(const ScopedPropVariant&) const; - bool operator!=(const ScopedPropVariant&) const; - DISALLOW_COPY_AND_ASSIGN(ScopedPropVariant); -}; - -} // namespace win -} // namespace base - -#endif // BASE_WIN_SCOPED_PROPVARIANT_H_ diff --git a/base/win/scoped_select_object.h b/base/win/scoped_select_object.h deleted file mode 100644 index 347de798e2..0000000000 --- a/base/win/scoped_select_object.h +++ /dev/null @@ -1,43 +0,0 @@ -// Copyright (c) 2011 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef BASE_WIN_SCOPED_SELECT_OBJECT_H_ -#define BASE_WIN_SCOPED_SELECT_OBJECT_H_ - -#include - -#include "base/basictypes.h" -#include "base/logging.h" - -namespace base { -namespace win { - -// Helper class for deselecting object from DC. -class ScopedSelectObject { - public: - ScopedSelectObject(HDC hdc, HGDIOBJ object) - : hdc_(hdc), - oldobj_(SelectObject(hdc, object)) { - DCHECK(hdc_); - DCHECK(object); - DCHECK(oldobj_ != NULL && oldobj_ != HGDI_ERROR); - } - - ~ScopedSelectObject() { - HGDIOBJ object = SelectObject(hdc_, oldobj_); - DCHECK((GetObjectType(oldobj_) != OBJ_REGION && object != NULL) || - (GetObjectType(oldobj_) == OBJ_REGION && object != HGDI_ERROR)); - } - - private: - HDC hdc_; - HGDIOBJ oldobj_; - - DISALLOW_COPY_AND_ASSIGN(ScopedSelectObject); -}; - -} // namespace win -} // namespace base - -#endif // BASE_WIN_SCOPED_SELECT_OBJECT_H_ diff --git a/base/win/scoped_variant.cc b/base/win/scoped_variant.cc deleted file mode 100644 index f57ab93f6c..0000000000 --- a/base/win/scoped_variant.cc +++ /dev/null @@ -1,276 +0,0 @@ -// Copyright (c) 2010 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "base/win/scoped_variant.h" -#include "base/logging.h" - -namespace base { -namespace win { - -// Global, const instance of an empty variant. -const VARIANT ScopedVariant::kEmptyVariant = { VT_EMPTY }; - -ScopedVariant::~ScopedVariant() { - COMPILE_ASSERT(sizeof(ScopedVariant) == sizeof(VARIANT), ScopedVariantSize); - ::VariantClear(&var_); -} - -ScopedVariant::ScopedVariant(const wchar_t* str) { - var_.vt = VT_EMPTY; - Set(str); -} - -ScopedVariant::ScopedVariant(const wchar_t* str, UINT length) { - var_.vt = VT_BSTR; - var_.bstrVal = ::SysAllocStringLen(str, length); -} - -ScopedVariant::ScopedVariant(int value, VARTYPE vt) { - var_.vt = vt; - var_.lVal = value; -} - -ScopedVariant::ScopedVariant(double value, VARTYPE vt) { - DCHECK(vt == VT_R8 || vt == VT_DATE); - var_.vt = vt; - var_.dblVal = value; -} - -ScopedVariant::ScopedVariant(IDispatch* dispatch) { - var_.vt = VT_EMPTY; - Set(dispatch); -} - -ScopedVariant::ScopedVariant(IUnknown* unknown) { - var_.vt = VT_EMPTY; - Set(unknown); -} - -ScopedVariant::ScopedVariant(SAFEARRAY* safearray) { - var_.vt = VT_EMPTY; - Set(safearray); -} - -ScopedVariant::ScopedVariant(const VARIANT& var) { - var_.vt = VT_EMPTY; - Set(var); -} - -void ScopedVariant::Reset(const VARIANT& var) { - if (&var != &var_) { - ::VariantClear(&var_); - var_ = var; - } -} - -VARIANT ScopedVariant::Release() { - VARIANT var = var_; - var_.vt = VT_EMPTY; - return var; -} - -void ScopedVariant::Swap(ScopedVariant& var) { - VARIANT tmp = var_; - var_ = var.var_; - var.var_ = tmp; -} - -VARIANT* ScopedVariant::Receive() { - DCHECK(!IsLeakableVarType(var_.vt)) << "variant leak. type: " << var_.vt; - return &var_; -} - -VARIANT ScopedVariant::Copy() const { - VARIANT ret = { VT_EMPTY }; - ::VariantCopy(&ret, &var_); - return ret; -} - -int ScopedVariant::Compare(const VARIANT& var, bool ignore_case) const { - ULONG flags = ignore_case ? NORM_IGNORECASE : 0; - HRESULT hr = ::VarCmp(const_cast(&var_), const_cast(&var), - LOCALE_USER_DEFAULT, flags); - int ret = 0; - - switch (hr) { - case VARCMP_LT: - ret = -1; - break; - - case VARCMP_GT: - case VARCMP_NULL: - ret = 1; - break; - - default: - // Equal. - break; - } - - return ret; -} - -void ScopedVariant::Set(const wchar_t* str) { - DCHECK(!IsLeakableVarType(var_.vt)) << "leaking variant: " << var_.vt; - var_.vt = VT_BSTR; - var_.bstrVal = ::SysAllocString(str); -} - -void ScopedVariant::Set(int8 i8) { - DCHECK(!IsLeakableVarType(var_.vt)) << "leaking variant: " << var_.vt; - var_.vt = VT_I1; - var_.cVal = i8; -} - -void ScopedVariant::Set(uint8 ui8) { - DCHECK(!IsLeakableVarType(var_.vt)) << "leaking variant: " << var_.vt; - var_.vt = VT_UI1; - var_.bVal = ui8; -} - -void ScopedVariant::Set(int16 i16) { - DCHECK(!IsLeakableVarType(var_.vt)) << "leaking variant: " << var_.vt; - var_.vt = VT_I2; - var_.iVal = i16; -} - -void ScopedVariant::Set(uint16 ui16) { - DCHECK(!IsLeakableVarType(var_.vt)) << "leaking variant: " << var_.vt; - var_.vt = VT_UI2; - var_.uiVal = ui16; -} - -void ScopedVariant::Set(int32 i32) { - DCHECK(!IsLeakableVarType(var_.vt)) << "leaking variant: " << var_.vt; - var_.vt = VT_I4; - var_.lVal = i32; -} - -void ScopedVariant::Set(uint32 ui32) { - DCHECK(!IsLeakableVarType(var_.vt)) << "leaking variant: " << var_.vt; - var_.vt = VT_UI4; - var_.ulVal = ui32; -} - -void ScopedVariant::Set(int64 i64) { - DCHECK(!IsLeakableVarType(var_.vt)) << "leaking variant: " << var_.vt; - var_.vt = VT_I8; - var_.llVal = i64; -} - -void ScopedVariant::Set(uint64 ui64) { - DCHECK(!IsLeakableVarType(var_.vt)) << "leaking variant: " << var_.vt; - var_.vt = VT_UI8; - var_.ullVal = ui64; -} - -void ScopedVariant::Set(float r32) { - DCHECK(!IsLeakableVarType(var_.vt)) << "leaking variant: " << var_.vt; - var_.vt = VT_R4; - var_.fltVal = r32; -} - -void ScopedVariant::Set(double r64) { - DCHECK(!IsLeakableVarType(var_.vt)) << "leaking variant: " << var_.vt; - var_.vt = VT_R8; - var_.dblVal = r64; -} - -void ScopedVariant::SetDate(DATE date) { - DCHECK(!IsLeakableVarType(var_.vt)) << "leaking variant: " << var_.vt; - var_.vt = VT_DATE; - var_.date = date; -} - -void ScopedVariant::Set(IDispatch* disp) { - DCHECK(!IsLeakableVarType(var_.vt)) << "leaking variant: " << var_.vt; - var_.vt = VT_DISPATCH; - var_.pdispVal = disp; - if (disp) - disp->AddRef(); -} - -void ScopedVariant::Set(bool b) { - DCHECK(!IsLeakableVarType(var_.vt)) << "leaking variant: " << var_.vt; - var_.vt = VT_BOOL; - var_.boolVal = b ? VARIANT_TRUE : VARIANT_FALSE; -} - -void ScopedVariant::Set(IUnknown* unk) { - DCHECK(!IsLeakableVarType(var_.vt)) << "leaking variant: " << var_.vt; - var_.vt = VT_UNKNOWN; - var_.punkVal = unk; - if (unk) - unk->AddRef(); -} - -void ScopedVariant::Set(SAFEARRAY* array) { - DCHECK(!IsLeakableVarType(var_.vt)) << "leaking variant: " << var_.vt; - if (SUCCEEDED(::SafeArrayGetVartype(array, &var_.vt))) { - var_.vt |= VT_ARRAY; - var_.parray = array; - } else { - DCHECK(!array) << "Unable to determine safearray vartype"; - var_.vt = VT_EMPTY; - } -} - -void ScopedVariant::Set(const VARIANT& var) { - DCHECK(!IsLeakableVarType(var_.vt)) << "leaking variant: " << var_.vt; - if (FAILED(::VariantCopy(&var_, &var))) { - DLOG(ERROR) << "VariantCopy failed"; - var_.vt = VT_EMPTY; - } -} - -ScopedVariant& ScopedVariant::operator=(const VARIANT& var) { - if (&var != &var_) { - VariantClear(&var_); - Set(var); - } - return *this; -} - -bool ScopedVariant::IsLeakableVarType(VARTYPE vt) { - bool leakable = false; - switch (vt & VT_TYPEMASK) { - case VT_BSTR: - case VT_DISPATCH: - // we treat VT_VARIANT as leakable to err on the safe side. - case VT_VARIANT: - case VT_UNKNOWN: - case VT_SAFEARRAY: - - // very rarely used stuff (if ever): - case VT_VOID: - case VT_PTR: - case VT_CARRAY: - case VT_USERDEFINED: - case VT_LPSTR: - case VT_LPWSTR: - case VT_RECORD: - case VT_INT_PTR: - case VT_UINT_PTR: - case VT_FILETIME: - case VT_BLOB: - case VT_STREAM: - case VT_STORAGE: - case VT_STREAMED_OBJECT: - case VT_STORED_OBJECT: - case VT_BLOB_OBJECT: - case VT_VERSIONED_STREAM: - case VT_BSTR_BLOB: - leakable = true; - break; - } - - if (!leakable && (vt & VT_ARRAY) != 0) { - leakable = true; - } - - return leakable; -} - -} // namespace win -} // namespace base diff --git a/base/win/scoped_variant.h b/base/win/scoped_variant.h deleted file mode 100644 index b6e65798fb..0000000000 --- a/base/win/scoped_variant.h +++ /dev/null @@ -1,166 +0,0 @@ -// Copyright (c) 2011 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef BASE_WIN_SCOPED_VARIANT_H_ -#define BASE_WIN_SCOPED_VARIANT_H_ - -#include -#include - -#include "base/base_export.h" -#include "base/basictypes.h" - -namespace base { -namespace win { - -// Scoped VARIANT class for automatically freeing a COM VARIANT at the -// end of a scope. Additionally provides a few functions to make the -// encapsulated VARIANT easier to use. -// Instead of inheriting from VARIANT, we take the containment approach -// in order to have more control over the usage of the variant and guard -// against memory leaks. -class BASE_EXPORT ScopedVariant { - public: - // Declaration of a global variant variable that's always VT_EMPTY - static const VARIANT kEmptyVariant; - - // Default constructor. - ScopedVariant() { - // This is equivalent to what VariantInit does, but less code. - var_.vt = VT_EMPTY; - } - - // Constructor to create a new VT_BSTR VARIANT. - // NOTE: Do not pass a BSTR to this constructor expecting ownership to - // be transferred - explicit ScopedVariant(const wchar_t* str); - - // Creates a new VT_BSTR variant of a specified length. - ScopedVariant(const wchar_t* str, UINT length); - - // Creates a new integral type variant and assigns the value to - // VARIANT.lVal (32 bit sized field). - explicit ScopedVariant(int value, VARTYPE vt = VT_I4); - - // Creates a new double-precision type variant. |vt| must be either VT_R8 - // or VT_DATE. - explicit ScopedVariant(double value, VARTYPE vt = VT_R8); - - // VT_DISPATCH - explicit ScopedVariant(IDispatch* dispatch); - - // VT_UNKNOWN - explicit ScopedVariant(IUnknown* unknown); - - // SAFEARRAY - explicit ScopedVariant(SAFEARRAY* safearray); - - // Copies the variant. - explicit ScopedVariant(const VARIANT& var); - - ~ScopedVariant(); - - inline VARTYPE type() const { - return var_.vt; - } - - // Give ScopedVariant ownership over an already allocated VARIANT. - void Reset(const VARIANT& var = kEmptyVariant); - - // Releases ownership of the VARIANT to the caller. - VARIANT Release(); - - // Swap two ScopedVariant's. - void Swap(ScopedVariant& var); - - // Returns a copy of the variant. - VARIANT Copy() const; - - // The return value is 0 if the variants are equal, 1 if this object is - // greater than |var|, -1 if it is smaller. - int Compare(const VARIANT& var, bool ignore_case = false) const; - - // Retrieves the pointer address. - // Used to receive a VARIANT as an out argument (and take ownership). - // The function DCHECKs on the current value being empty/null. - // Usage: GetVariant(var.receive()); - VARIANT* Receive(); - - void Set(const wchar_t* str); - - // Setters for simple types. - void Set(int8 i8); - void Set(uint8 ui8); - void Set(int16 i16); - void Set(uint16 ui16); - void Set(int32 i32); - void Set(uint32 ui32); - void Set(int64 i64); - void Set(uint64 ui64); - void Set(float r32); - void Set(double r64); - void Set(bool b); - - // Creates a copy of |var| and assigns as this instance's value. - // Note that this is different from the Reset() method that's used to - // free the current value and assume ownership. - void Set(const VARIANT& var); - - // COM object setters - void Set(IDispatch* disp); - void Set(IUnknown* unk); - - // SAFEARRAY support - void Set(SAFEARRAY* array); - - // Special setter for DATE since DATE is a double and we already have - // a setter for double. - void SetDate(DATE date); - - // Allows const access to the contained variant without DCHECKs etc. - // This support is necessary for the V_XYZ (e.g. V_BSTR) set of macros to - // work properly but still doesn't allow modifications since we want control - // over that. - const VARIANT* operator&() const { - return &var_; - } - - // Like other scoped classes (e.g scoped_refptr, ScopedComPtr, ScopedBstr) - // we support the assignment operator for the type we wrap. - ScopedVariant& operator=(const VARIANT& var); - - // A hack to pass a pointer to the variant where the accepting - // function treats the variant as an input-only, read-only value - // but the function prototype requires a non const variant pointer. - // There's no DCHECK or anything here. Callers must know what they're doing. - VARIANT* AsInput() const { - // The nature of this function is const, so we declare - // it as such and cast away the constness here. - return const_cast(&var_); - } - - // Allows the ScopedVariant instance to be passed to functions either by value - // or by const reference. - operator const VARIANT&() const { - return var_; - } - - // Used as a debug check to see if we're leaking anything. - static bool IsLeakableVarType(VARTYPE vt); - - protected: - VARIANT var_; - - private: - // Comparison operators for ScopedVariant are not supported at this point. - // Use the Compare method instead. - bool operator==(const ScopedVariant& var) const; - bool operator!=(const ScopedVariant& var) const; - DISALLOW_COPY_AND_ASSIGN(ScopedVariant); -}; - -} // namespace win -} // namesoace base - -#endif // BASE_WIN_SCOPED_VARIANT_H_ diff --git a/base/win/scoped_variant_unittest.cc b/base/win/scoped_variant_unittest.cc deleted file mode 100644 index 1f017cf94a..0000000000 --- a/base/win/scoped_variant_unittest.cc +++ /dev/null @@ -1,261 +0,0 @@ -// Copyright (c) 2011 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "base/win/scoped_variant.h" -#include "testing/gtest/include/gtest/gtest.h" - -namespace base { -namespace win { - -namespace { - -static const wchar_t kTestString1[] = L"Used to create BSTRs"; -static const wchar_t kTestString2[] = L"Also used to create BSTRs"; - -void GiveMeAVariant(VARIANT* ret) { - EXPECT_TRUE(ret != NULL); - ret->vt = VT_BSTR; - V_BSTR(ret) = ::SysAllocString(kTestString1); -} - -// A dummy IDispatch implementation (if you can call it that). -// The class does nothing intelligent really. Only increments a counter -// when AddRef is called and decrements it when Release is called. -class FakeComObject : public IDispatch { - public: - FakeComObject() : ref_(0) { - } - - STDMETHOD_(DWORD, AddRef)() { - ref_++; - return ref_; - } - - STDMETHOD_(DWORD, Release)() { - ref_--; - return ref_; - } - - STDMETHOD(QueryInterface)(REFIID, void**) { - return E_NOTIMPL; - } - - STDMETHOD(GetTypeInfoCount)(UINT*) { - return E_NOTIMPL; - } - - STDMETHOD(GetTypeInfo)(UINT, LCID, ITypeInfo**) { - return E_NOTIMPL; - } - - STDMETHOD(GetIDsOfNames)(REFIID, LPOLESTR*, UINT, LCID, DISPID*) { - return E_NOTIMPL; - } - - STDMETHOD(Invoke)(DISPID, REFIID, LCID, WORD, DISPPARAMS*, VARIANT*, - EXCEPINFO*, UINT*) { - return E_NOTIMPL; - } - - // A way to check the internal reference count of the class. - int ref_count() const { - return ref_; - } - - protected: - int ref_; -}; - -} // namespace - -TEST(ScopedVariantTest, ScopedVariant) { - ScopedVariant var; - EXPECT_TRUE(var.type() == VT_EMPTY); - // V_BSTR(&var) = NULL; <- NOTE: Assignment like that is not supported - - ScopedVariant var_bstr(L"VT_BSTR"); - EXPECT_EQ(VT_BSTR, V_VT(&var_bstr)); - EXPECT_TRUE(V_BSTR(&var_bstr) != NULL); // can't use EXPECT_NE for BSTR - var_bstr.Reset(); - EXPECT_NE(VT_BSTR, V_VT(&var_bstr)); - var_bstr.Set(kTestString2); - EXPECT_EQ(VT_BSTR, V_VT(&var_bstr)); - - VARIANT tmp = var_bstr.Release(); - EXPECT_EQ(VT_EMPTY, V_VT(&var_bstr)); - EXPECT_EQ(VT_BSTR, V_VT(&tmp)); - EXPECT_EQ(0, lstrcmp(V_BSTR(&tmp), kTestString2)); - - var.Reset(tmp); - EXPECT_EQ(VT_BSTR, V_VT(&var)); - EXPECT_EQ(0, lstrcmpW(V_BSTR(&var), kTestString2)); - - var_bstr.Swap(var); - EXPECT_EQ(VT_EMPTY, V_VT(&var)); - EXPECT_EQ(VT_BSTR, V_VT(&var_bstr)); - EXPECT_EQ(0, lstrcmpW(V_BSTR(&var_bstr), kTestString2)); - var_bstr.Reset(); - - // Test the Compare and Copy routines. - GiveMeAVariant(var_bstr.Receive()); - ScopedVariant var_bstr2(V_BSTR(&var_bstr)); - EXPECT_EQ(0, var_bstr.Compare(var_bstr2)); - var_bstr2.Reset(); - EXPECT_NE(0, var_bstr.Compare(var_bstr2)); - var_bstr2.Reset(var_bstr.Copy()); - EXPECT_EQ(0, var_bstr.Compare(var_bstr2)); - var_bstr2.Reset(); - var_bstr2.Set(V_BSTR(&var_bstr)); - EXPECT_EQ(0, var_bstr.Compare(var_bstr2)); - var_bstr2.Reset(); - var_bstr.Reset(); - - // Test for the SetDate setter. - SYSTEMTIME sys_time; - ::GetSystemTime(&sys_time); - DATE date; - ::SystemTimeToVariantTime(&sys_time, &date); - var.Reset(); - var.SetDate(date); - EXPECT_EQ(VT_DATE, var.type()); - EXPECT_EQ(date, V_DATE(&var)); - - // Simple setter tests. These do not require resetting the variant - // after each test since the variant type is not "leakable" (i.e. doesn't - // need to be freed explicitly). - - // We need static cast here since char defaults to int (!?). - var.Set(static_cast('v')); - EXPECT_EQ(VT_I1, var.type()); - EXPECT_EQ('v', V_I1(&var)); - - var.Set(static_cast(123)); - EXPECT_EQ(VT_I2, var.type()); - EXPECT_EQ(123, V_I2(&var)); - - var.Set(static_cast(123)); - EXPECT_EQ(VT_I4, var.type()); - EXPECT_EQ(123, V_I4(&var)); - - var.Set(static_cast(123)); - EXPECT_EQ(VT_I8, var.type()); - EXPECT_EQ(123, V_I8(&var)); - - var.Set(static_cast(123)); - EXPECT_EQ(VT_UI1, var.type()); - EXPECT_EQ(123, V_UI1(&var)); - - var.Set(static_cast(123)); - EXPECT_EQ(VT_UI2, var.type()); - EXPECT_EQ(123, V_UI2(&var)); - - var.Set(static_cast(123)); - EXPECT_EQ(VT_UI4, var.type()); - EXPECT_EQ(123, V_UI4(&var)); - - var.Set(static_cast(123)); - EXPECT_EQ(VT_UI8, var.type()); - EXPECT_EQ(123, V_UI8(&var)); - - var.Set(123.123f); - EXPECT_EQ(VT_R4, var.type()); - EXPECT_EQ(123.123f, V_R4(&var)); - - var.Set(static_cast(123.123)); - EXPECT_EQ(VT_R8, var.type()); - EXPECT_EQ(123.123, V_R8(&var)); - - var.Set(true); - EXPECT_EQ(VT_BOOL, var.type()); - EXPECT_EQ(VARIANT_TRUE, V_BOOL(&var)); - var.Set(false); - EXPECT_EQ(VT_BOOL, var.type()); - EXPECT_EQ(VARIANT_FALSE, V_BOOL(&var)); - - // Com interface tests - - var.Set(static_cast(NULL)); - EXPECT_EQ(VT_DISPATCH, var.type()); - EXPECT_EQ(NULL, V_DISPATCH(&var)); - var.Reset(); - - var.Set(static_cast(NULL)); - EXPECT_EQ(VT_UNKNOWN, var.type()); - EXPECT_EQ(NULL, V_UNKNOWN(&var)); - var.Reset(); - - FakeComObject faker; - EXPECT_EQ(0, faker.ref_count()); - var.Set(static_cast(&faker)); - EXPECT_EQ(VT_DISPATCH, var.type()); - EXPECT_EQ(&faker, V_DISPATCH(&var)); - EXPECT_EQ(1, faker.ref_count()); - var.Reset(); - EXPECT_EQ(0, faker.ref_count()); - - var.Set(static_cast(&faker)); - EXPECT_EQ(VT_UNKNOWN, var.type()); - EXPECT_EQ(&faker, V_UNKNOWN(&var)); - EXPECT_EQ(1, faker.ref_count()); - var.Reset(); - EXPECT_EQ(0, faker.ref_count()); - - { - ScopedVariant disp_var(&faker); - EXPECT_EQ(VT_DISPATCH, disp_var.type()); - EXPECT_EQ(&faker, V_DISPATCH(&disp_var)); - EXPECT_EQ(1, faker.ref_count()); - } - EXPECT_EQ(0, faker.ref_count()); - - { - ScopedVariant ref1(&faker); - EXPECT_EQ(1, faker.ref_count()); - ScopedVariant ref2(static_cast(ref1)); - EXPECT_EQ(2, faker.ref_count()); - ScopedVariant ref3; - ref3 = static_cast(ref2); - EXPECT_EQ(3, faker.ref_count()); - } - EXPECT_EQ(0, faker.ref_count()); - - { - ScopedVariant unk_var(static_cast(&faker)); - EXPECT_EQ(VT_UNKNOWN, unk_var.type()); - EXPECT_EQ(&faker, V_UNKNOWN(&unk_var)); - EXPECT_EQ(1, faker.ref_count()); - } - EXPECT_EQ(0, faker.ref_count()); - - VARIANT raw; - raw.vt = VT_UNKNOWN; - raw.punkVal = &faker; - EXPECT_EQ(0, faker.ref_count()); - var.Set(raw); - EXPECT_EQ(1, faker.ref_count()); - var.Reset(); - EXPECT_EQ(0, faker.ref_count()); - - { - ScopedVariant number(123); - EXPECT_EQ(VT_I4, number.type()); - EXPECT_EQ(123, V_I4(&number)); - } - - // SAFEARRAY tests - var.Set(static_cast(NULL)); - EXPECT_EQ(VT_EMPTY, var.type()); - - SAFEARRAY* sa = ::SafeArrayCreateVector(VT_UI1, 0, 100); - ASSERT_TRUE(sa != NULL); - - var.Set(sa); - EXPECT_TRUE(ScopedVariant::IsLeakableVarType(var.type())); - EXPECT_EQ(VT_ARRAY | VT_UI1, var.type()); - EXPECT_EQ(sa, V_ARRAY(&var)); - // The array is destroyed in the destructor of var. -} - -} // namespace win -} // namespace base diff --git a/base/win/shortcut.cc b/base/win/shortcut.cc deleted file mode 100644 index 57a93dc652..0000000000 --- a/base/win/shortcut.cc +++ /dev/null @@ -1,249 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "base/win/shortcut.h" - -#include -#include -#include - -#include "base/file_util.h" -#include "base/threading/thread_restrictions.h" -#include "base/win/scoped_comptr.h" -#include "base/win/win_util.h" -#include "base/win/windows_version.h" - -namespace base { -namespace win { - -namespace { - -// Initializes |i_shell_link| and |i_persist_file| (releasing them first if they -// are already initialized). -// If |shortcut| is not NULL, loads |shortcut| into |i_persist_file|. -// If any of the above steps fail, both |i_shell_link| and |i_persist_file| will -// be released. -void InitializeShortcutInterfaces( - const wchar_t* shortcut, - ScopedComPtr* i_shell_link, - ScopedComPtr* i_persist_file) { - i_shell_link->Release(); - i_persist_file->Release(); - if (FAILED(i_shell_link->CreateInstance(CLSID_ShellLink, NULL, - CLSCTX_INPROC_SERVER)) || - FAILED(i_persist_file->QueryFrom(*i_shell_link)) || - (shortcut && FAILED((*i_persist_file)->Load(shortcut, STGM_READWRITE)))) { - i_shell_link->Release(); - i_persist_file->Release(); - } -} - -} // namespace - -bool CreateOrUpdateShortcutLink(const FilePath& shortcut_path, - const ShortcutProperties& properties, - ShortcutOperation operation) { - base::ThreadRestrictions::AssertIOAllowed(); - - // A target is required unless |operation| is SHORTCUT_UPDATE_EXISTING. - if (operation != SHORTCUT_UPDATE_EXISTING && - !(properties.options & ShortcutProperties::PROPERTIES_TARGET)) { - NOTREACHED(); - return false; - } - - bool shortcut_existed = PathExists(shortcut_path); - - // Interfaces to the old shortcut when replacing an existing shortcut. - ScopedComPtr old_i_shell_link; - ScopedComPtr old_i_persist_file; - - // Interfaces to the shortcut being created/updated. - ScopedComPtr i_shell_link; - ScopedComPtr i_persist_file; - switch (operation) { - case SHORTCUT_CREATE_ALWAYS: - InitializeShortcutInterfaces(NULL, &i_shell_link, &i_persist_file); - break; - case SHORTCUT_UPDATE_EXISTING: - InitializeShortcutInterfaces(shortcut_path.value().c_str(), &i_shell_link, - &i_persist_file); - break; - case SHORTCUT_REPLACE_EXISTING: - InitializeShortcutInterfaces(shortcut_path.value().c_str(), - &old_i_shell_link, &old_i_persist_file); - // Confirm |shortcut_path| exists and is a shortcut by verifying - // |old_i_persist_file| was successfully initialized in the call above. If - // so, initialize the interfaces to begin writing a new shortcut (to - // overwrite the current one if successful). - if (old_i_persist_file.get()) - InitializeShortcutInterfaces(NULL, &i_shell_link, &i_persist_file); - break; - default: - NOTREACHED(); - } - - // Return false immediately upon failure to initialize shortcut interfaces. - if (!i_persist_file.get()) - return false; - - if ((properties.options & ShortcutProperties::PROPERTIES_TARGET) && - FAILED(i_shell_link->SetPath(properties.target.value().c_str()))) { - return false; - } - - if ((properties.options & ShortcutProperties::PROPERTIES_WORKING_DIR) && - FAILED(i_shell_link->SetWorkingDirectory( - properties.working_dir.value().c_str()))) { - return false; - } - - if (properties.options & ShortcutProperties::PROPERTIES_ARGUMENTS) { - if (FAILED(i_shell_link->SetArguments(properties.arguments.c_str()))) - return false; - } else if (old_i_persist_file.get()) { - wchar_t current_arguments[MAX_PATH] = {0}; - if (SUCCEEDED(old_i_shell_link->GetArguments(current_arguments, - MAX_PATH))) { - i_shell_link->SetArguments(current_arguments); - } - } - - if ((properties.options & ShortcutProperties::PROPERTIES_DESCRIPTION) && - FAILED(i_shell_link->SetDescription(properties.description.c_str()))) { - return false; - } - - if ((properties.options & ShortcutProperties::PROPERTIES_ICON) && - FAILED(i_shell_link->SetIconLocation(properties.icon.value().c_str(), - properties.icon_index))) { - return false; - } - - bool has_app_id = - (properties.options & ShortcutProperties::PROPERTIES_APP_ID) != 0; - bool has_dual_mode = - (properties.options & ShortcutProperties::PROPERTIES_DUAL_MODE) != 0; - if ((has_app_id || has_dual_mode) && - GetVersion() >= VERSION_WIN7) { - ScopedComPtr property_store; - if (FAILED(property_store.QueryFrom(i_shell_link)) || !property_store.get()) - return false; - - if (has_app_id && - !SetAppIdForPropertyStore(property_store, properties.app_id.c_str())) { - return false; - } - if (has_dual_mode && - !SetBooleanValueForPropertyStore(property_store, - PKEY_AppUserModel_IsDualMode, - properties.dual_mode)) { - return false; - } - } - - // Release the interfaces to the old shortcut to make sure it doesn't prevent - // overwriting it if needed. - old_i_persist_file.Release(); - old_i_shell_link.Release(); - - HRESULT result = i_persist_file->Save(shortcut_path.value().c_str(), TRUE); - - // Release the interfaces in case the SHChangeNotify call below depends on - // the operations above being fully completed. - i_persist_file.Release(); - i_shell_link.Release(); - - // If we successfully created/updated the icon, notify the shell that we have - // done so. - const bool succeeded = SUCCEEDED(result); - if (succeeded) { - if (shortcut_existed) { - // TODO(gab): SHCNE_UPDATEITEM might be sufficient here; further testing - // required. - SHChangeNotify(SHCNE_ASSOCCHANGED, SHCNF_IDLIST, NULL, NULL); - } else { - SHChangeNotify(SHCNE_CREATE, SHCNF_PATH, shortcut_path.value().c_str(), - NULL); - } - } - - return succeeded; -} - -bool ResolveShortcut(const FilePath& shortcut_path, - FilePath* target_path, - string16* args) { - base::ThreadRestrictions::AssertIOAllowed(); - - HRESULT result; - ScopedComPtr i_shell_link; - - // Get pointer to the IShellLink interface. - result = i_shell_link.CreateInstance(CLSID_ShellLink, NULL, - CLSCTX_INPROC_SERVER); - if (FAILED(result)) - return false; - - ScopedComPtr persist; - // Query IShellLink for the IPersistFile interface. - result = persist.QueryFrom(i_shell_link); - if (FAILED(result)) - return false; - - // Load the shell link. - result = persist->Load(shortcut_path.value().c_str(), STGM_READ); - if (FAILED(result)) - return false; - - WCHAR temp[MAX_PATH]; - if (target_path) { - // Try to find the target of a shortcut. - result = i_shell_link->Resolve(0, SLR_NO_UI | SLR_NOSEARCH); - if (FAILED(result)) - return false; - - result = i_shell_link->GetPath(temp, MAX_PATH, NULL, SLGP_UNCPRIORITY); - if (FAILED(result)) - return false; - - *target_path = FilePath(temp); - } - - if (args) { - result = i_shell_link->GetArguments(temp, MAX_PATH); - if (FAILED(result)) - return false; - - *args = string16(temp); - } - return true; -} - -bool TaskbarPinShortcutLink(const wchar_t* shortcut) { - base::ThreadRestrictions::AssertIOAllowed(); - - // "Pin to taskbar" is only supported after Win7. - if (GetVersion() < VERSION_WIN7) - return false; - - int result = reinterpret_cast(ShellExecute(NULL, L"taskbarpin", shortcut, - NULL, NULL, 0)); - return result > 32; -} - -bool TaskbarUnpinShortcutLink(const wchar_t* shortcut) { - base::ThreadRestrictions::AssertIOAllowed(); - - // "Unpin from taskbar" is only supported after Win7. - if (base::win::GetVersion() < base::win::VERSION_WIN7) - return false; - - int result = reinterpret_cast(ShellExecute(NULL, L"taskbarunpin", - shortcut, NULL, NULL, 0)); - return result > 32; -} - -} // namespace win -} // namespace base diff --git a/base/win/shortcut.h b/base/win/shortcut.h deleted file mode 100644 index c68edb9c6f..0000000000 --- a/base/win/shortcut.h +++ /dev/null @@ -1,143 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef BASE_WIN_SHORTCUT_H_ -#define BASE_WIN_SHORTCUT_H_ - -#include - -#include "base/files/file_path.h" -#include "base/logging.h" -#include "base/strings/string16.h" - -namespace base { -namespace win { - -enum ShortcutOperation { - // Create a new shortcut (overwriting if necessary). - SHORTCUT_CREATE_ALWAYS = 0, - // Overwrite an existing shortcut (fails if the shortcut doesn't exist). - // If the arguments are not specified on the new shortcut, keep the old - // shortcut's arguments. - SHORTCUT_REPLACE_EXISTING, - // Update specified properties only on an existing shortcut. - SHORTCUT_UPDATE_EXISTING, -}; - -// Properties for shortcuts. Properties set will be applied to the shortcut on -// creation/update, others will be ignored. -// Callers are encouraged to use the setters provided which take care of -// setting |options| as desired. -struct ShortcutProperties { - enum IndividualProperties { - PROPERTIES_TARGET = 1 << 0, - PROPERTIES_WORKING_DIR = 1 << 1, - PROPERTIES_ARGUMENTS = 1 << 2, - PROPERTIES_DESCRIPTION = 1 << 3, - PROPERTIES_ICON = 1 << 4, - PROPERTIES_APP_ID = 1 << 5, - PROPERTIES_DUAL_MODE = 1 << 6, - }; - - ShortcutProperties() : icon_index(-1), dual_mode(false), options(0U) {} - - void set_target(const FilePath& target_in) { - target = target_in; - options |= PROPERTIES_TARGET; - } - - void set_working_dir(const FilePath& working_dir_in) { - working_dir = working_dir_in; - options |= PROPERTIES_WORKING_DIR; - } - - void set_arguments(const string16& arguments_in) { - // Size restriction as per MSDN at http://goo.gl/TJ7q5. - DCHECK(arguments_in.size() < MAX_PATH); - arguments = arguments_in; - options |= PROPERTIES_ARGUMENTS; - } - - void set_description(const string16& description_in) { - // Size restriction as per MSDN at http://goo.gl/OdNQq. - DCHECK(description_in.size() < MAX_PATH); - description = description_in; - options |= PROPERTIES_DESCRIPTION; - } - - void set_icon(const FilePath& icon_in, int icon_index_in) { - icon = icon_in; - icon_index = icon_index_in; - options |= PROPERTIES_ICON; - } - - void set_app_id(const string16& app_id_in) { - app_id = app_id_in; - options |= PROPERTIES_APP_ID; - } - - void set_dual_mode(bool dual_mode_in) { - dual_mode = dual_mode_in; - options |= PROPERTIES_DUAL_MODE; - } - - // The target to launch from this shortcut. This is mandatory when creating - // a shortcut. - FilePath target; - // The name of the working directory when launching the shortcut. - FilePath working_dir; - // The arguments to be applied to |target| when launching from this shortcut. - // The length of this string must be less than MAX_PATH. - string16 arguments; - // The localized description of the shortcut. - // The length of this string must be less than MAX_PATH. - string16 description; - // The path to the icon (can be a dll or exe, in which case |icon_index| is - // the resource id). - FilePath icon; - int icon_index; - // The app model id for the shortcut (Win7+). - string16 app_id; - // Whether this is a dual mode shortcut (Win8+). - bool dual_mode; - // Bitfield made of IndividualProperties. Properties set in |options| will be - // set on the shortcut, others will be ignored. - uint32 options; -}; - -// This method creates (or updates) a shortcut link at |shortcut_path| using the -// information given through |properties|. -// Ensure you have initialized COM before calling into this function. -// |operation|: a choice from the ShortcutOperation enum. -// If |operation| is SHORTCUT_REPLACE_EXISTING or SHORTCUT_UPDATE_EXISTING and -// |shortcut_path| does not exist, this method is a no-op and returns false. -BASE_EXPORT bool CreateOrUpdateShortcutLink( - const FilePath& shortcut_path, - const ShortcutProperties& properties, - ShortcutOperation operation); - -// Resolve Windows shortcut (.LNK file) -// This methods tries to resolve a shortcut .LNK file. The path of the shortcut -// to resolve is in |shortcut_path|. If |target_path| is not NULL, the target -// will be resolved and placed in |target_path|. If |args| is not NULL, the -// arguments will be retrieved and placed in |args|. The function returns true -// if all requested fields are found successfully. -// Callers can safely use the same variable for both |shortcut_path| and -// |target_path|. -BASE_EXPORT bool ResolveShortcut(const FilePath& shortcut_path, - FilePath* target_path, - string16* args); - -// Pins a shortcut to the Windows 7 taskbar. The shortcut file must already -// exist and be a shortcut that points to an executable. -BASE_EXPORT bool TaskbarPinShortcutLink(const wchar_t* shortcut); - -// Unpins a shortcut from the Windows 7 taskbar. The shortcut must exist and -// already be pinned to the taskbar. -BASE_EXPORT bool TaskbarUnpinShortcutLink(const wchar_t* shortcut); - -} // namespace win -} // namespace base - -#endif // BASE_WIN_SHORTCUT_H_ diff --git a/base/win/shortcut_unittest.cc b/base/win/shortcut_unittest.cc deleted file mode 100644 index b3247b6184..0000000000 --- a/base/win/shortcut_unittest.cc +++ /dev/null @@ -1,273 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "base/win/shortcut.h" - -#include - -#include "base/file_util.h" -#include "base/files/file_path.h" -#include "base/files/scoped_temp_dir.h" -#include "base/test/test_file_util.h" -#include "base/test/test_shortcut_win.h" -#include "base/win/scoped_com_initializer.h" -#include "testing/gtest/include/gtest/gtest.h" - -namespace base { -namespace win { - -namespace { - -static const char kFileContents[] = "This is a target."; -static const char kFileContents2[] = "This is another target."; - -class ShortcutTest : public testing::Test { - protected: - virtual void SetUp() OVERRIDE { - ASSERT_TRUE(temp_dir_.CreateUniqueTempDir()); - ASSERT_TRUE(temp_dir_2_.CreateUniqueTempDir()); - - link_file_ = temp_dir_.path().Append(L"My Link.lnk"); - - // Shortcut 1's properties - { - const FilePath target_file(temp_dir_.path().Append(L"Target 1.txt")); - file_util::WriteFile(target_file, kFileContents, - arraysize(kFileContents)); - - link_properties_.set_target(target_file); - link_properties_.set_working_dir(temp_dir_.path()); - link_properties_.set_arguments(L"--magic --awesome"); - link_properties_.set_description(L"Chrome is awesome."); - link_properties_.set_icon(link_properties_.target, 4); - link_properties_.set_app_id(L"Chrome"); - link_properties_.set_dual_mode(false); - } - - // Shortcut 2's properties (all different from properties of shortcut 1). - { - const FilePath target_file_2(temp_dir_.path().Append(L"Target 2.txt")); - file_util::WriteFile(target_file_2, kFileContents2, - arraysize(kFileContents2)); - - FilePath icon_path_2; - file_util::CreateTemporaryFileInDir(temp_dir_.path(), &icon_path_2); - - link_properties_2_.set_target(target_file_2); - link_properties_2_.set_working_dir(temp_dir_2_.path()); - link_properties_2_.set_arguments(L"--super --crazy"); - link_properties_2_.set_description(L"The best in the west."); - link_properties_2_.set_icon(icon_path_2, 0); - link_properties_2_.set_app_id(L"Chrome.UserLevelCrazySuffix"); - link_properties_2_.set_dual_mode(true); - } - } - - ScopedCOMInitializer com_initializer_; - ScopedTempDir temp_dir_; - ScopedTempDir temp_dir_2_; - - // The link file to be created/updated in the shortcut tests below. - FilePath link_file_; - - // Properties for the created shortcut. - ShortcutProperties link_properties_; - - // Properties for the updated shortcut. - ShortcutProperties link_properties_2_; -}; - -} // namespace - -TEST_F(ShortcutTest, CreateAndResolveShortcut) { - ShortcutProperties only_target_properties; - only_target_properties.set_target(link_properties_.target); - - ASSERT_TRUE(CreateOrUpdateShortcutLink( - link_file_, only_target_properties, SHORTCUT_CREATE_ALWAYS)); - - FilePath resolved_name; - EXPECT_TRUE(ResolveShortcut(link_file_, &resolved_name, NULL)); - - char read_contents[arraysize(kFileContents)]; - file_util::ReadFile(resolved_name, read_contents, arraysize(read_contents)); - EXPECT_STREQ(kFileContents, read_contents); -} - -TEST_F(ShortcutTest, ResolveShortcutWithArgs) { - ASSERT_TRUE(CreateOrUpdateShortcutLink( - link_file_, link_properties_, SHORTCUT_CREATE_ALWAYS)); - - FilePath resolved_name; - string16 args; - EXPECT_TRUE(ResolveShortcut(link_file_, &resolved_name, &args)); - - char read_contents[arraysize(kFileContents)]; - file_util::ReadFile(resolved_name, read_contents, arraysize(read_contents)); - EXPECT_STREQ(kFileContents, read_contents); - EXPECT_EQ(link_properties_.arguments, args); -} - -TEST_F(ShortcutTest, CreateShortcutWithOnlySomeProperties) { - ShortcutProperties target_and_args_properties; - target_and_args_properties.set_target(link_properties_.target); - target_and_args_properties.set_arguments(link_properties_.arguments); - - ASSERT_TRUE(CreateOrUpdateShortcutLink( - link_file_, target_and_args_properties, - SHORTCUT_CREATE_ALWAYS)); - - ValidateShortcut(link_file_, target_and_args_properties); -} - -TEST_F(ShortcutTest, CreateShortcutVerifyProperties) { - ASSERT_TRUE(CreateOrUpdateShortcutLink( - link_file_, link_properties_, SHORTCUT_CREATE_ALWAYS)); - - ValidateShortcut(link_file_, link_properties_); -} - -TEST_F(ShortcutTest, UpdateShortcutVerifyProperties) { - ASSERT_TRUE(CreateOrUpdateShortcutLink( - link_file_, link_properties_, SHORTCUT_CREATE_ALWAYS)); - - ASSERT_TRUE(CreateOrUpdateShortcutLink( - link_file_, link_properties_2_, SHORTCUT_UPDATE_EXISTING)); - - ValidateShortcut(link_file_, link_properties_2_); -} - -TEST_F(ShortcutTest, UpdateShortcutUpdateOnlyTargetAndResolve) { - ASSERT_TRUE(CreateOrUpdateShortcutLink( - link_file_, link_properties_, SHORTCUT_CREATE_ALWAYS)); - - ShortcutProperties update_only_target_properties; - update_only_target_properties.set_target(link_properties_2_.target); - - ASSERT_TRUE(CreateOrUpdateShortcutLink( - link_file_, update_only_target_properties, - SHORTCUT_UPDATE_EXISTING)); - - ShortcutProperties expected_properties = link_properties_; - expected_properties.set_target(link_properties_2_.target); - ValidateShortcut(link_file_, expected_properties); - - FilePath resolved_name; - EXPECT_TRUE(ResolveShortcut(link_file_, &resolved_name, NULL)); - - char read_contents[arraysize(kFileContents2)]; - file_util::ReadFile(resolved_name, read_contents, arraysize(read_contents)); - EXPECT_STREQ(kFileContents2, read_contents); -} - -TEST_F(ShortcutTest, UpdateShortcutMakeDualMode) { - ASSERT_TRUE(CreateOrUpdateShortcutLink( - link_file_, link_properties_, SHORTCUT_CREATE_ALWAYS)); - - ShortcutProperties make_dual_mode_properties; - make_dual_mode_properties.set_dual_mode(true); - - ASSERT_TRUE(CreateOrUpdateShortcutLink( - link_file_, make_dual_mode_properties, - SHORTCUT_UPDATE_EXISTING)); - - ShortcutProperties expected_properties = link_properties_; - expected_properties.set_dual_mode(true); - ValidateShortcut(link_file_, expected_properties); -} - -TEST_F(ShortcutTest, UpdateShortcutRemoveDualMode) { - ASSERT_TRUE(CreateOrUpdateShortcutLink( - link_file_, link_properties_2_, SHORTCUT_CREATE_ALWAYS)); - - ShortcutProperties remove_dual_mode_properties; - remove_dual_mode_properties.set_dual_mode(false); - - ASSERT_TRUE(CreateOrUpdateShortcutLink( - link_file_, remove_dual_mode_properties, - SHORTCUT_UPDATE_EXISTING)); - - ShortcutProperties expected_properties = link_properties_2_; - expected_properties.set_dual_mode(false); - ValidateShortcut(link_file_, expected_properties); -} - -TEST_F(ShortcutTest, UpdateShortcutClearArguments) { - ASSERT_TRUE(CreateOrUpdateShortcutLink( - link_file_, link_properties_, SHORTCUT_CREATE_ALWAYS)); - - ShortcutProperties clear_arguments_properties; - clear_arguments_properties.set_arguments(string16()); - - ASSERT_TRUE(CreateOrUpdateShortcutLink( - link_file_, clear_arguments_properties, - SHORTCUT_UPDATE_EXISTING)); - - ShortcutProperties expected_properties = link_properties_; - expected_properties.set_arguments(string16()); - ValidateShortcut(link_file_, expected_properties); -} - -TEST_F(ShortcutTest, FailUpdateShortcutThatDoesNotExist) { - ASSERT_FALSE(CreateOrUpdateShortcutLink( - link_file_, link_properties_, SHORTCUT_UPDATE_EXISTING)); - ASSERT_FALSE(PathExists(link_file_)); -} - -TEST_F(ShortcutTest, ReplaceShortcutAllProperties) { - ASSERT_TRUE(CreateOrUpdateShortcutLink( - link_file_, link_properties_, SHORTCUT_CREATE_ALWAYS)); - - ASSERT_TRUE(CreateOrUpdateShortcutLink( - link_file_, link_properties_2_, SHORTCUT_REPLACE_EXISTING)); - - ValidateShortcut(link_file_, link_properties_2_); -} - -TEST_F(ShortcutTest, ReplaceShortcutSomeProperties) { - ASSERT_TRUE(CreateOrUpdateShortcutLink( - link_file_, link_properties_, SHORTCUT_CREATE_ALWAYS)); - - ShortcutProperties new_properties; - new_properties.set_target(link_properties_2_.target); - new_properties.set_arguments(link_properties_2_.arguments); - new_properties.set_description(link_properties_2_.description); - ASSERT_TRUE(CreateOrUpdateShortcutLink( - link_file_, new_properties, SHORTCUT_REPLACE_EXISTING)); - - // Expect only properties in |new_properties| to be set, all other properties - // should have been overwritten. - ShortcutProperties expected_properties(new_properties); - expected_properties.set_working_dir(FilePath()); - expected_properties.set_icon(FilePath(), 0); - expected_properties.set_app_id(string16()); - expected_properties.set_dual_mode(false); - ValidateShortcut(link_file_, expected_properties); -} - -TEST_F(ShortcutTest, FailReplaceShortcutThatDoesNotExist) { - ASSERT_FALSE(CreateOrUpdateShortcutLink( - link_file_, link_properties_, SHORTCUT_REPLACE_EXISTING)); - ASSERT_FALSE(PathExists(link_file_)); -} - -// Test that the old arguments remain on the replaced shortcut when not -// otherwise specified. -TEST_F(ShortcutTest, ReplaceShortcutKeepOldArguments) { - ASSERT_TRUE(CreateOrUpdateShortcutLink( - link_file_, link_properties_, SHORTCUT_CREATE_ALWAYS)); - - // Do not explicitly set the arguments. - link_properties_2_.options &= - ~ShortcutProperties::PROPERTIES_ARGUMENTS; - ASSERT_TRUE(CreateOrUpdateShortcutLink( - link_file_, link_properties_2_, SHORTCUT_REPLACE_EXISTING)); - - ShortcutProperties expected_properties(link_properties_2_); - expected_properties.set_arguments(link_properties_.arguments); - ValidateShortcut(link_file_, expected_properties); -} - -} // namespace win -} // namespace base diff --git a/base/win/startup_information.cc b/base/win/startup_information.cc deleted file mode 100644 index aff52eb794..0000000000 --- a/base/win/startup_information.cc +++ /dev/null @@ -1,109 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "base/win/startup_information.h" - -#include "base/logging.h" -#include "base/win/windows_version.h" - -namespace { - -typedef BOOL (WINAPI *InitializeProcThreadAttributeListFunction)( - LPPROC_THREAD_ATTRIBUTE_LIST attribute_list, - DWORD attribute_count, - DWORD flags, - PSIZE_T size); -static InitializeProcThreadAttributeListFunction - initialize_proc_thread_attribute_list; - -typedef BOOL (WINAPI *UpdateProcThreadAttributeFunction)( - LPPROC_THREAD_ATTRIBUTE_LIST attribute_list, - DWORD flags, - DWORD_PTR attribute, - PVOID value, - SIZE_T size, - PVOID previous_value, - PSIZE_T return_size); -static UpdateProcThreadAttributeFunction update_proc_thread_attribute_list; - -typedef VOID (WINAPI *DeleteProcThreadAttributeListFunction)( - LPPROC_THREAD_ATTRIBUTE_LIST lpAttributeList); -static DeleteProcThreadAttributeListFunction delete_proc_thread_attribute_list; - -} // namespace - -namespace base { -namespace win { - -StartupInformation::StartupInformation() { - memset(&startup_info_, 0, sizeof(startup_info_)); - - // Pre Windows Vista doesn't support STARTUPINFOEX. - if (base::win::GetVersion() < base::win::VERSION_VISTA) { - startup_info_.StartupInfo.cb = sizeof(STARTUPINFO); - return; - } - - startup_info_.StartupInfo.cb = sizeof(startup_info_); - - // Load the attribute API functions. - if (!initialize_proc_thread_attribute_list || - !update_proc_thread_attribute_list || - !delete_proc_thread_attribute_list) { - HMODULE module = ::GetModuleHandleW(L"kernel32.dll"); - initialize_proc_thread_attribute_list = - reinterpret_cast( - ::GetProcAddress(module, "InitializeProcThreadAttributeList")); - update_proc_thread_attribute_list = - reinterpret_cast( - ::GetProcAddress(module, "UpdateProcThreadAttribute")); - delete_proc_thread_attribute_list = - reinterpret_cast( - ::GetProcAddress(module, "DeleteProcThreadAttributeList")); - } -} - -StartupInformation::~StartupInformation() { - if (startup_info_.lpAttributeList) { - delete_proc_thread_attribute_list(startup_info_.lpAttributeList); - delete [] reinterpret_cast(startup_info_.lpAttributeList); - } -} - -bool StartupInformation::InitializeProcThreadAttributeList( - DWORD attribute_count) { - if (startup_info_.StartupInfo.cb != sizeof(startup_info_) || - startup_info_.lpAttributeList) - return false; - - SIZE_T size = 0; - initialize_proc_thread_attribute_list(NULL, attribute_count, 0, &size); - if (size == 0) - return false; - - startup_info_.lpAttributeList = - reinterpret_cast(new BYTE[size]); - if (!initialize_proc_thread_attribute_list(startup_info_.lpAttributeList, - attribute_count, 0, &size)) { - delete [] reinterpret_cast(startup_info_.lpAttributeList); - startup_info_.lpAttributeList = NULL; - return false; - } - - return true; -} - -bool StartupInformation::UpdateProcThreadAttribute( - DWORD_PTR attribute, - void* value, - size_t size) { - if (!startup_info_.lpAttributeList) - return false; - return !!update_proc_thread_attribute_list(startup_info_.lpAttributeList, 0, - attribute, value, size, NULL, NULL); -} - -} // namespace win -} // namespace base - diff --git a/base/win/startup_information.h b/base/win/startup_information.h deleted file mode 100644 index 7cef81f2c8..0000000000 --- a/base/win/startup_information.h +++ /dev/null @@ -1,49 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef BASE_WIN_STARTUP_INFORMATION_H_ -#define BASE_WIN_STARTUP_INFORMATION_H_ - -#include - -#include "base/base_export.h" -#include "base/basictypes.h" - -namespace base { -namespace win { - -// Manages the lifetime of additional attributes in STARTUPINFOEX. -class BASE_EXPORT StartupInformation { - public: - StartupInformation(); - - ~StartupInformation(); - - // Initialize the attribute list for the specified number of entries. - bool InitializeProcThreadAttributeList(DWORD attribute_count); - - // Sets one entry in the initialized attribute list. - bool UpdateProcThreadAttribute(DWORD_PTR attribute, - void* value, - size_t size); - - LPSTARTUPINFOW startup_info() { return &startup_info_.StartupInfo; } - const LPSTARTUPINFOW startup_info() const { - return const_cast(&startup_info_.StartupInfo); - } - - bool has_extended_startup_info() const { - return !!startup_info_.lpAttributeList; - } - - private: - STARTUPINFOEXW startup_info_; - DISALLOW_COPY_AND_ASSIGN(StartupInformation); -}; - -} // namespace win -} // namespace base - -#endif // BASE_WIN_SCOPED_STARTUP_INFO_EX_H_ - diff --git a/base/win/startup_information_unittest.cc b/base/win/startup_information_unittest.cc deleted file mode 100644 index 1903564d87..0000000000 --- a/base/win/startup_information_unittest.cc +++ /dev/null @@ -1,76 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include - -#include - -#include "base/command_line.h" -#include "base/test/multiprocess_test.h" -#include "base/win/scoped_handle.h" -#include "base/win/scoped_process_information.h" -#include "base/win/startup_information.h" -#include "base/win/windows_version.h" -#include "testing/multiprocess_func_list.h" - -const wchar_t kSectionName[] = L"EventTestSection"; -const size_t kSectionSize = 4096; - -MULTIPROCESS_TEST_MAIN(FireInheritedEvents) { - HANDLE section = ::OpenFileMappingW(PAGE_READWRITE, false, kSectionName); - HANDLE* events = reinterpret_cast(::MapViewOfFile(section, - PAGE_READWRITE, 0, 0, kSectionSize)); - // This event should not be valid because it wasn't explicitly inherited. - if (::SetEvent(events[1])) - return -1; - // This event should be valid because it was explicitly inherited. - if (!::SetEvent(events[0])) - return -1; - - return 0; -} - -class StartupInformationTest : public base::MultiProcessTest {}; - -// Verify that only the explicitly specified event is inherited. -TEST_F(StartupInformationTest, InheritStdOut) { - if (base::win::GetVersion() < base::win::VERSION_VISTA) - return; - - base::win::ScopedProcessInformation process_info; - base::win::StartupInformation startup_info; - - HANDLE section = ::CreateFileMappingW(INVALID_HANDLE_VALUE, NULL, - PAGE_READWRITE, 0, kSectionSize, - kSectionName); - ASSERT_TRUE(section); - - HANDLE* events = reinterpret_cast(::MapViewOfFile(section, - FILE_MAP_READ | FILE_MAP_WRITE, 0, 0, kSectionSize)); - - // Make two inheritable events. - SECURITY_ATTRIBUTES security_attributes = { sizeof(security_attributes), - NULL, true }; - events[0] = ::CreateEvent(&security_attributes, false, false, NULL); - ASSERT_TRUE(events[0]); - events[1] = ::CreateEvent(&security_attributes, false, false, NULL); - ASSERT_TRUE(events[1]); - - ASSERT_TRUE(startup_info.InitializeProcThreadAttributeList(1)); - ASSERT_TRUE(startup_info.UpdateProcThreadAttribute( - PROC_THREAD_ATTRIBUTE_HANDLE_LIST, &events[0], - sizeof(events[0]))); - - std::wstring cmd_line = - this->MakeCmdLine("FireInheritedEvents", false).GetCommandLineString(); - - ASSERT_TRUE(::CreateProcess(NULL, const_cast(cmd_line.c_str()), - NULL, NULL, true, EXTENDED_STARTUPINFO_PRESENT, - NULL, NULL, startup_info.startup_info(), - process_info.Receive())) << ::GetLastError(); - // Only the first event should be signalled - EXPECT_EQ(WAIT_OBJECT_0, ::WaitForMultipleObjects(2, events, false, - 4000)); -} - diff --git a/base/win/text_services_message_filter.cc b/base/win/text_services_message_filter.cc deleted file mode 100644 index 7ce233d9fd..0000000000 --- a/base/win/text_services_message_filter.cc +++ /dev/null @@ -1,82 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "base/win/text_services_message_filter.h" - -namespace base { -namespace win { - -TextServicesMessageFilter::TextServicesMessageFilter() - : client_id_(TF_CLIENTID_NULL), - is_initialized_(false) { -} - -TextServicesMessageFilter::~TextServicesMessageFilter() { - if (is_initialized_) - thread_mgr_->Deactivate(); -} - -bool TextServicesMessageFilter::Init() { - if (FAILED(thread_mgr_.CreateInstance(CLSID_TF_ThreadMgr))) - return false; - - if (FAILED(message_pump_.QueryFrom(thread_mgr_))) - return false; - - if (FAILED(keystroke_mgr_.QueryFrom(thread_mgr_))) - return false; - - if (FAILED(thread_mgr_->Activate(&client_id_))) - return false; - - is_initialized_ = true; - return is_initialized_; -} - -// Wraps for ITfMessagePump::PeekMessage with win32 PeekMessage signature. -// Obtains messages from application message queue. -BOOL TextServicesMessageFilter::DoPeekMessage(MSG* msg, - HWND window_handle, - UINT msg_filter_min, - UINT msg_filter_max, - UINT remove_msg) { - BOOL result = FALSE; - if (FAILED(message_pump_->PeekMessage(msg, window_handle, - msg_filter_min, msg_filter_max, - remove_msg, &result))) { - result = FALSE; - } - - return result; -} - -// Sends message to Text Service Manager. -// The message will be used to input composition text. -// Returns true if |message| was consumed by text service manager. -bool TextServicesMessageFilter::ProcessMessage(const MSG& msg) { - if (msg.message == WM_KEYDOWN) { - BOOL eaten = FALSE; - HRESULT hr = keystroke_mgr_->TestKeyDown(msg.wParam, msg.lParam, &eaten); - if (FAILED(hr) && !eaten) - return false; - eaten = FALSE; - hr = keystroke_mgr_->KeyDown(msg.wParam, msg.lParam, &eaten); - return (SUCCEEDED(hr) && !!eaten); - } - - if (msg.message == WM_KEYUP) { - BOOL eaten = FALSE; - HRESULT hr = keystroke_mgr_->TestKeyUp(msg.wParam, msg.lParam, &eaten); - if (FAILED(hr) && !eaten) - return false; - eaten = FALSE; - hr = keystroke_mgr_->KeyUp(msg.wParam, msg.lParam, &eaten); - return (SUCCEEDED(hr) && !!eaten); - } - - return false; -} - -} // namespace win -} // namespace base diff --git a/base/win/text_services_message_filter.h b/base/win/text_services_message_filter.h deleted file mode 100644 index 704c1da640..0000000000 --- a/base/win/text_services_message_filter.h +++ /dev/null @@ -1,48 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef BASE_WIN_TEXT_SERVICES_MESSAGE_FILTER_H_ -#define BASE_WIN_TEXT_SERVICES_MESSAGE_FILTER_H_ - -#include -#include - -#include "base/memory/scoped_ptr.h" -#include "base/message_loop/message_pump_win.h" -#include "base/win/metro.h" -#include "base/win/scoped_comptr.h" - -namespace base { -namespace win { - -// TextServicesMessageFilter extends MessageFilter with methods that are using -// Text Services Framework COM component. -class BASE_EXPORT TextServicesMessageFilter - : public base::MessagePumpForUI::MessageFilter { - public: - TextServicesMessageFilter(); - virtual ~TextServicesMessageFilter(); - virtual BOOL DoPeekMessage(MSG* msg, - HWND window_handle, - UINT msg_filter_min, - UINT msg_filter_max, - UINT remove_msg) OVERRIDE; - virtual bool ProcessMessage(const MSG& msg) OVERRIDE; - - bool Init(); - - private: - TfClientId client_id_; - bool is_initialized_; - base::win::ScopedComPtr thread_mgr_; - base::win::ScopedComPtr message_pump_; - base::win::ScopedComPtr keystroke_mgr_; - - DISALLOW_COPY_AND_ASSIGN(TextServicesMessageFilter); -}; - -} // namespace win -} // namespace base - -#endif // BASE_WIN_TEXT_SERVICES_MESSAGE_FILTER_H_ diff --git a/base/win/win_util.cc b/base/win/win_util.cc deleted file mode 100644 index cdfff8f7ba..0000000000 --- a/base/win/win_util.cc +++ /dev/null @@ -1,350 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "base/win/win_util.h" - -#include -#include -#include -#include // Must be before propkey. -#include -#include -#include -#include -#include -#include - -#include "base/lazy_instance.h" -#include "base/logging.h" -#include "base/memory/scoped_ptr.h" -#include "base/strings/string_util.h" -#include "base/strings/stringprintf.h" -#include "base/threading/thread_restrictions.h" -#include "base/win/registry.h" -#include "base/win/scoped_co_mem.h" -#include "base/win/scoped_handle.h" -#include "base/win/scoped_propvariant.h" -#include "base/win/windows_version.h" - -namespace { - -// Sets the value of |property_key| to |property_value| in |property_store|. -bool SetPropVariantValueForPropertyStore( - IPropertyStore* property_store, - const PROPERTYKEY& property_key, - const base::win::ScopedPropVariant& property_value) { - DCHECK(property_store); - - HRESULT result = property_store->SetValue(property_key, property_value.get()); - if (result == S_OK) - result = property_store->Commit(); - return SUCCEEDED(result); -} - -void __cdecl ForceCrashOnSigAbort(int) { - *((int*)0) = 0x1337; -} - -const wchar_t kWindows8OSKRegPath[] = - L"Software\\Classes\\CLSID\\{054AAE20-4BEA-4347-8A35-64A533254A9D}" - L"\\LocalServer32"; - -} // namespace - -namespace base { -namespace win { - -static bool g_crash_on_process_detach = false; - -#define NONCLIENTMETRICS_SIZE_PRE_VISTA \ - SIZEOF_STRUCT_WITH_SPECIFIED_LAST_MEMBER(NONCLIENTMETRICS, lfMessageFont) - -void GetNonClientMetrics(NONCLIENTMETRICS* metrics) { - DCHECK(metrics); - - static const UINT SIZEOF_NONCLIENTMETRICS = - (base::win::GetVersion() >= base::win::VERSION_VISTA) ? - sizeof(NONCLIENTMETRICS) : NONCLIENTMETRICS_SIZE_PRE_VISTA; - metrics->cbSize = SIZEOF_NONCLIENTMETRICS; - const bool success = !!SystemParametersInfo(SPI_GETNONCLIENTMETRICS, - SIZEOF_NONCLIENTMETRICS, metrics, - 0); - DCHECK(success); -} - -bool GetUserSidString(std::wstring* user_sid) { - // Get the current token. - HANDLE token = NULL; - if (!::OpenProcessToken(::GetCurrentProcess(), TOKEN_QUERY, &token)) - return false; - base::win::ScopedHandle token_scoped(token); - - DWORD size = sizeof(TOKEN_USER) + SECURITY_MAX_SID_SIZE; - scoped_ptr user_bytes(new BYTE[size]); - TOKEN_USER* user = reinterpret_cast(user_bytes.get()); - - if (!::GetTokenInformation(token, TokenUser, user, size, &size)) - return false; - - if (!user->User.Sid) - return false; - - // Convert the data to a string. - wchar_t* sid_string; - if (!::ConvertSidToStringSid(user->User.Sid, &sid_string)) - return false; - - *user_sid = sid_string; - - ::LocalFree(sid_string); - - return true; -} - -bool IsShiftPressed() { - return (::GetKeyState(VK_SHIFT) & 0x8000) == 0x8000; -} - -bool IsCtrlPressed() { - return (::GetKeyState(VK_CONTROL) & 0x8000) == 0x8000; -} - -bool IsAltPressed() { - return (::GetKeyState(VK_MENU) & 0x8000) == 0x8000; -} - -bool UserAccountControlIsEnabled() { - // This can be slow if Windows ends up going to disk. Should watch this key - // for changes and only read it once, preferably on the file thread. - // http://code.google.com/p/chromium/issues/detail?id=61644 - base::ThreadRestrictions::ScopedAllowIO allow_io; - - base::win::RegKey key(HKEY_LOCAL_MACHINE, - L"SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Policies\\System", - KEY_READ); - DWORD uac_enabled; - if (key.ReadValueDW(L"EnableLUA", &uac_enabled) != ERROR_SUCCESS) - return true; - // Users can set the EnableLUA value to something arbitrary, like 2, which - // Vista will treat as UAC enabled, so we make sure it is not set to 0. - return (uac_enabled != 0); -} - -bool SetBooleanValueForPropertyStore(IPropertyStore* property_store, - const PROPERTYKEY& property_key, - bool property_bool_value) { - ScopedPropVariant property_value; - if (FAILED(InitPropVariantFromBoolean(property_bool_value, - property_value.Receive()))) { - return false; - } - - return SetPropVariantValueForPropertyStore(property_store, - property_key, - property_value); -} - -bool SetStringValueForPropertyStore(IPropertyStore* property_store, - const PROPERTYKEY& property_key, - const wchar_t* property_string_value) { - ScopedPropVariant property_value; - if (FAILED(InitPropVariantFromString(property_string_value, - property_value.Receive()))) { - return false; - } - - return SetPropVariantValueForPropertyStore(property_store, - property_key, - property_value); -} - -bool SetAppIdForPropertyStore(IPropertyStore* property_store, - const wchar_t* app_id) { - // App id should be less than 64 chars and contain no space. And recommended - // format is CompanyName.ProductName[.SubProduct.ProductNumber]. - // See http://msdn.microsoft.com/en-us/library/dd378459%28VS.85%29.aspx - DCHECK(lstrlen(app_id) < 64 && wcschr(app_id, L' ') == NULL); - - return SetStringValueForPropertyStore(property_store, - PKEY_AppUserModel_ID, - app_id); -} - -static const char16 kAutoRunKeyPath[] = - L"Software\\Microsoft\\Windows\\CurrentVersion\\Run"; - -bool AddCommandToAutoRun(HKEY root_key, const string16& name, - const string16& command) { - base::win::RegKey autorun_key(root_key, kAutoRunKeyPath, KEY_SET_VALUE); - return (autorun_key.WriteValue(name.c_str(), command.c_str()) == - ERROR_SUCCESS); -} - -bool RemoveCommandFromAutoRun(HKEY root_key, const string16& name) { - base::win::RegKey autorun_key(root_key, kAutoRunKeyPath, KEY_SET_VALUE); - return (autorun_key.DeleteValue(name.c_str()) == ERROR_SUCCESS); -} - -bool ReadCommandFromAutoRun(HKEY root_key, - const string16& name, - string16* command) { - base::win::RegKey autorun_key(root_key, kAutoRunKeyPath, KEY_QUERY_VALUE); - return (autorun_key.ReadValue(name.c_str(), command) == ERROR_SUCCESS); -} - -void SetShouldCrashOnProcessDetach(bool crash) { - g_crash_on_process_detach = crash; -} - -bool ShouldCrashOnProcessDetach() { - return g_crash_on_process_detach; -} - -void SetAbortBehaviorForCrashReporting() { - // Prevent CRT's abort code from prompting a dialog or trying to "report" it. - // Disabling the _CALL_REPORTFAULT behavior is important since otherwise it - // has the sideffect of clearing our exception filter, which means we - // don't get any crash. - _set_abort_behavior(0, _WRITE_ABORT_MSG | _CALL_REPORTFAULT); - - // Set a SIGABRT handler for good measure. We will crash even if the default - // is left in place, however this allows us to crash earlier. And it also - // lets us crash in response to code which might directly call raise(SIGABRT) - signal(SIGABRT, ForceCrashOnSigAbort); -} - -bool IsTouchEnabledDevice() { - if (base::win::GetVersion() < base::win::VERSION_WIN7) - return false; - const int kMultiTouch = NID_INTEGRATED_TOUCH | NID_MULTI_INPUT | NID_READY; - int sm = GetSystemMetrics(SM_DIGITIZER); - if ((sm & kMultiTouch) == kMultiTouch) { - return true; - } - return false; -} - -bool DisplayVirtualKeyboard() { - if (base::win::GetVersion() < base::win::VERSION_WIN8) - return false; - - static base::LazyInstance::Leaky osk_path = - LAZY_INSTANCE_INITIALIZER; - - if (osk_path.Get().empty()) { - // We need to launch TabTip.exe from the location specified under the - // LocalServer32 key for the {{054AAE20-4BEA-4347-8A35-64A533254A9D}} - // CLSID. - // TabTip.exe is typically found at - // c:\program files\common files\microsoft shared\ink on English Windows. - // We don't want to launch TabTip.exe from - // c:\program files (x86)\common files\microsoft shared\ink. This path is - // normally found on 64 bit Windows. - base::win::RegKey key(HKEY_LOCAL_MACHINE, - kWindows8OSKRegPath, - KEY_READ | KEY_WOW64_64KEY); - DWORD osk_path_length = 1024; - if (key.ReadValue(NULL, - WriteInto(&osk_path.Get(), osk_path_length), - &osk_path_length, - NULL) != ERROR_SUCCESS) { - DLOG(WARNING) << "Failed to read on screen keyboard path from registry"; - return false; - } - size_t common_program_files_offset = - osk_path.Get().find(L"%CommonProgramFiles%"); - // Typically the path to TabTip.exe read from the registry will start with - // %CommonProgramFiles% which needs to be replaced with the corrsponding - // expanded string. - // If the path does not begin with %CommonProgramFiles% we use it as is. - if (common_program_files_offset != string16::npos) { - // Preserve the beginning quote in the path. - osk_path.Get().erase(common_program_files_offset, - wcslen(L"%CommonProgramFiles%")); - // The path read from the registry contains the %CommonProgramFiles% - // environment variable prefix. On 64 bit Windows the SHGetKnownFolderPath - // function returns the common program files path with the X86 suffix for - // the FOLDERID_ProgramFilesCommon value. - // To get the correct path to TabTip.exe we first read the environment - // variable CommonProgramW6432 which points to the desired common - // files path. Failing that we fallback to the SHGetKnownFolderPath API. - - // We then replace the %CommonProgramFiles% value with the actual common - // files path found in the process. - string16 common_program_files_path; - scoped_ptr common_program_files_wow6432; - DWORD buffer_size = - GetEnvironmentVariable(L"CommonProgramW6432", NULL, 0); - if (buffer_size) { - common_program_files_wow6432.reset(new wchar_t[buffer_size]); - GetEnvironmentVariable(L"CommonProgramW6432", - common_program_files_wow6432.get(), - buffer_size); - common_program_files_path = common_program_files_wow6432.get(); - DCHECK(!common_program_files_path.empty()); - } else { - base::win::ScopedCoMem common_program_files; - if (FAILED(SHGetKnownFolderPath(FOLDERID_ProgramFilesCommon, 0, NULL, - &common_program_files))) { - return false; - } - common_program_files_path = common_program_files; - } - - osk_path.Get().insert(1, common_program_files_path); - } - } - - HINSTANCE ret = ::ShellExecuteW(NULL, - L"", - osk_path.Get().c_str(), - NULL, - NULL, - SW_SHOW); - return reinterpret_cast(ret) > 32; -} - -bool DismissVirtualKeyboard() { - if (base::win::GetVersion() < base::win::VERSION_WIN8) - return false; - - // We dismiss the virtual keyboard by generating the ESC keystroke - // programmatically. - const wchar_t kOSKClassName[] = L"IPTip_Main_Window"; - HWND osk = ::FindWindow(kOSKClassName, NULL); - if (::IsWindow(osk) && ::IsWindowEnabled(osk)) { - PostMessage(osk, WM_SYSCOMMAND, SC_CLOSE, 0); - return true; - } - return false; -} - -} // namespace win -} // namespace base - -#ifdef _MSC_VER - -// There are optimizer bugs in x86 VS2012 pre-Update 1. -#if _MSC_VER == 1700 && defined _M_IX86 && _MSC_FULL_VER < 170051106 - -#pragma message("Relevant defines:") -#define __STR2__(x) #x -#define __STR1__(x) __STR2__(x) -#define __PPOUT__(x) "#define " #x " " __STR1__(x) -#if defined(_M_IX86) - #pragma message(__PPOUT__(_M_IX86)) -#endif -#if defined(_M_X64) - #pragma message(__PPOUT__(_M_X64)) -#endif -#if defined(_MSC_FULL_VER) - #pragma message(__PPOUT__(_MSC_FULL_VER)) -#endif - -#pragma message("Visual Studio 2012 x86 must be updated to at least Update 1") -#error Must install Update 1 to Visual Studio 2012. -#endif - -#endif // _MSC_VER - diff --git a/base/win/win_util.h b/base/win/win_util.h deleted file mode 100644 index 7577ab8810..0000000000 --- a/base/win/win_util.h +++ /dev/null @@ -1,127 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -// ============================================================================= -// PLEASE READ -// -// In general, you should not be adding stuff to this file. -// -// - If your thing is only used in one place, just put it in a reasonable -// location in or near that one place. It's nice you want people to be able -// to re-use your function, but realistically, if it hasn't been necessary -// before after so many years of development, it's probably not going to be -// used in other places in the future unless you know of them now. -// -// - If your thing is used by multiple callers and is UI-related, it should -// probably be in app/win/ instead. Try to put it in the most specific file -// possible (avoiding the *_util files when practical). -// -// ============================================================================= - -#ifndef BASE_WIN_WIN_UTIL_H_ -#define BASE_WIN_WIN_UTIL_H_ - -#include - -#include - -#include "base/base_export.h" -#include "base/strings/string16.h" - -struct IPropertyStore; -struct _tagpropertykey; -typedef _tagpropertykey PROPERTYKEY; - -namespace base { -namespace win { - -BASE_EXPORT void GetNonClientMetrics(NONCLIENTMETRICS* metrics); - -// Returns the string representing the current user sid. -BASE_EXPORT bool GetUserSidString(std::wstring* user_sid); - -// Returns true if the shift key is currently pressed. -BASE_EXPORT bool IsShiftPressed(); - -// Returns true if the ctrl key is currently pressed. -BASE_EXPORT bool IsCtrlPressed(); - -// Returns true if the alt key is currently pressed. -BASE_EXPORT bool IsAltPressed(); - -// Returns false if user account control (UAC) has been disabled with the -// EnableLUA registry flag. Returns true if user account control is enabled. -// NOTE: The EnableLUA registry flag, which is ignored on Windows XP -// machines, might still exist and be set to 0 (UAC disabled), in which case -// this function will return false. You should therefore check this flag only -// if the OS is Vista or later. -BASE_EXPORT bool UserAccountControlIsEnabled(); - -// Sets the boolean value for a given key in given IPropertyStore. -BASE_EXPORT bool SetBooleanValueForPropertyStore( - IPropertyStore* property_store, - const PROPERTYKEY& property_key, - bool property_bool_value); - -// Sets the string value for a given key in given IPropertyStore. -BASE_EXPORT bool SetStringValueForPropertyStore( - IPropertyStore* property_store, - const PROPERTYKEY& property_key, - const wchar_t* property_string_value); - -// Sets the application id in given IPropertyStore. The function is intended -// for tagging application/chromium shortcut, browser window and jump list for -// Win7. -BASE_EXPORT bool SetAppIdForPropertyStore(IPropertyStore* property_store, - const wchar_t* app_id); - -// Adds the specified |command| using the specified |name| to the AutoRun key. -// |root_key| could be HKCU or HKLM or the root of any user hive. -BASE_EXPORT bool AddCommandToAutoRun(HKEY root_key, const string16& name, - const string16& command); -// Removes the command specified by |name| from the AutoRun key. |root_key| -// could be HKCU or HKLM or the root of any user hive. -BASE_EXPORT bool RemoveCommandFromAutoRun(HKEY root_key, const string16& name); - -// Reads the command specified by |name| from the AutoRun key. |root_key| -// could be HKCU or HKLM or the root of any user hive. Used for unit-tests. -BASE_EXPORT bool ReadCommandFromAutoRun(HKEY root_key, - const string16& name, - string16* command); - -// Sets whether to crash the process during exit. This is inspected by DLLMain -// and used to intercept unexpected terminations of the process (via calls to -// exit(), abort(), _exit(), ExitProcess()) and convert them into crashes. -// Note that not all mechanisms for terminating the process are covered by -// this. In particular, TerminateProcess() is not caught. -BASE_EXPORT void SetShouldCrashOnProcessDetach(bool crash); -BASE_EXPORT bool ShouldCrashOnProcessDetach(); - -// Adjusts the abort behavior so that crash reports can be generated when the -// process is aborted. -BASE_EXPORT void SetAbortBehaviorForCrashReporting(); - -// A touch enabled device by this definition is something that has -// integrated multi-touch ready to use and has Windows version > Windows7. -BASE_EXPORT bool IsTouchEnabledDevice(); - -// Get the size of a struct up to and including the specified member. -// This is necessary to set compatible struct sizes for different versions -// of certain Windows APIs (e.g. SystemParametersInfo). -#define SIZEOF_STRUCT_WITH_SPECIFIED_LAST_MEMBER(struct_name, member) \ - offsetof(struct_name, member) + \ - (sizeof static_cast(NULL)->member) - -// Displays the on screen keyboard on Windows 8 and above. Returns true on -// success. -BASE_EXPORT bool DisplayVirtualKeyboard(); - -// Dismisses the on screen keyboard if it is being displayed on Windows 8 and. -// above. Returns true on success. -BASE_EXPORT bool DismissVirtualKeyboard(); - -} // namespace win -} // namespace base - -#endif // BASE_WIN_WIN_UTIL_H_ diff --git a/base/win/win_util_unittest.cc b/base/win/win_util_unittest.cc deleted file mode 100644 index 11536a9e82..0000000000 --- a/base/win/win_util_unittest.cc +++ /dev/null @@ -1,58 +0,0 @@ -// Copyright (c) 2010 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include - -#include "base/basictypes.h" -#include "base/strings/string_util.h" -#include "base/win/win_util.h" -#include "base/win/windows_version.h" -#include "testing/gtest/include/gtest/gtest.h" - -namespace base { -namespace win { - -namespace { - -// Saves the current thread's locale ID when initialized, and restores it when -// the instance is going out of scope. -class ThreadLocaleSaver { - public: - ThreadLocaleSaver() : original_locale_id_(GetThreadLocale()) {} - ~ThreadLocaleSaver() { SetThreadLocale(original_locale_id_); } - - private: - LCID original_locale_id_; - - DISALLOW_COPY_AND_ASSIGN(ThreadLocaleSaver); -}; - -} // namespace - -// The test is somewhat silly, because the Vista bots some have UAC enabled -// and some have it disabled. At least we check that it does not crash. -TEST(BaseWinUtilTest, TestIsUACEnabled) { - if (GetVersion() >= base::win::VERSION_VISTA) { - UserAccountControlIsEnabled(); - } else { - EXPECT_TRUE(UserAccountControlIsEnabled()); - } -} - -TEST(BaseWinUtilTest, TestGetUserSidString) { - std::wstring user_sid; - EXPECT_TRUE(GetUserSidString(&user_sid)); - EXPECT_TRUE(!user_sid.empty()); -} - -TEST(BaseWinUtilTest, TestGetNonClientMetrics) { - NONCLIENTMETRICS metrics = {0}; - GetNonClientMetrics(&metrics); - EXPECT_TRUE(metrics.cbSize > 0); - EXPECT_TRUE(metrics.iScrollWidth > 0); - EXPECT_TRUE(metrics.iScrollHeight > 0); -} - -} // namespace win -} // namespace base diff --git a/base/win/windows_version.cc b/base/win/windows_version.cc deleted file mode 100644 index 9564d0bed8..0000000000 --- a/base/win/windows_version.cc +++ /dev/null @@ -1,111 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "base/win/windows_version.h" - -#include - -#include "base/logging.h" -#include "base/strings/utf_string_conversions.h" -#include "base/win/registry.h" - -namespace base { -namespace win { - -// static -OSInfo* OSInfo::GetInstance() { - // Note: we don't use the Singleton class because it depends on AtExitManager, - // and it's convenient for other modules to use this classs without it. This - // pattern is copied from gurl.cc. - static OSInfo* info; - if (!info) { - OSInfo* new_info = new OSInfo(); - if (InterlockedCompareExchangePointer( - reinterpret_cast(&info), new_info, NULL)) { - delete new_info; - } - } - return info; -} - -OSInfo::OSInfo() - : version_(VERSION_PRE_XP), - architecture_(OTHER_ARCHITECTURE), - wow64_status_(GetWOW64StatusForProcess(GetCurrentProcess())) { - OSVERSIONINFOEX version_info = { sizeof version_info }; - GetVersionEx(reinterpret_cast(&version_info)); - version_number_.major = version_info.dwMajorVersion; - version_number_.minor = version_info.dwMinorVersion; - version_number_.build = version_info.dwBuildNumber; - if ((version_number_.major == 5) && (version_number_.minor > 0)) { - // Treat XP Pro x64, Home Server, and Server 2003 R2 as Server 2003. - version_ = (version_number_.minor == 1) ? VERSION_XP : VERSION_SERVER_2003; - } else if (version_number_.major == 6) { - switch (version_number_.minor) { - case 0: - // Treat Windows Server 2008 the same as Windows Vista. - version_ = VERSION_VISTA; - break; - case 1: - // Treat Windows Server 2008 R2 the same as Windows 7. - version_ = VERSION_WIN7; - break; - default: - DCHECK_EQ(version_number_.minor, 2); - // Treat Windows Server 2012 the same as Windows 8. - version_ = VERSION_WIN8; - break; - } - } else if (version_number_.major > 6) { - NOTREACHED(); - version_ = VERSION_WIN_LAST; - } - service_pack_.major = version_info.wServicePackMajor; - service_pack_.minor = version_info.wServicePackMinor; - - SYSTEM_INFO system_info = { 0 }; - GetNativeSystemInfo(&system_info); - switch (system_info.wProcessorArchitecture) { - case PROCESSOR_ARCHITECTURE_INTEL: architecture_ = X86_ARCHITECTURE; break; - case PROCESSOR_ARCHITECTURE_AMD64: architecture_ = X64_ARCHITECTURE; break; - case PROCESSOR_ARCHITECTURE_IA64: architecture_ = IA64_ARCHITECTURE; break; - } - processors_ = system_info.dwNumberOfProcessors; - allocation_granularity_ = system_info.dwAllocationGranularity; -} - -OSInfo::~OSInfo() { -} - -std::string OSInfo::processor_model_name() { - if (processor_model_name_.empty()) { - const wchar_t kProcessorNameString[] = - L"HARDWARE\\DESCRIPTION\\System\\CentralProcessor\\0"; - base::win::RegKey key(HKEY_LOCAL_MACHINE, kProcessorNameString, KEY_READ); - string16 value; - key.ReadValue(L"ProcessorNameString", &value); - processor_model_name_ = UTF16ToUTF8(value); - } - return processor_model_name_; -} - -// static -OSInfo::WOW64Status OSInfo::GetWOW64StatusForProcess(HANDLE process_handle) { - typedef BOOL (WINAPI* IsWow64ProcessFunc)(HANDLE, PBOOL); - IsWow64ProcessFunc is_wow64_process = reinterpret_cast( - GetProcAddress(GetModuleHandle(L"kernel32.dll"), "IsWow64Process")); - if (!is_wow64_process) - return WOW64_DISABLED; - BOOL is_wow64 = FALSE; - if (!(*is_wow64_process)(process_handle, &is_wow64)) - return WOW64_UNKNOWN; - return is_wow64 ? WOW64_ENABLED : WOW64_DISABLED; -} - -Version GetVersion() { - return OSInfo::GetInstance()->version(); -} - -} // namespace win -} // namespace base diff --git a/base/win/windows_version.h b/base/win/windows_version.h deleted file mode 100644 index d466dad98e..0000000000 --- a/base/win/windows_version.h +++ /dev/null @@ -1,110 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef BASE_WIN_WINDOWS_VERSION_H_ -#define BASE_WIN_WINDOWS_VERSION_H_ - -#include - -#include "base/base_export.h" -#include "base/basictypes.h" - -typedef void* HANDLE; - -namespace base { -namespace win { - -// The running version of Windows. This is declared outside OSInfo for -// syntactic sugar reasons; see the declaration of GetVersion() below. -// NOTE: Keep these in order so callers can do things like -// "if (base::win::GetVersion() >= base::win::VERSION_VISTA) ...". -enum Version { - VERSION_PRE_XP = 0, // Not supported. - VERSION_XP, - VERSION_SERVER_2003, // Also includes XP Pro x64 and Server 2003 R2. - VERSION_VISTA, // Also includes Windows Server 2008. - VERSION_WIN7, // Also includes Windows Server 2008 R2. - VERSION_WIN8, // Also includes Windows Server 2012. - VERSION_WIN_LAST, // Indicates error condition. -}; - -// A singleton that can be used to query various pieces of information about the -// OS and process state. Note that this doesn't use the base Singleton class, so -// it can be used without an AtExitManager. -class BASE_EXPORT OSInfo { - public: - struct VersionNumber { - int major; - int minor; - int build; - }; - - struct ServicePack { - int major; - int minor; - }; - - // The processor architecture this copy of Windows natively uses. For - // example, given an x64-capable processor, we have three possibilities: - // 32-bit Chrome running on 32-bit Windows: X86_ARCHITECTURE - // 32-bit Chrome running on 64-bit Windows via WOW64: X64_ARCHITECTURE - // 64-bit Chrome running on 64-bit Windows: X64_ARCHITECTURE - enum WindowsArchitecture { - X86_ARCHITECTURE, - X64_ARCHITECTURE, - IA64_ARCHITECTURE, - OTHER_ARCHITECTURE, - }; - - // Whether a process is running under WOW64 (the wrapper that allows 32-bit - // processes to run on 64-bit versions of Windows). This will return - // WOW64_DISABLED for both "32-bit Chrome on 32-bit Windows" and "64-bit - // Chrome on 64-bit Windows". WOW64_UNKNOWN means "an error occurred", e.g. - // the process does not have sufficient access rights to determine this. - enum WOW64Status { - WOW64_DISABLED, - WOW64_ENABLED, - WOW64_UNKNOWN, - }; - - static OSInfo* GetInstance(); - - Version version() const { return version_; } - // The next two functions return arrays of values, [major, minor(, build)]. - VersionNumber version_number() const { return version_number_; } - ServicePack service_pack() const { return service_pack_; } - WindowsArchitecture architecture() const { return architecture_; } - int processors() const { return processors_; } - size_t allocation_granularity() const { return allocation_granularity_; } - WOW64Status wow64_status() const { return wow64_status_; } - std::string processor_model_name(); - - // Like wow64_status(), but for the supplied handle instead of the current - // process. This doesn't touch member state, so you can bypass the singleton. - static WOW64Status GetWOW64StatusForProcess(HANDLE process_handle); - - private: - OSInfo(); - ~OSInfo(); - - Version version_; - VersionNumber version_number_; - ServicePack service_pack_; - WindowsArchitecture architecture_; - int processors_; - size_t allocation_granularity_; - WOW64Status wow64_status_; - std::string processor_model_name_; - - DISALLOW_COPY_AND_ASSIGN(OSInfo); -}; - -// Because this is by far the most commonly-requested value from the above -// singleton, we add a global-scope accessor here as syntactic sugar. -BASE_EXPORT Version GetVersion(); - -} // namespace win -} // namespace base - -#endif // BASE_WIN_WINDOWS_VERSION_H_ diff --git a/base/win/wrapped_window_proc.cc b/base/win/wrapped_window_proc.cc deleted file mode 100644 index 61b79eda88..0000000000 --- a/base/win/wrapped_window_proc.cc +++ /dev/null @@ -1,63 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "base/win/wrapped_window_proc.h" - -#include "base/atomicops.h" -#include "base/logging.h" -#include "base/process/memory.h" - -namespace { - -base::win::WinProcExceptionFilter s_exception_filter = NULL; - -} // namespace. - -namespace base { -namespace win { - -WinProcExceptionFilter SetWinProcExceptionFilter( - WinProcExceptionFilter filter) { - subtle::AtomicWord rv = subtle::NoBarrier_AtomicExchange( - reinterpret_cast(&s_exception_filter), - reinterpret_cast(filter)); - return reinterpret_cast(rv); -} - -int CallExceptionFilter(EXCEPTION_POINTERS* info) { - return s_exception_filter ? s_exception_filter(info) : - EXCEPTION_CONTINUE_SEARCH; -} - -BASE_EXPORT void InitializeWindowClass( - const char16* class_name, - WNDPROC window_proc, - UINT style, - int class_extra, - int window_extra, - HCURSOR cursor, - HBRUSH background, - const char16* menu_name, - HICON large_icon, - HICON small_icon, - WNDCLASSEX* class_out) { - class_out->cbSize = sizeof(WNDCLASSEX); - class_out->style = style; - class_out->lpfnWndProc = window_proc; - class_out->cbClsExtra = class_extra; - class_out->cbWndExtra = window_extra; - class_out->hInstance = base::GetModuleFromAddress(window_proc); - class_out->hIcon = large_icon; - class_out->hCursor = cursor; - class_out->hbrBackground = background; - class_out->lpszMenuName = menu_name; - class_out->lpszClassName = class_name; - class_out->hIconSm = small_icon; - - // Check if |window_proc| is valid. - DCHECK(class_out->hInstance != NULL); -} - -} // namespace win -} // namespace base diff --git a/base/win/wrapped_window_proc.h b/base/win/wrapped_window_proc.h deleted file mode 100644 index d464a9c279..0000000000 --- a/base/win/wrapped_window_proc.h +++ /dev/null @@ -1,85 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -// Provides a way to handle exceptions that happen while a WindowProc is -// running. The behavior of exceptions generated inside a WindowProc is OS -// dependent, but it is possible that the OS just ignores the exception and -// continues execution, which leads to unpredictable behavior for Chrome. - -#ifndef BASE_WIN_WRAPPED_WINDOW_PROC_H_ -#define BASE_WIN_WRAPPED_WINDOW_PROC_H_ - -#include - -#include "base/base_export.h" -#include "base/strings/string16.h" - -namespace base { -namespace win { - -// An exception filter for a WindowProc. The return value determines how the -// exception should be handled, following standard SEH rules. However, the -// expected behavior for this function is to not return, instead of returning -// EXCEPTION_EXECUTE_HANDLER or similar, given that in general we are not -// prepared to handle exceptions. -typedef int (__cdecl *WinProcExceptionFilter)(EXCEPTION_POINTERS* info); - -// Sets the filter to deal with exceptions inside a WindowProc. Returns the old -// exception filter, if any. -// This function should be called before any window is created. -BASE_EXPORT WinProcExceptionFilter SetWinProcExceptionFilter( - WinProcExceptionFilter filter); - -// Calls the registered exception filter. -BASE_EXPORT int CallExceptionFilter(EXCEPTION_POINTERS* info); - -// Initializes the WNDCLASSEX structure |*class_out| to be passed to -// RegisterClassEx() making sure that it is associated with the module -// containing the window procedure. -BASE_EXPORT void InitializeWindowClass( - const char16* class_name, - WNDPROC window_proc, - UINT style, - int class_extra, - int window_extra, - HCURSOR cursor, - HBRUSH background, - const char16* menu_name, - HICON large_icon, - HICON small_icon, - WNDCLASSEX* class_out); - -// Wrapper that supplies a standard exception frame for the provided WindowProc. -// The normal usage is something like this: -// -// LRESULT CALLBACK MyWinProc(HWND hwnd, UINT message, -// WPARAM wparam, LPARAM lparam) { -// // Do Something. -// } -// -// ... -// -// WNDCLASSEX wc = {0}; -// wc.lpfnWndProc = WrappedWindowProc; -// wc.lpszClassName = class_name; -// ... -// RegisterClassEx(&wc); -// -// CreateWindowW(class_name, window_name, ... -// -template -LRESULT CALLBACK WrappedWindowProc(HWND hwnd, UINT message, - WPARAM wparam, LPARAM lparam) { - LRESULT rv = 0; - __try { - rv = proc(hwnd, message, wparam, lparam); - } __except(CallExceptionFilter(GetExceptionInformation())) { - } - return rv; -} - -} // namespace win -} // namespace base - -#endif // BASE_WIN_WRAPPED_WINDOW_PROC_H_ diff --git a/base/win/wrapped_window_proc_unittest.cc b/base/win/wrapped_window_proc_unittest.cc deleted file mode 100644 index 161c913481..0000000000 --- a/base/win/wrapped_window_proc_unittest.cc +++ /dev/null @@ -1,79 +0,0 @@ -// Copyright (c) 2011 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "base/message_loop/message_loop.h" -#include "base/win/wrapped_window_proc.h" -#include "testing/gtest/include/gtest/gtest.h" - -namespace { - -DWORD kExceptionCode = 12345; -WPARAM kCrashMsg = 98765; - -// A trivial WindowProc that generates an exception. -LRESULT CALLBACK TestWindowProc(HWND hwnd, UINT message, - WPARAM wparam, LPARAM lparam) { - if (message == kCrashMsg) - RaiseException(kExceptionCode, 0, 0, NULL); - return DefWindowProc(hwnd, message, wparam, lparam); -} - -// This class implements an exception filter that can be queried about a past -// exception. -class TestWrappedExceptionFiter { - public: - TestWrappedExceptionFiter() : called_(false) { - EXPECT_FALSE(s_filter_); - s_filter_ = this; - } - - ~TestWrappedExceptionFiter() { - EXPECT_EQ(s_filter_, this); - s_filter_ = NULL; - } - - bool called() { - return called_; - } - - // The actual exception filter just records the exception. - static int Filter(EXCEPTION_POINTERS* info) { - EXPECT_FALSE(s_filter_->called_); - if (info->ExceptionRecord->ExceptionCode == kExceptionCode) - s_filter_->called_ = true; - return EXCEPTION_EXECUTE_HANDLER; - } - - private: - bool called_; - static TestWrappedExceptionFiter* s_filter_; -}; -TestWrappedExceptionFiter* TestWrappedExceptionFiter::s_filter_ = NULL; - -} // namespace. - -TEST(WrappedWindowProc, CatchesExceptions) { - HINSTANCE hinst = GetModuleHandle(NULL); - std::wstring class_name(L"TestClass"); - - WNDCLASS wc = {0}; - wc.lpfnWndProc = base::win::WrappedWindowProc; - wc.hInstance = hinst; - wc.lpszClassName = class_name.c_str(); - RegisterClass(&wc); - - HWND window = CreateWindow(class_name.c_str(), 0, 0, 0, 0, 0, 0, HWND_MESSAGE, - 0, hinst, 0); - ASSERT_TRUE(window); - - // Before generating the exception we make sure that the filter will see it. - TestWrappedExceptionFiter wrapper; - base::win::WinProcExceptionFilter old_filter = - base::win::SetWinProcExceptionFilter(TestWrappedExceptionFiter::Filter); - - SendMessage(window, kCrashMsg, 0, 0); - EXPECT_TRUE(wrapper.called()); - - base::win::SetWinProcExceptionFilter(old_filter); -} diff --git a/build/OWNERS b/build/OWNERS deleted file mode 100644 index 72e8ffc0db..0000000000 --- a/build/OWNERS +++ /dev/null @@ -1 +0,0 @@ -* diff --git a/build/README.chromium b/build/README.chromium deleted file mode 100644 index 012df35c7a..0000000000 --- a/build/README.chromium +++ /dev/null @@ -1,15 +0,0 @@ -List of property sheets to be included by projects: - common.vsprops - Not used anymore. No-op. Kept for compatibility with current projects. - - debug.vsprops - Enables debug settings. Must be included directly in Debug configuration. Includes internal\essential.vsprops. - - external_code.vsprops - Contains settings made to simplify usage of external (non-Google) code. It relaxes the warning levels. Should be included after debug.vsprops or release.vsprops to override their settings. - - output_dll_copy.rules - Run to enable automatic copy of DLL when they are as an input file in a vcproj project. - - release.vsprops - Enables release settings. Must be included directly in Release configuration. Includes internal\essential.vsprops. Also includes "internal\release_impl$(CHROME_BUILD_TYPE).vsprops". So the behavior is dependant on the CHROME_BUILD_TYPE environment variable. diff --git a/build/all.gyp b/build/all.gyp deleted file mode 100644 index 6c6aee993a..0000000000 --- a/build/all.gyp +++ /dev/null @@ -1,908 +0,0 @@ -# Copyright (c) 2012 The Chromium Authors. All rights reserved. -# Use of this source code is governed by a BSD-style license that can be -# found in the LICENSE file. - -{ - 'targets': [ - { - 'target_name': 'All', - 'type': 'none', - 'xcode_create_dependents_test_runner': 1, - 'dependencies': [ - 'some.gyp:*', - '../base/base.gyp:*', - '../chrome/chrome.gyp:*', - '../content/content.gyp:*', - '../crypto/crypto.gyp:*', - '../media/media.gyp:*', - '../net/net.gyp:*', - '../sdch/sdch.gyp:*', - '../sql/sql.gyp:*', - '../sync/sync.gyp:*', - '../testing/gmock.gyp:*', - '../testing/gtest.gyp:*', - '../third_party/icu/icu.gyp:*', - '../third_party/libxml/libxml.gyp:*', - '../third_party/sqlite/sqlite.gyp:*', - '../third_party/zlib/zlib.gyp:*', - '../ui/snapshot/snapshot.gyp:*', - '../ui/ui.gyp:*', - '../url/url.gyp:*', - ], - 'conditions': [ - ['OS!="ios"', { - 'dependencies': [ - '../cc/cc_tests.gyp:*', - '../components/components.gyp:*', - '../device/bluetooth/bluetooth.gyp:*', - '../device/device_tests.gyp:*', - '../device/usb/usb.gyp:*', - '../gpu/gpu.gyp:*', - '../gpu/tools/tools.gyp:*', - '../ipc/ipc.gyp:*', - '../jingle/jingle.gyp:*', - '../ppapi/ppapi.gyp:*', - '../ppapi/ppapi_internal.gyp:*', - '../printing/printing.gyp:*', - '../skia/skia.gyp:*', - '../third_party/cacheinvalidation/cacheinvalidation.gyp:*', - '../third_party/cld/cld.gyp:*', - '../third_party/codesighs/codesighs.gyp:*', - '../third_party/ffmpeg/ffmpeg.gyp:*', - '../third_party/iccjpeg/iccjpeg.gyp:*', - '../third_party/libpng/libpng.gyp:*', - '../third_party/libusb/libusb.gyp:*', - '../third_party/libwebp/libwebp.gyp:*', - '../third_party/libxslt/libxslt.gyp:*', - '../third_party/lzma_sdk/lzma_sdk.gyp:*', - '../third_party/mesa/mesa.gyp:*', - '../third_party/modp_b64/modp_b64.gyp:*', - '../third_party/npapi/npapi.gyp:*', - '../third_party/ots/ots.gyp:*', - '../third_party/qcms/qcms.gyp:*', - '../third_party/re2/re2.gyp:re2', - '../third_party/WebKit/public/all.gyp:*', - '../tools/perf/clear_system_cache/clear_system_cache.gyp:*', - '../v8/tools/gyp/v8.gyp:*', - '../webkit/renderer/compositor_bindings/compositor_bindings_tests.gyp:*', - '../webkit/support/webkit_support.gyp:*', - '<(libjpeg_gyp_path):*', - ], - }, { # 'OS=="ios"' - 'dependencies': [ - '../ios/ios.gyp:*', - ], - }], - ['os_posix==1 and OS!="android" and OS!="ios"', { - 'dependencies': [ - '../third_party/yasm/yasm.gyp:*#host', - ], - }], - ['OS=="mac" or OS=="ios" or OS=="win"', { - 'dependencies': [ - '../third_party/nss/nss.gyp:*', - ], - }], - ['OS=="win" or OS=="ios" or OS=="linux"', { - 'dependencies': [ - '../breakpad/breakpad.gyp:*', - ], - }], - ['OS=="mac"', { - 'dependencies': [ - '../third_party/ocmock/ocmock.gyp:*', - ], - }], - ['OS=="linux"', { - 'dependencies': [ - '../courgette/courgette.gyp:*', - '../dbus/dbus.gyp:*', - '../sandbox/sandbox.gyp:*', - ], - 'conditions': [ - ['branding=="Chrome"', { - 'dependencies': [ - '../chrome/chrome.gyp:linux_packages_<(channel)', - ], - }], - ['chromeos==0', { - 'dependencies': [ - '../third_party/cros_dbus_cplusplus/cros_dbus_cplusplus.gyp:*', - '../third_party/libmtp/libmtp.gyp:*', - '../third_party/mtpd/mtpd.gyp:*', - ], - }], - ], - }], - ['use_x11==1', { - 'dependencies': [ - '../tools/xdisplaycheck/xdisplaycheck.gyp:*', - ], - }], - ['toolkit_uses_gtk==1', { - 'dependencies': [ - '../tools/gtk_clipboard_dump/gtk_clipboard_dump.gyp:*', - ], - }], - ['OS=="win"', { - 'conditions': [ - ['win_use_allocator_shim==1', { - 'dependencies': [ - '../base/allocator/allocator.gyp:*', - ], - }], - # Don't enable dependencies that don't work on Win64. - ['target_arch!="x64"', { - 'dependencies': [ - # TODO(jschuh) Enable Win64 Memory Watcher. crbug.com/176877 - '../tools/memory_watcher/memory_watcher.gyp:*', - # TODO(jschuh) Enable Win64 Chrome Frame. crbug.com/176875 - '../chrome_frame/chrome_frame.gyp:*', - ], - }], - ], - 'dependencies': [ - '../cloud_print/cloud_print.gyp:*', - '../courgette/courgette.gyp:*', - '../rlz/rlz.gyp:*', - '../sandbox/sandbox.gyp:*', - '../third_party/angle_dx11/src/build_angle.gyp:*', - '../third_party/bspatch/bspatch.gyp:*', - ], - }, { - 'dependencies': [ - '../third_party/libevent/libevent.gyp:*', - ], - }], - ['toolkit_views==1', { - 'dependencies': [ - '../ui/views/controls/webview/webview.gyp:*', - '../ui/views/views.gyp:*', - ], - }], - ['use_aura==1', { - 'dependencies': [ - '../ui/aura/aura.gyp:*', - '../ui/oak/oak.gyp:*', - ], - }], - ['use_ash==1', { - 'dependencies': [ - '../ash/ash.gyp:*', - ], - }], - ['remoting==1', { - 'dependencies': [ - '../remoting/remoting.gyp:*', - ], - }], - ['use_openssl==0', { - 'dependencies': [ - '../net/third_party/nss/ssl.gyp:*', - ], - }], - ['enable_app_list==1', { - 'dependencies': [ - '../ui/app_list/app_list.gyp:*', - ], - }], - ], - }, # target_name: All - { - 'target_name': 'All_syzygy', - 'type': 'none', - 'conditions': [ - ['OS=="win" and fastbuild==0 and target_arch=="ia32"', { - 'dependencies': [ - '../chrome/installer/mini_installer_syzygy.gyp:*', - ], - }, - ], - ], - }, # target_name: All_syzygy - { - 'target_name': 'chromium_builder_tests', - 'type': 'none', - 'dependencies': [ - '../base/base.gyp:base_unittests', - '../chrome/chrome.gyp:unit_tests', - '../crypto/crypto.gyp:crypto_unittests', - '../media/media.gyp:media_unittests', - '../net/net.gyp:net_unittests', - '../sql/sql.gyp:sql_unittests', - '../ui/ui.gyp:ui_unittests', - '../url/url.gyp:url_unittests', - ], - 'conditions': [ - ['OS!="ios"', { - 'dependencies': [ - '../cc/cc_tests.gyp:cc_unittests', - '../chrome/chrome.gyp:browser_tests', - '../chrome/chrome.gyp:chromedriver2_tests', - '../chrome/chrome.gyp:chromedriver2_unittests', - '../chrome/chrome.gyp:interactive_ui_tests', - '../chrome/chrome.gyp:sync_integration_tests', - '../cloud_print/cloud_print.gyp:cloud_print_unittests', - '../components/components.gyp:components_unittests', - '../content/content.gyp:content_browsertests', - '../content/content.gyp:content_shell', - '../content/content.gyp:content_unittests', - '../device/device_tests.gyp:device_unittests', - '../gpu/gpu.gyp:gpu_unittests', - '../gpu/gles2_conform_support/gles2_conform_support.gyp:gles2_conform_support', - '../ipc/ipc.gyp:ipc_tests', - '../jingle/jingle.gyp:jingle_unittests', - '../ppapi/ppapi_internal.gyp:ppapi_unittests', - '../printing/printing.gyp:printing_unittests', - '../remoting/remoting.gyp:remoting_unittests', - '../sync/sync.gyp:sync_unit_tests', - '../third_party/cacheinvalidation/cacheinvalidation.gyp:cacheinvalidation_unittests', - '../third_party/libphonenumber/libphonenumber.gyp:libphonenumber_unittests', - '../webkit/renderer/compositor_bindings/compositor_bindings_tests.gyp:webkit_compositor_bindings_unittests', - '../third_party/WebKit/public/all.gyp:all_blink', - ], - }], - ['OS=="win"', { - 'dependencies': [ - '../chrome/chrome.gyp:crash_service', - '../chrome/chrome.gyp:installer_util_unittests', - '../chrome/chrome.gyp:mini_installer_test', - # mini_installer_tests depends on mini_installer. This should be - # defined in installer.gyp. - '../chrome/installer/mini_installer.gyp:mini_installer', - '../chrome_frame/chrome_frame.gyp:npchrome_frame', - '../courgette/courgette.gyp:courgette_unittests', - '../sandbox/sandbox.gyp:sbox_integration_tests', - '../sandbox/sandbox.gyp:sbox_unittests', - '../sandbox/sandbox.gyp:sbox_validation_tests', - '../third_party/WebKit/public/blink_test_plugin.gyp:blink_test_plugin', - '../ui/app_list/app_list.gyp:app_list_unittests', - '../ui/views/views.gyp:views_unittests', - ], - 'conditions': [ - ['target_arch!="x64"', { - 'dependencies': [ - '../chrome_frame/chrome_frame.gyp:chrome_frame_net_tests', - '../chrome_frame/chrome_frame.gyp:chrome_frame_perftests', - '../chrome_frame/chrome_frame.gyp:chrome_frame_reliability_tests', - '../chrome_frame/chrome_frame.gyp:chrome_frame_tests', - '../chrome_frame/chrome_frame.gyp:chrome_frame_unittests', - ] - }, { # target_arch!="x64" - 'dependencies!': [ - '../chrome_frame/chrome_frame.gyp:npchrome_frame', - ], - 'defines': [ - 'OMIT_CHROME_FRAME', - ], - }], # target_arch=="x64" - # remoting_host_installation uses lots of non-trivial GYP that tend - # to break because of differences between ninja and msbuild. Make - # sure this target is built by the builders on the main waterfall. - # See http://crbug.com/180600. - ['wix_exists == "True" and sas_dll_exists == "True"', { - 'dependencies': [ - '../remoting/remoting.gyp:remoting_host_installation', - ], - }], - ], - }], - ['OS=="linux"', { - 'dependencies': [ - '../sandbox/sandbox.gyp:sandbox_linux_unittests', - '../dbus/dbus.gyp:dbus_unittests', - ], - }], - ['OS=="mac"', { - 'dependencies': [ - '../ui/app_list/app_list.gyp:app_list_unittests', - '../ui/message_center/message_center.gyp:*', - ], - }], - ['test_isolation_mode != "noop"', { - 'dependencies': [ - 'chromium_swarm_tests', - ], - }], - ], - }, # target_name: chromium_builder_tests - { - 'target_name': 'chromium_2010_builder_tests', - 'type': 'none', - 'dependencies': [ - 'chromium_builder_tests', - ], - }, # target_name: chromium_2010_builder_tests - ], - 'conditions': [ - ['OS!="ios"', { - 'targets': [ - { - 'target_name': 'all_webkit', - 'type': 'none', - 'dependencies': [ - '../third_party/WebKit/public/all.gyp:all_blink', - '../content/content.gyp:content_shell', - ], - }, # target_name: all_webkit - { - 'target_name': 'chromium_builder_nacl_win_integration', - 'type': 'none', - 'dependencies': [ - 'chromium_builder_qa', # needed for pyauto - 'chromium_builder_tests', - ], - }, # target_name: chromium_builder_nacl_win_integration - { - 'target_name': 'chromium_builder_perf', - 'type': 'none', - 'dependencies': [ - 'chromium_builder_qa', # needed for pyauto - '../cc/cc_tests.gyp:cc_perftests', - '../chrome/chrome.gyp:performance_browser_tests', - '../chrome/chrome.gyp:performance_ui_tests', - '../chrome/chrome.gyp:sync_performance_tests', - '../tools/perf/clear_system_cache/clear_system_cache.gyp:*', - ], - }, # target_name: chromium_builder_perf - { - 'target_name': 'chromium_gpu_builder', - 'type': 'none', - 'dependencies': [ - '../chrome/chrome.gyp:gpu_tests', - '../chrome/chrome.gyp:performance_browser_tests', - '../chrome/chrome.gyp:performance_ui_tests', - '../content/content.gyp:content_browsertests', - '../content/content.gyp:content_gl_tests', - '../gpu/gpu.gyp:gl_tests', - ], - 'conditions': [ - ['internal_gles2_conform_tests', { - 'dependencies': [ - '../gpu/gles2_conform_test/gles2_conform_test.gyp:gles2_conform_test', - ], - }], # internal_gles2_conform - ], - }, # target_name: chromium_gpu_builder - { - 'target_name': 'chromium_gpu_debug_builder', - 'type': 'none', - 'dependencies': [ - '../chrome/chrome.gyp:gpu_tests', - '../content/content.gyp:content_browsertests', - '../content/content.gyp:content_gl_tests', - '../gpu/gpu.gyp:gl_tests', - ], - 'conditions': [ - ['internal_gles2_conform_tests', { - 'dependencies': [ - '../gpu/gles2_conform_test/gles2_conform_test.gyp:gles2_conform_test', - ], - }], # internal_gles2_conform - ], - }, # target_name: chromium_gpu_debug_builder - { - 'target_name': 'chromium_builder_qa', - 'type': 'none', - 'dependencies': [ - '../chrome/chrome.gyp:chrome', - # Dependencies of pyauto_functional tests. - '../remoting/remoting.gyp:remoting_webapp', - ], - 'conditions': [ - # If you change this condition, make sure you also change it - # in chrome_tests.gypi - ['enable_automation==1 and (OS=="mac" or ((OS=="win" or os_posix==1) and target_arch==python_arch))', { - 'dependencies': [ - '../chrome/chrome.gyp:pyautolib', - ], - }], - ['OS=="mac"', { - 'dependencies': [ - '../remoting/remoting.gyp:remoting_me2me_host_archive', - ], - }], - ['OS=="win"', { - 'dependencies': [ - '../chrome/chrome.gyp:crash_service', - ], - }], - ['OS=="win" and target_arch=="ia32"', { - 'dependencies': [ - '../chrome/chrome.gyp:crash_service_win64', - ], - }], - ['OS=="win" and component != "shared_library" and wix_exists == "True" and sas_dll_exists == "True"', { - 'dependencies': [ - '../remoting/remoting.gyp:remoting_host_installation', - ], - }], - ], - }, # target_name: chromium_builder_qa - { - 'target_name': 'chromium_builder_perf_av', - 'type': 'none', - 'dependencies': [ - 'all_webkit', # to run layout tests - 'chromium_builder_qa', # needed for perf pyauto tests - ], - }, # target_name: chromium_builder_perf_av - { - # This target contains everything we need to run tests on the special - # device-equipped WebRTC bots. We have device-requiring tests in - # PyAuto, browser_tests and content_browsertests. - 'target_name': 'chromium_builder_webrtc', - 'type': 'none', - 'dependencies': [ - 'chromium_builder_qa', # needed for perf pyauto tests - '../chrome/chrome.gyp:browser_tests', - '../content/content.gyp:content_browsertests', - '../content/content.gyp:content_unittests', - '../third_party/libjingle/libjingle.gyp:peerconnection_server', - '../third_party/webrtc/tools/tools.gyp:frame_analyzer', - '../third_party/webrtc/tools/tools.gyp:rgba_to_i420_converter', - ], - 'conditions': [ - ['OS=="win"', { - 'dependencies': [ - '../chrome/chrome.gyp:crash_service', - ], - }], - ], - }, # target_name: chromium_builder_webrtc - { - 'target_name': 'chromium_builder_chromedriver', - 'type': 'none', - 'dependencies': [ - '../chrome/chrome.gyp:chromedriver2_server', - '../chrome/chrome.gyp:chromedriver2_tests', - '../chrome/chrome.gyp:chromedriver2_unittests', - ], - }, # target_name: chromium_builder_chromedriver - { - 'target_name': 'chromium_builder_asan', - 'type': 'none', - 'dependencies': [ - '../chrome/chrome.gyp:chrome', - - # We refer to content_shell directly rather than all_webkit - # because we don't want the _unittests binaries. - '../content/content.gyp:content_browsertests', - '../content/content.gyp:content_shell', - - '../net/net.gyp:dns_fuzz_stub', - ], - }, - ], # targets - }], - ['OS=="mac"', { - 'targets': [ - { - # Target to build everything plus the dmg. We don't put the dmg - # in the All target because developers really don't need it. - 'target_name': 'all_and_dmg', - 'type': 'none', - 'dependencies': [ - 'All', - '../chrome/chrome.gyp:build_app_dmg', - ], - }, - # These targets are here so the build bots can use them to build - # subsets of a full tree for faster cycle times. - { - 'target_name': 'chromium_builder_dbg', - 'type': 'none', - 'dependencies': [ - '../cc/cc_tests.gyp:cc_unittests', - '../chrome/chrome.gyp:browser_tests', - '../chrome/chrome.gyp:interactive_ui_tests', - '../chrome/chrome.gyp:sync_integration_tests', - '../chrome/chrome.gyp:unit_tests', - '../cloud_print/cloud_print.gyp:cloud_print_unittests', - '../components/components.gyp:components_unittests', - '../content/content.gyp:content_browsertests', - '../content/content.gyp:content_unittests', - '../device/device_tests.gyp:device_unittests', - '../gpu/gpu.gyp:gpu_unittests', - '../ipc/ipc.gyp:ipc_tests', - '../jingle/jingle.gyp:jingle_unittests', - '../media/media.gyp:media_unittests', - '../ppapi/ppapi_internal.gyp:ppapi_unittests', - '../printing/printing.gyp:printing_unittests', - '../remoting/remoting.gyp:remoting_unittests', - '../rlz/rlz.gyp:*', - '../sql/sql.gyp:sql_unittests', - '../sync/sync.gyp:sync_unit_tests', - '../third_party/cacheinvalidation/cacheinvalidation.gyp:cacheinvalidation_unittests', - '../third_party/libphonenumber/libphonenumber.gyp:libphonenumber_unittests', - '../tools/perf/clear_system_cache/clear_system_cache.gyp:*', - '../ui/ui.gyp:ui_unittests', - '../url/url.gyp:url_unittests', - '../webkit/renderer/compositor_bindings/compositor_bindings_tests.gyp:webkit_compositor_bindings_unittests', - ], - }, - { - 'target_name': 'chromium_builder_rel', - 'type': 'none', - 'dependencies': [ - '../cc/cc_tests.gyp:cc_unittests', - '../chrome/chrome.gyp:browser_tests', - '../chrome/chrome.gyp:performance_browser_tests', - '../chrome/chrome.gyp:performance_ui_tests', - '../chrome/chrome.gyp:sync_integration_tests', - '../chrome/chrome.gyp:unit_tests', - '../cloud_print/cloud_print.gyp:cloud_print_unittests', - '../components/components.gyp:components_unittests', - '../content/content.gyp:content_browsertests', - '../content/content.gyp:content_unittests', - '../device/device_tests.gyp:device_unittests', - '../gpu/gpu.gyp:gpu_unittests', - '../ipc/ipc.gyp:ipc_tests', - '../jingle/jingle.gyp:jingle_unittests', - '../media/media.gyp:media_unittests', - '../ppapi/ppapi_internal.gyp:ppapi_unittests', - '../printing/printing.gyp:printing_unittests', - '../remoting/remoting.gyp:remoting_unittests', - '../sql/sql.gyp:sql_unittests', - '../sync/sync.gyp:sync_unit_tests', - '../third_party/cacheinvalidation/cacheinvalidation.gyp:cacheinvalidation_unittests', - '../third_party/libphonenumber/libphonenumber.gyp:libphonenumber_unittests', - '../tools/perf/clear_system_cache/clear_system_cache.gyp:*', - '../ui/ui.gyp:ui_unittests', - '../url/url.gyp:url_unittests', - '../webkit/renderer/compositor_bindings/compositor_bindings_tests.gyp:webkit_compositor_bindings_unittests', - ], - }, - { - 'target_name': 'chromium_builder_dbg_tsan_mac', - 'type': 'none', - 'dependencies': [ - '../base/base.gyp:base_unittests', - '../cloud_print/cloud_print.gyp:cloud_print_unittests', - '../crypto/crypto.gyp:crypto_unittests', - '../ipc/ipc.gyp:ipc_tests', - '../jingle/jingle.gyp:jingle_unittests', - '../media/media.gyp:media_unittests', - '../net/net.gyp:net_unittests', - '../printing/printing.gyp:printing_unittests', - '../remoting/remoting.gyp:remoting_unittests', - '../third_party/cacheinvalidation/cacheinvalidation.gyp:cacheinvalidation_unittests', - '../third_party/libphonenumber/libphonenumber.gyp:libphonenumber_unittests', - '../url/url.gyp:url_unittests', - ], - }, - { - # TODO(dpranke): Update the bots to refer to 'chromium_builder_asan'. - 'target_name': 'chromium_builder_asan_mac', - 'type': 'none', - 'dependencies': [ - 'chromium_builder_asan' - ], - }, - { - 'target_name': 'chromium_builder_dbg_valgrind_mac', - 'type': 'none', - 'dependencies': [ - '../base/base.gyp:base_unittests', - '../chrome/chrome.gyp:unit_tests', - '../cloud_print/cloud_print.gyp:cloud_print_unittests', - '../components/components.gyp:components_unittests', - '../content/content.gyp:content_unittests', - '../crypto/crypto.gyp:crypto_unittests', - '../device/device_tests.gyp:device_unittests', - '../ipc/ipc.gyp:ipc_tests', - '../jingle/jingle.gyp:jingle_unittests', - '../media/media.gyp:media_unittests', - '../net/net.gyp:net_unittests', - '../printing/printing.gyp:printing_unittests', - '../remoting/remoting.gyp:remoting_unittests', - '../sql/sql.gyp:sql_unittests', - '../sync/sync.gyp:sync_unit_tests', - '../third_party/cacheinvalidation/cacheinvalidation.gyp:cacheinvalidation_unittests', - '../third_party/libphonenumber/libphonenumber.gyp:libphonenumber_unittests', - '../ui/ui.gyp:ui_unittests', - '../url/url.gyp:url_unittests', - ], - }, - ], # targets - }], # OS="mac" - ['OS=="win"', { - 'targets': [ - # These targets are here so the build bots can use them to build - # subsets of a full tree for faster cycle times. - { - 'target_name': 'chromium_builder', - 'type': 'none', - 'dependencies': [ - '../cc/cc_tests.gyp:cc_unittests', - '../chrome/chrome.gyp:browser_tests', - '../chrome/chrome.gyp:installer_util_unittests', - '../chrome/chrome.gyp:interactive_ui_tests', - '../chrome/chrome.gyp:mini_installer_test', - '../chrome/chrome.gyp:performance_browser_tests', - '../chrome/chrome.gyp:performance_ui_tests', - '../chrome/chrome.gyp:sync_integration_tests', - '../chrome/chrome.gyp:unit_tests', - '../cloud_print/cloud_print.gyp:cloud_print_unittests', - '../components/components.gyp:components_unittests', - '../content/content.gyp:content_browsertests', - '../content/content.gyp:content_unittests', - # mini_installer_tests depends on mini_installer. This should be - # defined in installer.gyp. - '../chrome/installer/mini_installer.gyp:mini_installer', - '../chrome_frame/chrome_frame.gyp:npchrome_frame', - '../courgette/courgette.gyp:courgette_unittests', - '../device/device_tests.gyp:device_unittests', - '../gpu/gpu.gyp:gpu_unittests', - '../ipc/ipc.gyp:ipc_tests', - '../jingle/jingle.gyp:jingle_unittests', - '../media/media.gyp:media_unittests', - '../ppapi/ppapi_internal.gyp:ppapi_unittests', - '../printing/printing.gyp:printing_unittests', - '../remoting/remoting.gyp:remoting_unittests', - '../sql/sql.gyp:sql_unittests', - '../sync/sync.gyp:sync_unit_tests', - '../third_party/cacheinvalidation/cacheinvalidation.gyp:cacheinvalidation_unittests', - '../third_party/libphonenumber/libphonenumber.gyp:libphonenumber_unittests', - '../tools/perf/clear_system_cache/clear_system_cache.gyp:*', - '../ui/ui.gyp:ui_unittests', - '../ui/views/views.gyp:views_unittests', - '../url/url.gyp:url_unittests', - '../webkit/renderer/compositor_bindings/compositor_bindings_tests.gyp:webkit_compositor_bindings_unittests', - '../third_party/WebKit/public/blink_test_plugin.gyp:blink_test_plugin', - ], - 'conditions': [ - ['target_arch!="x64"', { - 'dependencies': [ - '../chrome_frame/chrome_frame.gyp:chrome_frame_net_tests', - '../chrome_frame/chrome_frame.gyp:chrome_frame_perftests', - '../chrome_frame/chrome_frame.gyp:chrome_frame_reliability_tests', - '../chrome_frame/chrome_frame.gyp:chrome_frame_tests', - '../chrome_frame/chrome_frame.gyp:chrome_frame_unittests', - ] - }, { # target_arch!="x64" - 'dependencies!': [ - '../chrome_frame/chrome_frame.gyp:npchrome_frame', - ], - 'defines': [ - 'OMIT_CHROME_FRAME', - ], - }], # target_arch=="x64" - ], - }, - { - 'target_name': 'chromium_builder_win_cf', - 'type': 'none', - 'conditions': [ - ['target_arch!="x64"', { - 'dependencies': [ - '../chrome_frame/chrome_frame.gyp:chrome_frame_net_tests', - '../chrome_frame/chrome_frame.gyp:chrome_frame_perftests', - '../chrome_frame/chrome_frame.gyp:chrome_frame_reliability_tests', - '../chrome_frame/chrome_frame.gyp:chrome_frame_tests', - '../chrome_frame/chrome_frame.gyp:chrome_frame_unittests', - '../chrome_frame/chrome_frame.gyp:npchrome_frame', - ], - }], # target_arch!="x64" - ], - }, - { - 'target_name': 'chromium_builder_dbg_tsan_win', - 'type': 'none', - 'dependencies': [ - '../base/base.gyp:base_unittests', - '../cloud_print/cloud_print.gyp:cloud_print_unittests', - '../components/components.gyp:components_unittests', - '../content/content.gyp:content_unittests', - '../crypto/crypto.gyp:crypto_unittests', - '../ipc/ipc.gyp:ipc_tests', - '../jingle/jingle.gyp:jingle_unittests', - '../media/media.gyp:media_unittests', - '../net/net.gyp:net_unittests', - '../printing/printing.gyp:printing_unittests', - '../remoting/remoting.gyp:remoting_unittests', - '../sql/sql.gyp:sql_unittests', - '../third_party/cacheinvalidation/cacheinvalidation.gyp:cacheinvalidation_unittests', - '../third_party/libphonenumber/libphonenumber.gyp:libphonenumber_unittests', - '../url/url.gyp:url_unittests', - ], - }, - { - 'target_name': 'chromium_builder_dbg_drmemory_win', - 'type': 'none', - 'dependencies': [ - '../base/base.gyp:base_unittests', - '../chrome/chrome.gyp:unit_tests', - '../chrome/chrome.gyp:browser_tests', - '../cloud_print/cloud_print.gyp:cloud_print_unittests', - '../components/components.gyp:components_unittests', - '../content/content.gyp:content_unittests', - '../crypto/crypto.gyp:crypto_unittests', - '../device/device_tests.gyp:device_unittests', - '../ipc/ipc.gyp:ipc_tests', - '../jingle/jingle.gyp:jingle_unittests', - '../media/media.gyp:media_unittests', - '../net/net.gyp:net_unittests', - '../printing/printing.gyp:printing_unittests', - '../remoting/remoting.gyp:remoting_unittests', - '../sql/sql.gyp:sql_unittests', - '../third_party/cacheinvalidation/cacheinvalidation.gyp:cacheinvalidation_unittests', - '../third_party/libphonenumber/libphonenumber.gyp:libphonenumber_unittests', - '../url/url.gyp:url_unittests', - ], - }, - { - 'target_name': 'webkit_builder_win', - 'type': 'none', - 'dependencies': [ - 'all_webkit', - ], - }, - ], # targets - 'conditions': [ - ['branding=="Chrome"', { - 'targets': [ - { - 'target_name': 'chrome_official_builder', - 'type': 'none', - 'dependencies': [ - '../chrome/chrome.gyp:crash_service', - '../chrome/chrome.gyp:policy_templates', - '../chrome/installer/mini_installer.gyp:mini_installer', - '../courgette/courgette.gyp:courgette', - '../cloud_print/cloud_print.gyp:cloud_print', - '../remoting/remoting.gyp:remoting_webapp', - '../third_party/widevine/cdm/widevine_cdm.gyp:widevinecdmadapter', - ], - 'conditions': [ - # If you change this condition, make sure you also change it - # in chrome_tests.gypi - ['enable_automation==1 and (OS=="mac" or (os_posix==1 and target_arch==python_arch))', { - 'dependencies': [ - '../chrome/chrome.gyp:pyautolib', - ], - }], - ['internal_pdf', { - 'dependencies': [ - '../pdf/pdf.gyp:pdf', - ], - }], # internal_pdf - ['target_arch=="ia32"', { - 'dependencies': [ - '../chrome/chrome.gyp:crash_service_win64', - '../chrome_frame/chrome_frame.gyp:npchrome_frame', - '../courgette/courgette.gyp:courgette64', - # Omitting tests from Win64 to speed up cycle times. - '../chrome/chrome.gyp:automated_ui_tests', - '../chrome/chrome.gyp:chromedriver', - '../chrome/chrome.gyp:interactive_ui_tests', - '../chrome/chrome.gyp:reliability_tests', - ], - }], - ['component != "shared_library" and wix_exists == "True" and \ - sas_dll_exists == "True"', { - 'dependencies': [ - '../remoting/remoting.gyp:remoting_host_installation', - ], - }], # component != "shared_library" - ['target_arch=="x64"', { - 'defines': [ - 'OMIT_CHROME_FRAME', - ], - }], # target_arch=="x64" - ] - }, - ], # targets - }], # branding=="Chrome" - ], # conditions - }], # OS="win" - ['use_aura==1', { - 'targets': [ - { - 'target_name': 'aura_builder', - 'type': 'none', - 'dependencies': [ - '../cc/cc_tests.gyp:cc_unittests', - '../chrome/chrome.gyp:browser_tests', - '../chrome/chrome.gyp:chrome', - '../chrome/chrome.gyp:interactive_ui_tests', - '../chrome/chrome.gyp:unit_tests', - '../components/components.gyp:components_unittests', - '../content/content.gyp:content_browsertests', - '../content/content.gyp:content_unittests', - '../device/device_tests.gyp:device_unittests', - '../ppapi/ppapi_internal.gyp:ppapi_unittests', - '../remoting/remoting.gyp:remoting_unittests', - '../ui/app_list/app_list.gyp:*', - '../ui/aura/aura.gyp:*', - '../ui/compositor/compositor.gyp:*', - '../ui/message_center/message_center.gyp:*', - '../ui/ui.gyp:ui_unittests', - '../ui/snapshot/snapshot.gyp:snapshot_unittests', - '../ui/views/views.gyp:views', - '../ui/views/views.gyp:views_examples_with_content_exe', - '../ui/views/views.gyp:views_unittests', - '../ui/keyboard/keyboard.gyp:*', - '../webkit/renderer/compositor_bindings/compositor_bindings_tests.gyp:webkit_compositor_bindings_unittests', - 'all_webkit', - ], - 'conditions': [ - ['OS=="win"', { - 'dependencies': [ - '../chrome/chrome.gyp:crash_service', - '../chrome_frame/chrome_frame.gyp:npchrome_frame', - ], - }], - ['OS=="win" and target_arch!="x64"', { - 'dependencies': [ - '../chrome_frame/chrome_frame.gyp:chrome_frame_net_tests', - '../chrome_frame/chrome_frame.gyp:chrome_frame_perftests', - '../chrome_frame/chrome_frame.gyp:chrome_frame_reliability_tests', - '../chrome_frame/chrome_frame.gyp:chrome_frame_tests', - '../chrome_frame/chrome_frame.gyp:chrome_frame_unittests', - ], - }], - ['OS=="win" and target_arch=="x64"', { - 'dependencies!': [ - '../chrome_frame/chrome_frame.gyp:npchrome_frame', - ], - 'defines': [ - 'OMIT_CHROME_FRAME', - ], - }], - ['OS=="win" and target_arch=="ia32"', { - 'dependencies': [ - '../chrome/chrome.gyp:crash_service_win64', - ], - }], - ['use_ash==1', { - 'dependencies': [ - '../ash/ash.gyp:ash_shell', - '../ash/ash.gyp:ash_unittests', - ], - }], - ['OS=="linux"', { - # Tests that currently only work on Linux. - 'dependencies': [ - '../base/base.gyp:base_unittests', - '../ipc/ipc.gyp:ipc_tests', - '../sql/sql.gyp:sql_unittests', - '../sync/sync.gyp:sync_unit_tests', - ], - }], - ['OS=="mac"', { - # Exclude dependencies that are not currently implemented. - 'dependencies!': [ - '../chrome/chrome.gyp:chrome', - '../chrome/chrome.gyp:unit_tests', - '../device/device_tests.gyp:device_unittests', - '../ui/views/views.gyp:views_unittests', - ], - }], - ['chromeos==1', { - 'dependencies': [ - '../chromeos/chromeos.gyp:chromeos_unittests', - ], - }], - ], - }, - ], # targets - }], # "use_aura==1" - ['test_isolation_mode != "noop"', { - 'targets': [ - { - 'target_name': 'chromium_swarm_tests', - 'type': 'none', - 'dependencies': [ - '../base/base.gyp:base_unittests_run', - '../chrome/chrome.gyp:browser_tests_run', - '../chrome/chrome.gyp:interactive_ui_tests_run', - '../chrome/chrome.gyp:sync_integration_tests_run', - '../chrome/chrome.gyp:unit_tests_run', - '../net/net.gyp:net_unittests_run', - ], - }, # target_name: chromium_swarm_tests - ], - }], - ], # conditions -} diff --git a/build/all_android.gyp b/build/all_android.gyp deleted file mode 100644 index 2e3711e496..0000000000 --- a/build/all_android.gyp +++ /dev/null @@ -1,136 +0,0 @@ -# Copyright (c) 2012 The Chromium Authors. All rights reserved. -# Use of this source code is governed by a BSD-style license that can be -# found in the LICENSE file. - -# This is all.gyp file for Android to prevent breakage in Android and other -# platform; It will be churning a lot in the short term and eventually be merged -# into all.gyp. - -{ - 'variables': { - # A hook that can be overridden in other repositories to add additional - # compilation targets to 'All' - 'android_app_targets%': [], - }, - 'targets': [ - { - 'target_name': 'All', - 'type': 'none', - 'dependencies': [ - '../content/content.gyp:content_shell_apk', - '<@(android_app_targets)', - 'android_builder_tests', - '../android_webview/android_webview.gyp:android_webview_apk', - '../chrome/chrome.gyp:chromium_testshell', - '../remoting/remoting.gyp:remoting_apk', - # TODO(nyquist) This should instead by a target for sync when all of - # the sync-related code for Android has been upstreamed. - # See http://crbug.com/159203 - '../third_party/cacheinvalidation/cacheinvalidation.gyp:cacheinvalidation_javalib', - ], - }, # target_name: All - { - 'target_name': 'all_webkit', - 'type': 'none', - 'dependencies': [ - '../third_party/WebKit/public/all.gyp:all_blink', - '../content/content.gyp:content_shell_apk', - ], - }, # target_name: all_webkit - { - # The current list of tests for android. This is temporary - # until the full set supported. If adding a new test here, - # please also add it to build/android/pylib/gtest/gtest_config.py, - # else the test is not run. - # - # WARNING: - # Do not add targets here without communicating the implications - # on tryserver triggers and load. Discuss with jrg please. - 'target_name': 'android_builder_tests', - 'type': 'none', - 'dependencies': [ - '../android_webview/android_webview.gyp:android_webview_unittests', - '../base/android/jni_generator/jni_generator.gyp:jni_generator_tests', - '../base/base.gyp:base_unittests', - '../breakpad/breakpad.gyp:breakpad_unittests', - # Also compile the tools needed to deal with minidumps, they are - # needed to run minidump tests upstream. - '../breakpad/breakpad.gyp:dump_syms#host', - '../breakpad/breakpad.gyp:symupload#host', - '../breakpad/breakpad.gyp:minidump_dump#host', - '../breakpad/breakpad.gyp:minidump_stackwalk#host', - '../build/android/tests/multiple_proguards/multiple_proguards.gyp:multiple_proguards_test_apk', - '../cc/cc_tests.gyp:cc_perftests_apk', - '../cc/cc_tests.gyp:cc_unittests', - '../chrome/chrome.gyp:unit_tests', - '../components/components.gyp:components_unittests', - '../content/content.gyp:content_browsertests', - '../content/content.gyp:content_shell_test_apk', - '../content/content.gyp:content_unittests', - '../gpu/gpu.gyp:gl_tests', - '../gpu/gpu.gyp:gpu_unittests', - '../ipc/ipc.gyp:ipc_tests', - '../media/media.gyp:media_unittests', - '../net/net.gyp:net_unittests', - '../sandbox/sandbox.gyp:sandbox_linux_unittests', - '../sql/sql.gyp:sql_unittests', - '../sync/sync.gyp:sync_unit_tests', - '../third_party/WebKit/public/all.gyp:*', - '../tools/android/android_tools.gyp:android_tools', - '../tools/android/device_stats_monitor/device_stats_monitor.gyp:device_stats_monitor', - '../tools/android/findbugs_plugin/findbugs_plugin.gyp:findbugs_plugin_test', - '../ui/ui.gyp:ui_unittests', - # Required by ui_unittests. - # TODO(wangxianzhu): It'd better let ui_unittests depend on it, but - # this would cause circular gyp dependency which needs refactoring the - # gyps to resolve. - '../chrome/chrome_resources.gyp:packed_resources', - ], - 'conditions': [ - ['"<(gtest_target_type)"=="shared_library"', { - 'dependencies': [ - # Unit test bundles packaged as an apk. - '../android_webview/android_webview.gyp:android_webview_unittests_apk', - '../base/base.gyp:base_unittests_apk', - '../cc/cc_tests.gyp:cc_unittests_apk', - '../chrome/chrome.gyp:unit_tests_apk', - '../components/components.gyp:components_unittests_apk', - '../content/content.gyp:content_browsertests_apk', - '../content/content.gyp:content_unittests_apk', - '../content/content.gyp:video_decode_accelerator_unittest_apk', - '../gpu/gpu.gyp:gl_tests_apk', - '../gpu/gpu.gyp:gpu_unittests_apk', - '../ipc/ipc.gyp:ipc_tests_apk', - '../media/media.gyp:media_unittests_apk', - '../net/net.gyp:net_unittests_apk', - '../sandbox/sandbox.gyp:sandbox_linux_jni_unittests_apk', - '../sql/sql.gyp:sql_unittests_apk', - '../sync/sync.gyp:sync_unit_tests_apk', - '../ui/ui.gyp:ui_unittests_apk', - '../android_webview/android_webview.gyp:android_webview_test_apk', - '../chrome/chrome.gyp:chromium_testshell_test_apk', - '../chrome/chrome.gyp:chromium_testshell_uiautomator_tests', - '../webkit/renderer/compositor_bindings/compositor_bindings_tests.gyp:webkit_compositor_bindings_unittests_apk' - ], - }], - ], - }, - { - # Experimental / in-progress targets that are expected to fail - # but we still try to compile them on bots (turning the stage - # orange, not red). - 'target_name': 'android_experimental', - 'type': 'none', - 'dependencies': [ - ], - }, - { - # In-progress targets that are expected to fail and are NOT run - # on any bot. - 'target_name': 'android_in_progress', - 'type': 'none', - 'dependencies': [ - ], - }, - ], # targets -} diff --git a/build/android/AndroidManifest.xml b/build/android/AndroidManifest.xml deleted file mode 100644 index 0822e36585..0000000000 --- a/build/android/AndroidManifest.xml +++ /dev/null @@ -1,13 +0,0 @@ - - - - - diff --git a/build/android/CheckInstallApk-debug.apk b/build/android/CheckInstallApk-debug.apk deleted file mode 100644 index 3dc31910a5388024da4558c9e5f249a37e3783bd..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 37106 zcmdq|bC_gLw>Ai8sS91UZL7<+ZQHhOcGz|_iwjcU`aXlY09VQcd-0RV(1G{_AKAc`D0(BdE$qoM{-mLo}V!ElknL=k2}Ng)f0(8l1c zg@we;?t+z5J|S9JfL+S9GNL29V_#mJU0B$kQ!U;`nKT!LCM@4M$60@{aR7uFL9sj_ z?04{J1+}SsiX)NHu!EtE$bU81MUr*+@7)$I;J6orP8dl(}fvkdW7FdjcT5=98dXB7GB>2zF4iv5ZYR;*M7S zL@x}yu!RvUd3b}q!PTnEU8F4^3RPH3%`9?Qzh}w~tG)=z^1lgx^4FM-ujQ(?F?lX~ z9dxe4y+>WLZkb~Hw1nF$NJB#XSB@3_jeQ$|&;>Lg^D+>B*#`gw?M$5PElp$%?JUhq zon8L2ADT36w;+HTI=gCl!q%HiSTGOqRZRl(y9S|JG7PlBAJ9nN3xXDjc}i$i&Hf;ZTERDuMd%Ka?(*UmJ>#1z-%k~xbkp|>@b<#3A-}qu{tr$nkZfN`f3Ihz> zK5Z>_p_|sdlFtEV&K%$MmzP-NruQ9&#ya zZ_1NwLkuLlc(>r&73T~m6OFOIAFn6N$ByJ>+(Tv)hNpMzz^73Ur>OC?4=l@vMvsO( zE@3AL_fw5FM^AI_C!P6b9!UmS5OgK0L3{ZjSbPJlPsplQe(5!~#N;Kc^j<2M$DK^c z1t;;UXI0tL-o?(Fw=vIqaN=A*~%?QJ%Ky>xNy*X*X;mpY|i zun*t3Q#e;Bk5{B$YW)9*fAux7CQv`mp42hXvF*2gT04CV7Ax3>fB8xF^7e8PqQzaX ztUYB-R%16u9royH;lDX>Bz5Ij;-lwHV)4oe|6VtO<`s+Vf6wpLoxehJthxu&qxl>b zWUu<7a& zld-8Yy`ht{F(?4`UnRhc9smNs1tbH7FMpf20rmh_fD15X3rtx8>;Uut51?!VtWEU4YMKBgLx4LFM!*tN03Gnt1gO~( z*v=AQ4AB3VE>~b{V}J#)+zF_~0hluXAGFy1zoNzBe_IRj|ILg%fFu9kof9lT_CMJY z1kTt6$blOWExU0Wa*ra(>&fs(_&*rWeXmW%<`z*cs^wQvEJ z+Wd<{2Vma+cLI=!zf=GsfH4>_{%fy)E$eUIKY{ii0T{yqK?npR5a2*gT!1eppbQ0E znSZyyzc&A0?e}l`FON?DV)U=w{q4&H82|0}pFsJK0F1GLAP3?ru*H98!GA~a&o%LP z1ct!Xa{yYp-M?1S^k14lK@kCnKnXa#|CL4sO2Ds#|HuOtfPiuUWd2JY4^Sor;{O*s z{+IY)dHI_O^`9lc80>E!|Ff?A|7`K^9RJPyue$y11VK4tNgn#D!Pu~BT!~dxF-+lg__utO{a`?CWAN_y(`e#u8=>I40 z|Ed1JeE!uB+^_-vzLz)SN9iAv004hM1nlqc`OL)0(B06;#+1&&#KDrm(pcZd(ACb^ z!qkc0!Ok2IsURl~2ZR0h>i|wtLPQA|OZ)}Y-%Vciyh$7YAOuK?2&#CjPiK2(o0z&j z_8xg&bgM2cdC$(!R)aQ@1kn@{UkJ!dMN|Gvw~+Z2OG;g5u`9N?gKo@fH3ckDVYP^$ zC2IW2F*q~DI5p3*xgdT1xOLb->vBv(k$NrvOcg&r4D+E728H3vxcb$MNWe_oF z`IFcfflMp{t5`Ia+*?vZvYN~-)EkL55_WFFT0?zz`Iv^o@Qt!!X?w(Z`7G1HCM!0Q z2iEaAt+zjX%i#!wlY;X*K=*d6eLv&dvIG8 zBNU|Grm_|JHl{+miROPZE_jB(4W62A9;bo7Kg#~BnU420TPQszasTXE_Onoq?N31N zA3gIT_1|UsGpO&)=DZQk`IIb~RoZSptG?CxP(NW#4R$@f^09w-^l_gz)mE03CT4tq z;bFazdF^)cYl!196_1|)!-UpojEjqJbUKy8_7KG1#av{Wd2*p1Hu7=LY&6%FnFqf! zicbG-2aKEF=d>khMdv29Y8HGD;*vv{T3GG#VbGob8t`(WYrNQsI~Ye7chrsSJSBMh zTYDSt<9Fr#Qd-m>ames+hRn)y#yZYpc^TX#d3Y0ZPp&fRk3Rw$6&8}v$PSh1DojaH z?d%pl(N@nCBy09tj#;^NdntpU>1DRwE|0Nox}O$%sn#d6)k`K`8TU1u>! zVHC9bPko#6v;ll~ODqBglhf83{x@taO_Sjh4jec6gXgiqMdKn{32D98Q`=b=9LK%wq-5TxpH8?5)N8=oH?A!xO>ABf*vFE#K|J3J9 zDx@2p@8hg_&+7+5+`Hoj{E)rxwX7Vxo$~~Xnlheh?Zfe2$3;EXL}l3lLrrc_$~Yq zuIGhNs;N~>%DRo+!$o2qyoy?n-BQQ=%=DvuYe_+-{Y;7ldq20w=o-Jj5uo{JZ?3p- zbW$OS=D6gPgS<+?$-~VYOPce38_t;)Sfwd>`VmrO1>*>jNQ|qbP6&oTFy2&sMmB6X z2?dEeC;jaBE$$JI=gA^xT}~_ewCCDSyD^&KusrUx4O)AzpCKEg6w4tBg{hzqS z`WuiC=8`Po-;gT0H(HAics~}GaBt7QC<{BEJ?!CHmaRpV1SKjMX9|SvDkSHA+!b>H z@S&iv!QsLXVX>~kz)x<vre<3_FEAW1=|SQNX1PmJOO6;kIHOT9)EXtU0oGLn=exqx~Z^o@8%BQApYeJJyuX^Du`7C|A$ zBB6C^FYmB!-3PuT>gvy3FC(8v&}Py$L2FrCuC8RN?~o+^Avd>eD*Ml_iJv71jnsZj zgSfL7cV0nm3b2A`bx|t;D*<2eFF|L#buJv*M>)ft@sD`61gls^J5HoM55o|gSBIpL zWLH}sw*`$+y25ylo+@-}HnP6?^Oy5}{L(+!@1Ep*)|_lV$gCJm5bOz>O#X&4dsG3Y ze{0_La5`dfFRu%=xV})F10TB#yT_9S(wQnCw^ln;MmEn%a>~&tCzok9ygVLFH!ZP& zrJ0#j!s&T9#u7itLyusRLBd87YF4rLN41XBkZi`ZJc#KF(rYe4_wTeruwL(q-o1^{ zMDwfmM_VtSrd4)(-n0f)16vc}vF^%TUKQQv*^%@)DR-Pp?)`#(saGXAy=Q#HRjx;lp8|g`OS_M3BgWnsK6btEl43Kk4wib6dl4z?sSEN_Hf^*>;6Fxhg)*`-UHVd zS{9de{IoTNENNNW)?24J0x?IE;K!a;ibERzhU@D|qoszJW?M`G0(EPY!^6kyv{KF) zc2;Lsa6y^S^BRBACZhVd^JxM_>fwD&c-?>~Ytm?dl8^!`EkGsU;Cc(Ct03p%U=(M2 zqT_ed59ft@#1ap62sH4jIgls*VB8%QDxNL|TTl z$*e*S&D?fQ2ns^NAS8=2S%m^r1ml?Db$n;99hZeJt2DtVt3RM6x&|h)zkzxT;4g!mT5J_k#*F7%HSLr#32{gGO&CdsTpd>*y=IXnHI# zP=NwpF-?VpE49Y-z2<}TggIBM^nPSD_2cT2P_2uTUdBdwBO~|#6Je%~QCjiDx8)t0 z85hs6mTfTGMV#UKGx4bvA$u}xB2vtnVZe!oMZN+erGgdVem!>PCga7Ju|`}Ol<;SW z)t-37lT^e=Mlo9Ya$lH$_BsfI&LAO(cU{~9gb*S~T?h&yx??t!+%iqE79ig;N#CJ; z)gL}~@SD_lb7{+4a@SZ9H+8Idal9M_t7=-S^x(yd4Yw`Oe(TxB&ECE1-IV`xN%O4d z?Yw%wO=8iJZlQO|F2-Xc;j_IVW^N?f#fupKzWqjDr!3&~|n-f=ym`7V^y|2$qQBb1guEKG| zPcVlrBsv`hEu>Q&TE&&RVy-OO>PbQ?hLHLy=LN4^9Aw~v-3gSf0zDsv(&p{=VGADp zr=P@UFQZsZZFj?iT20!&!<$>2%N{18`{Yc_B(d<#m~>SE_Hovn~z$Bb!-Z8 zavbFm*kpHyRyi6ml_TmakyWDCp*5*}wF1J>T{ZZV?h}IMAgJ#8PmYzZL71W<`wE}( zC2Bq5X;O-ocNFeN2;O%XKlTp@?iqX@Hp|X;n+Rkh@-)rmyH@N=*2c<8A6a|nWsdmS z7*DWq;PKLK^PFn@ULeaZXyyrChcGx^r#Cpd8q>Tu){|v9n=`mczQ4y7ii^RXByUV@ zz0h0EY>XdoUf5bA;J?p2grB%=2!G>e;dTdEn=@Br(ZaT|))_D1DTjp}NuCI!WLk|N z4#q-Upi?vr94fs#Oqgfc0n;XC(3ElkBK zC#TMTUh?5`*-qo58}0M}jYh3zY?m}r_o8@H#*!7gKvQ~f(FEJpzx>)r^`k_kp;brq zGwssDz%s)3H1&4%xeqF%eKdk85HTn1wH^AhX=;@N1dNDCp7;LQtku0Tqu7?ScWcXS zy7v5-^K@A(`#F;o_p`9lb{2m+R~PQ#th&kFJ$$VqxxE`JwmsXdd-|-I;@qQg@$u_V zy;X}ji0;H7#}ODs8wsglwMr3{QCga1?aD!>;6WzgBBX;#A}a2fH9Qey?)IggJ2d~7 ztL^t421vH@hGrb^LdwQMm>JIb#f;_ySF<+b**KRRYEm+i(>#?;^2*~i2JJYlVGs%r zOk5YOcAbkMQGv8xbfZEp#Eu|Rda>jZFI8e;Zv!l)wK5Qjr@xE@G0DcD#h`i_SNFTX z6*iz-!x}|hokVg{22s(ATuC>oF)Vqnw7|~n>9j%2TZisT<Dv9nrZ$<6~iK{Qz(WBH_3 z8$-6mVxh9Ie~eIAH@xRNnm5#OA$$;&=E^VYCj19;)D#1rAcKzO+B{E;j5fQMl#5wM zZzz`@>-j=@MkNJJRFMw;=sVfG2*IK6ooqSH!vbAV%J7`=%5fZdKl_(>e!P3x^?Y8g z^*o|8<~lKl7(i_?RQ~j$sF7aFkE%TW{4{I*-33`FswRYiqXa?*zO4jTj;+(#m4~P- zsv<8lAmR+IX+% zE;b)fta7NNt^s0+qK1XvuTY6;Xz(1swyRAfcN?Z1sSzwZH4fi$5BF! zPUP=)G(s|Y-`>3}C1X()M7J8T1hjQCt%-K$>!z4CwPd7iF!@81;Q8Z8mifL~?_T(M z_t7?wdh3dv&l^oQ8gqEB<=vj`eFSJ4|c0Z!nm;I7ZIbXv5UN+&5~T3fDd2 zN6~jRQZm2nL@^*I_lMWpf2;GDfW~CPG-fg~DTr)QnTxulHNaVer?ezWUFV;hd&i|_ z)oS8-zjD8+Jn~H-S>cE5-w8fFNzq+I_mpX>tWpiVbc}(o{avlR-JhlBM;83R$Yojc z`a1lcC<+lIFbw~A>w%E|;rMWes-UAgj%J1q+DqM*mc=yp$n&Fx$FUcpI2p_w+8ll=c9)Uhr8gOct|!m7QW^{T4{`QR8$hCrHLp|4};qFCa4U)DhzkHj@PTN#wB`b1_S|m@7WBE z*0Xvs8r89iDQ=I^;2yBS&F-Nz{#_E`!gFLbFsL^?2b`nb!O>ejSoE2@2wRV=e2)jw z={Y%rm>Vl)qoAso!*lHEZSTAM9t)x7HwnEjx-&etp*}Z-1T1=dsdCG-qy+>ey2Os(`)Mnl;(SU&EcBXY9{? z=K3>8;&@XlpD%15e_H(IN|Z|Vq&sU?e7&WH`3ooE*H{SCqaNgi@V)7cNR?ES>c1+d zzB5s_F75V3t*RS3TG95<-3`*w$~DZZ{^_YYZ=(sKa6caq56?!4<4Kb5Ir7?i2$TMC zUf{oru>FbJfmKOKcEhdV2`zc^OW>v*~~BBbNF#?{jR{Laf7h8%HNekhjjA@q^s3Dc3oCf?^5d+nQa?T;7du9xi3$!mGO z*gCxjN4p>I+&u5c@<+-9Zy@4$H!+}ya8NF%Z9=C}^FWZOsSB)LoSgi;BH7-gRy5tOv>bjRU8 zB3y8syU(blSC@MOK%iQ+TUUu|&g(4gJE&G7`Xi8zVe}e=by-2^D2a`}lCH4utIjkHd+&w69{KdmF&>?@Bv@4wdV|LtgrG#+)di2#T2>meg;a``$x zqM?@?PQfMAJrnl&C#OeVTbFx8$OptK2H^&oN`YVwA8WKwDTWx|{?~JfZ_zLU=QypS zQAa(D&?BoK-a1zGi7v`sNQt~4+uJ0Q3r20xKCuyk!tsVenQrJ^)}N~n&=k|Rw3D|n z`GUd@y`Y4~NU+Nym?$k?qR&F{8W;`6fvU?Ro2*j$IL#~OKR*ZV8m&>I8)C)xKR^9c zE!?#>@#ls9R7v&rGep3{W<(LT+7r53iqYSxD#Xe_p~I<#czgoxF;FpsC6K_rVo5%l z4iY1YcRCB`Y8}0`QT&buzv0h%g)!*h*7@~z0-xByVWEc?V~oTkihjBr*WnO|CJ0_9 z$fCj|=E7uM^sXaGx2wCpNs>IumX3b)Q`A)dQNPJTG3R0Nv^Q=s@$sbYONGATnDIc# zA7xj0%4Sv(JN@|PE3L(y?!zYM+jGjO@lC`W)>kyxfdH5=a1uwHt5?(tX>Z{|YC&jO z-?N_#NOaE(gCwt5dFRT0cR~{AH89ZYHJgPO21xr?g$hvYZ%=0b8uOQ{=tWe~z z2F=Xz=x`>wi;UVo=A$YphcvS8Ae^p4SVII7Ri1vk=Iy=Y>4z$ql;n%%wCKa1Q&cBI z7}T^(Etx%?ZTkhh;&%i~l}KF~D(+39eZwVVmGC*OoxQyF^ogH@#g@4U4ntHCCiIZU zzo9NniFMy@Xz`o$*P)v+_Zmuq-|qb)dueA7^XGJ?18V1Y^yS;JuBDk=lbRDjHXO*c zoX|3Q%`|dbme;g5zcY4KYWzq|7fdEGEu%=VQBnHZvKim=(u%`#eBOA~Z1?xF+_!9E zP}Z}-@1sG=Px%AztlDt3KTfQDE-M)rd3$3?;Z%NZwCw^O(+>&Zt!SUXDKWWRBQHnbFR_9gZcgL{Z?jK-gZU(rEr}qm} zgqvA^dep+ZolP;>XB1_f*4kw*UVu@mGv}Y=KHQuX&y^|BfhVapuYKN0ETIiWf`yHT zcRCvfley>$j`z84<9L|ExT4wEGM>NsTsY3q4pF_+Wt4&l>l?^54o%d$o5ozB>7sVSx+rs9@G zQ>)Ximg#xz#G$oYM~iHyp2CJX_Dog{ci`*ZS{_xSy}iw~F&eavJu8p{5LCg2<{?U9Q!a>{-9Qd?#?%ps>|MFwTURN*9OlNimnNUzLB>=dv7^!-$YqZYIWSqT8&pZ zrWxKd=CgB~_6pg`=G(1!aLUiK(E1jW8g`S9Z838cQxo}oXwLRwMf1=jtv?`)z%O6| zJN*DlGB`;#J5-C!$;5N8({}u=w`+B3$^CmLZMNs~EomzWQOH|yYgU(Ok8>|tQdGmd ztu}2nG)(kFpdK458}YdbPorrfrS@cF*&~(rrmsG>t#BUsITZz2_xzG_6=;%k z@vu%kJvrrMw@)r&J9oyYA=tLzP(07ggovuC5NMO%O>`F`vW?Um4Ra(mr`KE>IglD! zxv^L;%P}?>)oXkj|B0(9fuhkotAUy8LeLP4)JUD3o?d?**;k)XeLuNDqlx*ZIM$f` z%{nbe|Y_G%d6eYdwQ;Sy^%f zu_5~@*?5(kmxd-Re#yXUvh}k4^hB-obpHpgPP-CQ0vZbCg%X<@`j-LV@8!F7)XL!> zN{q#p1xye)rv0c7BisdT12W^x@gX1tOr<$;ELP2>_EJqV(o1Y+UlP%nziBQUS8V>e zVL0Av`~JqzbLXWq22!wAndQ_)O!z#pxscV9+|k}-OR9y3nI>h5Xv`Cs9B?{w)WW}| z*OlI+foJ`aJAtWOU3Rf~zW_JA`z38oU*bSl;fQypWjOq-lh9wKHnU>H#_q&9hY+gC zIro%)`}&EF)V=42f0ahePS96x(><{5?c2@S;-j8-<5{k@g$jQcKfg;wdiMgZ`l;lk z>q0caI0UTz18`iem{MW;lyD?v*xpz)#-L2Q__7V!)7tL1LID#erwt zYk&USJlc0$Zh!JjTibawW5XfDGjebUwX;g#rZuqXrF-9xtd(kPP>vYXkToi{kx)_w zBI347AG>I=V&AUYxD+#`&7_2LAH7XOUUuOhdc1q*8M0!E!mLnXCz(=x-c@*ih#x&! zZz?<{xa;LuiW_CmC}u(65G_w;i8#!#A0NUE@?@`jX